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 public static MLSxEntryParser getInstance() {
83 return INSTANCE;
84 }
85
86 public static FTPFile parseEntry(final String entry) {
87 return INSTANCE.parseFTPEntry(entry);
88 }
89
90
91
92
93
94
95
96
97 public static Calendar parseGMTdateTime(final String timestamp) {
98 final SimpleDateFormat dateFormat;
99 final boolean hasMillis;
100 if (timestamp.contains(".")) {
101 dateFormat = new SimpleDateFormat("yyyyMMddHHmmss.SSS");
102 hasMillis = true;
103 } else {
104 dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
105 hasMillis = false;
106 }
107 final TimeZone gmtTimeZone = TimeZone.getTimeZone("GMT");
108
109 dateFormat.setTimeZone(gmtTimeZone);
110 final GregorianCalendar gCalendar = new GregorianCalendar(gmtTimeZone);
111 final ParsePosition pos = new ParsePosition(0);
112 dateFormat.setLenient(false);
113 final Date parsed = dateFormat.parse(timestamp, pos);
114 if (pos.getIndex() != timestamp.length()) {
115 return null;
116 }
117 gCalendar.setTime(parsed);
118 if (!hasMillis) {
119 gCalendar.clear(Calendar.MILLISECOND);
120 }
121 return gCalendar;
122 }
123
124
125
126
127
128
129
130
131 public static Instant parseGmtInstant(final String timestamp) {
132 return parseGMTdateTime(timestamp).toInstant();
133 }
134
135
136
137
138 public MLSxEntryParser() {
139 }
140
141
142
143
144 private void doUnixPerms(final FTPFile file, final String valueLowerCase) {
145 for (final char c : valueLowerCase.toCharArray()) {
146
147 switch (c) {
148 case 'a':
149 file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true);
150 break;
151 case 'c':
152 file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true);
153 break;
154 case 'd':
155 file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true);
156 break;
157 case 'e':
158 file.setPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION, true);
159 break;
160 case 'f':
161
162 break;
163 case 'l':
164 file.setPermission(FTPFile.USER_ACCESS, FTPFile.EXECUTE_PERMISSION, true);
165 break;
166 case 'm':
167 file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true);
168 break;
169 case 'p':
170 file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true);
171 break;
172 case 'r':
173 file.setPermission(FTPFile.USER_ACCESS, FTPFile.READ_PERMISSION, true);
174 break;
175 case 'w':
176 file.setPermission(FTPFile.USER_ACCESS, FTPFile.WRITE_PERMISSION, true);
177 break;
178 default:
179 break;
180
181 }
182 }
183 }
184
185 @Override
186 public FTPFile parseFTPEntry(final String entry) {
187 if (entry.startsWith(" ")) {
188 if (entry.length() > 1) {
189 final FTPFile file = new FTPFile();
190 file.setRawListing(entry);
191 file.setName(entry.substring(1));
192 return file;
193 }
194 return null;
195
196 }
197 final String[] parts = entry.split(" ", 2);
198 if (parts.length != 2 || parts[1].isEmpty()) {
199 return null;
200 }
201 final String factList = parts[0];
202 if (!factList.endsWith(";")) {
203 return null;
204 }
205 final FTPFile file = new FTPFile();
206 file.setRawListing(entry);
207 file.setName(parts[1]);
208 final String[] facts = factList.split(";");
209 final boolean hasUnixMode = parts[0].toLowerCase(Locale.ENGLISH).contains("unix.mode=");
210 for (final String fact : facts) {
211 final String[] factparts = fact.split("=", -1);
212
213
214
215 if (factparts.length != 2) {
216 return null;
217 }
218 final String factname = factparts[0].toLowerCase(Locale.ENGLISH);
219 final String factvalue = factparts[1];
220 if (factvalue.isEmpty()) {
221 continue;
222 }
223 final String valueLowerCase = factvalue.toLowerCase(Locale.ENGLISH);
224 if ("size".equals(factname) || "sizd".equals(factname)) {
225 file.setSize(Long.parseLong(factvalue));
226 } else if ("modify".equals(factname)) {
227 final Calendar parsed = parseGMTdateTime(factvalue);
228 if (parsed == null) {
229 return null;
230 }
231 file.setTimestamp(parsed);
232 } else if ("type".equals(factname)) {
233 final Integer intType = TYPE_TO_INT.get(valueLowerCase);
234 if (intType == null) {
235 file.setType(FTPFile.UNKNOWN_TYPE);
236 } else {
237 file.setType(intType.intValue());
238 }
239 } else if (factname.startsWith("unix.")) {
240 final String unixfact = factname.substring("unix.".length()).toLowerCase(Locale.ENGLISH);
241 if ("group".equals(unixfact)) {
242 file.setGroup(factvalue);
243 } else if ("owner".equals(unixfact)) {
244 file.setUser(factvalue);
245 } else if ("mode".equals(unixfact)) {
246 final int off = factvalue.length() - 3;
247 for (int i = 0; i < 3; i++) {
248 final int ch = factvalue.charAt(off + i) - '0';
249 if (ch >= 0 && ch <= 7) {
250 for (final int p : UNIX_PERMS[ch]) {
251 file.setPermission(UNIX_GROUPS[i], p, true);
252 }
253 } else {
254
255 }
256 }
257 }
258 }
259 else if (!hasUnixMode && "perm".equals(factname)) {
260 doUnixPerms(file, valueLowerCase);
261 }
262 }
263 return file;
264 }
265 }