1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.util.resource;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.net.MalformedURLException;
25 import java.net.URI;
26 import java.net.URISyntaxException;
27 import java.net.URL;
28 import java.nio.channels.FileChannel;
29 import java.nio.channels.ReadableByteChannel;
30 import java.nio.file.DirectoryIteratorException;
31 import java.nio.file.DirectoryStream;
32 import java.nio.file.Files;
33 import java.nio.file.InvalidPathException;
34 import java.nio.file.LinkOption;
35 import java.nio.file.Path;
36 import java.nio.file.StandardOpenOption;
37 import java.nio.file.attribute.FileTime;
38 import java.util.ArrayList;
39 import java.util.List;
40
41 import org.eclipse.jetty.util.IO;
42 import org.eclipse.jetty.util.URIUtil;
43 import org.eclipse.jetty.util.log.Log;
44 import org.eclipse.jetty.util.log.Logger;
45
46
47
48
49 public class PathResource extends Resource
50 {
51 private static final Logger LOG = Log.getLogger(PathResource.class);
52 private final static LinkOption NO_FOLLOW_LINKS[] = new LinkOption[] { LinkOption.NOFOLLOW_LINKS };
53 private final static LinkOption FOLLOW_LINKS[] = new LinkOption[] {};
54
55 private final Path path;
56 private final Path alias;
57 private final URI uri;
58
59 private static final Path checkAliasPath(final Path path)
60 {
61 Path abs = path;
62 if (!abs.isAbsolute())
63 {
64 abs = path.toAbsolutePath();
65 }
66
67 try
68 {
69 if (Files.isSymbolicLink(path))
70 return Files.readSymbolicLink(path);
71 if (Files.exists(path))
72 {
73 Path real = abs.toRealPath(FOLLOW_LINKS);
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109 int absCount = abs.getNameCount();
110 int realCount = real.getNameCount();
111 if (absCount != realCount)
112 {
113
114 return real;
115 }
116
117
118 for (int i = realCount-1; i >= 0; i--)
119 {
120 if (!abs.getName(i).toString().equals(real.getName(i).toString()))
121 {
122 return real;
123 }
124 }
125 }
126 }
127 catch (IOException e)
128 {
129 LOG.ignore(e);
130 }
131 catch (Exception e)
132 {
133 LOG.warn("bad alias ({} {}) for {}", e.getClass().getName(), e.getMessage(),path);
134 }
135 return null;
136 }
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155 public PathResource(File file)
156 {
157 this(file.toPath());
158 }
159
160
161
162
163
164
165 public PathResource(Path path)
166 {
167 this.path = path.toAbsolutePath();
168 this.uri = this.path.toUri();
169 this.alias = checkAliasPath(path);
170 }
171
172
173
174
175
176
177
178
179
180 public PathResource(URI uri) throws IOException
181 {
182 if (!uri.isAbsolute())
183 {
184 throw new IllegalArgumentException("not an absolute uri");
185 }
186
187 if (!uri.getScheme().equalsIgnoreCase("file"))
188 {
189 throw new IllegalArgumentException("not file: scheme");
190 }
191
192 Path path;
193 try
194 {
195 path = new File(uri).toPath();
196 }
197 catch (InvalidPathException e)
198 {
199 throw e;
200 }
201 catch (IllegalArgumentException e)
202 {
203 throw e;
204 }
205 catch (Exception e)
206 {
207 LOG.ignore(e);
208 throw new IOException("Unable to build Path from: " + uri,e);
209 }
210
211 this.path = path.toAbsolutePath();
212 this.uri = path.toUri();
213 this.alias = checkAliasPath(path);
214 }
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235 public PathResource(URL url) throws IOException, URISyntaxException
236 {
237 this(url.toURI());
238 }
239
240 @Override
241 public Resource addPath(final String subpath) throws IOException, MalformedURLException
242 {
243 String cpath = URIUtil.canonicalPath(subpath);
244
245 if ((cpath == null) || (cpath.length() == 0))
246 throw new MalformedURLException();
247
248 if ("/".equals(cpath))
249 return this;
250
251
252
253
254
255 return new PathResource(this.path.getFileSystem().getPath(path.toString(), subpath));
256 }
257
258 @Override
259 public void close()
260 {
261
262 }
263
264 @Override
265 public boolean delete() throws SecurityException
266 {
267 try
268 {
269 return Files.deleteIfExists(path);
270 }
271 catch (IOException e)
272 {
273 LOG.ignore(e);
274 return false;
275 }
276 }
277
278 @Override
279 public boolean equals(Object obj)
280 {
281 if (this == obj)
282 {
283 return true;
284 }
285 if (obj == null)
286 {
287 return false;
288 }
289 if (getClass() != obj.getClass())
290 {
291 return false;
292 }
293 PathResource other = (PathResource)obj;
294 if (path == null)
295 {
296 if (other.path != null)
297 {
298 return false;
299 }
300 }
301 else if (!path.equals(other.path))
302 {
303 return false;
304 }
305 return true;
306 }
307
308 @Override
309 public boolean exists()
310 {
311 return Files.exists(path,NO_FOLLOW_LINKS);
312 }
313
314 @Override
315 public File getFile() throws IOException
316 {
317 return path.toFile();
318 }
319
320
321
322
323 public Path getPath()
324 {
325 return path;
326 }
327
328 @Override
329 public InputStream getInputStream() throws IOException
330 {
331 return Files.newInputStream(path,StandardOpenOption.READ);
332 }
333
334 @Override
335 public String getName()
336 {
337 return path.toAbsolutePath().toString();
338 }
339
340 @Override
341 public ReadableByteChannel getReadableByteChannel() throws IOException
342 {
343 return FileChannel.open(path,StandardOpenOption.READ);
344 }
345
346 @Override
347 public URI getURI()
348 {
349 return this.uri;
350 }
351
352 @Override
353 public URL getURL()
354 {
355 try
356 {
357 return path.toUri().toURL();
358 }
359 catch (MalformedURLException e)
360 {
361 return null;
362 }
363 }
364
365 @Override
366 public int hashCode()
367 {
368 final int prime = 31;
369 int result = 1;
370 result = (prime * result) + ((path == null)?0:path.hashCode());
371 return result;
372 }
373
374 @Override
375 public boolean isContainedIn(Resource r) throws MalformedURLException
376 {
377
378 return false;
379 }
380
381 @Override
382 public boolean isDirectory()
383 {
384 return Files.isDirectory(path,FOLLOW_LINKS);
385 }
386
387 @Override
388 public long lastModified()
389 {
390 try
391 {
392 FileTime ft = Files.getLastModifiedTime(path,FOLLOW_LINKS);
393 return ft.toMillis();
394 }
395 catch (IOException e)
396 {
397 LOG.ignore(e);
398 return 0;
399 }
400 }
401
402 @Override
403 public long length()
404 {
405 try
406 {
407 return Files.size(path);
408 }
409 catch (IOException e)
410 {
411
412 return 0L;
413 }
414 }
415
416 @Override
417 public boolean isAlias()
418 {
419 return this.alias!=null;
420 }
421
422
423
424
425
426
427 public Path getAliasPath()
428 {
429 return this.alias;
430 }
431
432 @Override
433 public URI getAlias()
434 {
435 return this.alias==null?null:this.alias.toUri();
436 }
437
438 @Override
439 public String[] list()
440 {
441 try (DirectoryStream<Path> dir = Files.newDirectoryStream(path))
442 {
443 List<String> entries = new ArrayList<>();
444 for (Path entry : dir)
445 {
446 String name = entry.getFileName().toString();
447
448 if (Files.isDirectory(entry))
449 {
450 name += "/";
451 }
452
453 entries.add(name);
454 }
455 int size = entries.size();
456 return entries.toArray(new String[size]);
457 }
458 catch (DirectoryIteratorException e)
459 {
460 LOG.debug(e);
461 }
462 catch (IOException e)
463 {
464 LOG.debug(e);
465 }
466 return null;
467 }
468
469 @Override
470 public boolean renameTo(Resource dest) throws SecurityException
471 {
472 if (dest instanceof PathResource)
473 {
474 PathResource destRes = (PathResource)dest;
475 try
476 {
477 Path result = Files.move(path,destRes.path);
478 return Files.exists(result,NO_FOLLOW_LINKS);
479 }
480 catch (IOException e)
481 {
482 LOG.ignore(e);
483 return false;
484 }
485 }
486 else
487 {
488 return false;
489 }
490 }
491
492 @Override
493 public void copyTo(File destination) throws IOException
494 {
495 if (isDirectory())
496 {
497 IO.copyDir(this.path.toFile(),destination);
498 }
499 else
500 {
501 Files.copy(this.path,destination.toPath());
502 }
503 }
504
505 @Override
506 public String toString()
507 {
508 return this.uri.toASCIIString();
509 }
510 }