UnixFileSystem.java revision 51a43d9402a355b24c0445df615d8f4975f04fc3
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;
2951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiimport sun.security.action.GetPropertyAction;
3051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
3151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
3251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebskiclass UnixFileSystem extends FileSystem {
3351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
3451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private final char slash;
3551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private final char colon;
3651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private final String javaHome;
3751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
3851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public UnixFileSystem() {
3951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        slash = AccessController.doPrivileged(
4051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            new GetPropertyAction("file.separator")).charAt(0);
4151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        colon = AccessController.doPrivileged(
4251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            new GetPropertyAction("path.separator")).charAt(0);
4351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        javaHome = AccessController.doPrivileged(
4451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            new GetPropertyAction("java.home"));
4551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
4651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
4751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
4851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* -- Normalization and construction -- */
4951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
5051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public char getSeparator() {
5151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return slash;
5251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
5351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
5451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public char getPathSeparator() {
5551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return colon;
5651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
5751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
5851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* A normal Unix pathname contains no duplicate slashes and does not end
5951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski       with a slash.  It may be the empty string. */
6051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
6151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* Normalize the given pathname, whose length is len, starting at the given
6251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski       offset; everything before this offset is already normal. */
6351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private String normalize(String pathname, int len, int off) {
6451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (len == 0) return pathname;
6551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int n = len;
6651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        while ((n > 0) && (pathname.charAt(n - 1) == '/')) n--;
6751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (n == 0) return "/";
6851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        StringBuffer sb = new StringBuffer(pathname.length());
6951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (off > 0) sb.append(pathname.substring(0, off));
7051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        char prevChar = 0;
7151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (int i = off; i < n; i++) {
7251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            char c = pathname.charAt(i);
7351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if ((prevChar == '/') && (c == '/')) continue;
7451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            sb.append(c);
7551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            prevChar = c;
7651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
7751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return sb.toString();
7851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
7951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
8051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* Check that the given pathname is normal.  If not, invoke the real
8151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski       normalizer on the part of the pathname that requires normalization.
8251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski       This way we iterate through the whole pathname string only once. */
8351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String normalize(String pathname) {
8451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int n = pathname.length();
8551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        char prevChar = 0;
8651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        for (int i = 0; i < n; i++) {
8751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            char c = pathname.charAt(i);
8851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if ((prevChar == '/') && (c == '/'))
8951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return normalize(pathname, n, i - 1);
9051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            prevChar = c;
9151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
9251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (prevChar == '/') return normalize(pathname, n, n - 1);
9351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return pathname;
9451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
9551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
9651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int prefixLength(String pathname) {
9751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (pathname.length() == 0) return 0;
9851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return (pathname.charAt(0) == '/') ? 1 : 0;
9951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
10051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
10151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String resolve(String parent, String child) {
10251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (child.equals("")) return parent;
10351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (child.charAt(0) == '/') {
10451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (parent.equals("/")) return child;
10551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return parent + child;
10651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
10751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (parent.equals("/")) return parent + child;
10851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return parent + '/' + child;
10951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
11051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
11151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String getDefaultParent() {
11251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return "/";
11351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
11451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
11551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String fromURIPath(String path) {
11651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        String p = path;
11751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (p.endsWith("/") && (p.length() > 1)) {
11851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            // "/foo/" --> "/foo", but "/" --> "/"
11951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            p = p.substring(0, p.length() - 1);
12051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
12151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return p;
12251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
12351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
12451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
12551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* -- Path operations -- */
12651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
12751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public boolean isAbsolute(File f) {
12851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return (f.getPrefixLength() != 0);
12951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
13051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
13151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String resolve(File f) {
13251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (isAbsolute(f)) return f.getPath();
13351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return resolve(System.getProperty("user.dir"), f.getPath());
13451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
13551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
13651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // Caches for canonicalization results to improve startup performance.
13751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // The first cache handles repeated canonicalizations of the same path
13851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // name. The prefix cache handles repeated canonicalizations within the
13951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // same directory, and must not create results differing from the true
14051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // canonicalization algorithm in canonicalize_md.c. For this reason the
14151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // prefix cache is conservative and is not used for complex path names.
14251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private ExpiringCache cache = new ExpiringCache();
14351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // On Unix symlinks can jump anywhere in the file system, so we only
14451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // treat prefixes in java.home as trusted and cacheable in the
14551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // canonicalization algorithm
14651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private ExpiringCache javaHomePrefixCache = new ExpiringCache();
14751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
14851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public String canonicalize(String path) throws IOException {
14951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (!useCanonCaches) {
15051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return canonicalize0(path);
15151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } else {
15251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            String res = cache.get(path);
15351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (res == null) {
15451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                String dir = null;
15551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                String resDir = null;
15651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (useCanonPrefixCache) {
15751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // Note that this can cause symlinks that should
15851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // be resolved to a destination directory to be
15951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // resolved to the directory they're contained in
16051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    dir = parentOrNull(path);
16151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (dir != null) {
16251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        resDir = javaHomePrefixCache.get(dir);
16351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        if (resDir != null) {
16451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            // Hit only in prefix cache; full path is canonical
16551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            String filename = path.substring(1 + dir.length());
16651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            res = resDir + slash + filename;
16751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            cache.put(dir + slash + filename, res);
16851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        }
16951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
17051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
17151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (res == null) {
17251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    res = canonicalize0(path);
17351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    cache.put(path, res);
17451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    if (useCanonPrefixCache &&
17551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        dir != null && dir.startsWith(javaHome)) {
17651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        resDir = parentOrNull(res);
17751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        // Note that we don't allow a resolved symlink
17851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        // to elsewhere in java.home to pollute the
17951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        // prefix cache (java.home prefix cache could
18051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        // just as easily be a set at this point)
18151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        if (resDir != null && resDir.equals(dir)) {
18251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            File f = new File(res);
18351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            if (f.exists() && !f.isDirectory()) {
18451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                                javaHomePrefixCache.put(dir, resDir);
18551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                            }
18651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                        }
18751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    }
18851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
18951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
19051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return res;
19151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
19251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
19351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private native String canonicalize0(String path) throws IOException;
19451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // Best-effort attempt to get parent of this path; used for
19551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // optimization of filename canonicalization. This must return null for
19651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // any cases where the code in canonicalize_md.c would throw an
19751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // exception or otherwise deal with non-simple pathnames like handling
19851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // of "." and "..". It may conservatively return null in other
19951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // situations as well. Returning null will cause the underlying
20051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    // (expensive) canonicalization routine to be called.
20151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    static String parentOrNull(String path) {
20251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        if (path == null) return null;
20351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        char sep = File.separatorChar;
20451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int last = path.length() - 1;
20551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int idx = last;
20651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int adjacentDots = 0;
20751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        int nonDotCount = 0;
20851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        while (idx > 0) {
20951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            char c = path.charAt(idx);
21051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (c == '.') {
21151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (++adjacentDots >= 2) {
21251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // Punt on pathnames containing . and ..
21351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return null;
21451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
21551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            } else if (c == sep) {
21651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (adjacentDots == 1 && nonDotCount == 0) {
21751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // Punt on pathnames containing . and ..
21851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return null;
21951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
22051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                if (idx == 0 ||
22151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    idx >= last - 1 ||
22251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    path.charAt(idx - 1) == sep) {
22351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // Punt on pathnames containing adjacent slashes
22451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    // toward the end
22551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                    return null;
22651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                }
22751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                return path.substring(0, idx);
22851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            } else {
22951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                ++nonDotCount;
23051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                adjacentDots = 0;
23151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
23251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            --idx;
23351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
23451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return null;
23551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
23651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
23751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* -- Attribute accessors -- */
23851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
239ca51934b62bc5af84596f74ae451a09b932330efPrzemyslaw Szczepaniak    /* ----- BEGIN android -----
240ca51934b62bc5af84596f74ae451a09b932330efPrzemyslaw Szczepaniak    public native int getBooleanAttributes0(File f);*/
241ca51934b62bc5af84596f74ae451a09b932330efPrzemyslaw Szczepaniak    public native int getBooleanAttributes0(String abspath);
24251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
24351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int getBooleanAttributes(File f) {
244ca51934b62bc5af84596f74ae451a09b932330efPrzemyslaw Szczepaniak        /* ----- BEGIN android -----
245ca51934b62bc5af84596f74ae451a09b932330efPrzemyslaw Szczepaniak        int rv = getBooleanAttributes0(f);*/
24651a43d9402a355b24c0445df615d8f4975f04fc3Przemyslaw Szczepaniak        int rv = getBooleanAttributes0(f.getPath());
247ca51934b62bc5af84596f74ae451a09b932330efPrzemyslaw Szczepaniak        // ----- END android -----
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
25351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public native boolean checkAccess(File f, int access);
25451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public native long getLastModifiedTime(File f);
25551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public native long getLength(File f);
25651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public native boolean setPermission(File f, int access, boolean enable, boolean owneronly);
25751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
25851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* -- File operations -- */
25951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
26051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public native boolean createFileExclusively(String path)
26151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        throws IOException;
26251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public boolean delete(File f) {
26351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // Keep canonicalization caches in sync after file deletion
26451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // and renaming operations. Could be more clever than this
26551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // (i.e., only remove/update affected entries) but probably
26651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // not worth it since these entries expire after 30 seconds
26751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // anyway.
26851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        cache.clear();
26951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        javaHomePrefixCache.clear();
27051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return delete0(f);
27151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
27251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private native boolean delete0(File f);
27351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public native String[] list(File f);
27451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public native boolean createDirectory(File f);
27551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public boolean rename(File f1, File f2) {
27651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // Keep canonicalization caches in sync after file deletion
27751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // and renaming operations. Could be more clever than this
27851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // (i.e., only remove/update affected entries) but probably
27951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // not worth it since these entries expire after 30 seconds
28051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        // anyway.
28151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        cache.clear();
28251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        javaHomePrefixCache.clear();
28351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return rename0(f1, f2);
28451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
28551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private native boolean rename0(File f1, File f2);
28651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public native boolean setLastModifiedTime(File f, long time);
28751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public native boolean setReadOnly(File f);
28851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
28951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
29051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* -- Filesystem interface -- */
29151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
29251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public File[] listRoots() {
29351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        try {
29451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            SecurityManager security = System.getSecurityManager();
29551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            if (security != null) {
29651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski                security.checkRead("/");
29751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            }
29851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return new File[] { new File("/") };
29951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        } catch (SecurityException x) {
30051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski            return new File[0];
30151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        }
30251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
30351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
30451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* -- Disk usage -- */
30551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public native long getSpace(File f, int t);
30651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
30751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    /* -- Basic infrastructure -- */
30851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
30951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int compare(File f1, File f2) {
31051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return f1.getPath().compareTo(f2.getPath());
31151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
31251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
31351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    public int hashCode(File f) {
31451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        return f.getPath().hashCode() ^ 1234321;
31551b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
31651b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
31751b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
31851b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    private static native void initIDs();
31951b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
32051b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    static {
32151b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski        initIDs();
32251b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski    }
32351b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski
32451b1b6997fd3f980076b8081f7f1165ccc2a4008Piotr Jastrzebski}
325