151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski/* 251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. 351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is free software; you can redistribute it and/or modify it 651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * under the terms of the GNU General Public License version 2 only, as 751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * published by the Free Software Foundation. Oracle designates this 851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * particular file as subject to the "Classpath" exception as provided 951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * by Oracle in the LICENSE file that accompanied this code. 1051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 1151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * This code is distributed in the hope that it will be useful, but WITHOUT 1251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * version 2 for more details (a copy is included in the LICENSE file that 1551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * accompanied this code). 1651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 1751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * You should have received a copy of the GNU General Public License version 1851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 2 along with this work; if not, write to the Free Software Foundation, 1951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * 2151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * or visit www.oracle.com if you need additional information or have any 2351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski * questions. 2451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski */ 2551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 2651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskipackage java.io; 2751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 2851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport java.security.AccessController; 295873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath 305873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamathimport dalvik.system.BlockGuard; 3151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport sun.security.action.GetPropertyAction; 3251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 3351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 3451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiclass UnixFileSystem extends FileSystem { 3551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 3651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private final char slash; 3751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private final char colon; 3851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private final String javaHome; 3951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 4051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public UnixFileSystem() { 4151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski slash = AccessController.doPrivileged( 4251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski new GetPropertyAction("file.separator")).charAt(0); 4351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski colon = AccessController.doPrivileged( 4451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski new GetPropertyAction("path.separator")).charAt(0); 4551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski javaHome = AccessController.doPrivileged( 4651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski new GetPropertyAction("java.home")); 4751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 4851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 4951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 5051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /* -- Normalization and construction -- */ 5151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 5251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public char getSeparator() { 5351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return slash; 5451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 5551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 5651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public char getPathSeparator() { 5751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return colon; 5851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 5951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 609d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath /* 619d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath * A normal Unix pathname does not contain consecutive slashes and does not end 629d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath * with a slash. The empty string and "/" are special cases that are also 639d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath * considered normal. 649d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath */ 6551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public String normalize(String pathname) { 6651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int n = pathname.length(); 679d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath char[] normalized = pathname.toCharArray(); 689d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath int index = 0; 6951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski char prevChar = 0; 7051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski for (int i = 0; i < n; i++) { 719d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath char current = normalized[i]; 729d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath // Remove duplicate slashes. 739d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath if (!(current == '/' && prevChar == '/')) { 749d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath normalized[index++] = current; 759d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath } 769d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath 779d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath prevChar = current; 7851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 799d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath 809d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath // Omit the trailing slash, except when pathname == "/". 819d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath if (prevChar == '/' && n > 1) { 829d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath index--; 839d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath } 849d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath 859d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath return (index != n) ? new String(normalized, 0, index) : pathname; 8651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 8751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 8851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public int prefixLength(String pathname) { 8951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (pathname.length() == 0) return 0; 9051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return (pathname.charAt(0) == '/') ? 1 : 0; 9151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 9251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 939d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath // Invariant: Both |parent| and |child| are normalized paths. 9451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public String resolve(String parent, String child) { 959d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath if (child.isEmpty() || child.equals("/")) { 969d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath return parent; 979d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath } 989d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath 9951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (child.charAt(0) == '/') { 10051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (parent.equals("/")) return child; 10151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return parent + child; 10251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 1039d555f25ad1b3b238cd559396cb5e05b788934bbNarayan Kamath 10451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (parent.equals("/")) return parent + child; 10551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return parent + '/' + child; 10651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 10751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 10851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public String getDefaultParent() { 10951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return "/"; 11051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 11151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 11251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public String fromURIPath(String path) { 11351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski String p = path; 11451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (p.endsWith("/") && (p.length() > 1)) { 11551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // "/foo/" --> "/foo", but "/" --> "/" 11651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski p = p.substring(0, p.length() - 1); 11751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 11851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return p; 11951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 12051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 12151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 12251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /* -- Path operations -- */ 12351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 12451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public boolean isAbsolute(File f) { 12551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return (f.getPrefixLength() != 0); 12651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 12751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 12851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public String resolve(File f) { 12951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (isAbsolute(f)) return f.getPath(); 13051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return resolve(System.getProperty("user.dir"), f.getPath()); 13151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 13251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 13351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Caches for canonicalization results to improve startup performance. 13451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // The first cache handles repeated canonicalizations of the same path 13551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // name. The prefix cache handles repeated canonicalizations within the 13651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // same directory, and must not create results differing from the true 13751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // canonicalization algorithm in canonicalize_md.c. For this reason the 13851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // prefix cache is conservative and is not used for complex path names. 13951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private ExpiringCache cache = new ExpiringCache(); 14051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // On Unix symlinks can jump anywhere in the file system, so we only 14151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // treat prefixes in java.home as trusted and cacheable in the 14251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // canonicalization algorithm 14351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private ExpiringCache javaHomePrefixCache = new ExpiringCache(); 14451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 14551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public String canonicalize(String path) throws IOException { 14651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (!useCanonCaches) { 14751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return canonicalize0(path); 14851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else { 14951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski String res = cache.get(path); 15051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (res == null) { 15151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski String dir = null; 15251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski String resDir = null; 15351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (useCanonPrefixCache) { 15451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Note that this can cause symlinks that should 15551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // be resolved to a destination directory to be 15651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // resolved to the directory they're contained in 15751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski dir = parentOrNull(path); 15851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (dir != null) { 15951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski resDir = javaHomePrefixCache.get(dir); 16051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (resDir != null) { 16151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Hit only in prefix cache; full path is canonical 16251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski String filename = path.substring(1 + dir.length()); 16351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski res = resDir + slash + filename; 16451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski cache.put(dir + slash + filename, res); 16551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 16651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 16751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 16851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (res == null) { 1695873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath BlockGuard.getThreadPolicy().onReadFromDisk(); 17051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski res = canonicalize0(path); 17151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski cache.put(path, res); 17251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (useCanonPrefixCache && 17351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski dir != null && dir.startsWith(javaHome)) { 17451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski resDir = parentOrNull(res); 17551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Note that we don't allow a resolved symlink 17651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // to elsewhere in java.home to pollute the 17751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // prefix cache (java.home prefix cache could 17851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // just as easily be a set at this point) 17951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (resDir != null && resDir.equals(dir)) { 18051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski File f = new File(res); 18151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (f.exists() && !f.isDirectory()) { 18251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski javaHomePrefixCache.put(dir, resDir); 18351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 18451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 18551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 18651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 18751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 18851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return res; 18951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 19051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 19151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private native String canonicalize0(String path) throws IOException; 19251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Best-effort attempt to get parent of this path; used for 19351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // optimization of filename canonicalization. This must return null for 19451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // any cases where the code in canonicalize_md.c would throw an 19551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // exception or otherwise deal with non-simple pathnames like handling 19651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // of "." and "..". It may conservatively return null in other 19751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // situations as well. Returning null will cause the underlying 19851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // (expensive) canonicalization routine to be called. 19951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski static String parentOrNull(String path) { 20051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (path == null) return null; 20151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski char sep = File.separatorChar; 20251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int last = path.length() - 1; 20351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int idx = last; 20451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int adjacentDots = 0; 20551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski int nonDotCount = 0; 20651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski while (idx > 0) { 20751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski char c = path.charAt(idx); 20851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (c == '.') { 20951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (++adjacentDots >= 2) { 21051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Punt on pathnames containing . and .. 21151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return null; 21251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 21351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else if (c == sep) { 21451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (adjacentDots == 1 && nonDotCount == 0) { 21551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Punt on pathnames containing . and .. 21651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return null; 21751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 21851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (idx == 0 || 21951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski idx >= last - 1 || 22051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski path.charAt(idx - 1) == sep) { 22151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Punt on pathnames containing adjacent slashes 22251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // toward the end 22351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return null; 22451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 22551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return path.substring(0, idx); 22651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } else { 22751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski ++nonDotCount; 22851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski adjacentDots = 0; 22951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 23051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski --idx; 23151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 23251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return null; 23351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 23451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 23551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /* -- Attribute accessors -- */ 23651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 2375873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath private native int getBooleanAttributes0(String abspath); 23851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 23961cf642f86a0af82e88fb27f31e6842435326b5aPrzemyslaw Szczepaniak // Android-changed: Added thread policy check 24051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public int getBooleanAttributes(File f) { 2415873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath BlockGuard.getThreadPolicy().onReadFromDisk(); 2425873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath 24351a43d9402a355b24c0445df615d8f4975f04fc3Przemyslaw Szczepaniak int rv = getBooleanAttributes0(f.getPath()); 24451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski String name = f.getName(); 24551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski boolean hidden = (name.length() > 0) && (name.charAt(0) == '.'); 24651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return rv | (hidden ? BA_HIDDEN : 0); 24751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 24851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 24961cf642f86a0af82e88fb27f31e6842435326b5aPrzemyslaw Szczepaniak // Android-changed: Added thread policy check 2505873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath public boolean checkAccess(File f, int access) { 2515873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath BlockGuard.getThreadPolicy().onReadFromDisk(); 2525873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath return checkAccess0(f, access); 2535873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath } 2545873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath private native boolean checkAccess0(File f, int access); 2555873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath 25661cf642f86a0af82e88fb27f31e6842435326b5aPrzemyslaw Szczepaniak // Android-changed: Added thread policy check 2575873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath public long getLastModifiedTime(File f) { 2585873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath BlockGuard.getThreadPolicy().onReadFromDisk(); 2595873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath return getLastModifiedTime0(f); 2605873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath } 2615873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath private native long getLastModifiedTime0(File f); 2625873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath 26361cf642f86a0af82e88fb27f31e6842435326b5aPrzemyslaw Szczepaniak // Android-changed: Added thread policy check 2645873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath public long getLength(File f) { 2655873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath BlockGuard.getThreadPolicy().onReadFromDisk(); 2665873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath return getLength0(f); 2675873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath } 2685873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath private native long getLength0(File f); 2695873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath 27061cf642f86a0af82e88fb27f31e6842435326b5aPrzemyslaw Szczepaniak // Android-changed: Added thread policy check 2715873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath public boolean setPermission(File f, int access, boolean enable, boolean owneronly) { 2725873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath BlockGuard.getThreadPolicy().onWriteToDisk(); 2735873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath return setPermission0(f, access, enable, owneronly); 2745873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath } 2755873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath private native boolean setPermission0(File f, int access, boolean enable, boolean owneronly); 27651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 27751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /* -- File operations -- */ 27861cf642f86a0af82e88fb27f31e6842435326b5aPrzemyslaw Szczepaniak // Android-changed: Added thread policy check 2795873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath public boolean createFileExclusively(String path) throws IOException { 2805873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath BlockGuard.getThreadPolicy().onWriteToDisk(); 2815873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath return createFileExclusively0(path); 2825873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath } 2835873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath private native boolean createFileExclusively0(String path) throws IOException; 2845873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath 28561cf642f86a0af82e88fb27f31e6842435326b5aPrzemyslaw Szczepaniak // Android-changed: Added thread policy check 28651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public boolean delete(File f) { 28751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Keep canonicalization caches in sync after file deletion 28851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // and renaming operations. Could be more clever than this 28951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // (i.e., only remove/update affected entries) but probably 29051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // not worth it since these entries expire after 30 seconds 29151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // anyway. 29251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski cache.clear(); 29351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski javaHomePrefixCache.clear(); 2945873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath BlockGuard.getThreadPolicy().onWriteToDisk(); 29551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return delete0(f); 29651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 2975873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath 29851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private native boolean delete0(File f); 2995873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath 30061cf642f86a0af82e88fb27f31e6842435326b5aPrzemyslaw Szczepaniak // Android-changed: Added thread policy check 3015873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath public String[] list(File f) { 3025873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath BlockGuard.getThreadPolicy().onReadFromDisk(); 3035873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath return list0(f); 3045873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath } 3055873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath private native String[] list0(File f); 3065873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath 30761cf642f86a0af82e88fb27f31e6842435326b5aPrzemyslaw Szczepaniak // Android-changed: Added thread policy check 3085873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath public boolean createDirectory(File f) { 3095873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath BlockGuard.getThreadPolicy().onWriteToDisk(); 3105873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath return createDirectory0(f); 3115873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath } 3125873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath private native boolean createDirectory0(File f); 3135873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath 31461cf642f86a0af82e88fb27f31e6842435326b5aPrzemyslaw Szczepaniak // Android-changed: Added thread policy check 31551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public boolean rename(File f1, File f2) { 31651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // Keep canonicalization caches in sync after file deletion 31751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // and renaming operations. Could be more clever than this 31851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // (i.e., only remove/update affected entries) but probably 31951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // not worth it since these entries expire after 30 seconds 32051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski // anyway. 32151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski cache.clear(); 32251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski javaHomePrefixCache.clear(); 3235873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath BlockGuard.getThreadPolicy().onWriteToDisk(); 32451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return rename0(f1, f2); 32551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 3265873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath 32751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private native boolean rename0(File f1, File f2); 3285873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath 32961cf642f86a0af82e88fb27f31e6842435326b5aPrzemyslaw Szczepaniak // Android-changed: Added thread policy check 3305873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath public boolean setLastModifiedTime(File f, long time) { 3315873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath BlockGuard.getThreadPolicy().onWriteToDisk(); 3325873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath return setLastModifiedTime0(f, time); 3335873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath } 3345873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath private native boolean setLastModifiedTime0(File f, long time); 3355873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath 33661cf642f86a0af82e88fb27f31e6842435326b5aPrzemyslaw Szczepaniak // Android-changed: Added thread policy check 3375873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath public boolean setReadOnly(File f) { 3385873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath BlockGuard.getThreadPolicy().onWriteToDisk(); 3395873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath return setReadOnly0(f); 3405873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath } 3415873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath private native boolean setReadOnly0(File f); 34251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 34351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 34451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /* -- Filesystem interface -- */ 34551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 34651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public File[] listRoots() { 34751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski try { 34851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski SecurityManager security = System.getSecurityManager(); 34951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski if (security != null) { 35051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski security.checkRead("/"); 35151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 35251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return new File[] { new File("/") }; 35351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } catch (SecurityException x) { 35451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return new File[0]; 35551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 35651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 35751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 35851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /* -- Disk usage -- */ 35961cf642f86a0af82e88fb27f31e6842435326b5aPrzemyslaw Szczepaniak // Android-changed: Added thread policy check 3605873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath public long getSpace(File f, int t) { 3615873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath BlockGuard.getThreadPolicy().onReadFromDisk(); 3625873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath 3635873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath return getSpace0(f, t); 3645873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath } 3655873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath private native long getSpace0(File f, int t); 36651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 36751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski /* -- Basic infrastructure -- */ 36851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 36951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public int compare(File f1, File f2) { 37051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return f1.getPath().compareTo(f2.getPath()); 37151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 37251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 37351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski public int hashCode(File f) { 37451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski return f.getPath().hashCode() ^ 1234321; 37551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 37651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 37751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 37851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski private static native void initIDs(); 37951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 38051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski static { 38151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski initIDs(); 38251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski } 38351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski 38451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski} 385