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.*; 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 UnixFileSystem(UnixFileSystemProvider provider, String dir)50 UnixFileSystem(UnixFileSystemProvider provider, String dir) { 51 this.provider = provider; 52 this.defaultDirectory = Util.toBytes(UnixPath.normalizeAndCheck(dir)); 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 defaultDirectory()85 byte[] defaultDirectory() { 86 return defaultDirectory; 87 } 88 needToResolveAgainstDefaultDirectory()89 boolean needToResolveAgainstDefaultDirectory() { 90 return needToResolveAgainstDefaultDirectory; 91 } 92 rootDirectory()93 UnixPath rootDirectory() { 94 return rootDirectory; 95 } 96 isSolaris()97 boolean isSolaris() { 98 return false; 99 } 100 standardFileAttributeViews()101 static List<String> standardFileAttributeViews() { 102 return Arrays.asList("basic", "posix", "unix", "owner"); 103 } 104 105 @Override provider()106 public final FileSystemProvider provider() { 107 return provider; 108 } 109 110 @Override getSeparator()111 public final String getSeparator() { 112 return "/"; 113 } 114 115 @Override isOpen()116 public final boolean isOpen() { 117 return true; 118 } 119 120 @Override isReadOnly()121 public final boolean isReadOnly() { 122 return false; 123 } 124 125 @Override close()126 public final void close() throws IOException { 127 throw new UnsupportedOperationException(); 128 } 129 130 /** 131 * Copies non-POSIX attributes from the source to target file. 132 * 133 * Copying a file preserving attributes, or moving a file, will preserve 134 * the file owner/group/permissions/timestamps but it does not preserve 135 * other non-POSIX attributes. This method is invoked by the 136 * copy or move operation to preserve these attributes. It should copy 137 * extended attributes, ACLs, or other attributes. 138 * 139 * @param sfd 140 * Open file descriptor to source file 141 * @param tfd 142 * Open file descriptor to target file 143 */ copyNonPosixAttributes(int sfd, int tfd)144 void copyNonPosixAttributes(int sfd, int tfd) { 145 // no-op by default 146 } 147 148 /** 149 * Unix systems only have a single root directory (/) 150 */ 151 @Override getRootDirectories()152 public final Iterable<Path> getRootDirectories() { 153 final List<Path> allowedList = 154 Collections.unmodifiableList(Arrays.asList((Path)rootDirectory)); 155 return new Iterable<Path>() { 156 public Iterator<Path> iterator() { 157 try { 158 SecurityManager sm = System.getSecurityManager(); 159 if (sm != null) 160 sm.checkRead(rootDirectory.toString()); 161 return allowedList.iterator(); 162 } catch (SecurityException x) { 163 List<Path> disallowed = Collections.emptyList(); 164 return disallowed.iterator(); 165 } 166 } 167 }; 168 } 169 170 /** 171 * Returns object to iterate over entries in mounttab or equivalent 172 */ 173 abstract Iterable<UnixMountEntry> getMountEntries(); 174 175 /** 176 * Returns a FileStore to represent the file system for the given mount 177 * mount. 178 */ 179 abstract FileStore getFileStore(UnixMountEntry entry) throws IOException; 180 181 /** 182 * Iterator returned by getFileStores method. 183 */ 184 private class FileStoreIterator implements Iterator<FileStore> { 185 private final Iterator<UnixMountEntry> entries; 186 private FileStore next; 187 188 FileStoreIterator() { 189 this.entries = getMountEntries().iterator(); 190 } 191 192 private FileStore readNext() { 193 assert Thread.holdsLock(this); 194 for (;;) { 195 if (!entries.hasNext()) 196 return null; 197 UnixMountEntry entry = entries.next(); 198 199 // skip entries with the "ignore" option 200 if (entry.isIgnored()) 201 continue; 202 203 // check permission to read mount point 204 SecurityManager sm = System.getSecurityManager(); 205 if (sm != null) { 206 try { 207 sm.checkRead(Util.toString(entry.dir())); 208 } catch (SecurityException x) { 209 continue; 210 } 211 } 212 try { 213 return getFileStore(entry); 214 } catch (IOException ignore) { 215 // ignore as per spec 216 } 217 } 218 } 219 220 @Override 221 public synchronized boolean hasNext() { 222 if (next != null) 223 return true; 224 next = readNext(); 225 return next != null; 226 } 227 228 @Override 229 public synchronized FileStore next() { 230 if (next == null) 231 next = readNext(); 232 if (next == null) { 233 throw new NoSuchElementException(); 234 } else { 235 FileStore result = next; 236 next = null; 237 return result; 238 } 239 } 240 241 @Override 242 public void remove() { 243 throw new UnsupportedOperationException(); 244 } 245 } 246 247 @Override 248 public final Iterable<FileStore> getFileStores() { 249 SecurityManager sm = System.getSecurityManager(); 250 if (sm != null) { 251 try { 252 sm.checkPermission(new RuntimePermission("getFileStoreAttributes")); 253 } catch (SecurityException se) { 254 return Collections.emptyList(); 255 } 256 } 257 return new Iterable<FileStore>() { 258 public Iterator<FileStore> iterator() { 259 return new FileStoreIterator(); 260 } 261 }; 262 } 263 264 @Override 265 public final Path getPath(String first, String... more) { 266 String path; 267 if (more.length == 0) { 268 path = first; 269 } else { 270 StringBuilder sb = new StringBuilder(); 271 sb.append(first); 272 for (String segment: more) { 273 if (segment.length() > 0) { 274 if (sb.length() > 0) 275 sb.append('/'); 276 sb.append(segment); 277 } 278 } 279 path = sb.toString(); 280 } 281 return new UnixPath(this, path); 282 } 283 284 @Override 285 public PathMatcher getPathMatcher(String syntaxAndInput) { 286 int pos = syntaxAndInput.indexOf(':'); 287 if (pos <= 0 || pos == syntaxAndInput.length()) 288 throw new IllegalArgumentException(); 289 String syntax = syntaxAndInput.substring(0, pos); 290 String input = syntaxAndInput.substring(pos+1); 291 292 String expr; 293 if (syntax.equals(GLOB_SYNTAX)) { 294 expr = Globs.toUnixRegexPattern(input); 295 } else { 296 if (syntax.equals(REGEX_SYNTAX)) { 297 expr = input; 298 } else { 299 throw new UnsupportedOperationException("Syntax '" + syntax + 300 "' not recognized"); 301 } 302 } 303 304 // return matcher 305 final Pattern pattern = compilePathMatchPattern(expr); 306 307 return new PathMatcher() { 308 @Override 309 public boolean matches(Path path) { 310 return pattern.matcher(path.toString()).matches(); 311 } 312 }; 313 } 314 315 private static final String GLOB_SYNTAX = "glob"; 316 private static final String REGEX_SYNTAX = "regex"; 317 318 @Override 319 public final UserPrincipalLookupService getUserPrincipalLookupService() { 320 return LookupService.instance; 321 } 322 323 private static class LookupService { 324 static final UserPrincipalLookupService instance = 325 new UserPrincipalLookupService() { 326 @Override 327 public UserPrincipal lookupPrincipalByName(String name) 328 throws IOException 329 { 330 return UnixUserPrincipals.lookupUser(name); 331 } 332 333 @Override 334 public GroupPrincipal lookupPrincipalByGroupName(String group) 335 throws IOException 336 { 337 return UnixUserPrincipals.lookupGroup(group); 338 } 339 }; 340 } 341 342 // Override if the platform has different path match requrement, such as 343 // case insensitive or Unicode canonical equal on MacOSX 344 Pattern compilePathMatchPattern(String expr) { 345 return Pattern.compile(expr); 346 } 347 348 // Override if the platform uses different Unicode normalization form 349 // for native file path. For example on MacOSX, the native path is stored 350 // in Unicode NFD form. 351 char[] normalizeNativePath(char[] path) { 352 return path; 353 } 354 355 // Override if the native file path use non-NFC form. For example on MacOSX, 356 // the native path is stored in Unicode NFD form, the path need to be 357 // normalized back to NFC before passed back to Java level. 358 String normalizeJavaPath(String path) { 359 return path; 360 } 361 } 362