Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/java/io/UnixFileSystem.java
32287 views
/*1* Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.io;2627import java.security.AccessController;28import sun.security.action.GetPropertyAction;293031class UnixFileSystem extends FileSystem {3233private final char slash;34private final char colon;35private final String javaHome;3637public UnixFileSystem() {38slash = AccessController.doPrivileged(39new GetPropertyAction("file.separator")).charAt(0);40colon = AccessController.doPrivileged(41new GetPropertyAction("path.separator")).charAt(0);42javaHome = AccessController.doPrivileged(43new GetPropertyAction("java.home"));44}454647/* -- Normalization and construction -- */4849public char getSeparator() {50return slash;51}5253public char getPathSeparator() {54return colon;55}5657/* A normal Unix pathname contains no duplicate slashes and does not end58with a slash. It may be the empty string. */5960/* Normalize the given pathname, whose length is len, starting at the given61offset; everything before this offset is already normal. */62private String normalize(String pathname, int len, int off) {63if (len == 0) return pathname;64int n = len;65while ((n > 0) && (pathname.charAt(n - 1) == '/')) n--;66if (n == 0) return "/";67StringBuffer sb = new StringBuffer(pathname.length());68if (off > 0) sb.append(pathname.substring(0, off));69char prevChar = 0;70for (int i = off; i < n; i++) {71char c = pathname.charAt(i);72if ((prevChar == '/') && (c == '/')) continue;73sb.append(c);74prevChar = c;75}76return sb.toString();77}7879/* Check that the given pathname is normal. If not, invoke the real80normalizer on the part of the pathname that requires normalization.81This way we iterate through the whole pathname string only once. */82public String normalize(String pathname) {83int n = pathname.length();84char prevChar = 0;85for (int i = 0; i < n; i++) {86char c = pathname.charAt(i);87if ((prevChar == '/') && (c == '/'))88return normalize(pathname, n, i - 1);89prevChar = c;90}91if (prevChar == '/') return normalize(pathname, n, n - 1);92return pathname;93}9495public int prefixLength(String pathname) {96if (pathname.length() == 0) return 0;97return (pathname.charAt(0) == '/') ? 1 : 0;98}99100public String resolve(String parent, String child) {101if (child.equals("")) return parent;102if (child.charAt(0) == '/') {103if (parent.equals("/")) return child;104return parent + child;105}106if (parent.equals("/")) return parent + child;107return parent + '/' + child;108}109110public String getDefaultParent() {111return "/";112}113114public String fromURIPath(String path) {115String p = path;116if (p.endsWith("/") && (p.length() > 1)) {117// "/foo/" --> "/foo", but "/" --> "/"118p = p.substring(0, p.length() - 1);119}120return p;121}122123124/* -- Path operations -- */125126public boolean isAbsolute(File f) {127return (f.getPrefixLength() != 0);128}129130public String resolve(File f) {131if (isAbsolute(f)) return f.getPath();132return resolve(System.getProperty("user.dir"), f.getPath());133}134135// Caches for canonicalization results to improve startup performance.136// The first cache handles repeated canonicalizations of the same path137// name. The prefix cache handles repeated canonicalizations within the138// same directory, and must not create results differing from the true139// canonicalization algorithm in canonicalize_md.c. For this reason the140// prefix cache is conservative and is not used for complex path names.141private ExpiringCache cache = new ExpiringCache();142// On Unix symlinks can jump anywhere in the file system, so we only143// treat prefixes in java.home as trusted and cacheable in the144// canonicalization algorithm145private ExpiringCache javaHomePrefixCache = new ExpiringCache();146147public String canonicalize(String path) throws IOException {148if (!useCanonCaches) {149return canonicalize0(path);150} else {151String res = cache.get(path);152if (res == null) {153String dir = null;154String resDir = null;155if (useCanonPrefixCache) {156// Note that this can cause symlinks that should157// be resolved to a destination directory to be158// resolved to the directory they're contained in159dir = parentOrNull(path);160if (dir != null) {161resDir = javaHomePrefixCache.get(dir);162if (resDir != null) {163// Hit only in prefix cache; full path is canonical164String filename = path.substring(1 + dir.length());165res = resDir + slash + filename;166cache.put(dir + slash + filename, res);167}168}169}170if (res == null) {171res = canonicalize0(path);172cache.put(path, res);173if (useCanonPrefixCache &&174dir != null && dir.startsWith(javaHome)) {175resDir = parentOrNull(res);176// Note that we don't allow a resolved symlink177// to elsewhere in java.home to pollute the178// prefix cache (java.home prefix cache could179// just as easily be a set at this point)180if (resDir != null && resDir.equals(dir)) {181File f = new File(res);182if (f.exists() && !f.isDirectory()) {183javaHomePrefixCache.put(dir, resDir);184}185}186}187}188}189return res;190}191}192private native String canonicalize0(String path) throws IOException;193// Best-effort attempt to get parent of this path; used for194// optimization of filename canonicalization. This must return null for195// any cases where the code in canonicalize_md.c would throw an196// exception or otherwise deal with non-simple pathnames like handling197// of "." and "..". It may conservatively return null in other198// situations as well. Returning null will cause the underlying199// (expensive) canonicalization routine to be called.200static String parentOrNull(String path) {201if (path == null) return null;202char sep = File.separatorChar;203int last = path.length() - 1;204int idx = last;205int adjacentDots = 0;206int nonDotCount = 0;207while (idx > 0) {208char c = path.charAt(idx);209if (c == '.') {210if (++adjacentDots >= 2) {211// Punt on pathnames containing . and ..212return null;213}214} else if (c == sep) {215if (adjacentDots == 1 && nonDotCount == 0) {216// Punt on pathnames containing . and ..217return null;218}219if (idx == 0 ||220idx >= last - 1 ||221path.charAt(idx - 1) == sep) {222// Punt on pathnames containing adjacent slashes223// toward the end224return null;225}226return path.substring(0, idx);227} else {228++nonDotCount;229adjacentDots = 0;230}231--idx;232}233return null;234}235236/* -- Attribute accessors -- */237238public native int getBooleanAttributes0(File f);239240public int getBooleanAttributes(File f) {241int rv = getBooleanAttributes0(f);242String name = f.getName();243boolean hidden = (name.length() > 0) && (name.charAt(0) == '.');244return rv | (hidden ? BA_HIDDEN : 0);245}246247public native boolean checkAccess(File f, int access);248public native long getLastModifiedTime(File f);249public native long getLength(File f);250public native boolean setPermission(File f, int access, boolean enable, boolean owneronly);251252/* -- File operations -- */253254public native boolean createFileExclusively(String path)255throws IOException;256public boolean delete(File f) {257// Keep canonicalization caches in sync after file deletion258// and renaming operations. Could be more clever than this259// (i.e., only remove/update affected entries) but probably260// not worth it since these entries expire after 30 seconds261// anyway.262cache.clear();263javaHomePrefixCache.clear();264return delete0(f);265}266private native boolean delete0(File f);267public native String[] list(File f);268public native boolean createDirectory(File f);269public boolean rename(File f1, File f2) {270// Keep canonicalization caches in sync after file deletion271// and renaming operations. Could be more clever than this272// (i.e., only remove/update affected entries) but probably273// not worth it since these entries expire after 30 seconds274// anyway.275cache.clear();276javaHomePrefixCache.clear();277return rename0(f1, f2);278}279private native boolean rename0(File f1, File f2);280public native boolean setLastModifiedTime(File f, long time);281public native boolean setReadOnly(File f);282283284/* -- Filesystem interface -- */285286public File[] listRoots() {287try {288SecurityManager security = System.getSecurityManager();289if (security != null) {290security.checkRead("/");291}292return new File[] { new File("/") };293} catch (SecurityException x) {294return new File[0];295}296}297298/* -- Disk usage -- */299public native long getSpace(File f, int t);300301/* -- Basic infrastructure -- */302303public int compare(File f1, File f2) {304return f1.getPath().compareTo(f2.getPath());305}306307public int hashCode(File f) {308return f.getPath().hashCode() ^ 1234321;309}310311312private static native void initIDs();313314static {315initIDs();316}317318}319320321