1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.net.ftp.parser;
19
20 import java.text.ParsePosition;
21 import java.text.SimpleDateFormat;
22 import java.time.Instant;
23 import java.util.Calendar;
24 import java.util.Date;
25 import java.util.GregorianCalendar;
26 import java.util.HashMap;
27 import java.util.Locale;
28 import java.util.TimeZone;
29
30 import org.apache.commons.net.ftp.FTPFile;
31 import org.apache.commons.net.ftp.FTPFileEntryParserImpl;
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 public class MLSxEntryParser extends FTPFileEntryParserImpl {
62
63 private static final MLSxEntryParser INSTANCE = new MLSxEntryParser();
64
65 private static final HashMap<String, Integer> TYPE_TO_INT = new HashMap<>();
66 static {
67 TYPE_TO_INT.put("file", Integer.valueOf(FTPFile.FILE_TYPE));
68 TYPE_TO_INT.put("cdir", Integer.valueOf(FTPFile.DIRECTORY_TYPE));
69 TYPE_TO_INT.put("pdir", Integer.valueOf(FTPFile.DIRECTORY_TYPE));
70 TYPE_TO_INT.put("dir", Integer.valueOf(FTPFile.DIRECTORY_TYPE));
71 }
72
73 private static final int[] UNIX_GROUPS = {
74 FTPFile.USER_ACCESS, FTPFile.GROUP_ACCESS, FTPFile.WORLD_ACCESS, };
75
76 private static final int[][] UNIX_PERMS = {
77 {}, { FTPFile.EXECUTE_PERMISSION }, { FTPFile.WRITE_PERMISSION },
78 { FTPFile.EXECUTE_PERMISSION, FTPFile.WRITE_PERMISSION }, { FTPFile.READ_PERMISSION },
79 { FTPFile.READ_PERMISSION, FTPFile.EXECUTE_PERMISSION }, { FTPFile.READ_PERMISSION, FTPFile.WRITE_PERMISSION },
80 { FTPFile.READ_PERMISSION, FTPFile.WRITE_PERMISSION, FTPFile.EXECUTE_PERMISSION }, };
81
82
83
84
85
86
87 public static MLSxEntryParser getInstance() {
88 return INSTANCE;
89 }
90
91
92
93
94
95
96
97
98
99 public static FTPFile parseEntry(final String entry) {
100 return INSTANCE.parseFTPEntry(entry);
101 }
102
103
104
105
106
107
108
109
110 public static Calendar parseGMTdateTime(final String timestamp) {
111 final SimpleDateFormat dateFormat;
112 final boolean hasMillis;
113 if (timestamp.contains(".")) {
114 dateFormat = new SimpleDateFormat("yyyyMMddHHmmss.SSS");
115 hasMillis = true;
116 } else {
117 dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
118 hasMillis = false;
119 }
120 final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT");
121
122 dateFormat.setTimeZone(gmtTimeZone);
123 final GregorianCalendar gCalendar = new GregorianCalendar(gmtTimeZone);
124 final ParsePosition pos = new ParsePosition(0);
125 dateFormat.setLenient(false);
126 final Date parsed = dateFormat.parse(timestamp, pos);
127 if (pos.getIndex() != timestamp.length()) {
128 return null;
129 }
130 gCalendar.setTime(parsed);
131 if (!hasMillis) {
132 gCalendar.clear(Calendar.MILLISECOND);
133 }
134 return gCalendar;
135 }
136
137
138
139
140
141
142
143
144 public static Instant parseGmtInstant(final String timestamp) {
145 return parseGMTdateTime(timestamp).toInstant();
146 }
147
148
149
150
151
152
153 @Deprecated
154 public MLSxEntryParser() {
155
156 }
157
158
159
160
161 private void doUnixPerms(final FTPFile file, final String valueLowerCase) {
162 for (final char c : valueLowerCase.toCharArray()) {
163
164 switch (c) {
165 case 'a':
166 file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true);
167 break;
168 case 'c':
169 file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true);
170 break;
171 case 'd':
172 file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true);
173 break;
174 case 'e':
175 file.setPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION, true);
176 break;
177 case 'f':
178
179 break;
180 case 'l':
181 file.setPermission(FTPFile.USER_ACCESS, FTPFile.EXECUTE_PERMISSION, true);
182 break;
183 case 'm':
184 file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true);
185 break;
186 case 'p':
187 file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true);
188 break;
189 case 'r':
190 file.setPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION, true);
191 break;
192 case 'w':
193 file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true);
194 break;
195 default:
196 break;
197
198 }
199 }
200 }
201
202 @Override
203 public FTPFile parseFTPEntry(final String entry) {
204 if (entry.startsWith(" ")) {
205 if (entry.length() > 1) {
206 final FTPFile file = new FTPFile();
207 file.setRawListing(entry);
208 file.setName(entry.substring(1));
209 return file;
210 }
211 return null;
212
213 }
214 final String[] parts = entry.split(" ", 2);
215 if (parts.length != 2 || parts[1].isEmpty()) {
216 return null;
217 }
218 final String factList = parts[0];
219 if (!factList.endsWith(";")) {
220 return null;
221 }
222 final FTPFile file = new FTPFile();
223 file.setRawListing(entry);
224 file.setName(parts[1]);
225 final String[] facts = factList.split(";");
226 final boolean hasUnixMode = parts[0].toLowerCase(Locale.ENGLISH).contains("unix.mode=");
227 for (final String fact : facts) {
228 final String[] factparts = fact.split("=", -1);
229
230
231
232 if (factparts.length != 2) {
233 return null;
234 }
235 final String factname = factparts[0].toLowerCase(Locale.ENGLISH);
236 final String factvalue = factparts[1];
237 if (factvalue.isEmpty()) {
238 continue;
239 }
240 final String valueLowerCase = factvalue.toLowerCase(Locale.ENGLISH);
241 switch (factname) {
242 case "size":
243 case "sizd":
244 file.setSize(Long.parseLong(factvalue));
245 break;
246 case "modify": {
247 final Calendar parsed = parseGMTdateTime(factvalue);
248 if (parsed == null) {
249 return null;
250 }
251 file.setTimestamp(parsed);
252 break;
253 }
254 case "type": {
255 final Integer intType = TYPE_TO_INT.get(valueLowerCase);
256 if (intType == null) {
257 file.setType(FTPFile.UNKNOWN_TYPE);
258 } else {
259 file.setType(intType.intValue());
260 }
261 break;
262 }
263 default:
264 if (factname.startsWith("unix.")) {
265 final String unixfact = factname.substring("unix.".length()).toLowerCase(Locale.ENGLISH);
266 switch (unixfact) {
267 case "group":
268 file.setGroup(factvalue);
269 break;
270 case "owner":
271 file.setUser(factvalue);
272 break;
273 case "mode": {
274 final int off = factvalue.length() - 3;
275 for (int i = 0; i < 3; i++) {
276 final int ch = factvalue.charAt(off + i) - '0';
277 if (ch >= 0 && ch <= 7) {
278 for (final int p : UNIX_PERMS[ch]) {
279 file.setPermission(UNIX_GROUPS[i], p, true);
280 }
281 } else {
282
283 }
284 }
285 break;
286 }
287 default:
288 break;
289 }
290
291 } else if (!hasUnixMode && "perm".equals(factname)) {
292 doUnixPerms(file, valueLowerCase);
293 }
294 break;
295 }
296 }
297 return file;
298 }
299 }