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

Print this page




  59  * <DL>
  60  *    <DT> read <DD> read permission
  61  *    <DT> write <DD> write permission
  62  *    <DT> execute
  63  *    <DD> execute permission. Allows <code>Runtime.exec</code> to
  64  *         be called. Corresponds to <code>SecurityManager.checkExec</code>.
  65  *    <DT> delete
  66  *    <DD> delete permission. Allows <code>File.delete</code> to
  67  *         be called. Corresponds to <code>SecurityManager.checkDelete</code>.
  68  *    <DT> readlink
  69  *    <DD> read link permission. Allows the target of a
  70  *         <a href="../nio/file/package-summary.html#links">symbolic link</a>
  71  *         to be read by invoking the {@link java.nio.file.Files#readSymbolicLink
  72  *         readSymbolicLink } method.
  73  * </DL>
  74  * <P>
  75  * The actions string is converted to lowercase before processing.
  76  * <P>
  77  * Be careful when granting FilePermissions. Think about the implications
  78  * of granting read and especially write access to various files and
  79  * directories. The "&lt;&lt;ALL FILES>>" permission with write action is
  80  * especially dangerous. This grants permission to write to the entire
  81  * file system. One thing this effectively allows is replacement of the
  82  * system binary, including the JVM runtime environment.
  83  *
  84  * <p>Please note: Code can always read a file from the same
  85  * directory it's in (or a subdirectory of that directory); it does not
  86  * need explicit permission to do so.
  87  *
  88  * @see java.security.Permission
  89  * @see java.security.Permissions
  90  * @see java.security.PermissionCollection
  91  *
  92  *
  93  * @author Marianne Mueller
  94  * @author Roland Schemers
  95  * @since 1.2
  96  *
  97  * @serial exclude
  98  */
  99 


 163         sb.append("***\n");
 164         sb.append("cpath = "+cpath+"\n");
 165         sb.append("mask = "+mask+"\n");
 166         sb.append("actions = "+getActions()+"\n");
 167         sb.append("directory = "+directory+"\n");
 168         sb.append("recursive = "+recursive+"\n");
 169         sb.append("***\n");
 170         return sb.toString();
 171     }
 172 */
 173 
 174     private static final long serialVersionUID = 7930732926638008763L;
 175 
 176     /**
 177      * initialize a FilePermission object. Common to all constructors.
 178      * Also called during de-serialization.
 179      *
 180      * @param mask the actions mask to use.
 181      *
 182      */
 183     private void init(int mask)
 184     {
 185 
 186         if ((mask & ALL) != mask)
 187                 throw new IllegalArgumentException("invalid actions mask");
 188 
 189         if (mask == NONE)
 190                 throw new IllegalArgumentException("invalid actions mask");
 191 
 192         if ((cpath = getName()) == null)
 193                 throw new NullPointerException("name can't be null");
 194 
 195         this.mask = mask;
 196 
 197         if (cpath.equals("<<ALL FILES>>")) {
 198             directory = true;
 199             recursive = true;
 200             cpath = "";
 201             return;
 202         }
 203 
 204         // store only the canonical cpath if possible
 205         cpath = AccessController.doPrivileged(new PrivilegedAction<String>() {


 257      * indicates all the files and directories contained in that directory.
 258      * A pathname that ends with "/-" indicates (recursively) all files and
 259      * subdirectories contained in that directory. The special pathname
 260      * "&lt;&lt;ALL FILES&gt;&gt;" matches any file.
 261      *
 262      * <p>A pathname consisting of a single "*" indicates all the files
 263      * in the current directory, while a pathname consisting of a single "-"
 264      * indicates all the files in the current directory and
 265      * (recursively) all files and subdirectories contained in the current
 266      * directory.
 267      *
 268      * <p>A pathname containing an empty string represents an empty path.
 269      *
 270      * @param path the pathname of the file/directory.
 271      * @param actions the action string.
 272      *
 273      * @throws IllegalArgumentException
 274      *          If actions is <code>null</code>, empty or contains an action
 275      *          other than the specified possible actions.
 276      */
 277 
 278     public FilePermission(String path, String actions)
 279     {
 280         super(path);
 281         init(getMask(actions));
 282     }
 283 
 284     /**
 285      * Creates a new FilePermission object using an action mask.
 286      * More efficient than the FilePermission(String, String) constructor.
 287      * Can be used from within
 288      * code that needs to create a FilePermission object to pass into the
 289      * <code>implies</code> method.
 290      *
 291      * @param path the pathname of the file/directory.
 292      * @param mask the action mask to use.
 293      */
 294 
 295     // package private for use by the FilePermissionCollection add method
 296     FilePermission(String path, int mask)
 297     {
 298         super(path);
 299         init(mask);
 300     }
 301 
 302     /**
 303      * Checks if this FilePermission object "implies" the specified permission.
 304      * <P>
 305      * More specifically, this method returns true if:<p>
 306      * <ul>
 307      * <li> <i>p</i> is an instanceof FilePermission,<p>
 308      * <li> <i>p</i>'s actions are a proper subset of this
 309      * object's actions, and <p>
 310      * <li> <i>p</i>'s pathname is implied by this object's
 311      *      pathname. For example, "/tmp/*" implies "/tmp/foo", since
 312      *      "/tmp/*" encompasses all files in the "/tmp" directory,
 313      *      including the one named "foo".
 314      * </ul>
 315      *
 316      * @param p the permission to check against.
 317      *


 320      *                  <code>false</code> otherwise.
 321      */
 322     public boolean implies(Permission p) {
 323         if (!(p instanceof FilePermission))
 324             return false;
 325 
 326         FilePermission that = (FilePermission) p;
 327 
 328         // we get the effective mask. i.e., the "and" of this and that.
 329         // They must be equal to that.mask for implies to return true.
 330 
 331         return ((this.mask & that.mask) == that.mask) && impliesIgnoreMask(that);
 332     }
 333 
 334     /**
 335      * Checks if the Permission's actions are a proper subset of the
 336      * this object's actions. Returns the effective mask iff the
 337      * this FilePermission's path also implies that FilePermission's path.
 338      *
 339      * @param that the FilePermission to check against.
 340      * @param exact return immediately if the masks are not equal
 341      * @return the effective mask
 342      */
 343     boolean impliesIgnoreMask(FilePermission that) {
 344         if (this.directory) {
 345             if (this.recursive) {
 346                 // make sure that.path is longer then path so
 347                 // something like /foo/- does not imply /foo
 348                 if (that.directory) {
 349                     return (that.cpath.length() >= this.cpath.length()) &&
 350                             that.cpath.startsWith(this.cpath);
 351                 }  else {
 352                     return ((that.cpath.length() > this.cpath.length()) &&
 353                         that.cpath.startsWith(this.cpath));
 354                 }
 355             } else {
 356                 if (that.directory) {
 357                     // if the permission passed in is a directory
 358                     // specification, make sure that a non-recursive
 359                     // permission (i.e., this object) can't imply a recursive
 360                     // permission.


 395     public boolean equals(Object obj) {
 396         if (obj == this)
 397             return true;
 398 
 399         if (! (obj instanceof FilePermission))
 400             return false;
 401 
 402         FilePermission that = (FilePermission) obj;
 403 
 404         return (this.mask == that.mask) &&
 405             this.cpath.equals(that.cpath) &&
 406             (this.directory == that.directory) &&
 407             (this.recursive == that.recursive);
 408     }
 409 
 410     /**
 411      * Returns the hash code value for this object.
 412      *
 413      * @return a hash code value for this object.
 414      */
 415 
 416     public int hashCode() {
 417         return this.cpath.hashCode();
 418     }
 419 
 420     /**
 421      * Converts an actions String to an actions mask.
 422      *
 423      * @param actions the action string.
 424      * @return the actions mask.
 425      */
 426     private static int getMask(String actions) {
 427 
 428         int mask = NONE;
 429 
 430         // Null action valid?
 431         if (actions == null) {
 432             return mask;
 433         }
 434 
 435         // Use object identity comparison against known-interned strings for
 436         // performance benefit (these values are used heavily within the JDK).
 437         if (actions == SecurityConstants.FILE_READ_ACTION) {
 438             return READ;
 439         } else if (actions == SecurityConstants.FILE_WRITE_ACTION) {
 440             return WRITE;
 441         } else if (actions == SecurityConstants.FILE_EXECUTE_ACTION) {
 442             return EXECUTE;
 443         } else if (actions == SecurityConstants.FILE_DELETE_ACTION) {
 444             return DELETE;
 445         } else if (actions == SecurityConstants.FILE_READLINK_ACTION) {
 446             return READLINK;
 447         }


 535                     break;
 536                 default:
 537                     throw new IllegalArgumentException(
 538                             "invalid permission: " + actions);
 539                 }
 540                 i--;
 541             }
 542 
 543             // point i at the location of the comma minus one (or -1).
 544             i -= matchlen;
 545         }
 546 
 547         return mask;
 548     }
 549 
 550     /**
 551      * Return the current action mask. Used by the FilePermissionCollection.
 552      *
 553      * @return the actions mask.
 554      */
 555 
 556     int getMask() {
 557         return mask;
 558     }
 559 
 560     /**
 561      * Return the canonical string representation of the actions.
 562      * Always returns present actions in the following order:
 563      * read, write, execute, delete, readlink.
 564      *
 565      * @return the canonical string representation of the actions.
 566      */
 567     private static String getActions(int mask)
 568     {
 569         StringBuilder sb = new StringBuilder();
 570         boolean comma = false;
 571 
 572         if ((mask & READ) == READ) {
 573             comma = true;
 574             sb.append("read");
 575         }
 576 
 577         if ((mask & WRITE) == WRITE) {
 578             if (comma) sb.append(',');
 579             else comma = true;
 580             sb.append("write");
 581         }
 582 
 583         if ((mask & EXECUTE) == EXECUTE) {
 584             if (comma) sb.append(',');
 585             else comma = true;
 586             sb.append("execute");
 587         }
 588 


 593         }
 594 
 595         if ((mask & READLINK) == READLINK) {
 596             if (comma) sb.append(',');
 597             else comma = true;
 598             sb.append("readlink");
 599         }
 600 
 601         return sb.toString();
 602     }
 603 
 604     /**
 605      * Returns the "canonical string representation" of the actions.
 606      * That is, this method always returns present actions in the following order:
 607      * read, write, execute, delete, readlink. For example, if this FilePermission
 608      * object allows both write and read actions, a call to <code>getActions</code>
 609      * will return the string "read,write".
 610      *
 611      * @return the canonical string representation of the actions.
 612      */
 613     public String getActions()
 614     {
 615         if (actions == null)
 616             actions = getActions(this.mask);
 617 
 618         return actions;
 619     }
 620 
 621 
 622     /**
 623      * Returns a new PermissionCollection object for storing FilePermission
 624      * objects.
 625      * <p>
 626      * FilePermission objects must be stored in a manner that allows them
 627      * to be inserted into the collection in any order, but that also enables the
 628      * PermissionCollection <code>implies</code>
 629      * method to be implemented in an efficient (and consistent) manner.
 630      *
 631      * <p>For example, if you have two FilePermissions:
 632      * <OL>
 633      * <LI>  <code>"/tmp/-", "read"</code>
 634      * <LI>  <code>"/tmp/scratch/foo", "write"</code>
 635      * </OL>
 636      *
 637      * <p>and you are calling the <code>implies</code> method with the FilePermission:
 638      *
 639      * <pre>
 640      *   "/tmp/scratch/foo", "read,write",
 641      * </pre>
 642      *
 643      * then the <code>implies</code> function must
 644      * take into account both the "/tmp/-" and "/tmp/scratch/foo"
 645      * permissions, so the effective permission is "read,write",
 646      * and <code>implies</code> returns true. The "implies" semantics for
 647      * FilePermissions are handled properly by the PermissionCollection object
 648      * returned by this <code>newPermissionCollection</code> method.
 649      *
 650      * @return a new PermissionCollection object suitable for storing
 651      * FilePermissions.
 652      */
 653 
 654     public PermissionCollection newPermissionCollection() {
 655         return new FilePermissionCollection();
 656     }
 657 
 658     /**
 659      * WriteObject is called to save the state of the FilePermission
 660      * to a stream. The actions are serialized, and the superclass
 661      * takes care of the name.
 662      */
 663     private void writeObject(ObjectOutputStream s)
 664         throws IOException
 665     {
 666         // Write out the actions. The superclass takes care of the name
 667         // call getActions to make sure actions field is initialized
 668         if (actions == null)
 669             getActions();
 670         s.defaultWriteObject();
 671     }
 672 
 673     /**


 695  * <LI> "/tmp/scratch/foo", "write"
 696  * </OL>
 697  * And you are calling the implies function with the FilePermission:
 698  * "/tmp/scratch/foo", "read,write", then the implies function must
 699  * take into account both the /tmp/- and /tmp/scratch/foo
 700  * permissions, so the effective permission is "read,write".
 701  *
 702  * @see java.security.Permission
 703  * @see java.security.Permissions
 704  * @see java.security.PermissionCollection
 705  *
 706  *
 707  * @author Marianne Mueller
 708  * @author Roland Schemers
 709  *
 710  * @serial include
 711  *
 712  */
 713 
 714 final class FilePermissionCollection extends PermissionCollection
 715 implements Serializable {
 716 
 717     // Not serialized; see serialization section at end of class
 718     private transient List<Permission> perms;
 719 
 720     /**
 721      * Create an empty FilePermissions object.
 722      *
 723      */
 724 
 725     public FilePermissionCollection() {
 726         perms = new ArrayList<>();
 727     }
 728 
 729     /**
 730      * Adds a permission to the FilePermissions. The key for the hash is
 731      * permission.path.
 732      *
 733      * @param permission the Permission object to add.
 734      *
 735      * @exception IllegalArgumentException - if the permission is not a
 736      *                                       FilePermission
 737      *
 738      * @exception SecurityException - if this FilePermissionCollection object
 739      *                                has been marked readonly
 740      */
 741 
 742     public void add(Permission permission)
 743     {
 744         if (! (permission instanceof FilePermission))
 745             throw new IllegalArgumentException("invalid permission: "+
 746                                                permission);
 747         if (isReadOnly())
 748             throw new SecurityException(
 749                 "attempt to add a Permission to a readonly PermissionCollection");
 750 
 751         synchronized (this) {
 752             perms.add(permission);
 753         }
 754     }
 755 
 756     /**
 757      * Check and see if this set of permissions implies the permissions
 758      * expressed in "permission".
 759      *
 760      * @param p the Permission object to compare
 761      *
 762      * @return true if "permission" is a proper subset of a permission in
 763      * the set, false if not.
 764      */
 765 
 766     public boolean implies(Permission permission)
 767     {
 768         if (! (permission instanceof FilePermission))
 769                 return false;
 770 
 771         FilePermission fp = (FilePermission) permission;
 772 
 773         int desired = fp.getMask();
 774         int effective = 0;
 775         int needed = desired;
 776 
 777         synchronized (this) {
 778             int len = perms.size();
 779             for (int i = 0; i < len; i++) {
 780                 FilePermission x = (FilePermission) perms.get(i);
 781                 if (((needed & x.getMask()) != 0) && x.impliesIgnoreMask(fp)) {
 782                     effective |=  x.getMask();
 783                     if ((effective & desired) == desired)
 784                         return true;
 785                     needed = (desired ^ effective);
 786                 }
 787             }
 788         }
 789         return false;
 790     }
 791 
 792     /**
 793      * Returns an enumeration of all the FilePermission objects in the
 794      * container.
 795      *
 796      * @return an enumeration of all the FilePermission objects.
 797      */
 798 
 799     public Enumeration<Permission> elements() {
 800         // Convert Iterator into Enumeration
 801         synchronized (this) {
 802             return Collections.enumeration(perms);
 803         }
 804     }
 805 
 806     private static final long serialVersionUID = 2202956749081564585L;
 807 
 808     // Need to maintain serialization interoperability with earlier releases,
 809     // which had the serializable field:
 810     //    private Vector permissions;
 811 
 812     /**
 813      * @serialField permissions java.util.Vector
 814      *     A list of FilePermission objects.
 815      */
 816     private static final ObjectStreamField[] serialPersistentFields = {
 817         new ObjectStreamField("permissions", Vector.class),
 818     };


 824      * Writes the contents of the perms field out as a Vector for
 825      * serialization compatibility with earlier releases.
 826      */
 827     private void writeObject(ObjectOutputStream out) throws IOException {
 828         // Don't call out.defaultWriteObject()
 829 
 830         // Write out Vector
 831         Vector<Permission> permissions = new Vector<>(perms.size());
 832         synchronized (this) {
 833             permissions.addAll(perms);
 834         }
 835 
 836         ObjectOutputStream.PutField pfields = out.putFields();
 837         pfields.put("permissions", permissions);
 838         out.writeFields();
 839     }
 840 
 841     /*
 842      * Reads in a Vector of FilePermissions and saves them in the perms field.
 843      */
 844     private void readObject(ObjectInputStream in) throws IOException,
 845     ClassNotFoundException {

 846         // Don't call defaultReadObject()
 847 
 848         // Read in serialized fields
 849         ObjectInputStream.GetField gfields = in.readFields();
 850 
 851         // Get the one we want
 852         @SuppressWarnings("unchecked")
 853         Vector<Permission> permissions = (Vector<Permission>)gfields.get("permissions", null);
 854         perms = new ArrayList<>(permissions.size());
 855         perms.addAll(permissions);
 856     }
 857 }


  59  * <DL>
  60  *    <DT> read <DD> read permission
  61  *    <DT> write <DD> write permission
  62  *    <DT> execute
  63  *    <DD> execute permission. Allows <code>Runtime.exec</code> to
  64  *         be called. Corresponds to <code>SecurityManager.checkExec</code>.
  65  *    <DT> delete
  66  *    <DD> delete permission. Allows <code>File.delete</code> to
  67  *         be called. Corresponds to <code>SecurityManager.checkDelete</code>.
  68  *    <DT> readlink
  69  *    <DD> read link permission. Allows the target of a
  70  *         <a href="../nio/file/package-summary.html#links">symbolic link</a>
  71  *         to be read by invoking the {@link java.nio.file.Files#readSymbolicLink
  72  *         readSymbolicLink } method.
  73  * </DL>
  74  * <P>
  75  * The actions string is converted to lowercase before processing.
  76  * <P>
  77  * Be careful when granting FilePermissions. Think about the implications
  78  * of granting read and especially write access to various files and
  79  * directories. The "&lt;&lt;ALL FILES&gt;&gt;" permission with write action is
  80  * especially dangerous. This grants permission to write to the entire
  81  * file system. One thing this effectively allows is replacement of the
  82  * system binary, including the JVM runtime environment.
  83  *
  84  * <p>Please note: Code can always read a file from the same
  85  * directory it's in (or a subdirectory of that directory); it does not
  86  * need explicit permission to do so.
  87  *
  88  * @see java.security.Permission
  89  * @see java.security.Permissions
  90  * @see java.security.PermissionCollection
  91  *
  92  *
  93  * @author Marianne Mueller
  94  * @author Roland Schemers
  95  * @since 1.2
  96  *
  97  * @serial exclude
  98  */
  99 


 163         sb.append("***\n");
 164         sb.append("cpath = "+cpath+"\n");
 165         sb.append("mask = "+mask+"\n");
 166         sb.append("actions = "+getActions()+"\n");
 167         sb.append("directory = "+directory+"\n");
 168         sb.append("recursive = "+recursive+"\n");
 169         sb.append("***\n");
 170         return sb.toString();
 171     }
 172 */
 173 
 174     private static final long serialVersionUID = 7930732926638008763L;
 175 
 176     /**
 177      * initialize a FilePermission object. Common to all constructors.
 178      * Also called during de-serialization.
 179      *
 180      * @param mask the actions mask to use.
 181      *
 182      */
 183     private void init(int mask) {


 184         if ((mask & ALL) != mask)
 185                 throw new IllegalArgumentException("invalid actions mask");
 186 
 187         if (mask == NONE)
 188                 throw new IllegalArgumentException("invalid actions mask");
 189 
 190         if ((cpath = getName()) == null)
 191                 throw new NullPointerException("name can't be null");
 192 
 193         this.mask = mask;
 194 
 195         if (cpath.equals("<<ALL FILES>>")) {
 196             directory = true;
 197             recursive = true;
 198             cpath = "";
 199             return;
 200         }
 201 
 202         // store only the canonical cpath if possible
 203         cpath = AccessController.doPrivileged(new PrivilegedAction<String>() {


 255      * indicates all the files and directories contained in that directory.
 256      * A pathname that ends with "/-" indicates (recursively) all files and
 257      * subdirectories contained in that directory. The special pathname
 258      * "&lt;&lt;ALL FILES&gt;&gt;" matches any file.
 259      *
 260      * <p>A pathname consisting of a single "*" indicates all the files
 261      * in the current directory, while a pathname consisting of a single "-"
 262      * indicates all the files in the current directory and
 263      * (recursively) all files and subdirectories contained in the current
 264      * directory.
 265      *
 266      * <p>A pathname containing an empty string represents an empty path.
 267      *
 268      * @param path the pathname of the file/directory.
 269      * @param actions the action string.
 270      *
 271      * @throws IllegalArgumentException
 272      *          If actions is <code>null</code>, empty or contains an action
 273      *          other than the specified possible actions.
 274      */
 275     public FilePermission(String path, String actions) {


 276         super(path);
 277         init(getMask(actions));
 278     }
 279 
 280     /**
 281      * Creates a new FilePermission object using an action mask.
 282      * More efficient than the FilePermission(String, String) constructor.
 283      * Can be used from within
 284      * code that needs to create a FilePermission object to pass into the
 285      * <code>implies</code> method.
 286      *
 287      * @param path the pathname of the file/directory.
 288      * @param mask the action mask to use.
 289      */
 290 
 291     // package private for use by the FilePermissionCollection add method
 292     FilePermission(String path, int mask) {

 293         super(path);
 294         init(mask);
 295     }
 296 
 297     /**
 298      * Checks if this FilePermission object "implies" the specified permission.
 299      * <P>
 300      * More specifically, this method returns true if:<p>
 301      * <ul>
 302      * <li> <i>p</i> is an instanceof FilePermission,<p>
 303      * <li> <i>p</i>'s actions are a proper subset of this
 304      * object's actions, and <p>
 305      * <li> <i>p</i>'s pathname is implied by this object's
 306      *      pathname. For example, "/tmp/*" implies "/tmp/foo", since
 307      *      "/tmp/*" encompasses all files in the "/tmp" directory,
 308      *      including the one named "foo".
 309      * </ul>
 310      *
 311      * @param p the permission to check against.
 312      *


 315      *                  <code>false</code> otherwise.
 316      */
 317     public boolean implies(Permission p) {
 318         if (!(p instanceof FilePermission))
 319             return false;
 320 
 321         FilePermission that = (FilePermission) p;
 322 
 323         // we get the effective mask. i.e., the "and" of this and that.
 324         // They must be equal to that.mask for implies to return true.
 325 
 326         return ((this.mask & that.mask) == that.mask) && impliesIgnoreMask(that);
 327     }
 328 
 329     /**
 330      * Checks if the Permission's actions are a proper subset of the
 331      * this object's actions. Returns the effective mask iff the
 332      * this FilePermission's path also implies that FilePermission's path.
 333      *
 334      * @param that the FilePermission to check against.

 335      * @return the effective mask
 336      */
 337     boolean impliesIgnoreMask(FilePermission that) {
 338         if (this.directory) {
 339             if (this.recursive) {
 340                 // make sure that.path is longer then path so
 341                 // something like /foo/- does not imply /foo
 342                 if (that.directory) {
 343                     return (that.cpath.length() >= this.cpath.length()) &&
 344                             that.cpath.startsWith(this.cpath);
 345                 }  else {
 346                     return ((that.cpath.length() > this.cpath.length()) &&
 347                         that.cpath.startsWith(this.cpath));
 348                 }
 349             } else {
 350                 if (that.directory) {
 351                     // if the permission passed in is a directory
 352                     // specification, make sure that a non-recursive
 353                     // permission (i.e., this object) can't imply a recursive
 354                     // permission.


 389     public boolean equals(Object obj) {
 390         if (obj == this)
 391             return true;
 392 
 393         if (! (obj instanceof FilePermission))
 394             return false;
 395 
 396         FilePermission that = (FilePermission) obj;
 397 
 398         return (this.mask == that.mask) &&
 399             this.cpath.equals(that.cpath) &&
 400             (this.directory == that.directory) &&
 401             (this.recursive == that.recursive);
 402     }
 403 
 404     /**
 405      * Returns the hash code value for this object.
 406      *
 407      * @return a hash code value for this object.
 408      */

 409     public int hashCode() {
 410         return this.cpath.hashCode();
 411     }
 412 
 413     /**
 414      * Converts an actions String to an actions mask.
 415      *
 416      * @param actions the action string.
 417      * @return the actions mask.
 418      */
 419     private static int getMask(String actions) {

 420         int mask = NONE;
 421 
 422         // Null action valid?
 423         if (actions == null) {
 424             return mask;
 425         }
 426 
 427         // Use object identity comparison against known-interned strings for
 428         // performance benefit (these values are used heavily within the JDK).
 429         if (actions == SecurityConstants.FILE_READ_ACTION) {
 430             return READ;
 431         } else if (actions == SecurityConstants.FILE_WRITE_ACTION) {
 432             return WRITE;
 433         } else if (actions == SecurityConstants.FILE_EXECUTE_ACTION) {
 434             return EXECUTE;
 435         } else if (actions == SecurityConstants.FILE_DELETE_ACTION) {
 436             return DELETE;
 437         } else if (actions == SecurityConstants.FILE_READLINK_ACTION) {
 438             return READLINK;
 439         }


 527                     break;
 528                 default:
 529                     throw new IllegalArgumentException(
 530                             "invalid permission: " + actions);
 531                 }
 532                 i--;
 533             }
 534 
 535             // point i at the location of the comma minus one (or -1).
 536             i -= matchlen;
 537         }
 538 
 539         return mask;
 540     }
 541 
 542     /**
 543      * Return the current action mask. Used by the FilePermissionCollection.
 544      *
 545      * @return the actions mask.
 546      */

 547     int getMask() {
 548         return mask;
 549     }
 550 
 551     /**
 552      * Return the canonical string representation of the actions.
 553      * Always returns present actions in the following order:
 554      * read, write, execute, delete, readlink.
 555      *
 556      * @return the canonical string representation of the actions.
 557      */
 558     private static String getActions(int mask) {

 559         StringBuilder sb = new StringBuilder();
 560         boolean comma = false;
 561 
 562         if ((mask & READ) == READ) {
 563             comma = true;
 564             sb.append("read");
 565         }
 566 
 567         if ((mask & WRITE) == WRITE) {
 568             if (comma) sb.append(',');
 569             else comma = true;
 570             sb.append("write");
 571         }
 572 
 573         if ((mask & EXECUTE) == EXECUTE) {
 574             if (comma) sb.append(',');
 575             else comma = true;
 576             sb.append("execute");
 577         }
 578 


 583         }
 584 
 585         if ((mask & READLINK) == READLINK) {
 586             if (comma) sb.append(',');
 587             else comma = true;
 588             sb.append("readlink");
 589         }
 590 
 591         return sb.toString();
 592     }
 593 
 594     /**
 595      * Returns the "canonical string representation" of the actions.
 596      * That is, this method always returns present actions in the following order:
 597      * read, write, execute, delete, readlink. For example, if this FilePermission
 598      * object allows both write and read actions, a call to <code>getActions</code>
 599      * will return the string "read,write".
 600      *
 601      * @return the canonical string representation of the actions.
 602      */
 603     public String getActions() {

 604         if (actions == null)
 605             actions = getActions(this.mask);
 606 
 607         return actions;
 608     }
 609 

 610     /**
 611      * Returns a new PermissionCollection object for storing FilePermission
 612      * objects.
 613      * <p>
 614      * FilePermission objects must be stored in a manner that allows them
 615      * to be inserted into the collection in any order, but that also enables the
 616      * PermissionCollection <code>implies</code>
 617      * method to be implemented in an efficient (and consistent) manner.
 618      *
 619      * <p>For example, if you have two FilePermissions:
 620      * <OL>
 621      * <LI>  <code>"/tmp/-", "read"</code>
 622      * <LI>  <code>"/tmp/scratch/foo", "write"</code>
 623      * </OL>
 624      *
 625      * <p>and you are calling the <code>implies</code> method with the FilePermission:
 626      *
 627      * <pre>
 628      *   "/tmp/scratch/foo", "read,write",
 629      * </pre>
 630      *
 631      * then the <code>implies</code> function must
 632      * take into account both the "/tmp/-" and "/tmp/scratch/foo"
 633      * permissions, so the effective permission is "read,write",
 634      * and <code>implies</code> returns true. The "implies" semantics for
 635      * FilePermissions are handled properly by the PermissionCollection object
 636      * returned by this <code>newPermissionCollection</code> method.
 637      *
 638      * @return a new PermissionCollection object suitable for storing
 639      * FilePermissions.
 640      */

 641     public PermissionCollection newPermissionCollection() {
 642         return new FilePermissionCollection();
 643     }
 644 
 645     /**
 646      * WriteObject is called to save the state of the FilePermission
 647      * to a stream. The actions are serialized, and the superclass
 648      * takes care of the name.
 649      */
 650     private void writeObject(ObjectOutputStream s)
 651         throws IOException
 652     {
 653         // Write out the actions. The superclass takes care of the name
 654         // call getActions to make sure actions field is initialized
 655         if (actions == null)
 656             getActions();
 657         s.defaultWriteObject();
 658     }
 659 
 660     /**


 682  * <LI> "/tmp/scratch/foo", "write"
 683  * </OL>
 684  * And you are calling the implies function with the FilePermission:
 685  * "/tmp/scratch/foo", "read,write", then the implies function must
 686  * take into account both the /tmp/- and /tmp/scratch/foo
 687  * permissions, so the effective permission is "read,write".
 688  *
 689  * @see java.security.Permission
 690  * @see java.security.Permissions
 691  * @see java.security.PermissionCollection
 692  *
 693  *
 694  * @author Marianne Mueller
 695  * @author Roland Schemers
 696  *
 697  * @serial include
 698  *
 699  */
 700 
 701 final class FilePermissionCollection extends PermissionCollection
 702     implements Serializable
 703 {
 704     // Not serialized; see serialization section at end of class
 705     private transient List<Permission> perms;
 706 
 707     /**
 708      * Create an empty FilePermissionCollection object.

 709      */

 710     public FilePermissionCollection() {
 711         perms = new ArrayList<>();
 712     }
 713 
 714     /**
 715      * Adds a permission to the FilePermissionCollection. The key for the hash is
 716      * permission.path.
 717      *
 718      * @param permission the Permission object to add.
 719      *
 720      * @exception IllegalArgumentException - if the permission is not a
 721      *                                       FilePermission
 722      *
 723      * @exception SecurityException - if this FilePermissionCollection object
 724      *                                has been marked readonly
 725      */
 726     public void add(Permission permission) {


 727         if (! (permission instanceof FilePermission))
 728             throw new IllegalArgumentException("invalid permission: "+
 729                                                permission);
 730         if (isReadOnly())
 731             throw new SecurityException(
 732                 "attempt to add a Permission to a readonly PermissionCollection");
 733 
 734         synchronized (this) {
 735             perms.add(permission);
 736         }
 737     }
 738 
 739     /**
 740      * Check and see if this set of permissions implies the permissions
 741      * expressed in "permission".
 742      *
 743      * @param permission the Permission object to compare
 744      *
 745      * @return true if "permission" is a proper subset of a permission in
 746      * the set, false if not.
 747      */
 748     public boolean implies(Permission permission) {


 749         if (! (permission instanceof FilePermission))
 750             return false;
 751 
 752         FilePermission fp = (FilePermission) permission;
 753 
 754         int desired = fp.getMask();
 755         int effective = 0;
 756         int needed = desired;
 757 
 758         synchronized (this) {
 759             int len = perms.size();
 760             for (int i = 0; i < len; i++) {
 761                 FilePermission x = (FilePermission) perms.get(i);
 762                 if (((needed & x.getMask()) != 0) && x.impliesIgnoreMask(fp)) {
 763                     effective |=  x.getMask();
 764                     if ((effective & desired) == desired)
 765                         return true;
 766                     needed = (desired ^ effective);
 767                 }
 768             }
 769         }
 770         return false;
 771     }
 772 
 773     /**
 774      * Returns an enumeration of all the FilePermission objects in the
 775      * container.
 776      *
 777      * @return an enumeration of all the FilePermission objects.
 778      */

 779     public Enumeration<Permission> elements() {
 780         // Convert Iterator into Enumeration
 781         synchronized (this) {
 782             return Collections.enumeration(perms);
 783         }
 784     }
 785 
 786     private static final long serialVersionUID = 2202956749081564585L;
 787 
 788     // Need to maintain serialization interoperability with earlier releases,
 789     // which had the serializable field:
 790     //    private Vector permissions;
 791 
 792     /**
 793      * @serialField permissions java.util.Vector
 794      *     A list of FilePermission objects.
 795      */
 796     private static final ObjectStreamField[] serialPersistentFields = {
 797         new ObjectStreamField("permissions", Vector.class),
 798     };


 804      * Writes the contents of the perms field out as a Vector for
 805      * serialization compatibility with earlier releases.
 806      */
 807     private void writeObject(ObjectOutputStream out) throws IOException {
 808         // Don't call out.defaultWriteObject()
 809 
 810         // Write out Vector
 811         Vector<Permission> permissions = new Vector<>(perms.size());
 812         synchronized (this) {
 813             permissions.addAll(perms);
 814         }
 815 
 816         ObjectOutputStream.PutField pfields = out.putFields();
 817         pfields.put("permissions", permissions);
 818         out.writeFields();
 819     }
 820 
 821     /*
 822      * Reads in a Vector of FilePermissions and saves them in the perms field.
 823      */
 824     private void readObject(ObjectInputStream in)
 825         throws IOException, ClassNotFoundException
 826     {
 827         // Don't call defaultReadObject()
 828 
 829         // Read in serialized fields
 830         ObjectInputStream.GetField gfields = in.readFields();
 831 
 832         // Get the one we want
 833         @SuppressWarnings("unchecked")
 834         Vector<Permission> permissions = (Vector<Permission>)gfields.get("permissions", null);
 835         perms = new ArrayList<>(permissions.size());
 836         perms.addAll(permissions);
 837     }
 838 }