View Javadoc

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