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
23951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int getBooleanAttributes(File f) {
2405873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onReadFromDisk();
2415873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
24251a43d9402a355b24c0445df615d8f4975f04fc3Przemyslaw Szczepaniak        int rv = getBooleanAttributes0(f.getPath());
24351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        String name = f.getName();
24451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        boolean hidden = (name.length() > 0) && (name.charAt(0) == '.');
24551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return rv | (hidden ? BA_HIDDEN : 0);
24651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
24751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2485873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    public boolean checkAccess(File f, int access) {
2495873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onReadFromDisk();
2505873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        return checkAccess0(f, access);
2515873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    }
2525873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
2535873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    private native boolean checkAccess0(File f, int access);
2545873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
2555873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    public long getLastModifiedTime(File f) {
2565873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onReadFromDisk();
2575873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        return getLastModifiedTime0(f);
2585873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    }
2595873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
2605873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    private native long getLastModifiedTime0(File f);
2615873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
2625873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    public long getLength(File f) {
2635873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onReadFromDisk();
2645873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        return getLength0(f);
2655873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    }
2665873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
2675873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    private native long getLength0(File f);
2685873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
2695873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    public boolean setPermission(File f, int access, boolean enable, boolean owneronly) {
2705873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onWriteToDisk();
2715873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        return setPermission0(f, access, enable, owneronly);
2725873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    }
2735873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
2745873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    private native boolean setPermission0(File f, int access, boolean enable, boolean owneronly);
27551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
27651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* -- File operations -- */
27751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
2785873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    public boolean createFileExclusively(String path) throws IOException {
2795873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onWriteToDisk();
2805873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        return createFileExclusively0(path);
2815873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    }
2825873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
2835873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    private native boolean createFileExclusively0(String path) throws IOException;
2845873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
28551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public boolean delete(File f) {
28651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // Keep canonicalization caches in sync after file deletion
28751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // and renaming operations. Could be more clever than this
28851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // (i.e., only remove/update affected entries) but probably
28951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // not worth it since these entries expire after 30 seconds
29051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // anyway.
29151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        cache.clear();
29251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        javaHomePrefixCache.clear();
2935873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onWriteToDisk();
29451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return delete0(f);
29551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
2965873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
29751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private native boolean delete0(File f);
2985873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
2995873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    public String[] list(File f) {
3005873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onReadFromDisk();
3015873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        return list0(f);
3025873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    }
3035873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
3045873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    private native String[] list0(File f);
3055873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
3065873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    public boolean createDirectory(File f) {
3075873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onWriteToDisk();
3085873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        return createDirectory0(f);
3095873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    }
3105873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
3115873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    private native boolean createDirectory0(File f);
3125873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
31351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public boolean rename(File f1, File f2) {
31451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // Keep canonicalization caches in sync after file deletion
31551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // and renaming operations. Could be more clever than this
31651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // (i.e., only remove/update affected entries) but probably
31751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // not worth it since these entries expire after 30 seconds
31851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // anyway.
31951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        cache.clear();
32051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        javaHomePrefixCache.clear();
3215873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onWriteToDisk();
32251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return rename0(f1, f2);
32351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
3245873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
32551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private native boolean rename0(File f1, File f2);
3265873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
3275873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    public boolean setLastModifiedTime(File f, long time) {
3285873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onWriteToDisk();
3295873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        return setLastModifiedTime0(f, time);
3305873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    }
3315873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
3325873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    private native boolean setLastModifiedTime0(File f, long time);
3335873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
3345873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    public boolean setReadOnly(File f) {
3355873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onWriteToDisk();
3365873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        return setReadOnly0(f);
3375873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    }
3385873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
3395873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    private native boolean setReadOnly0(File f);
34051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
34151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
34251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* -- Filesystem interface -- */
34351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
34451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public File[] listRoots() {
34551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        try {
34651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            SecurityManager security = System.getSecurityManager();
34751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (security != null) {
34851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                security.checkRead("/");
34951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
35051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return new File[] { new File("/") };
35151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } catch (SecurityException x) {
35251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return new File[0];
35351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
35451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
35551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
35651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* -- Disk usage -- */
3575873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    public long getSpace(File f, int t) {
3585873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        BlockGuard.getThreadPolicy().onReadFromDisk();
3595873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
3605873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath        return getSpace0(f, t);
3615873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    }
3625873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath
3635873edf853a48362e8ee4e75181f654d0b88b8efNarayan Kamath    private native long getSpace0(File f, int t);
36451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
36551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* -- Basic infrastructure -- */
36651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
36751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int compare(File f1, File f2) {
36851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return f1.getPath().compareTo(f2.getPath());
36951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
37051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
37151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int hashCode(File f) {
37251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return f.getPath().hashCode() ^ 1234321;
37351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
37451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
37551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
37651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static native void initIDs();
37751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
37851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    static {
37951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        initIDs();
38051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
38151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
38251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski}
383