1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.waarp.common.file;
21
22 import org.waarp.common.command.exception.CommandAbstractException;
23 import org.waarp.common.command.exception.Reply501Exception;
24 import org.waarp.common.command.exception.Reply530Exception;
25 import org.waarp.common.command.exception.Reply550Exception;
26 import org.waarp.common.command.exception.Reply553Exception;
27 import org.waarp.common.logging.WaarpLogger;
28 import org.waarp.common.logging.WaarpLoggerFactory;
29 import org.waarp.common.utility.DetectionUtils;
30 import org.waarp.common.utility.ParametersChecker;
31 import org.waarp.common.utility.WaarpStringUtils;
32
33 import java.io.File;
34 import java.io.IOException;
35 import java.io.UnsupportedEncodingException;
36 import java.net.URLDecoder;
37 import java.util.ArrayList;
38 import java.util.List;
39
40
41
42
43 public abstract class AbstractDir implements DirInterface {
44
45
46
47 private static final WaarpLogger logger =
48 WaarpLoggerFactory.getLogger(AbstractDir.class);
49
50
51
52 protected String currentDir;
53
54
55
56 protected SessionInterface session;
57
58
59
60
61
62 protected OptsMLSxInterface optsMLSx;
63
64
65
66 protected static final boolean ISUNIX;
67
68
69
70 protected static final File[] roots;
71
72
73
74
75 static {
76 ISUNIX = !DetectionUtils.isWindows();
77 if (!ISUNIX) {
78 roots = File.listRoots();
79 } else {
80 roots = new File[] { new File("/") };
81 }
82 }
83
84
85
86
87
88
89 protected final File getCorrespondingRoot(final File file) {
90 if (ISUNIX) {
91 return new File("/");
92 }
93 final String path = file.getAbsolutePath();
94 for (final File root : roots) {
95 if (path.startsWith(root.getAbsolutePath())) {
96 return root;
97 }
98 }
99
100 logger.warn("No root found for " + file.getAbsolutePath());
101 return roots[0];
102 }
103
104
105
106
107
108
109
110
111 public static String normalizePath(final String path) {
112 return path.replace('\\', SEPARATORCHAR);
113 }
114
115
116
117
118
119
120
121
122
123
124 public static String pathFromURI(String path) {
125
126 if (path.startsWith("file://")) {
127 int charToRemove = 7;
128
129 if (path.charAt(7) == '/' && path.charAt(9) == ':') {
130 charToRemove++;
131 }
132
133 path = path.substring(charToRemove);
134 if (path.contains("%")) {
135 try {
136 path = URLDecoder.decode(path, WaarpStringUtils.UTF8.name());
137 } catch (final UnsupportedEncodingException e) {
138 logger.warn("Cannot convert filename to UTF-8: " + path);
139 } catch (final IllegalArgumentException e) {
140
141 }
142 }
143 }
144 return path;
145 }
146
147
148
149
150 @Override
151 public final SessionInterface getSession() {
152 return session;
153 }
154
155 @Override
156 public final String validatePath(final String path)
157 throws CommandAbstractException {
158 String extDir;
159 if (isAbsolute(path)) {
160 extDir = path;
161 final File newDir = new File(extDir);
162 try {
163 return validatePath(newDir);
164 } catch (final Reply553Exception e) {
165
166 }
167 }
168 if (path.charAt(0) == SEPARATORCHAR) {
169 extDir = path;
170 } else {
171 extDir = currentDir + SEPARATOR + path;
172 }
173
174 final String baseDir = getSession().getAuth().getBaseDirectory();
175
176 final File newDir = new File(baseDir, extDir);
177 return validatePath(newDir);
178 }
179
180
181
182
183
184
185
186 public final boolean isAbsolute(final String path) {
187 File file = new File(path);
188 if (!ISUNIX) {
189 return file.isAbsolute();
190 } else {
191 file = file.getParentFile();
192 return file != null && file.isAbsolute() && file.isDirectory() &&
193 !file.getAbsolutePath().equals(File.separator);
194 }
195 }
196
197
198
199
200
201
202
203
204
205
206 protected final String consolidatePath(final String path)
207 throws CommandAbstractException {
208 if (ParametersChecker.isEmpty(path)) {
209 throw new Reply501Exception("Path must not be empty");
210 }
211
212 if (isAbsolute(path)) {
213 return normalizePath(path);
214 }
215 String extDir = normalizePath(path);
216 if (extDir.charAt(0) != SEPARATORCHAR) {
217 extDir = currentDir + SEPARATOR + extDir;
218 }
219 return extDir;
220 }
221
222
223
224
225
226
227
228
229 protected final String getCanonicalPath(final File dir) {
230 if (ISUNIX) {
231
232 final StringBuilder builder = new StringBuilder();
233
234 final List<String> list = new ArrayList<String>();
235 File newdir = dir;
236 String lastdir = newdir.getName();
237 list.add(lastdir);
238 File parent = newdir.getParentFile();
239 while (parent != null) {
240 newdir = parent;
241 lastdir = newdir.getName();
242 list.add(lastdir);
243 parent = newdir.getParentFile();
244 }
245
246 for (int i = list.size() - 1; i >= 0; i--) {
247 final String curdir = list.get(i);
248 if (".".equals(curdir)) {
249 list.remove(i);
250 } else if ("..".equals(curdir)) {
251 list.remove(i);
252 final int len = list.size();
253 if (len > 0 && i < len) {
254 list.remove(i);
255 }
256 }
257 }
258 if (list.isEmpty()) {
259 return "/";
260 }
261
262 for (int i = list.size() - 1; i >= 0; i--) {
263 builder.append('/').append(list.get(i));
264 }
265 return builder.toString();
266 }
267
268
269 try {
270 return dir.getCanonicalPath();
271 } catch (final IOException e) {
272 return dir.getAbsolutePath();
273 }
274 }
275
276
277
278
279
280
281
282
283
284
285
286
287 protected final String validatePath(final File dir)
288 throws CommandAbstractException {
289 String extDir;
290 extDir = normalizePath(getCanonicalPath(dir));
291
292 extDir = getSession().getAuth().getRelativePath(extDir);
293
294 if (getSession().getAuth().isBusinessPathValid(extDir)) {
295 return extDir;
296 }
297 throw new Reply553Exception("Pathname not allowed");
298 }
299
300 @Override
301 public final boolean isPathInCurrentDir(final String path) {
302 final String extDir;
303 if (isAbsolute(path)) {
304 extDir = path;
305 final File newDir = new File(extDir);
306 return isPathInCurrentDir(newDir);
307 }
308 if (path.charAt(0) == SEPARATORCHAR) {
309 extDir = path;
310 } else {
311 extDir = currentDir + SEPARATOR + path;
312 }
313
314 final String baseDir = getSession().getAuth().getBaseDirectory();
315
316 final File newDir = new File(baseDir, extDir);
317 return isPathInCurrentDir(newDir);
318 }
319
320
321
322
323
324
325
326
327
328
329 protected final boolean isPathInCurrentDir(final File dir) {
330 String extDir;
331 extDir = normalizePath(getCanonicalPath(dir));
332
333 extDir = getSession().getAuth().getRelativePath(extDir);
334
335 if (extDir.startsWith(currentDir)) {
336 return true;
337 }
338 logger.warn("File not OK: {} not in {}", extDir, currentDir);
339 return false;
340 }
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359 protected abstract List<String> wildcardFiles(String pathWithWildcard)
360 throws CommandAbstractException;
361
362 @Override
363 public final String getPwd() {
364 return currentDir;
365 }
366
367 @Override
368 public final boolean changeParentDirectory() throws CommandAbstractException {
369 return changeDirectory("..");
370 }
371
372 @Override
373 public FileInterface setFile(final String path, final boolean append)
374 throws CommandAbstractException {
375 checkIdentify();
376 final String newpath = consolidatePath(path);
377 final List<String> paths = wildcardFiles(newpath);
378 if (paths.size() != 1) {
379 throw new Reply550Exception(
380 "File not found: " + paths.size() + " founds");
381 }
382 final String extDir = paths.get(0);
383 return newFile(extDir, append);
384 }
385
386 @Override
387 public final void checkIdentify() throws Reply530Exception {
388 if (!getSession().getAuth().isIdentified()) {
389 throw new Reply530Exception("User not authentified");
390 }
391 }
392
393 @Override
394 public final void clear() {
395 currentDir = null;
396 }
397
398 @Override
399 public final void initAfterIdentification() {
400 currentDir = getSession().getAuth().getBusinessPath();
401 }
402
403 @Override
404 public final OptsMLSxInterface getOptsMLSx() {
405 return optsMLSx;
406 }
407
408 }