• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.nio.fs;
27 
28 import java.nio.file.*;
29 import java.nio.file.attribute.*;
30 import java.nio.file.spi.FileTypeDetector;
31 import java.nio.channels.*;
32 import java.net.URI;
33 import java.util.concurrent.ExecutorService;
34 import java.io.IOException;
35 import java.io.FilePermission;
36 import java.util.*;
37 import java.security.AccessController;
38 
39 import sun.nio.ch.ThreadPool;
40 import sun.security.util.SecurityConstants;
41 import static sun.nio.fs.UnixNativeDispatcher.*;
42 import static sun.nio.fs.UnixConstants.*;
43 
44 /**
45  * Base implementation of FileSystemProvider
46  */
47 
48 public abstract class UnixFileSystemProvider
49     extends AbstractFileSystemProvider
50 {
51     private static final String USER_DIR = "user.dir";
52     private final UnixFileSystem theFileSystem;
53 
UnixFileSystemProvider()54     public UnixFileSystemProvider() {
55         String userDir = System.getProperty(USER_DIR);
56         theFileSystem = newFileSystem(userDir);
57     }
58 
59     /**
60      * Constructs a new file system using the given default directory.
61      */
newFileSystem(String dir)62     abstract UnixFileSystem newFileSystem(String dir);
63 
64     @Override
getScheme()65     public final String getScheme() {
66         return "file";
67     }
68 
checkUri(URI uri)69     private void checkUri(URI uri) {
70         if (!uri.getScheme().equalsIgnoreCase(getScheme()))
71             throw new IllegalArgumentException("URI does not match this provider");
72         if (uri.getAuthority() != null)
73             throw new IllegalArgumentException("Authority component present");
74         if (uri.getPath() == null)
75             throw new IllegalArgumentException("Path component is undefined");
76         if (!uri.getPath().equals("/"))
77             throw new IllegalArgumentException("Path component should be '/'");
78         if (uri.getQuery() != null)
79             throw new IllegalArgumentException("Query component present");
80         if (uri.getFragment() != null)
81             throw new IllegalArgumentException("Fragment component present");
82     }
83 
84     @Override
newFileSystem(URI uri, Map<String,?> env)85     public final FileSystem newFileSystem(URI uri, Map<String,?> env) {
86         checkUri(uri);
87         throw new FileSystemAlreadyExistsException();
88     }
89 
90     @Override
getFileSystem(URI uri)91     public final FileSystem getFileSystem(URI uri) {
92         checkUri(uri);
93         return theFileSystem;
94     }
95 
96     @Override
getPath(URI uri)97     public Path getPath(URI uri) {
98         return UnixUriUtils.fromUri(theFileSystem, uri);
99     }
100 
checkPath(Path obj)101     UnixPath checkPath(Path obj) {
102         if (obj == null)
103             throw new NullPointerException();
104         if (!(obj instanceof UnixPath))
105             throw new ProviderMismatchException();
106         return (UnixPath)obj;
107     }
108 
109     @Override
110     @SuppressWarnings("unchecked")
getFileAttributeView(Path obj, Class<V> type, LinkOption... options)111     public <V extends FileAttributeView> V getFileAttributeView(Path obj,
112                                                                 Class<V> type,
113                                                                 LinkOption... options)
114     {
115         UnixPath file = UnixPath.toUnixPath(obj);
116         boolean followLinks = Util.followLinks(options);
117         if (type == BasicFileAttributeView.class)
118             return (V) UnixFileAttributeViews.createBasicView(file, followLinks);
119         if (type == PosixFileAttributeView.class)
120             return (V) UnixFileAttributeViews.createPosixView(file, followLinks);
121         if (type == FileOwnerAttributeView.class)
122             return (V) UnixFileAttributeViews.createOwnerView(file, followLinks);
123         if (type == null)
124             throw new NullPointerException();
125         return (V) null;
126     }
127 
128     @Override
129     @SuppressWarnings("unchecked")
readAttributes(Path file, Class<A> type, LinkOption... options)130     public <A extends BasicFileAttributes> A readAttributes(Path file,
131                                                                Class<A> type,
132                                                                LinkOption... options)
133         throws IOException
134     {
135         Class<? extends BasicFileAttributeView> view;
136         if (type == BasicFileAttributes.class)
137             view = BasicFileAttributeView.class;
138         else if (type == PosixFileAttributes.class)
139             view = PosixFileAttributeView.class;
140         else if (type == null)
141             throw new NullPointerException();
142         else
143             throw new UnsupportedOperationException();
144         return (A) getFileAttributeView(file, view, options).readAttributes();
145     }
146 
147     @Override
getFileAttributeView(Path obj, String name, LinkOption... options)148     protected DynamicFileAttributeView getFileAttributeView(Path obj,
149                                                             String name,
150                                                             LinkOption... options)
151     {
152         UnixPath file = UnixPath.toUnixPath(obj);
153         boolean followLinks = Util.followLinks(options);
154         if (name.equals("basic"))
155             return UnixFileAttributeViews.createBasicView(file, followLinks);
156         if (name.equals("posix"))
157             return UnixFileAttributeViews.createPosixView(file, followLinks);
158         if (name.equals("unix"))
159             return UnixFileAttributeViews.createUnixView(file, followLinks);
160         if (name.equals("owner"))
161             return UnixFileAttributeViews.createOwnerView(file, followLinks);
162         return null;
163     }
164 
165     @Override
newFileChannel(Path obj, Set<? extends OpenOption> options, FileAttribute<?>... attrs)166     public FileChannel newFileChannel(Path obj,
167                                       Set<? extends OpenOption> options,
168                                       FileAttribute<?>... attrs)
169         throws IOException
170     {
171         UnixPath file = checkPath(obj);
172         int mode = UnixFileModeAttribute
173             .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);
174         try {
175             return UnixChannelFactory.newFileChannel(file, options, mode);
176         } catch (UnixException x) {
177             x.rethrowAsIOException(file);
178             return null;
179         }
180     }
181 
182     @Override
newAsynchronousFileChannel(Path obj, Set<? extends OpenOption> options, ExecutorService executor, FileAttribute<?>... attrs)183     public AsynchronousFileChannel newAsynchronousFileChannel(Path obj,
184                                                               Set<? extends OpenOption> options,
185                                                               ExecutorService executor,
186                                                               FileAttribute<?>... attrs) throws IOException
187     {
188         UnixPath file = checkPath(obj);
189         int mode = UnixFileModeAttribute
190             .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);
191         ThreadPool pool = (executor == null) ? null : ThreadPool.wrap(executor, 0);
192         try {
193             return UnixChannelFactory
194                 .newAsynchronousFileChannel(file, options, mode, pool);
195         } catch (UnixException x) {
196             x.rethrowAsIOException(file);
197             return null;
198         }
199     }
200 
201 
202     @Override
newByteChannel(Path obj, Set<? extends OpenOption> options, FileAttribute<?>... attrs)203     public SeekableByteChannel newByteChannel(Path obj,
204                                               Set<? extends OpenOption> options,
205                                               FileAttribute<?>... attrs)
206          throws IOException
207     {
208         UnixPath file = UnixPath.toUnixPath(obj);
209         int mode = UnixFileModeAttribute
210             .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs);
211         try {
212             return UnixChannelFactory.newFileChannel(file, options, mode);
213         } catch (UnixException x) {
214             x.rethrowAsIOException(file);
215             return null;  // keep compiler happy
216         }
217     }
218 
219     @Override
implDelete(Path obj, boolean failIfNotExists)220     boolean implDelete(Path obj, boolean failIfNotExists) throws IOException {
221         UnixPath file = UnixPath.toUnixPath(obj);
222         file.checkDelete();
223 
224         // need file attributes to know if file is directory
225         UnixFileAttributes attrs = null;
226         try {
227             attrs = UnixFileAttributes.get(file, false);
228             if (attrs.isDirectory()) {
229                 rmdir(file);
230             } else {
231                 unlink(file);
232             }
233             return true;
234         } catch (UnixException x) {
235             // no-op if file does not exist
236             if (!failIfNotExists && x.errno() == ENOENT)
237                 return false;
238 
239             // DirectoryNotEmptyException if not empty
240             if (attrs != null && attrs.isDirectory() &&
241                 (x.errno() == EEXIST || x.errno() == ENOTEMPTY))
242                 throw new DirectoryNotEmptyException(file.getPathForExceptionMessage());
243 
244             x.rethrowAsIOException(file);
245             return false;
246         }
247     }
248 
249     @Override
copy(Path source, Path target, CopyOption... options)250     public void copy(Path source, Path target, CopyOption... options)
251         throws IOException
252     {
253         UnixCopyFile.copy(UnixPath.toUnixPath(source),
254                           UnixPath.toUnixPath(target),
255                           options);
256     }
257 
258     @Override
move(Path source, Path target, CopyOption... options)259     public void move(Path source, Path target, CopyOption... options)
260         throws IOException
261     {
262         UnixCopyFile.move(UnixPath.toUnixPath(source),
263                           UnixPath.toUnixPath(target),
264                           options);
265     }
266 
267     @Override
checkAccess(Path obj, AccessMode... modes)268     public void checkAccess(Path obj, AccessMode... modes) throws IOException {
269         UnixPath file = UnixPath.toUnixPath(obj);
270         boolean e = false;
271         boolean r = false;
272         boolean w = false;
273         boolean x = false;
274 
275         if (modes.length == 0) {
276             e = true;
277         } else {
278             for (AccessMode mode: modes) {
279                 switch (mode) {
280                     case READ : r = true; break;
281                     case WRITE : w = true; break;
282                     case EXECUTE : x = true; break;
283                     default: throw new AssertionError("Should not get here");
284                 }
285             }
286         }
287 
288         int mode = 0;
289         if (e || r) {
290             file.checkRead();
291             mode |= (r) ? R_OK : F_OK;
292         }
293         if (w) {
294             file.checkWrite();
295             mode |= W_OK;
296         }
297         if (x) {
298             SecurityManager sm = System.getSecurityManager();
299             if (sm != null) {
300                 // not cached
301                 sm.checkExec(file.getPathForPermissionCheck());
302             }
303             mode |= X_OK;
304         }
305         try {
306             access(file, mode);
307         } catch (UnixException exc) {
308             exc.rethrowAsIOException(file);
309         }
310     }
311 
312     @Override
isSameFile(Path obj1, Path obj2)313     public boolean isSameFile(Path obj1, Path obj2) throws IOException {
314         UnixPath file1 = UnixPath.toUnixPath(obj1);
315         if (file1.equals(obj2))
316             return true;
317         if (obj2 == null)
318             throw new NullPointerException();
319         if (!(obj2 instanceof UnixPath))
320             return false;
321         UnixPath file2 = (UnixPath)obj2;
322 
323         // check security manager access to both files
324         file1.checkRead();
325         file2.checkRead();
326 
327         UnixFileAttributes attrs1;
328         UnixFileAttributes attrs2;
329         try {
330              attrs1 = UnixFileAttributes.get(file1, true);
331         } catch (UnixException x) {
332             x.rethrowAsIOException(file1);
333             return false;    // keep compiler happy
334         }
335         try {
336             attrs2 = UnixFileAttributes.get(file2, true);
337         } catch (UnixException x) {
338             x.rethrowAsIOException(file2);
339             return false;    // keep compiler happy
340         }
341         return attrs1.isSameFile(attrs2);
342     }
343 
344     @Override
isHidden(Path obj)345     public boolean isHidden(Path obj) {
346         UnixPath file = UnixPath.toUnixPath(obj);
347         file.checkRead();
348         UnixPath name = file.getFileName();
349         if (name == null)
350             return false;
351         return (name.asByteArray()[0] == '.');
352     }
353 
354     /**
355      * Returns a FileStore to represent the file system where the given file
356      * reside.
357      */
getFileStore(UnixPath path)358     abstract FileStore getFileStore(UnixPath path) throws IOException;
359 
360     @Override
getFileStore(Path obj)361     public FileStore getFileStore(Path obj) throws IOException {
362         // BEGIN Android-changed: getFileStore(Path) always throws SecurityException.
363         // Complete information about file systems is neither available to regular apps nor the
364         // system server due to SELinux policies.
365         /*
366         UnixPath file = UnixPath.toUnixPath(obj);
367         SecurityManager sm = System.getSecurityManager();
368         if (sm != null) {
369             sm.checkPermission(new RuntimePermission("getFileStoreAttributes"));
370             file.checkRead();
371         }
372         return getFileStore(file);
373         */
374         throw new SecurityException("getFileStore");
375         // END Android-changed: getFileStore(Path) always throws SecurityException.
376     }
377 
378     @Override
createDirectory(Path obj, FileAttribute<?>... attrs)379     public void createDirectory(Path obj, FileAttribute<?>... attrs)
380         throws IOException
381     {
382         UnixPath dir = UnixPath.toUnixPath(obj);
383         dir.checkWrite();
384 
385         int mode = UnixFileModeAttribute.toUnixMode(UnixFileModeAttribute.ALL_PERMISSIONS, attrs);
386         try {
387             mkdir(dir, mode);
388         } catch (UnixException x) {
389             if (x.errno() == EISDIR)
390                 throw new FileAlreadyExistsException(dir.toString());
391             x.rethrowAsIOException(dir);
392         }
393     }
394 
395 
396     @Override
newDirectoryStream(Path obj, DirectoryStream.Filter<? super Path> filter)397     public DirectoryStream<Path> newDirectoryStream(Path obj, DirectoryStream.Filter<? super Path> filter)
398         throws IOException
399     {
400         UnixPath dir = UnixPath.toUnixPath(obj);
401         dir.checkRead();
402         if (filter == null)
403             throw new NullPointerException();
404 
405         // can't return SecureDirectoryStream on kernels that don't support openat
406         // or O_NOFOLLOW
407         if (!openatSupported() || O_NOFOLLOW == 0) {
408             try {
409                 long ptr = opendir(dir);
410                 return new UnixDirectoryStream(dir, ptr, filter);
411             } catch (UnixException x) {
412                 if (x.errno() == ENOTDIR)
413                     throw new NotDirectoryException(dir.getPathForExceptionMessage());
414                 x.rethrowAsIOException(dir);
415             }
416         }
417 
418         // open directory and dup file descriptor for use by
419         // opendir/readdir/closedir
420         int dfd1 = -1;
421         int dfd2 = -1;
422         long dp = 0L;
423         try {
424             dfd1 = open(dir, O_RDONLY, 0);
425             dfd2 = dup(dfd1);
426             dp = fdopendir(dfd1);
427         } catch (UnixException x) {
428             if (dfd1 != -1)
429                 UnixNativeDispatcher.close(dfd1);
430             if (dfd2 != -1)
431                 UnixNativeDispatcher.close(dfd2);
432             if (x.errno() == UnixConstants.ENOTDIR)
433                 throw new NotDirectoryException(dir.getPathForExceptionMessage());
434             x.rethrowAsIOException(dir);
435         }
436         return new UnixSecureDirectoryStream(dir, dp, dfd2, filter);
437     }
438 
439     @Override
createSymbolicLink(Path obj1, Path obj2, FileAttribute<?>... attrs)440     public void createSymbolicLink(Path obj1, Path obj2, FileAttribute<?>... attrs)
441         throws IOException
442     {
443         UnixPath link = UnixPath.toUnixPath(obj1);
444         UnixPath target = UnixPath.toUnixPath(obj2);
445 
446         // no attributes supported when creating links
447         if (attrs.length > 0) {
448             UnixFileModeAttribute.toUnixMode(0, attrs);  // may throw NPE or UOE
449             throw new UnsupportedOperationException("Initial file attributes" +
450                 "not supported when creating symbolic link");
451         }
452 
453         // permission check
454         SecurityManager sm = System.getSecurityManager();
455         if (sm != null) {
456             sm.checkPermission(new LinkPermission("symbolic"));
457             link.checkWrite();
458         }
459 
460         // create link
461         try {
462             symlink(target.asByteArray(), link);
463         } catch (UnixException x) {
464             x.rethrowAsIOException(link);
465         }
466     }
467 
468     @Override
createLink(Path obj1, Path obj2)469     public void createLink(Path obj1, Path obj2) throws IOException {
470         UnixPath link = UnixPath.toUnixPath(obj1);
471         UnixPath existing = UnixPath.toUnixPath(obj2);
472 
473         // permission check
474         SecurityManager sm = System.getSecurityManager();
475         if (sm != null) {
476             sm.checkPermission(new LinkPermission("hard"));
477             link.checkWrite();
478             existing.checkWrite();
479         }
480         try {
481             link(existing, link);
482         } catch (UnixException x) {
483             x.rethrowAsIOException(link, existing);
484         }
485     }
486 
487     @Override
readSymbolicLink(Path obj1)488     public Path readSymbolicLink(Path obj1) throws IOException {
489         UnixPath link = UnixPath.toUnixPath(obj1);
490         // permission check
491         SecurityManager sm = System.getSecurityManager();
492         if (sm != null) {
493             FilePermission perm = new FilePermission(link.getPathForPermissionCheck(),
494                 SecurityConstants.FILE_READLINK_ACTION);
495             sm.checkPermission(perm);
496         }
497         try {
498             byte[] target = readlink(link);
499             return new UnixPath(link.getFileSystem(), target);
500         } catch (UnixException x) {
501            if (x.errno() == UnixConstants.EINVAL)
502                 throw new NotLinkException(link.getPathForExceptionMessage());
503             x.rethrowAsIOException(link);
504             return null;    // keep compiler happy
505         }
506     }
507 
508     /**
509      * Returns a {@code FileTypeDetector} for this platform.
510      */
getFileTypeDetector()511     FileTypeDetector getFileTypeDetector() {
512         return new AbstractFileTypeDetector() {
513             @Override
514             public String implProbeContentType(Path file) {
515                 return null;
516             }
517         };
518     }
519 
520     /**
521      * Returns a {@code FileTypeDetector} that chains the given array of file
522      * type detectors. When the {@code implProbeContentType} method is invoked
523      * then each of the detectors is invoked in turn, the result from the
524      * first to detect the file type is returned.
525      */
526     final FileTypeDetector chain(final AbstractFileTypeDetector... detectors) {
527         return new AbstractFileTypeDetector() {
528             @Override
529             protected String implProbeContentType(Path file) throws IOException {
530                 for (AbstractFileTypeDetector detector : detectors) {
531                     String result = detector.implProbeContentType(file);
532                     if (result != null && !result.isEmpty()) {
533                         return result;
534                     }
535                 }
536                 return null;
537             }
538         };
539     }
540 }
541