View Javadoc

    1   /*
    2    * Copyright 2001-2005 The Apache Software Foundation
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *     http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  package org.apache.commons.net.ftp.parser;
    17  import java.text.ParseException;
    18
    19  import org.apache.commons.net.ftp.FTPClientConfig;
    20  import org.apache.commons.net.ftp.FTPFile;
    21
    22  /***
    23   * Implementation FTPFileEntryParser and FTPFileListParser for standard
    24   * Unix Systems.
    25   *
    26   * This class is based on the logic of Daniel Savarese's
    27   * DefaultFTPListParser, but adapted to use regular expressions and to fit the
    28   * new FTPFileEntryParser interface.
    29   * @version $Id: UnixFTPEntryParser.java 161712 2005-04-18 02:57:04Z scohen $
    30   * @see org.apache.commons.net.ftp.FTPFileEntryParser FTPFileEntryParser (for usage instructions)
    31   */
    32  public class UnixFTPEntryParser extends ConfigurableFTPFileEntryParserImpl
    33  {
    34      /***
    35       * months abbreviations looked for by this parser.  Also used
    36       * to determine which month is matched by the parser
    37       */
    38      private static final String DEFAULT_MONTHS =
    39          "(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)";
    40
    41      static final String DEFAULT_DATE_FORMAT
    42  		= "MMM d yyyy"; //Nov 9 2001
    43
    44      static final String DEFAULT_RECENT_DATE_FORMAT
    45  		= "MMM d HH:mm"; //Nov 9 20:06
    46
    47      static final String NUMERIC_DATE_FORMAT
    48  		= "yyyy-MM-dd HH:mm"; //2001-11-09 20:06
    49
    50      /***
    51       * Some Linux distributions are now shipping an FTP server which formats
    52       * file listing dates in an all-numeric format:
    53       * <code>"yyyy-MM-dd HH:mm</code>.
    54       * This is a very welcome development,  and hopefully it will soon become
    55       * the standard.  However, since it is so new, for now, and possibly
    56       * forever, we merely accomodate it, but do not make it the default.
    57       * <p>
    58       * For now end users may specify this format only via
    59       * <code>UnixFTPEntryParser(FTPClientConfig)</code>.
    60       * Steve Cohen - 2005-04-17
    61       */
    62      public static final FTPClientConfig NUMERIC_DATE_CONFIG =
    63          new FTPClientConfig(
    64                  FTPClientConfig.SYST_UNIX,
    65                  NUMERIC_DATE_FORMAT,
    66                  null, null, null, null);
    67
    68      /***
    69       * this is the regular expression used by this parser.
    70       *
    71       * Permissions:
    72       *    r   the file is readable
    73       *    w   the file is writable
    74       *    x   the file is executable
    75       *    -   the indicated permission is not granted
    76       *    L   mandatory locking occurs during access (the set-group-ID bit is
    77       *        on and the group execution bit is off)
    78       *    s   the set-user-ID or set-group-ID bit is on, and the corresponding
    79       *        user or group execution bit is also on
    80       *    S   undefined bit-state (the set-user-ID bit is on and the user
    81       *        execution bit is off)
    82       *    t   the 1000 (octal) bit, or sticky bit, is on [see chmod(1)], and
    83       *        execution is on
    84       *    T   the 1000 bit is turned on, and execution is off (undefined bit-
    85       *        state)
    86       */
    87      private static final String REGEX =
    88          "([bcdlfmpSs-])"
    89          +"(((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-]))((r|-)(w|-)([xsStTL-])))//+?//s+"
    90          + "(//d+)//s+"
    91          + "(//S+)//s+"
    92          + "(?:(//S+)//s+)?"
    93          + "(//d+)//s+"
    94
    95          /*
    96            numeric or standard format date
    97          */
    98          + "((?://d+[-/]//d+[-/]//d+)|(?://S+//s+//S+))//s+"
    99
    100         /*
    101            year (for non-recent standard format)
    102 		   or time (for numeric or recent standard format
    103 		*/
    104 		+ "(//d+(?:://d+)?)//s+"
    105
    106 		+ "(//S*)(//s*.*)";
    107
    108
    109     /***
    110      * The default constructor for a UnixFTPEntryParser object.
    111      *
    112      * @exception IllegalArgumentException
    113      * Thrown if the regular expression is unparseable.  Should not be seen
    114      * under normal conditions.  It it is seen, this is a sign that
    115      * <code>REGEX</code> is  not a valid regular expression.
    116      */
    117     public UnixFTPEntryParser()
    118     {
    119         this(null);
    120     }
    121
    122     /***
    123      * This constructor allows the creation of a UnixFTPEntryParser object with
    124      * something other than the default configuration.
    125      *
    126      * @param config The {@link FTPClientConfig configuration} object used to
    127      * configure this parser.
    128      * @exception IllegalArgumentException
    129      * Thrown if the regular expression is unparseable.  Should not be seen
    130      * under normal conditions.  It it is seen, this is a sign that
    131      * <code>REGEX</code> is  not a valid regular expression.
    132      * @since 1.4
    133      */
    134     public UnixFTPEntryParser(FTPClientConfig config)
    135     {
    136         super(REGEX);
    137         configure(config);
    138     }
    139
    140
    141     /***
    142      * Parses a line of a unix (standard) FTP server file listing and converts
    143      * it into a usable format in the form of an <code> FTPFile </code>
    144      * instance.  If the file listing line doesn't describe a file,
    145      * <code> null </code> is returned, otherwise a <code> FTPFile </code>
    146      * instance representing the files in the directory is returned.
    147      * <p>
    148      * @param entry A line of text from the file listing
    149      * @return An FTPFile instance corresponding to the supplied entry
    150      */
    151 	public FTPFile parseFTPEntry(String entry) {
    152         FTPFile file = new FTPFile();
    153         file.setRawListing(entry);
    154         int type;
    155         boolean isDevice = false;
    156
    157         if (matches(entry))
    158         {
    159             String typeStr = group(1);
    160             String hardLinkCount = group(15);
    161             String usr = group(16);
    162             String grp = group(17);
    163             String filesize = group(18);
    164             String datestr = group(19) + " " + group(20);
    165             String name = group(21);
    166             String endtoken = group(22);
    167
    168             try
    169             {
    170                 file.setTimestamp(super.parseTimestamp(datestr));
    171             }
    172             catch (ParseException e)
    173             {
    174             	return null;  // this is a parsing failure too.
    175             }
    176
    177
    178             // bcdlfmpSs-
    179             switch (typeStr.charAt(0))
    180             {
    181             case 'd':
    182                 type = FTPFile.DIRECTORY_TYPE;
    183                 break;
    184             case 'l':
    185                 type = FTPFile.SYMBOLIC_LINK_TYPE;
    186                 break;
    187             case 'b':
    188             case 'c':
    189                 isDevice = true;
    190                 // break; - fall through
    191             case 'f':
    192             case '-':
    193             	type = FTPFile.FILE_TYPE;
    194             	break;
    195             default:
    196                 type = FTPFile.UNKNOWN_TYPE;
    197             }
    198
    199             file.setType(type);
    200
    201             int g = 4;
    202             for (int access = 0; access < 3; access++, g += 4)
    203             {
    204                 // Use != '-' to avoid having to check for suid and sticky bits
    205                 file.setPermission(access, FTPFile.READ_PERMISSION,
    206                                    (!group(g).equals("-")));
    207                 file.setPermission(access, FTPFile.WRITE_PERMISSION,
    208                                    (!group(g + 1).equals("-")));
    209
    210                 String execPerm = group(g + 2);
    211                 if (!execPerm.equals("-") && !Character.isUpperCase(execPerm.charAt(0)))
    212                 {
    213                     file.setPermission(access, FTPFile.EXECUTE_PERMISSION, true);
    214                 }
    215                 else
    216                 {
    217                     file.setPermission(access, FTPFile.EXECUTE_PERMISSION, false);
    218                 }
    219             }
    220
    221             if (!isDevice)
    222             {
    223                 try
    224                 {
    225                     file.setHardLinkCount(Integer.parseInt(hardLinkCount));
    226                 }
    227                 catch (NumberFormatException e)
    228                 {
    229                     // intentionally do nothing
    230                 }
    231             }
    232
    233             file.setUser(usr);
    234             file.setGroup(grp);
    235
    236             try
    237             {
    238                 file.setSize(Long.parseLong(filesize));
    239             }
    240             catch (NumberFormatException e)
    241             {
    242                 // intentionally do nothing
    243             }
    244
    245             if (null == endtoken)
    246             {
    247                 file.setName(name);
    248             }
    249             else
    250             {
    251                 // oddball cases like symbolic links, file names
    252                 // with spaces in them.
    253                 name += endtoken;
    254                 if (type == FTPFile.SYMBOLIC_LINK_TYPE)
    255                 {
    256
    257                     int end = name.indexOf(" -> ");
    258                     // Give up if no link indicator is present
    259                     if (end == -1)
    260                     {
    261                         file.setName(name);
    262                     }
    263                     else
    264                     {
    265                         file.setName(name.substring(0, end));
    266                         file.setLink(name.substring(end + 4));
    267                     }
    268
    269                 }
    270                 else
    271                 {
    272                     file.setName(name);
    273                 }
    274             }
    275             return file;
    276         }
    277         return null;
    278 	}
    279
    280     /***
    281      * Defines a default configuration to be used when this class is
    282      * instantiated without a {@link  FTPClientConfig  FTPClientConfig}
    283      * parameter being specified.
    284      * @return the default configuration for this parser.
    285      */
    286     protected FTPClientConfig getDefaultConfiguration() {
    287         return new FTPClientConfig(
    288                 FTPClientConfig.SYST_UNIX,
    289                 DEFAULT_DATE_FORMAT,
    290                 DEFAULT_RECENT_DATE_FORMAT,
    291                 null, null, null);
    292     }
    293
    294
    295
    296
    297 }