1
2
3
4
5
6
7
8
9
10
11
12
13
14
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";
43
44 static final String DEFAULT_RECENT_DATE_FORMAT
45 = "MMM d HH:mm";
46
47 static final String NUMERIC_DATE_FORMAT
48 = "yyyy-MM-dd HH:mm";
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
97
98 + "((?:\\d+[-/]\\d+[-/]\\d+)|(?:\\S+\\s+\\S+))\\s+"
99
100
101
102
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;
175 }
176
177
178
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
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
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
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
243 }
244
245 if (null == endtoken)
246 {
247 file.setName(name);
248 }
249 else
250 {
251
252
253 name += endtoken;
254 if (type == FTPFile.SYMBOLIC_LINK_TYPE)
255 {
256
257 int end = name.indexOf(" -> ");
258
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 }