< prev index next >

src/java.base/share/classes/java/io/FilePermission.java

Print this page
rev 16962 : 8177969: Faster FilePermission::implies by avoiding the use of Path::relativize
   1 /*
   2  * Copyright (c) 1997, 2015, Oracle and/or its affiliates. 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


 192 //                sb.append('\n');
 193 //            }
 194 //        }
 195 //        sb.append("***\n");
 196 //        return sb.toString();
 197 //    }
 198 
 199     private static final long serialVersionUID = 7930732926638008763L;
 200 
 201     /**
 202      * Always use the internal default file system, in case it was modified
 203      * with java.nio.file.spi.DefaultFileSystemProvider.
 204      */
 205     private static final java.nio.file.FileSystem builtInFS =
 206             DefaultFileSystemProvider.create()
 207                     .getFileSystem(URI.create("file:///"));
 208 
 209     private static final Path here = builtInFS.getPath(
 210             GetPropertyAction.privilegedGetProperty("user.dir"));
 211 




 212     /**
 213      * A private constructor that clones some and updates some,
 214      * always with a different name.
 215      * @param input
 216      */
 217     private FilePermission(String name,
 218                            FilePermission input,
 219                            Path npath,
 220                            Path npath2,
 221                            int mask,
 222                            String actions) {
 223         super(name);
 224         // Customizables
 225         this.npath = npath;
 226         this.npath2 = npath2;
 227         this.actions = actions;
 228         this.mask = mask;
 229         // Cloneds
 230         this.allFiles = input.allFiles;
 231         this.invalid = input.invalid;


 324                 allFiles = true;
 325                 npath = builtInFS.getPath("");
 326                 // other fields remain default
 327                 return;
 328             }
 329 
 330             boolean rememberStar = false;
 331             if (name.endsWith("*")) {
 332                 rememberStar = true;
 333                 recursive = false;
 334                 name = name.substring(0, name.length()-1) + "-";
 335             }
 336 
 337             try {
 338                 // new File() can "normalize" some name, for example, "/C:/X" on
 339                 // Windows. Some JDK codes generate such illegal names.
 340                 npath = builtInFS.getPath(new File(name).getPath())
 341                         .normalize();
 342                 // lastName should always be non-null now
 343                 Path lastName = npath.getFileName();
 344                 if (lastName != null && lastName.toString().equals("-")) {
 345                     directory = true;
 346                     recursive = !rememberStar;
 347                     npath = npath.getParent();
 348                 }
 349                 if (npath == null) {
 350                     npath = builtInFS.getPath("");
 351                 }
 352                 invalid = false;
 353             } catch (InvalidPathException ipe) {
 354                 // Still invalid. For compatibility reason, accept it
 355                 // but make this permission useless.
 356                 npath = builtInFS.getPath("-u-s-e-l-e-s-s-");
 357                 invalid = true;
 358             }
 359 
 360         } else {
 361             if ((cpath = getName()) == null)
 362                 throw new NullPointerException("name can't be null");
 363 
 364             this.mask = mask;


 662                 return (this.cpath.equals(that.cpath));
 663             }
 664         }
 665     }
 666 
 667     /**
 668      * Returns the depth between an outer path p1 and an inner path p2. -1
 669      * is returned if
 670      *
 671      * - p1 does not contains p2.
 672      * - this is not decidable. For example, p1="../x", p2="y".
 673      * - the depth is not decidable. For example, p1="/", p2="x".
 674      *
 675      * This method can return 2 if the depth is greater than 2.
 676      *
 677      * @param p1 the expected outer path, normalized
 678      * @param p2 the expected inner path, normalized
 679      * @return the depth in between
 680      */
 681     private static int containsPath(Path p1, Path p2) {
 682         Path p;
 683         try {
 684             p = p2.relativize(p1).normalize();
 685             if (p.getName(0).toString().isEmpty()) {









 686                 return 0;






 687             } else {
 688                 for (Path item: p) {
 689                     String s = item.toString();
 690                     if (!s.equals("..")) {







 691                         return -1;
 692                     }


 693                 }
 694                 return p.getNameCount();




















 695             }
 696         } catch (IllegalArgumentException iae) {

 697             return -1;
 698         }








 699     }
 700 
 701     /**
 702      * Checks two FilePermission objects for equality. Checks that <i>obj</i> is
 703      * a FilePermission, and has the same pathname and actions as this object.
 704      *
 705      * @implNote More specifically, two pathnames are the same if and only if
 706      * they have the same wildcard flag and their {@code cpath}
 707      * (if {@code jdk.io.permissionsUseCanonicalPath} is {@code true}) or
 708      * {@code npath} (if {@code jdk.io.permissionsUseCanonicalPath}
 709      * is {@code false}) are equal. Or they are both {@literal "<<ALL FILES>>"}.
 710      * <p>
 711      * When {@code jdk.io.permissionsUseCanonicalPath} is {@code false}, an
 712      * invalid {@code FilePermission} does not equal to any object except
 713      * for itself, even if they are created using the same invalid path.
 714      *
 715      * @param obj the object we are testing for equality with this object.
 716      * @return <code>true</code> if obj is a FilePermission, and has the same
 717      *          pathname and actions as this FilePermission object,
 718      *          <code>false</code> otherwise.


   1 /*
   2  * Copyright (c) 1997, 2017, Oracle and/or its affiliates. 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


 192 //                sb.append('\n');
 193 //            }
 194 //        }
 195 //        sb.append("***\n");
 196 //        return sb.toString();
 197 //    }
 198 
 199     private static final long serialVersionUID = 7930732926638008763L;
 200 
 201     /**
 202      * Always use the internal default file system, in case it was modified
 203      * with java.nio.file.spi.DefaultFileSystemProvider.
 204      */
 205     private static final java.nio.file.FileSystem builtInFS =
 206             DefaultFileSystemProvider.create()
 207                     .getFileSystem(URI.create("file:///"));
 208 
 209     private static final Path here = builtInFS.getPath(
 210             GetPropertyAction.privilegedGetProperty("user.dir"));
 211 
 212     private static final Path EMPTY_PATH = builtInFS.getPath("");
 213     private static final Path DASH_PATH = builtInFS.getPath("-");
 214     private static final Path DOTDOT_PATH = builtInFS.getPath("..");
 215 
 216     /**
 217      * A private constructor that clones some and updates some,
 218      * always with a different name.
 219      * @param input
 220      */
 221     private FilePermission(String name,
 222                            FilePermission input,
 223                            Path npath,
 224                            Path npath2,
 225                            int mask,
 226                            String actions) {
 227         super(name);
 228         // Customizables
 229         this.npath = npath;
 230         this.npath2 = npath2;
 231         this.actions = actions;
 232         this.mask = mask;
 233         // Cloneds
 234         this.allFiles = input.allFiles;
 235         this.invalid = input.invalid;


 328                 allFiles = true;
 329                 npath = builtInFS.getPath("");
 330                 // other fields remain default
 331                 return;
 332             }
 333 
 334             boolean rememberStar = false;
 335             if (name.endsWith("*")) {
 336                 rememberStar = true;
 337                 recursive = false;
 338                 name = name.substring(0, name.length()-1) + "-";
 339             }
 340 
 341             try {
 342                 // new File() can "normalize" some name, for example, "/C:/X" on
 343                 // Windows. Some JDK codes generate such illegal names.
 344                 npath = builtInFS.getPath(new File(name).getPath())
 345                         .normalize();
 346                 // lastName should always be non-null now
 347                 Path lastName = npath.getFileName();
 348                 if (lastName != null && lastName.equals(DASH_PATH)) {
 349                     directory = true;
 350                     recursive = !rememberStar;
 351                     npath = npath.getParent();
 352                 }
 353                 if (npath == null) {
 354                     npath = builtInFS.getPath("");
 355                 }
 356                 invalid = false;
 357             } catch (InvalidPathException ipe) {
 358                 // Still invalid. For compatibility reason, accept it
 359                 // but make this permission useless.
 360                 npath = builtInFS.getPath("-u-s-e-l-e-s-s-");
 361                 invalid = true;
 362             }
 363 
 364         } else {
 365             if ((cpath = getName()) == null)
 366                 throw new NullPointerException("name can't be null");
 367 
 368             this.mask = mask;


 666                 return (this.cpath.equals(that.cpath));
 667             }
 668         }
 669     }
 670 
 671     /**
 672      * Returns the depth between an outer path p1 and an inner path p2. -1
 673      * is returned if
 674      *
 675      * - p1 does not contains p2.
 676      * - this is not decidable. For example, p1="../x", p2="y".
 677      * - the depth is not decidable. For example, p1="/", p2="x".
 678      *
 679      * This method can return 2 if the depth is greater than 2.
 680      *
 681      * @param p1 the expected outer path, normalized
 682      * @param p2 the expected inner path, normalized
 683      * @return the depth in between
 684      */
 685     private static int containsPath(Path p1, Path p2) {
 686 
 687         // Two paths must have the same root. For example,
 688         // there is no contains relation between any two of
 689         // "/x", "x", "C:/x", "C:x", and "//host/share/x".
 690         if (!Objects.equals(p1.getRoot(), p2.getRoot())) {
 691             return -1;
 692         }
 693 
 694         // Empty path (i.e. "." or "") is a strange beast,
 695         // because its getNameCount()==1 but getName(0) is null.
 696         // It's better to deal with it separately.
 697         if (p1.equals(EMPTY_PATH)) {
 698             if (p2.equals(EMPTY_PATH)) {
 699                 return 0;
 700             } else if (p2.getName(0).equals(DOTDOT_PATH)) {
 701                 // "." contains p2 iif p2 has no "..". Since a
 702                 // a normalized path can only have 0 or more
 703                 // ".." at the beginning. We only need to look
 704                 // at the head.
 705                 return -1;
 706             } else {
 707                 // and the distance is p2's name count. i.e.
 708                 // 3 between "." and "a/b/c".
 709                 return p2.getNameCount();
 710             }
 711         } else if (p2.equals(EMPTY_PATH)) {
 712             int c1 = p1.getNameCount();
 713             if (!p1.getName(c1 - 1).equals(DOTDOT_PATH)) {
 714                 // "." is inside p1 iif p1 is 1 or more "..".
 715                 // For the same reason above, we only need to
 716                 // look at the tail.
 717                 return -1;
 718             }
 719             // and the distance is the count of ".."
 720             return c1;
 721         }
 722 
 723         // Good. No more empty paths.
 724 
 725         // Common heads are removed
 726 
 727         int c1 = p1.getNameCount();
 728         int c2 = p2.getNameCount();
 729 
 730         int n = Math.min(c1, c2);
 731         int i = 0;
 732         while (i < n) {
 733             if (!p1.getName(i).equals(p2.getName(i)))
 734                 break;
 735             i++;
 736         }
 737 
 738         // for p1 containing p2, p1 must be 0-or-more "..",
 739         // and p2 cannot have "..". For the same reason, we only
 740         // check tail of p1 and head of p2.
 741         if (i < c1 && !p1.getName(c1 - 1).equals(DOTDOT_PATH)) {
 742             return -1;
 743         }
 744 
 745         if (i < c2 && p2.getName(i).equals(DOTDOT_PATH)) {
 746             return -1;
 747         }
 748 
 749         // and the distance is the name counts added (after removing
 750         // the common heads).
 751 
 752         // For example: p1 = "../../..", p2 = "../a".
 753         // After removing the common heads, they become "../.." and "a",
 754         // and the distance is (3-1)+(2-1) = 3.
 755         return c1 - i + c2 - i;
 756     }
 757 
 758     /**
 759      * Checks two FilePermission objects for equality. Checks that <i>obj</i> is
 760      * a FilePermission, and has the same pathname and actions as this object.
 761      *
 762      * @implNote More specifically, two pathnames are the same if and only if
 763      * they have the same wildcard flag and their {@code cpath}
 764      * (if {@code jdk.io.permissionsUseCanonicalPath} is {@code true}) or
 765      * {@code npath} (if {@code jdk.io.permissionsUseCanonicalPath}
 766      * is {@code false}) are equal. Or they are both {@literal "<<ALL FILES>>"}.
 767      * <p>
 768      * When {@code jdk.io.permissionsUseCanonicalPath} is {@code false}, an
 769      * invalid {@code FilePermission} does not equal to any object except
 770      * for itself, even if they are created using the same invalid path.
 771      *
 772      * @param obj the object we are testing for equality with this object.
 773      * @return <code>true</code> if obj is a FilePermission, and has the same
 774      *          pathname and actions as this FilePermission object,
 775      *          <code>false</code> otherwise.


< prev index next >