1 /* 2 * Copyright (c) 2008, 2009, 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.channels.*; 31 import java.net.URI; 32 import java.util.concurrent.ExecutorService; 33 import java.io.IOException; 34 import java.io.FilePermission; 35 import java.util.*; 36 import java.security.AccessController; 37 38 import sun.nio.ch.ThreadPool; 39 import sun.security.util.SecurityConstants; 40 import static sun.nio.fs.UnixNativeDispatcher.*; 41 import static sun.nio.fs.UnixConstants.*; 42 43 /** 44 * Base implementation of FileSystemProvider 45 */ 46 47 public abstract class UnixFileSystemProvider 48 extends AbstractFileSystemProvider 49 { 50 private static final String USER_DIR = "user.dir"; 51 private final UnixFileSystem theFileSystem; 52 53 public UnixFileSystemProvider() { 54 String userDir = System.getProperty(USER_DIR); 55 theFileSystem = newFileSystem(userDir); 56 } 57 58 /** 59 * Constructs a new file system using the given default directory. 60 */ 61 abstract UnixFileSystem newFileSystem(String dir); 62 63 @Override 64 public final String getScheme() { 65 return "file"; 66 } 67 68 private void checkUri(URI uri) { 69 if (!uri.getScheme().equalsIgnoreCase(getScheme())) 70 throw new IllegalArgumentException("URI does not match this provider"); 71 if (uri.getAuthority() != null) 72 throw new IllegalArgumentException("Authority component present"); 73 if (uri.getPath() == null) 74 throw new IllegalArgumentException("Path component is undefined"); 75 if (!uri.getPath().equals("/")) 76 throw new IllegalArgumentException("Path component should be '/'"); 77 if (uri.getQuery() != null) 78 throw new IllegalArgumentException("Query component present"); 79 if (uri.getFragment() != null) 80 throw new IllegalArgumentException("Fragment component present"); 81 } 82 83 @Override 84 public final FileSystem newFileSystem(URI uri, Map<String,?> env) { 85 checkUri(uri); 86 throw new FileSystemAlreadyExistsException(); 87 } 88 89 @Override 90 public final FileSystem getFileSystem(URI uri) { 91 checkUri(uri); 92 return theFileSystem; 93 } 94 95 @Override 96 public Path getPath(URI uri) { 97 return UnixUriUtils.fromUri(theFileSystem, uri); 98 } 99 100 UnixPath checkPath(Path obj) { 101 if (obj == null) 102 throw new NullPointerException(); 103 if (!(obj instanceof UnixPath)) 104 throw new ProviderMismatchException(); 105 return (UnixPath)obj; 106 } 107 108 boolean followLinks(LinkOption... options) { 109 boolean followLinks = true; 110 for (LinkOption option: options) { 111 if (option == LinkOption.NOFOLLOW_LINKS) { 112 followLinks = false; 113 continue; 114 } 115 if (option == null) 116 throw new NullPointerException(); 117 throw new AssertionError("Should not get here"); 118 } 119 return followLinks; 120 } 121 122 @Override 123 @SuppressWarnings("unchecked") 124 public <V extends FileAttributeView> V getFileAttributeView(Path obj, 125 Class<V> type, 126 LinkOption... options) 127 { 128 UnixPath file = UnixPath.toUnixPath(obj); 129 boolean followLinks = followLinks(options); 130 if (type == BasicFileAttributeView.class) 131 return (V) UnixFileAttributeViews.createBasicView(file, followLinks); 132 if (type == PosixFileAttributeView.class) 133 return (V) UnixFileAttributeViews.createPosixView(file, followLinks); 134 if (type == FileOwnerAttributeView.class) 135 return (V) UnixFileAttributeViews.createOwnerView(file, followLinks); 136 if (type == null) 137 throw new NullPointerException(); 138 return (V) null; 139 } 140 141 @Override 142 @SuppressWarnings("unchecked") 143 public <A extends BasicFileAttributes> A readAttributes(Path file, 144 Class<A> type, 145 LinkOption... options) 146 throws IOException 147 { 148 Class<? extends BasicFileAttributeView> view; 149 if (type == BasicFileAttributes.class) 150 view = BasicFileAttributeView.class; 151 else if (type == PosixFileAttributes.class) 152 view = PosixFileAttributeView.class; 153 else if (type == null) 154 throw new NullPointerException(); 155 else 156 throw new UnsupportedOperationException(); 157 return (A) getFileAttributeView(file, view, options).readAttributes(); 158 } 159 160 @Override 161 protected DynamicFileAttributeView getFileAttributeView(Path obj, 162 String name, 163 LinkOption... options) 164 { 165 UnixPath file = UnixPath.toUnixPath(obj); 166 boolean followLinks = followLinks(options); 167 if (name.equals("basic")) 168 return UnixFileAttributeViews.createBasicView(file, followLinks); 169 if (name.equals("posix")) 170 return UnixFileAttributeViews.createPosixView(file, followLinks); 171 if (name.equals("unix")) 172 return UnixFileAttributeViews.createUnixView(file, followLinks); 173 if (name.equals("owner")) 174 return UnixFileAttributeViews.createOwnerView(file, followLinks); 175 return null; 176 } 177 178 @Override 179 public FileChannel newFileChannel(Path obj, 180 Set<? extends OpenOption> options, 181 FileAttribute<?>... attrs) 182 throws IOException 183 { 184 UnixPath file = checkPath(obj); 185 int mode = UnixFileModeAttribute 186 .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs); 187 try { 188 return UnixChannelFactory.newFileChannel(file, options, mode); 189 } catch (UnixException x) { 190 x.rethrowAsIOException(file); 191 return null; 192 } 193 } 194 195 @Override 196 public AsynchronousFileChannel newAsynchronousFileChannel(Path obj, 197 Set<? extends OpenOption> options, 198 ExecutorService executor, 199 FileAttribute<?>... attrs) throws IOException 200 { 201 UnixPath file = checkPath(obj); 202 int mode = UnixFileModeAttribute 203 .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs); 204 ThreadPool pool = (executor == null) ? null : ThreadPool.wrap(executor, 0); 205 try { 206 return UnixChannelFactory 207 .newAsynchronousFileChannel(file, options, mode, pool); 208 } catch (UnixException x) { 209 x.rethrowAsIOException(file); 210 return null; 211 } 212 } 213 214 215 @Override 216 public SeekableByteChannel newByteChannel(Path obj, 217 Set<? extends OpenOption> options, 218 FileAttribute<?>... attrs) 219 throws IOException 220 { 221 UnixPath file = UnixPath.toUnixPath(obj); 222 int mode = UnixFileModeAttribute 223 .toUnixMode(UnixFileModeAttribute.ALL_READWRITE, attrs); 224 try { 225 return UnixChannelFactory.newFileChannel(file, options, mode); 226 } catch (UnixException x) { 227 x.rethrowAsIOException(file); 228 return null; // keep compiler happy 229 } 230 } 231 232 @Override 233 boolean implDelete(Path obj, boolean failIfNotExists) throws IOException { 234 UnixPath file = UnixPath.toUnixPath(obj); 235 file.checkDelete(); 236 237 // need file attributes to know if file is directory 238 UnixFileAttributes attrs = null; 239 try { 240 attrs = UnixFileAttributes.get(file, false); 241 if (attrs.isDirectory()) { 242 rmdir(file); 243 } else { 244 unlink(file); 245 } 246 return true; 247 } catch (UnixException x) { 248 // no-op if file does not exist 249 if (!failIfNotExists && x.errno() == ENOENT) 250 return false; 251 252 // DirectoryNotEmptyException if not empty 253 if (attrs != null && attrs.isDirectory() && 254 (x.errno() == EEXIST || x.errno() == ENOTEMPTY)) 255 throw new DirectoryNotEmptyException(file.getPathForExecptionMessage()); 256 257 x.rethrowAsIOException(file); 258 return false; 259 } 260 } 261 262 @Override 263 public void copy(Path source, Path target, CopyOption... options) 264 throws IOException 265 { 266 UnixCopyFile.copy(UnixPath.toUnixPath(source), 267 UnixPath.toUnixPath(target), 268 options); 269 } 270 271 @Override 272 public void move(Path source, Path target, CopyOption... options) 273 throws IOException 274 { 275 UnixCopyFile.move(UnixPath.toUnixPath(source), 276 UnixPath.toUnixPath(target), 277 options); 278 } 279 280 @Override 281 public void checkAccess(Path obj, AccessMode... modes) throws IOException { 282 UnixPath file = UnixPath.toUnixPath(obj); 283 boolean e = false; 284 boolean r = false; 285 boolean w = false; 286 boolean x = false; 287 288 if (modes.length == 0) { 289 e = true; 290 } else { 291 for (AccessMode mode: modes) { 292 switch (mode) { 293 case READ : r = true; break; 294 case WRITE : w = true; break; 295 case EXECUTE : x = true; break; 296 default: throw new AssertionError("Should not get here"); 297 } 298 } 299 } 300 301 int mode = 0; 302 if (e || r) { 303 file.checkRead(); 304 mode |= (r) ? R_OK : F_OK; 305 } 306 if (w) { 307 file.checkWrite(); 308 mode |= W_OK; 309 } 310 if (x) { 311 SecurityManager sm = System.getSecurityManager(); 312 if (sm != null) { 313 // not cached 314 sm.checkExec(file.getPathForPermissionCheck()); 315 } 316 mode |= X_OK; 317 } 318 try { 319 access(file, mode); 320 } catch (UnixException exc) { 321 exc.rethrowAsIOException(file); 322 } 323 } 324 325 @Override 326 public boolean isSameFile(Path obj1, Path obj2) throws IOException { 327 UnixPath file1 = UnixPath.toUnixPath(obj1); 328 if (file1.equals(obj2)) 329 return true; 330 if (obj2 == null) 331 throw new NullPointerException(); 332 if (!(obj2 instanceof UnixPath)) 333 return false; 334 UnixPath file2 = (UnixPath)obj2; 335 336 // check security manager access to both files 337 file1.checkRead(); 338 file2.checkRead(); 339 340 UnixFileAttributes attrs1; 341 UnixFileAttributes attrs2; 342 try { 343 attrs1 = UnixFileAttributes.get(file1, true); 344 } catch (UnixException x) { 345 x.rethrowAsIOException(file1); 346 return false; // keep compiler happy 347 } 348 try { 349 attrs2 = UnixFileAttributes.get(file2, true); 350 } catch (UnixException x) { 351 x.rethrowAsIOException(file2); 352 return false; // keep compiler happy 353 } 354 return attrs1.isSameFile(attrs2); 355 } 356 357 @Override 358 public boolean isHidden(Path obj) { 359 UnixPath file = UnixPath.toUnixPath(obj); 360 file.checkRead(); 361 UnixPath name = file.getFileName(); 362 if (name == null) 363 return false; 364 return (name.asByteArray()[0] == '.'); 365 } 366 367 /** 368 * Returns a FileStore to represent the file system where the given file 369 * reside. 370 */ 371 abstract FileStore getFileStore(UnixPath path) throws IOException; 372 373 @Override 374 public FileStore getFileStore(Path obj) throws IOException { 375 UnixPath file = UnixPath.toUnixPath(obj); 376 SecurityManager sm = System.getSecurityManager(); 377 if (sm != null) { 378 sm.checkPermission(new RuntimePermission("getFileStoreAttributes")); 379 file.checkRead(); 380 } 381 return getFileStore(file); 382 } 383 384 @Override 385 public void createDirectory(Path obj, FileAttribute<?>... attrs) 386 throws IOException 387 { 388 UnixPath dir = UnixPath.toUnixPath(obj); 389 dir.checkWrite(); 390 391 int mode = UnixFileModeAttribute 392 .toUnixMode(UnixFileModeAttribute.ALL_PERMISSIONS, attrs); 393 try { 394 mkdir(dir, mode); 395 } catch (UnixException x) { 396 x.rethrowAsIOException(dir); 397 } 398 } 399 400 401 @Override 402 public DirectoryStream<Path> newDirectoryStream(Path obj, DirectoryStream.Filter<? super Path> filter) 403 throws IOException 404 { 405 UnixPath dir = UnixPath.toUnixPath(obj); 406 dir.checkRead(); 407 if (filter == null) 408 throw new NullPointerException(); 409 410 // can't return SecureDirectoryStream on kernels that don't support 411 // openat, etc. 412 if (!supportsAtSysCalls()) { 413 try { 414 long ptr = opendir(dir); 415 return new UnixDirectoryStream(dir, ptr, filter); 416 } catch (UnixException x) { 417 if (x.errno() == ENOTDIR) 418 throw new NotDirectoryException(dir.getPathForExecptionMessage()); 419 x.rethrowAsIOException(dir); 420 } 421 } 422 423 // open directory and dup file descriptor for use by 424 // opendir/readdir/closedir 425 int dfd1 = -1; 426 int dfd2 = -1; 427 long dp = 0L; 428 try { 429 dfd1 = open(dir, O_RDONLY, 0); 430 dfd2 = dup(dfd1); 431 dp = fdopendir(dfd1); 432 } catch (UnixException x) { 433 if (dfd1 != -1) 434 UnixNativeDispatcher.close(dfd1); 435 if (dfd2 != -1) 436 UnixNativeDispatcher.close(dfd2); 437 if (x.errno() == UnixConstants.ENOTDIR) 438 throw new NotDirectoryException(dir.getPathForExecptionMessage()); 439 x.rethrowAsIOException(dir); 440 } 441 return new UnixSecureDirectoryStream(dir, dp, dfd2, filter); 442 } 443 444 @Override 445 public void createSymbolicLink(Path obj1, Path obj2, FileAttribute<?>... attrs) 446 throws IOException 447 { 448 UnixPath link = UnixPath.toUnixPath(obj1); 449 UnixPath target = UnixPath.toUnixPath(obj2); 450 451 // no attributes supported when creating links 452 if (attrs.length > 0) { 453 UnixFileModeAttribute.toUnixMode(0, attrs); // may throw NPE or UOE 454 throw new UnsupportedOperationException("Initial file attributes" + 455 "not supported when creating symbolic link"); 456 } 457 458 // permission check 459 SecurityManager sm = System.getSecurityManager(); 460 if (sm != null) { 461 sm.checkPermission(new LinkPermission("symbolic")); 462 link.checkWrite(); 463 } 464 465 // create link 466 try { 467 symlink(target.asByteArray(), link); 468 } catch (UnixException x) { 469 x.rethrowAsIOException(link); 470 } 471 } 472 473 @Override 474 public void createLink(Path obj1, Path obj2) throws IOException { 475 UnixPath link = UnixPath.toUnixPath(obj1); 476 UnixPath existing = UnixPath.toUnixPath(obj2); 477 478 // permission check 479 SecurityManager sm = System.getSecurityManager(); 480 if (sm != null) { 481 sm.checkPermission(new LinkPermission("hard")); 482 link.checkWrite(); 483 existing.checkWrite(); 484 } 485 try { 486 link(existing, link); 487 } catch (UnixException x) { 488 x.rethrowAsIOException(link, existing); 489 } 490 } 491 492 @Override 493 public Path readSymbolicLink(Path obj1) throws IOException { 494 UnixPath link = UnixPath.toUnixPath(obj1); 495 // permission check 496 SecurityManager sm = System.getSecurityManager(); 497 if (sm != null) { 498 FilePermission perm = new FilePermission(link.getPathForPermissionCheck(), 499 SecurityConstants.FILE_READLINK_ACTION); 500 AccessController.checkPermission(perm); 501 } 502 try { 503 byte[] target = readlink(link); 504 return new UnixPath(link.getFileSystem(), target); 505 } catch (UnixException x) { 506 if (x.errno() == UnixConstants.EINVAL) 507 throw new NotLinkException(link.getPathForExecptionMessage()); 508 x.rethrowAsIOException(link); 509 return null; // keep compiler happy 510 } 511 } 512 }