Save This Page
Home » openjdk-7 » java » io » [javadoc | source]
    1   /*
    2    * Copyright 1998-2005 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   
   26   package java.io;
   27   
   28   import java.security.AccessController;
   29   import sun.security.action.GetPropertyAction;
   30   
   31   
   32   class UnixFileSystem extends FileSystem {
   33   
   34       private final char slash;
   35       private final char colon;
   36       private final String javaHome;
   37   
   38       public UnixFileSystem() {
   39           slash = AccessController.doPrivileged(
   40               new GetPropertyAction("file.separator")).charAt(0);
   41           colon = AccessController.doPrivileged(
   42               new GetPropertyAction("path.separator")).charAt(0);
   43           javaHome = AccessController.doPrivileged(
   44               new GetPropertyAction("java.home"));
   45       }
   46   
   47   
   48       /* -- Normalization and construction -- */
   49   
   50       public char getSeparator() {
   51           return slash;
   52       }
   53   
   54       public char getPathSeparator() {
   55           return colon;
   56       }
   57   
   58       /* A normal Unix pathname contains no duplicate slashes and does not end
   59          with a slash.  It may be the empty string. */
   60   
   61       /* Normalize the given pathname, whose length is len, starting at the given
   62          offset; everything before this offset is already normal. */
   63       private String normalize(String pathname, int len, int off) {
   64           if (len == 0) return pathname;
   65           int n = len;
   66           while ((n > 0) && (pathname.charAt(n - 1) == '/')) n--;
   67           if (n == 0) return "/";
   68           StringBuffer sb = new StringBuffer(pathname.length());
   69           if (off > 0) sb.append(pathname.substring(0, off));
   70           char prevChar = 0;
   71           for (int i = off; i < n; i++) {
   72               char c = pathname.charAt(i);
   73               if ((prevChar == '/') && (c == '/')) continue;
   74               sb.append(c);
   75               prevChar = c;
   76           }
   77           return sb.toString();
   78       }
   79   
   80       /* Check that the given pathname is normal.  If not, invoke the real
   81          normalizer on the part of the pathname that requires normalization.
   82          This way we iterate through the whole pathname string only once. */
   83       public String normalize(String pathname) {
   84           int n = pathname.length();
   85           char prevChar = 0;
   86           for (int i = 0; i < n; i++) {
   87               char c = pathname.charAt(i);
   88               if ((prevChar == '/') && (c == '/'))
   89                   return normalize(pathname, n, i - 1);
   90               prevChar = c;
   91           }
   92           if (prevChar == '/') return normalize(pathname, n, n - 1);
   93           return pathname;
   94       }
   95   
   96       public int prefixLength(String pathname) {
   97           if (pathname.length() == 0) return 0;
   98           return (pathname.charAt(0) == '/') ? 1 : 0;
   99       }
  100   
  101       public String resolve(String parent, String child) {
  102           if (child.equals("")) return parent;
  103           if (child.charAt(0) == '/') {
  104               if (parent.equals("/")) return child;
  105               return parent + child;
  106           }
  107           if (parent.equals("/")) return parent + child;
  108           return parent + '/' + child;
  109       }
  110   
  111       public String getDefaultParent() {
  112           return "/";
  113       }
  114   
  115       public String fromURIPath(String path) {
  116           String p = path;
  117           if (p.endsWith("/") && (p.length() > 1)) {
  118               // "/foo/" --> "/foo", but "/" --> "/"
  119               p = p.substring(0, p.length() - 1);
  120           }
  121           return p;
  122       }
  123   
  124   
  125       /* -- Path operations -- */
  126   
  127       public boolean isAbsolute(File f) {
  128           return (f.getPrefixLength() != 0);
  129       }
  130   
  131       public String resolve(File f) {
  132           if (isAbsolute(f)) return f.getPath();
  133           return resolve(System.getProperty("user.dir"), f.getPath());
  134       }
  135   
  136       // Caches for canonicalization results to improve startup performance.
  137       // The first cache handles repeated canonicalizations of the same path
  138       // name. The prefix cache handles repeated canonicalizations within the
  139       // same directory, and must not create results differing from the true
  140       // canonicalization algorithm in canonicalize_md.c. For this reason the
  141       // prefix cache is conservative and is not used for complex path names.
  142       private ExpiringCache cache = new ExpiringCache();
  143       // On Unix symlinks can jump anywhere in the file system, so we only
  144       // treat prefixes in java.home as trusted and cacheable in the
  145       // canonicalization algorithm
  146       private ExpiringCache javaHomePrefixCache = new ExpiringCache();
  147   
  148       public String canonicalize(String path) throws IOException {
  149           if (!useCanonCaches) {
  150               return canonicalize0(path);
  151           } else {
  152               String res = cache.get(path);
  153               if (res == null) {
  154                   String dir = null;
  155                   String resDir = null;
  156                   if (useCanonPrefixCache) {
  157                       // Note that this can cause symlinks that should
  158                       // be resolved to a destination directory to be
  159                       // resolved to the directory they're contained in
  160                       dir = parentOrNull(path);
  161                       if (dir != null) {
  162                           resDir = javaHomePrefixCache.get(dir);
  163                           if (resDir != null) {
  164                               // Hit only in prefix cache; full path is canonical
  165                               String filename = path.substring(1 + dir.length());
  166                               res = resDir + slash + filename;
  167                               cache.put(dir + slash + filename, res);
  168                           }
  169                       }
  170                   }
  171                   if (res == null) {
  172                       res = canonicalize0(path);
  173                       cache.put(path, res);
  174                       if (useCanonPrefixCache &&
  175                           dir != null && dir.startsWith(javaHome)) {
  176                           resDir = parentOrNull(res);
  177                           // Note that we don't allow a resolved symlink
  178                           // to elsewhere in java.home to pollute the
  179                           // prefix cache (java.home prefix cache could
  180                           // just as easily be a set at this point)
  181                           if (resDir != null && resDir.equals(dir)) {
  182                               File f = new File(res);
  183                               if (f.exists() && !f.isDirectory()) {
  184                                   javaHomePrefixCache.put(dir, resDir);
  185                               }
  186                           }
  187                       }
  188                   }
  189               }
  190               assert canonicalize0(path).equals(res) || path.startsWith(javaHome);
  191               return res;
  192           }
  193       }
  194       private native String canonicalize0(String path) throws IOException;
  195       // Best-effort attempt to get parent of this path; used for
  196       // optimization of filename canonicalization. This must return null for
  197       // any cases where the code in canonicalize_md.c would throw an
  198       // exception or otherwise deal with non-simple pathnames like handling
  199       // of "." and "..". It may conservatively return null in other
  200       // situations as well. Returning null will cause the underlying
  201       // (expensive) canonicalization routine to be called.
  202       static String parentOrNull(String path) {
  203           if (path == null) return null;
  204           char sep = File.separatorChar;
  205           int last = path.length() - 1;
  206           int idx = last;
  207           int adjacentDots = 0;
  208           int nonDotCount = 0;
  209           while (idx > 0) {
  210               char c = path.charAt(idx);
  211               if (c == '.') {
  212                   if (++adjacentDots >= 2) {
  213                       // Punt on pathnames containing . and ..
  214                       return null;
  215                   }
  216               } else if (c == sep) {
  217                   if (adjacentDots == 1 && nonDotCount == 0) {
  218                       // Punt on pathnames containing . and ..
  219                       return null;
  220                   }
  221                   if (idx == 0 ||
  222                       idx >= last - 1 ||
  223                       path.charAt(idx - 1) == sep) {
  224                       // Punt on pathnames containing adjacent slashes
  225                       // toward the end
  226                       return null;
  227                   }
  228                   return path.substring(0, idx);
  229               } else {
  230                   ++nonDotCount;
  231                   adjacentDots = 0;
  232               }
  233               --idx;
  234           }
  235           return null;
  236       }
  237   
  238       /* -- Attribute accessors -- */
  239   
  240       public native int getBooleanAttributes0(File f);
  241   
  242       public int getBooleanAttributes(File f) {
  243           int rv = getBooleanAttributes0(f);
  244           String name = f.getName();
  245           boolean hidden = (name.length() > 0) && (name.charAt(0) == '.');
  246           return rv | (hidden ? BA_HIDDEN : 0);
  247       }
  248   
  249       public native boolean checkAccess(File f, int access);
  250       public native long getLastModifiedTime(File f);
  251       public native long getLength(File f);
  252       public native boolean setPermission(File f, int access, boolean enable, boolean owneronly);
  253   
  254       /* -- File operations -- */
  255   
  256       public native boolean createFileExclusively(String path)
  257           throws IOException;
  258       public boolean delete(File f) {
  259           // Keep canonicalization caches in sync after file deletion
  260           // and renaming operations. Could be more clever than this
  261           // (i.e., only remove/update affected entries) but probably
  262           // not worth it since these entries expire after 30 seconds
  263           // anyway.
  264           cache.clear();
  265           javaHomePrefixCache.clear();
  266           return delete0(f);
  267       }
  268       private native boolean delete0(File f);
  269       public native String[] list(File f);
  270       public native boolean createDirectory(File f);
  271       public boolean rename(File f1, File f2) {
  272           // Keep canonicalization caches in sync after file deletion
  273           // and renaming operations. Could be more clever than this
  274           // (i.e., only remove/update affected entries) but probably
  275           // not worth it since these entries expire after 30 seconds
  276           // anyway.
  277           cache.clear();
  278           javaHomePrefixCache.clear();
  279           return rename0(f1, f2);
  280       }
  281       private native boolean rename0(File f1, File f2);
  282       public native boolean setLastModifiedTime(File f, long time);
  283       public native boolean setReadOnly(File f);
  284   
  285   
  286       /* -- Filesystem interface -- */
  287   
  288       public File[] listRoots() {
  289           try {
  290               SecurityManager security = System.getSecurityManager();
  291               if (security != null) {
  292                   security.checkRead("/");
  293               }
  294               return new File[] { new File("/") };
  295           } catch (SecurityException x) {
  296               return new File[0];
  297           }
  298       }
  299   
  300       /* -- Disk usage -- */
  301       public native long getSpace(File f, int t);
  302   
  303       /* -- Basic infrastructure -- */
  304   
  305       public int compare(File f1, File f2) {
  306           return f1.getPath().compareTo(f2.getPath());
  307       }
  308   
  309       public int hashCode(File f) {
  310           return f.getPath().hashCode() ^ 1234321;
  311       }
  312   
  313   
  314       private static native void initIDs();
  315   
  316       static {
  317           initIDs();
  318       }
  319   
  320   }

Save This Page
Home » openjdk-7 » java » io » [javadoc | source]