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