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.file.spi.*; 31 import java.io.IOException; 32 import java.util.*; 33 import java.util.regex.Pattern; 34 import java.security.AccessController; 35 import sun.security.action.GetPropertyAction; 36 37 /** 38 * Base implementation of FileSystem for Unix-like implementations. 39 */ 40 41 abstract class UnixFileSystem 42 extends FileSystem 43 { 44 private final UnixFileSystemProvider provider; 45 private final byte[] defaultDirectory; 46 private final boolean needToResolveAgainstDefaultDirectory; 47 private final UnixPath rootDirectory; 48 49 // package-private 50 UnixFileSystem(UnixFileSystemProvider provider, String dir) { 51 this.provider = provider; 52 this.defaultDirectory = UnixPath.normalizeAndCheck(dir).getBytes(); 53 if (this.defaultDirectory[0] != '/') { 54 throw new RuntimeException("default directory must be absolute"); 55 } 56 57 // if process-wide chdir is allowed or default directory is not the 58 // process working directory then paths must be resolved against the 59 // default directory. 60 String propValue = AccessController.doPrivileged( 61 new GetPropertyAction("sun.nio.fs.chdirAllowed", "false")); 62 boolean chdirAllowed = (propValue.length() == 0) ? 63 true : Boolean.valueOf(propValue); 64 if (chdirAllowed) { 65 this.needToResolveAgainstDefaultDirectory = true; 66 } else { 67 byte[] cwd = UnixNativeDispatcher.getcwd(); 68 boolean defaultIsCwd = (cwd.length == defaultDirectory.length); 69 if (defaultIsCwd) { 70 for (int i=0; i<cwd.length; i++) { 71 if (cwd[i] != defaultDirectory[i]) { 72 defaultIsCwd = false; 73 break; 74 } 75 } 76 } 77 this.needToResolveAgainstDefaultDirectory = !defaultIsCwd; 78 } 79 80 // the root directory 81 this.rootDirectory = new UnixPath(this, "/"); 82 } 83 84 // package-private 85 byte[] defaultDirectory() { 86 return defaultDirectory; 87 } 88 89 boolean needToResolveAgainstDefaultDirectory() { 90 return needToResolveAgainstDefaultDirectory; 91 } 92 93 UnixPath rootDirectory() { 94 return rootDirectory; 95 } 96 97 boolean isSolaris() { 98 return false; 99 } 100 101 @Override 102 public final FileSystemProvider provider() { 103 return provider; 104 } 105 106 @Override 107 public final String getSeparator() { 108 return "/"; 109 } 110 111 @Override 112 public final boolean isOpen() { 113 return true; 114 } 115 116 @Override 117 public final boolean isReadOnly() { 118 return false; 119 } 120 121 @Override 122 public final void close() throws IOException { 123 throw new UnsupportedOperationException(); 124 } 125 126 /** 127 * Copies non-POSIX attributes from the source to target file. 128 * 129 * Copying a file preserving attributes, or moving a file, will preserve 130 * the file owner/group/permissions/timestamps but it does not preserve 131 * other non-POSIX attributes. This method is invoked by the 132 * copy or move operation to preserve these attributes. It should copy 133 * extended attributes, ACLs, or other attributes. 134 * 135 * @param sfd 136 * Open file descriptor to source file 137 * @param tfd 138 * Open file descriptor to target file 139 */ 140 void copyNonPosixAttributes(int sfd, int tfd) { 141 // no-op by default 142 } 143 144 /** 145 * Unix systems only have a single root directory (/) 146 */ 147 @Override 148 public final Iterable<Path> getRootDirectories() { 149 final List<Path> allowedList = 150 Collections.unmodifiableList(Arrays.asList((Path)rootDirectory)); 151 return new Iterable<Path>() { 152 public Iterator<Path> iterator() { 153 try { 154 SecurityManager sm = System.getSecurityManager(); 155 if (sm != null) 156 sm.checkRead(rootDirectory.toString()); 157 return allowedList.iterator(); 158 } catch (SecurityException x) { 159 List<Path> disallowed = Collections.emptyList(); 160 return disallowed.iterator(); 161 } 162 } 163 }; 164 } 165 166 /** 167 * Returns object to iterate over entries in mounttab or equivalent 168 */ 169 abstract Iterable<UnixMountEntry> getMountEntries(); 170 171 /** 172 * Returns a FileStore to represent the file system where the given file 173 * reside. 174 */ 175 abstract FileStore getFileStore(UnixPath path) throws IOException; 176 177 /** 178 * Returns a FileStore to represent the file system for the given mount 179 * mount. 180 */ 181 abstract FileStore getFileStore(UnixMountEntry entry) throws IOException; 182 183 /** 184 * Iterator returned by getFileStores method. 185 */ 186 private class FileStoreIterator implements Iterator<FileStore> { 187 private final Iterator<UnixMountEntry> entries; 188 private FileStore next; 189 190 FileStoreIterator() { 191 this.entries = getMountEntries().iterator(); 192 } 193 194 private FileStore readNext() { 195 assert Thread.holdsLock(this); 196 for (;;) { 197 if (!entries.hasNext()) 198 return null; 199 UnixMountEntry entry = entries.next(); 200 201 // skip entries with the "ignore" option 202 if (entry.isIgnored()) 203 continue; 204 205 // check permission to read mount point 206 SecurityManager sm = System.getSecurityManager(); 207 if (sm != null) { 208 try { 209 sm.checkRead(new String(entry.dir())); 210 } catch (SecurityException x) { 211 continue; 212 } 213 } 214 try { 215 return getFileStore(entry); 216 } catch (IOException ignore) { 217 // ignore as per spec 218 } 219 } 220 } 221 222 @Override 223 public synchronized boolean hasNext() { 224 if (next != null) 225 return true; 226 next = readNext(); 227 return next != null; 228 } 229 230 @Override 231 public synchronized FileStore next() { 232 if (next == null) 233 next = readNext(); 234 if (next == null) { 235 throw new NoSuchElementException(); 236 } else { 237 FileStore result = next; 238 next = null; 239 return result; 240 } 241 } 242 243 @Override 244 public void remove() { 245 throw new UnsupportedOperationException(); 246 } 247 } 248 249 @Override 250 public final Iterable<FileStore> getFileStores() { 251 SecurityManager sm = System.getSecurityManager(); 252 if (sm != null) { 253 try { 254 sm.checkPermission(new RuntimePermission("getFileStoreAttributes")); 255 } catch (SecurityException se) { 256 return Collections.emptyList(); 257 } 258 } 259 return new Iterable<FileStore>() { 260 public Iterator<FileStore> iterator() { 261 return new FileStoreIterator(); 262 } 263 }; 264 } 265 266 @Override 267 public final UnixPath getPath(String path) { 268 return new UnixPath(this, path); 269 } 270 271 @Override 272 public PathMatcher getPathMatcher(String syntaxAndInput) { 273 int pos = syntaxAndInput.indexOf(':'); 274 if (pos <= 0 || pos == syntaxAndInput.length()) 275 throw new IllegalArgumentException(); 276 String syntax = syntaxAndInput.substring(0, pos); 277 String input = syntaxAndInput.substring(pos+1); 278 279 String expr; 280 if (syntax.equals(GLOB_SYNTAX)) { 281 expr = Globs.toUnixRegexPattern(input); 282 } else { 283 if (syntax.equals(REGEX_SYNTAX)) { 284 expr = input; 285 } else { 286 throw new UnsupportedOperationException("Syntax '" + syntax + 287 "' not recognized"); 288 } 289 } 290 291 // return matcher 292 final Pattern pattern = Pattern.compile(expr); 293 return new PathMatcher() { 294 @Override 295 public boolean matches(Path path) { 296 return pattern.matcher(path.toString()).matches(); 297 } 298 }; 299 } 300 private static final String GLOB_SYNTAX = "glob"; 301 private static final String REGEX_SYNTAX = "regex"; 302 303 protected boolean followLinks(LinkOption... options) { 304 boolean followLinks = true; 305 for (LinkOption option: options) { 306 if (option == LinkOption.NOFOLLOW_LINKS) { 307 followLinks = false; 308 continue; 309 } 310 if (option == null) 311 throw new NullPointerException(); 312 throw new AssertionError("Should not get here"); 313 } 314 return followLinks; 315 } 316 317 @SuppressWarnings("unchecked") 318 protected <V extends FileAttributeView> V newFileAttributeView(Class<V> view, 319 UnixPath file, 320 LinkOption... options) 321 { 322 if (view == null) 323 throw new NullPointerException(); 324 boolean followLinks = followLinks(options); 325 Class<?> c = view; 326 if (c == BasicFileAttributeView.class) 327 return (V) UnixFileAttributeViews.createBasicView(file, followLinks); 328 if (c == PosixFileAttributeView.class) 329 return (V) UnixFileAttributeViews.createPosixView(file, followLinks); 330 if (c == FileOwnerAttributeView.class) 331 return (V) UnixFileAttributeViews.createOwnerView(file, followLinks); 332 return (V) null; 333 } 334 335 static List<String> standardFileAttributeViews() { 336 return Arrays.asList("basic", "posix", "unix", "owner"); 337 } 338 339 protected DynamicFileAttributeView newFileAttributeView(String name, 340 UnixPath file, 341 LinkOption... options) 342 { 343 boolean followLinks = followLinks(options); 344 if (name.equals("basic")) 345 return UnixFileAttributeViews.createBasicView(file, followLinks); 346 if (name.equals("posix")) 347 return UnixFileAttributeViews.createPosixView(file, followLinks); 348 if (name.equals("unix")) 349 return UnixFileAttributeViews.createUnixView(file, followLinks); 350 if (name.equals("owner")) 351 return UnixFileAttributeViews.createOwnerView(file, followLinks); 352 return null; 353 } 354 355 @Override 356 public final UserPrincipalLookupService getUserPrincipalLookupService() { 357 return theLookupService; 358 } 359 360 private static final UserPrincipalLookupService theLookupService = 361 new UserPrincipalLookupService() { 362 @Override 363 public UserPrincipal lookupPrincipalByName(String name) 364 throws IOException 365 { 366 return UnixUserPrincipals.lookupUser(name); 367 } 368 369 @Override 370 public GroupPrincipal lookupPrincipalByGroupName(String group) 371 throws IOException 372 { 373 return UnixUserPrincipals.lookupGroup(group); 374 } 375 }; 376 }