1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.net.ftp.parser;
18
19 import java.util.Calendar;
20
21 import org.apache.commons.net.ftp.FTPFile;
22 import org.apache.commons.net.ftp.FTPFileEntryParser;
23
24
25
26 public class UnixFTPEntryParserTest extends AbstractFTPParseTest {
27
28 private static final String[] badsamples = { "zrwxr-xr-x 2 root root 4096 Mar 2 15:13 zxbox",
29 "dxrwr-xr-x 2 root root 4096 Aug 24 2001 zxjdbc", "drwxr-xr-x 2 root root 4096 Jam 4 00:03 zziplib",
30 "drwxr-xr-x 2 root 99 4096 Feb 23 30:01 zzplayer", "drwxr-xr-x 2 root root 4096 Aug 36 2001 zztpp",
31 "-rw-r--r-- 1 14 staff 80284 Aug 22 zxJDBC-1.2.3.tar.gz", "-rw-r--r-- 1 14 staff 119:26 Aug 22 2000 zxJDBC-1.2.3.zip",
32
33 "-rw-r--r-- 1ftp nogroup 126552 Jan 22 2001 zxJDBC-1.2.4.zip",
34 "-rw-r--r-- 1 root root 190144 2001-04-27 zxJDBC-2.0.1b1.zip",
35 "-rw-r--r-- 1 root root 111325 Apr -7 18:79 zxJDBC-2.0.1b1.tar.gz" };
36
37 private static final String[] goodsamples = { "-rw-r--r-- 1 500 500 21 Aug 8 14:14 JB3-TES1.gz",
38 "-rwxr-xr-x 2 root root 4096 Mar 2 15:13 zxbox", "drwxr-xr-x 2 root root 4096 Aug 24 2001 zxjdbc",
39 "drwxr-xr-x 2 root root 4096 Jan 4 00:03 zziplib", "drwxr-xr-x 2 root 99 4096 Feb 23 2001 zzplayer",
40 "drwxr-xr-x 2 root root 4096 Aug 6 2001 zztpp", "drwxr-xr-x 1 usernameftp 512 Jan 29 23:32 prog",
41 "lrw-r--r-- 1 14 14 80284 Aug 22 2000 zxJDBC-1.2.3.tar.gz",
42 "frw-r--r-- 1 14 staff 119926 Aug 22 2000 zxJDBC-1.2.3.zip",
43 "crw-r--r-- 1 ftp nogroup 83853 Jan 22 2001 zxJDBC-1.2.4.tar.gz",
44 "brw-r--r-- 1 ftp nogroup 126552 Jan 22 2001 zxJDBC-1.2.4.zip",
45 "-rw-r--r-- 1 root root 111325 Apr 27 2001 zxJDBC-2.0.1b1.tar.gz",
46 "-rw-r--r-- 1 root root 190144 Apr 27 2001 zxJDBC-2.0.1b1.zip",
47 "-rwxr-xr-x 2 500 500 166 Nov 2 2001 73131-testtes1.afp",
48 "-rw-r--r-- 1 500 500 166 Nov 9 2001 73131-testtes1.AFP",
49 "-rw-r--r-- 1 500 500 166 Nov 12 2001 73131-testtes2.afp",
50 "-rw-r--r-- 1 500 500 166 Nov 12 2001 73131-testtes2.AFP",
51 "-rw-r--r-- 1 500 500 2040000 Aug 5 07:35 testRemoteUPCopyNIX",
52 "-rw-r--r-- 1 500 500 2040000 Aug 5 07:31 testRemoteUPDCopyNIX",
53 "-rw-r--r-- 1 500 500 2040000 Aug 5 07:31 testRemoteUPVCopyNIX", "-rw-r--r-T 1 500 500 0 Mar 25 08:20 testSticky",
54 "-rwxr-xr-t 1 500 500 0 Mar 25 08:21 testStickyExec", "-rwSr-Sr-- 1 500 500 0 Mar 25 08:22 testSuid",
55 "-rwsr-sr-- 1 500 500 0 Mar 25 08:23 testSuidExec", "-rwsr-sr-- 1 500 500 0 Mar 25 0:23 testSuidExec2",
56 "drwxrwx---+ 23 500 500 0 Jan 10 13:09 testACL", "-rw-r--r-- 1 1 3518644 May 25 12:12 std",
57 "lrwxrwxrwx 1 neeme neeme 23 Mar 2 18:06 macros -> ./../../global/macros/.",
58 "-rw-r--r-- 1 ftp group with spaces in it as allowed in cygwin see bug 38634" + " 83853 Jan 22 2001 zxJDBC-1.2.4.tar.gz",
59
60 "crw-r----- 1 root kmem 0, 27 Jan 30 11:42 kmem",
61 "crw------- 1 root sys 109,767 Jul 2 2004 pci@1c,600000:devctl",
62 "-rwxrwx--- 1 ftp ftp-admin 816026400 Oct 5 2008 bloplab 7 cd1.img",
63
64
65 "-rw-r--r-- 1 1 3518644 May 25 12:12 std", "-rw-rw---- 1 ep1adm sapsys 0 6\u6708 3\u65e5 2003\u5e74 \u8a66\u9a13\u30d5\u30a1\u30a4\u30eb.csv",
66 "-rw-rw---- 1 ep1adm sapsys 0 8\u6708 17\u65e5 20:10 caerrinf",
67
68 };
69
70 public UnixFTPEntryParserTest(final String name) {
71 super(name);
72 }
73
74 private void checkPermissions(final FTPFile f) {
75 assertTrue("Should have user read permission.", f.hasPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION));
76 assertTrue("Should have user write permission.", f.hasPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION));
77 assertTrue("Should have user execute permission.", f.hasPermission(FTPFile.USER_ACCESS, FTPFile.EXECUTE_PERMISSION));
78 assertTrue("Should have group read permission.", f.hasPermission(FTPFile.GROUP_ACCESS, FTPFile.READ_PERMISSION));
79 assertFalse("Should NOT have group write permission.", f.hasPermission(FTPFile.GROUP_ACCESS, FTPFile.WRITE_PERMISSION));
80 assertTrue("Should have group execute permission.", f.hasPermission(FTPFile.GROUP_ACCESS, FTPFile.EXECUTE_PERMISSION));
81 assertTrue("Should have world read permission.", f.hasPermission(FTPFile.WORLD_ACCESS, FTPFile.READ_PERMISSION));
82 assertFalse("Should NOT have world write permission.", f.hasPermission(FTPFile.WORLD_ACCESS, FTPFile.WRITE_PERMISSION));
83 assertTrue("Should have world execute permission.", f.hasPermission(FTPFile.WORLD_ACCESS, FTPFile.EXECUTE_PERMISSION));
84 }
85
86 @Override
87 protected void doAdditionalGoodTests(final String test, final FTPFile f) {
88 final String link = f.getLink();
89 if (null != link) {
90 final int linklen = link.length();
91 if (linklen > 0) {
92 assertEquals(link, test.substring(test.length() - linklen));
93 assertEquals(f.getType(), FTPFile.SYMBOLIC_LINK_TYPE);
94 }
95 }
96 final int type = f.getType();
97 switch (test.charAt(0)) {
98 case 'd':
99 assertEquals("Type of " + test, type, FTPFile.DIRECTORY_TYPE);
100 break;
101 case 'l':
102 assertEquals("Type of " + test, type, FTPFile.SYMBOLIC_LINK_TYPE);
103 break;
104 case 'b':
105 case 'c':
106 assertEquals(0, f.getHardLinkCount());
107
108 case 'f':
109 case '-':
110 assertEquals("Type of " + test, type, FTPFile.FILE_TYPE);
111 break;
112 default:
113 assertEquals("Type of " + test, type, FTPFile.UNKNOWN_TYPE);
114 }
115
116 for (int access = FTPFile.USER_ACCESS; access <= FTPFile.WORLD_ACCESS; access++) {
117 for (int perm = FTPFile.READ_PERMISSION; perm <= FTPFile.EXECUTE_PERMISSION; perm++) {
118 final int pos = 3 * access + perm + 1;
119 final char permchar = test.charAt(pos);
120 assertEquals("Permission " + test.substring(1, 10), Boolean.valueOf(f.hasPermission(access, perm)),
121 Boolean.valueOf(permchar != '-' && !Character.isUpperCase(permchar)));
122 }
123 }
124
125 assertNotNull("Expected to find a timestamp", f.getTimestamp());
126
127
128 }
129
130 @Override
131 protected String[] getBadListing() {
132 return badsamples;
133 }
134
135 @Override
136 protected String[] getGoodListing() {
137 return goodsamples;
138 }
139
140 @Override
141 protected FTPFileEntryParser getParser() {
142 return new UnixFTPEntryParser();
143 }
144
145 public void testCorrectGroupNameParsing() {
146 final FTPFile f = getParser().parseFTPEntry("-rw-r--r-- 1 ftpuser ftpusers 12414535 Mar 17 11:07 test 1999 abc.pdf");
147 assertNotNull(f);
148 assertEquals(1, f.getHardLinkCount());
149 assertEquals("ftpuser", f.getUser());
150 assertEquals("ftpusers", f.getGroup());
151 assertEquals(12414535, f.getSize());
152 assertEquals("test 1999 abc.pdf", f.getName());
153
154 final Calendar cal = Calendar.getInstance();
155 cal.set(Calendar.MONTH, Calendar.MARCH);
156 cal.set(Calendar.DAY_OF_MONTH, 17);
157 cal.set(Calendar.HOUR_OF_DAY, 11);
158 cal.set(Calendar.MINUTE, 7);
159 cal.set(Calendar.SECOND, 0);
160 cal.set(Calendar.MILLISECOND, 0);
161
162 assertEquals(f.getTimestamp().get(Calendar.MONTH), cal.get(Calendar.MONTH));
163 assertEquals(f.getTimestamp().get(Calendar.DAY_OF_MONTH), cal.get(Calendar.DAY_OF_MONTH));
164 assertEquals(f.getTimestamp().get(Calendar.HOUR_OF_DAY), cal.get(Calendar.HOUR_OF_DAY));
165 assertEquals(f.getTimestamp().get(Calendar.MINUTE), cal.get(Calendar.MINUTE));
166 assertEquals(f.getTimestamp().get(Calendar.SECOND), cal.get(Calendar.SECOND));
167 }
168
169 @Override
170 public void testDefaultPrecision() {
171 testPrecision("drwxr-xr-x 2 user group 4096 Mar 2 2014 zxbox", CalendarUnit.DAY_OF_MONTH);
172 }
173
174 public void testFilenamesWithEmbeddedNumbers() {
175 final FTPFile f = getParser().parseFTPEntry("-rw-rw-rw- 1 user group 5840 Mar 19 09:34 123 456 abc.csv");
176 assertEquals("123 456 abc.csv", f.getName());
177 assertEquals(5840, f.getSize());
178 assertEquals("user", f.getUser());
179 assertEquals("group", f.getGroup());
180 }
181
182 public void testGroupNameWithSpaces() {
183 final FTPFile f = getParser().parseFTPEntry("drwx------ 4 maxm Domain Users 512 Oct 2 10:59 .metadata");
184 assertNotNull(f);
185 assertEquals("maxm", f.getUser());
186 assertEquals("Domain Users", f.getGroup());
187 }
188
189 public void testLeadingSpacesDefault() {
190 final FTPFile f = getParser().parseFTPEntry("drwxr-xr-x 2 john smith group 4096 Mar 2 15:13 zxbox");
191 assertNotNull(f);
192 assertEquals(" zxbox", f.getName());
193 }
194
195 public void testLeadingSpacesNET566() {
196 final FTPFile f = new UnixFTPEntryParser(null, false).parseFTPEntry("drwxr-xr-x 2 john smith group 4096 Mar 2 15:13 zxbox");
197 assertNotNull(f);
198 assertEquals(" zxbox", f.getName());
199 }
200
201 public void testNameWIthPunctuation() {
202 final FTPFile f = getParser().parseFTPEntry("drwx------ 4 maxm Domain Users 512 Oct 2 10:59 abc(test)123.pdf");
203 assertNotNull(f);
204 assertEquals("abc(test)123.pdf", f.getName());
205 }
206
207 public void testNET294() {
208 final FTPFile f = getParser().parseFTPEntry("-rwxrwx--- 1 ftp ftp-admin 816026400 Oct 5 2008 bloplab 7 cd1.img");
209 assertNotNull(f);
210 assertEquals("ftp", f.getUser());
211 assertEquals("ftp-admin", f.getGroup());
212 assertEquals(816026400L, f.getSize());
213 assertNotNull("Timestamp should not be null", f.getTimestamp());
214 assertEquals(2008, f.getTimestamp().get(Calendar.YEAR));
215 assertEquals("bloplab 7 cd1.img", f.getName());
216 }
217
218 public void testNoSpacesBeforeFileSize() {
219 final FTPFile f = getParser().parseFTPEntry("drwxr-x---+1464 chrism chrism 41472 Feb 25 13:17 20090225");
220 assertNotNull(f);
221 assertEquals(41472, f.getSize());
222 assertEquals(f.getType(), FTPFile.DIRECTORY_TYPE);
223 assertEquals("chrism", f.getUser());
224 assertEquals("chrism", f.getGroup());
225 assertEquals(1464, f.getHardLinkCount());
226 }
227
228 public void testNumericDateFormat() {
229 final String testNumericDF = "-rw-r----- 1 neeme neeme 346 2005-04-08 11:22 services.vsp";
230 final String testNumericDF2 = "lrwxrwxrwx 1 neeme neeme 23 2005-03-02 18:06 macros -> ./../../global/macros/.";
231
232 final UnixFTPEntryParser parser = new UnixFTPEntryParser(UnixFTPEntryParser.NUMERIC_DATE_CONFIG);
233
234 final FTPFile f = parser.parseFTPEntry(testNumericDF);
235 assertNotNull("Failed to parse " + testNumericDF, f);
236
237 final Calendar cal = Calendar.getInstance();
238 cal.clear();
239 cal.set(Calendar.YEAR, 2005);
240 cal.set(Calendar.MONTH, Calendar.APRIL);
241
242 cal.set(Calendar.DAY_OF_MONTH, 8);
243 cal.set(Calendar.HOUR_OF_DAY, 11);
244 cal.set(Calendar.MINUTE, 22);
245 assertEquals(cal.getTime(), f.getTimestamp().getTime());
246
247 final FTPFile f2 = parser.parseFTPEntry(testNumericDF2);
248 assertNotNull("Failed to parse " + testNumericDF2, f2);
249 assertEquals("symbolic link", "./../../global/macros/.", f2.getLink());
250
251 }
252
253 public void testOwnerAndGroupNameWithSpaces() {
254 final FTPFile f = getParser().parseFTPEntry("drwxr-xr-x 2 john smith test group 4096 Mar 2 15:13 zxbox");
255 assertNotNull(f);
256 assertEquals("john smith", f.getUser());
257 assertEquals("test group", f.getGroup());
258 }
259
260 public void testOwnerNameWithSpaces() {
261 final FTPFile f = getParser().parseFTPEntry("drwxr-xr-x 2 john smith group 4096 Mar 2 15:13 zxbox");
262 assertNotNull(f);
263 assertEquals("john smith", f.getUser());
264 }
265
266 @Override
267 public void testParseFieldsOnDirectory() throws Exception {
268 final FTPFile f = getParser().parseFTPEntry("drwxr-xr-x 2 user group 4096 Mar 2 15:13 zxbox");
269 assertNotNull("Could not parse entry.", f);
270 assertTrue("Should have been a directory.", f.isDirectory());
271 checkPermissions(f);
272 assertEquals(2, f.getHardLinkCount());
273 assertEquals("user", f.getUser());
274 assertEquals("group", f.getGroup());
275 assertEquals("zxbox", f.getName());
276 assertEquals(4096, f.getSize());
277
278 final Calendar cal = Calendar.getInstance();
279 cal.set(Calendar.MONTH, Calendar.MARCH);
280
281 cal.set(Calendar.DAY_OF_MONTH, 1);
282 cal.set(Calendar.HOUR_OF_DAY, 0);
283 cal.set(Calendar.MINUTE, 0);
284 cal.set(Calendar.SECOND, 0);
285 if (f.getTimestamp().getTime().before(cal.getTime())) {
286 cal.add(Calendar.YEAR, -1);
287 }
288 cal.set(Calendar.DAY_OF_MONTH, 2);
289 cal.set(Calendar.HOUR_OF_DAY, 15);
290 cal.set(Calendar.MINUTE, 13);
291
292 assertEquals(df.format(cal.getTime()), df.format(f.getTimestamp().getTime()));
293 }
294
295 @Override
296 public void testParseFieldsOnFile() throws Exception {
297 final FTPFile f = getParser().parseFTPEntry("-rwxr-xr-x 2 user my group 500 5000000000 Mar 2 15:13 zxbox");
298 assertNotNull("Could not parse entry.", f);
299 assertTrue("Should have been a file.", f.isFile());
300 checkPermissions(f);
301 assertEquals(2, f.getHardLinkCount());
302 assertEquals("user", f.getUser());
303 assertEquals("my group 500", f.getGroup());
304 assertEquals("zxbox", f.getName());
305 assertEquals(5000000000L, f.getSize());
306
307 final Calendar cal = Calendar.getInstance();
308 cal.set(Calendar.MONTH, Calendar.MARCH);
309
310 cal.set(Calendar.DAY_OF_MONTH, 1);
311 cal.set(Calendar.HOUR_OF_DAY, 0);
312 cal.set(Calendar.MINUTE, 0);
313 cal.set(Calendar.SECOND, 0);
314 if (f.getTimestamp().getTime().before(cal.getTime())) {
315 cal.add(Calendar.YEAR, -1);
316 }
317 cal.set(Calendar.DAY_OF_MONTH, 2);
318 cal.set(Calendar.HOUR_OF_DAY, 15);
319 cal.set(Calendar.MINUTE, 13);
320 assertEquals(df.format(cal.getTime()), df.format(f.getTimestamp().getTime()));
321 }
322
323
324 public void testParseFieldsOnFileJapaneseTime() {
325 final FTPFile f = getParser().parseFTPEntry("-rwxr-xr-x 2 user group 4096 3\u6708 2\u65e5 15:13 zxbox");
326 assertNotNull("Could not parse entry.", f);
327 assertTrue("Should have been a file.", f.isFile());
328 checkPermissions(f);
329 assertEquals(2, f.getHardLinkCount());
330 assertEquals("user", f.getUser());
331 assertEquals("group", f.getGroup());
332 assertEquals("zxbox", f.getName());
333 assertEquals(4096, f.getSize());
334
335 assertNotNull("Timestamp not null", f.getTimestamp());
336 final Calendar cal = Calendar.getInstance();
337 cal.set(Calendar.MONTH, Calendar.MARCH);
338 cal.set(Calendar.DATE, 1);
339 cal.set(Calendar.HOUR_OF_DAY, 0);
340 cal.set(Calendar.MINUTE, 0);
341 cal.set(Calendar.SECOND, 0);
342 if (f.getTimestamp().getTime().before(cal.getTime())) {
343 cal.add(Calendar.YEAR, -1);
344 }
345 cal.set(Calendar.DATE, 2);
346 cal.set(Calendar.HOUR_OF_DAY, 15);
347 cal.set(Calendar.MINUTE, 13);
348 assertEquals(df.format(cal.getTime()), df.format(f.getTimestamp().getTime()));
349 }
350
351
352 public void testParseFieldsOnFileJapaneseYear() {
353 final FTPFile f = getParser().parseFTPEntry("-rwxr-xr-x 2 user group 4096 3\u6708 2\u65e5 2003\u5e74 \u8a66\u9a13\u30d5\u30a1\u30a4\u30eb.csv");
354 assertNotNull("Could not parse entry.", f);
355 assertTrue("Should have been a file.", f.isFile());
356 checkPermissions(f);
357 assertEquals(2, f.getHardLinkCount());
358 assertEquals("user", f.getUser());
359 assertEquals("group", f.getGroup());
360 assertEquals("\u8a66\u9a13\u30d5\u30a1\u30a4\u30eb.csv", f.getName());
361 assertEquals(4096, f.getSize());
362
363 assertNotNull("Timestamp not null", f.getTimestamp());
364 final Calendar cal = Calendar.getInstance();
365 cal.set(Calendar.YEAR, 2003);
366 cal.set(Calendar.MONTH, Calendar.MARCH);
367 cal.set(Calendar.DATE, 2);
368 cal.set(Calendar.HOUR_OF_DAY, 0);
369 cal.set(Calendar.MINUTE, 0);
370 cal.set(Calendar.SECOND, 0);
371 assertEquals(df.format(cal.getTime()), df.format(f.getTimestamp().getTime()));
372 }
373
374 @Override
375 public void testRecentPrecision() {
376 testPrecision("drwxr-xr-x 2 user group 4096 Mar 2 15:13 zxbox", CalendarUnit.MINUTE);
377 }
378
379 public void testTrailingSpaces() {
380 final FTPFile f = getParser().parseFTPEntry("drwxr-xr-x 2 john smith group 4096 Mar 2 15:13 zxbox ");
381 assertNotNull(f);
382 assertEquals("zxbox ", f.getName());
383 }
384
385 public void testTrimLeadingSpacesNET566() {
386 final FTPFile f = new UnixFTPEntryParser(null, true).parseFTPEntry("drwxr-xr-x 2 john smith group 4096 Mar 2 15:13 zxbox");
387 assertNotNull(f);
388 assertEquals("zxbox", f.getName());
389 }
390 }