UnixFileSystem.java revision 5873edf853a48362e8ee4e75181f654d0b88b8ef
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
6051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* A normal Unix pathname contains no duplicate slashes and does not end
6151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski       with a slash.  It may be the empty string. */
6251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
6351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* Normalize the given pathname, whose length is len, starting at the given
6451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski       offset; everything before this offset is already normal. */
6551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private String normalize(String pathname, int len, int off) {
6651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len == 0) return pathname;
6751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int n = len;
6851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        while ((n > 0) && (pathname.charAt(n - 1) == '/')) n--;
6951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (n == 0) return "/";
7051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        StringBuffer sb = new StringBuffer(pathname.length());
7151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (off > 0) sb.append(pathname.substring(0, off));
7251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        char prevChar = 0;
7351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (int i = off; i < n; i++) {
7451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            char c = pathname.charAt(i);
7551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if ((prevChar == '/') && (c == '/')) continue;
7651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            sb.append(c);
7751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            prevChar = c;
7851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
7951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return sb.toString();
8051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
8151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
8251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* Check that the given pathname is normal.  If not, invoke the real
8351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski       normalizer on the part of the pathname that requires normalization.
8451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski       This way we iterate through the whole pathname string only once. */
8551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String normalize(String pathname) {
8651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int n = pathname.length();
8751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        char prevChar = 0;
8851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (int i = 0; i < n; i++) {
8951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            char c = pathname.charAt(i);
9051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if ((prevChar == '/') && (c == '/'))
9151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return normalize(pathname, n, i - 1);
9251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            prevChar = c;
9351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
9451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (prevChar == '/') return normalize(pathname, n, n - 1);
9551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return pathname;
9651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
9751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
9851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int prefixLength(String pathname) {
9951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (pathname.length() == 0) return 0;
10051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return (pathname.charAt(0) == '/') ? 1 : 0;
10151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
10251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
10351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String resolve(String parent, String child) {
10451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (child.equals("")) return parent;
10551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (child.charAt(0) == '/') {
10651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (parent.equals("/")) return child;
10751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return parent + child;
10851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
10951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (parent.equals("/")) return parent + child;
11051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return parent + '/' + child;
11151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
11251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
11351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String getDefaultParent() {
11451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return "/";
11551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
11651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
11751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String fromURIPath(String path) {
11851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        String p = path;
11951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (p.endsWith("/") && (p.length() > 1)) {
12051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // "/foo/" --> "/foo", but "/" --> "/"
12151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            p = p.substring(0, p.length() - 1);
12251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
12351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return p;
12451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
12551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
12651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
12751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* -- Path operations -- */
12851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
12951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public boolean isAbsolute(File f) {
13051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return (f.getPrefixLength() != 0);
13151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
13251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
13351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String resolve(File f) {
13451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (isAbsolute(f)) return f.getPath();
13551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return resolve(System.getProperty("user.dir"), f.getPath());
13651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
13751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
13851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // Caches for canonicalization results to improve startup performance.
13951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // The first cache handles repeated canonicalizations of the same path
14051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // name. The prefix cache handles repeated canonicalizations within the
14151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // same directory, and must not create results differing from the true
14251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // canonicalization algorithm in canonicalize_md.c. For this reason the
14351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // prefix cache is conservative and is not used for complex path names.
14451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private ExpiringCache cache = new ExpiringCache();
14551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // On Unix symlinks can jump anywhere in the file system, so we only
14651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // treat prefixes in java.home as trusted and cacheable in the
14751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // canonicalization algorithm
14851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private ExpiringCache javaHomePrefixCache = new ExpiringCache();
14951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
15051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String canonicalize(String path) throws IOException {
15151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (!useCanonCaches) {
15251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return canonicalize0(path);
15351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else {
15451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            String res = cache.get(path);
15551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (res == null) {
15651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                String dir = null;
15751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                String resDir = null;
15851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (useCanonPrefixCache) {
15951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // Note that this can cause symlinks that should
16051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // be resolved to a destination directory to be
16151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // resolved to the directory they're contained in
16251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    dir = parentOrNull(path);
16351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (dir != null) {
16451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        resDir = javaHomePrefixCache.get(dir);
16551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        if (resDir != null) {
16651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            // Hit only in prefix cache; full path is canonical
16751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            String filename = path.substring(1 + dir.length());
16851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            res = resDir + slash + filename;
16951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            cache.put(dir + slash + filename, res);
17051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        }
17151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
17251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
17351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (res == null) {
1745873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath                    BlockGuard.getThreadPolicy().onReadFromDisk();
17551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    res = canonicalize0(path);
17651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    cache.put(path, res);
17751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (useCanonPrefixCache &&
17851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        dir != null && dir.startsWith(javaHome)) {
17951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        resDir = parentOrNull(res);
18051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        // Note that we don't allow a resolved symlink
18151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        // to elsewhere in java.home to pollute the
18251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        // prefix cache (java.home prefix cache could
18351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        // just as easily be a set at this point)
18451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        if (resDir != null && resDir.equals(dir)) {
18551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            File f = new File(res);
18651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            if (f.exists() && !f.isDirectory()) {
18751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                javaHomePrefixCache.put(dir, resDir);
18851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            }
18951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        }
19051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
19151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
19251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
19351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return res;
19451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
19551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
19651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private native String canonicalize0(String path) throws IOException;
19751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // Best-effort attempt to get parent of this path; used for
19851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // optimization of filename canonicalization. This must return null for
19951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // any cases where the code in canonicalize_md.c would throw an
20051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // exception or otherwise deal with non-simple pathnames like handling
20151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // of "." and "..". It may conservatively return null in other
20251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // situations as well. Returning null will cause the underlying
20351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // (expensive) canonicalization routine to be called.
20451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    static String parentOrNull(String path) {
20551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (path == null) return null;
20651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        char sep = File.separatorChar;
20751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int last = path.length() - 1;
20851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int idx = last;
20951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int adjacentDots = 0;
21051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int nonDotCount = 0;
21151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        while (idx > 0) {
21251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            char c = path.charAt(idx);
21351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (c == '.') {
21451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (++adjacentDots >= 2) {
21551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // Punt on pathnames containing . and ..
21651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return null;
21751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
21851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            } else if (c == sep) {
21951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (adjacentDots == 1 && nonDotCount == 0) {
22051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // Punt on pathnames containing . and ..
22151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return null;
22251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
22351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (idx == 0 ||
22451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    idx >= last - 1 ||
22551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    path.charAt(idx - 1) == sep) {
22651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // Punt on pathnames containing adjacent slashes
22751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // toward the end
22851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return null;
22951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
23051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return path.substring(0, idx);
23151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            } else {
23251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                ++nonDotCount;
23351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                adjacentDots = 0;
23451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
23551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            --idx;
23651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
23751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return null;
23851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
23951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
24051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* -- Attribute accessors -- */
24151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2425873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    private native int getBooleanAttributes0(String abspath);
24351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
24451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int getBooleanAttributes(File f) {
2455873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onReadFromDisk();
2465873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
24751a43d9402a355b24c0445df615d8f4975f04fc3Przemyslaw Szczepaniak        int rv = getBooleanAttributes0(f.getPath());
24851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        String name = f.getName();
24951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        boolean hidden = (name.length() > 0) && (name.charAt(0) == '.');
25051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return rv | (hidden ? BA_HIDDEN : 0);
25151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
25251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2535873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    public boolean checkAccess(File f, int access) {
2545873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onReadFromDisk();
2555873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        return checkAccess0(f, access);
2565873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    }
2575873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
2585873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    private native boolean checkAccess0(File f, int access);
2595873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
2605873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    public long getLastModifiedTime(File f) {
2615873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onReadFromDisk();
2625873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        return getLastModifiedTime0(f);
2635873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    }
2645873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
2655873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    private native long getLastModifiedTime0(File f);
2665873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
2675873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    public long getLength(File f) {
2685873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onReadFromDisk();
2695873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        return getLength0(f);
2705873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    }
2715873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
2725873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    private native long getLength0(File f);
2735873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
2745873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    public boolean setPermission(File f, int access, boolean enable, boolean owneronly) {
2755873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onWriteToDisk();
2765873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        return setPermission0(f, access, enable, owneronly);
2775873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    }
2785873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
2795873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    private native boolean setPermission0(File f, int access, boolean enable, boolean owneronly);
28051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
28151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* -- File operations -- */
28251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2835873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    public boolean createFileExclusively(String path) throws IOException {
2845873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onWriteToDisk();
2855873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        return createFileExclusively0(path);
2865873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    }
2875873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
2885873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    private native boolean createFileExclusively0(String path) throws IOException;
2895873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
29051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public boolean delete(File f) {
29151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // Keep canonicalization caches in sync after file deletion
29251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // and renaming operations. Could be more clever than this
29351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // (i.e., only remove/update affected entries) but probably
29451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // not worth it since these entries expire after 30 seconds
29551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // anyway.
29651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        cache.clear();
29751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        javaHomePrefixCache.clear();
2985873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onWriteToDisk();
29951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return delete0(f);
30051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
3015873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
30251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private native boolean delete0(File f);
3035873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
3045873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    public String[] list(File f) {
3055873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onReadFromDisk();
3065873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        return list0(f);
3075873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    }
3085873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
3095873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    private native String[] list0(File f);
3105873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
3115873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    public boolean createDirectory(File f) {
3125873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onWriteToDisk();
3135873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        return createDirectory0(f);
3145873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    }
3155873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
3165873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    private native boolean createDirectory0(File f);
3175873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
31851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public boolean rename(File f1, File f2) {
31951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // Keep canonicalization caches in sync after file deletion
32051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // and renaming operations. Could be more clever than this
32151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // (i.e., only remove/update affected entries) but probably
32251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // not worth it since these entries expire after 30 seconds
32351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // anyway.
32451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        cache.clear();
32551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        javaHomePrefixCache.clear();
3265873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onWriteToDisk();
32751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return rename0(f1, f2);
32851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
3295873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
33051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private native boolean rename0(File f1, File f2);
3315873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
3325873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    public boolean setLastModifiedTime(File f, long time) {
3335873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onWriteToDisk();
3345873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        return setLastModifiedTime0(f, time);
3355873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    }
3365873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
3375873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    private native boolean setLastModifiedTime0(File f, long time);
3385873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
3395873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    public boolean setReadOnly(File f) {
3405873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onWriteToDisk();
3415873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        return setReadOnly0(f);
3425873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    }
3435873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
3445873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    private native boolean setReadOnly0(File f);
34551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
34651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
34751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* -- Filesystem interface -- */
34851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
34951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public File[] listRoots() {
35051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        try {
35151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            SecurityManager security = System.getSecurityManager();
35251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (security != null) {
35351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                security.checkRead("/");
35451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
35551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return new File[] { new File("/") };
35651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } catch (SecurityException x) {
35751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return new File[0];
35851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
35951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
36051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
36151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* -- Disk usage -- */
3625873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    public long getSpace(File f, int t) {
3635873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onReadFromDisk();
3645873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
3655873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        return getSpace0(f, t);
3665873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    }
3675873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
3685873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    private native long getSpace0(File f, int t);
36951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
37051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* -- Basic infrastructure -- */
37151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
37251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int compare(File f1, File f2) {
37351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return f1.getPath().compareTo(f2.getPath());
37451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
37551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
37651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int hashCode(File f) {
37751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return f.getPath().hashCode() ^ 1234321;
37851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
37951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
38051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
38151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static native void initIDs();
38251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
38351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    static {
38451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        initIDs();
38551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
38651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
38751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski}
388