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

    1   /*
    2    * Copyright (c) 1997, 2011, 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
   23    * questions.
   24    */
   25   
   26   package java.io;
   27   
   28   import java.security;
   29   import java.util.Enumeration;
   30   import java.util.List;
   31   import java.util.ArrayList;
   32   import java.util.Vector;
   33   import java.util.Collections;
   34   import java.io.ObjectStreamField;
   35   import java.io.ObjectOutputStream;
   36   import java.io.ObjectInputStream;
   37   import java.io.IOException;
   38   import sun.security.util.SecurityConstants;
   39   
   40   /**
   41    * This class represents access to a file or directory.  A FilePermission consists
   42    * of a pathname and a set of actions valid for that pathname.
   43    * <P>
   44    * Pathname is the pathname of the file or directory granted the specified
   45    * actions. A pathname that ends in "/*" (where "/" is
   46    * the file separator character, <code>File.separatorChar</code>) indicates
   47    * all the files and directories contained in that directory. A pathname
   48    * that ends with "/-" indicates (recursively) all files
   49    * and subdirectories contained in that directory. A pathname consisting of
   50    * the special token "&lt;&lt;ALL FILES&gt;&gt;" matches <b>any</b> file.
   51    * <P>
   52    * Note: A pathname consisting of a single "*" indicates all the files
   53    * in the current directory, while a pathname consisting of a single "-"
   54    * indicates all the files in the current directory and
   55    * (recursively) all files and subdirectories contained in the current
   56    * directory.
   57    * <P>
   58    * The actions to be granted are passed to the constructor in a string containing
   59    * a list of one or more comma-separated keywords. The possible keywords are
   60    * "read", "write", "execute", "delete", and "readlink". Their meaning is
   61    * defined as follows:
   62    * <P>
   63    * <DL>
   64    *    <DT> read <DD> read permission
   65    *    <DT> write <DD> write permission
   66    *    <DT> execute
   67    *    <DD> execute permission. Allows <code>Runtime.exec</code> to
   68    *         be called. Corresponds to <code>SecurityManager.checkExec</code>.
   69    *    <DT> delete
   70    *    <DD> delete permission. Allows <code>File.delete</code> to
   71    *         be called. Corresponds to <code>SecurityManager.checkDelete</code>.
   72    *    <DT> readlink
   73    *    <DD> read link permission. Allows the target of a
   74    *         <a href="../nio/file/package-summary.html#links">symbolic link</a>
   75    *         to be read by invoking the {@link java.nio.file.Files#readSymbolicLink
   76    *         readSymbolicLink } method.
   77    * </DL>
   78    * <P>
   79    * The actions string is converted to lowercase before processing.
   80    * <P>
   81    * Be careful when granting FilePermissions. Think about the implications
   82    * of granting read and especially write access to various files and
   83    * directories. The "&lt;&lt;ALL FILES>>" permission with write action is
   84    * especially dangerous. This grants permission to write to the entire
   85    * file system. One thing this effectively allows is replacement of the
   86    * system binary, including the JVM runtime environment.
   87    *
   88    * <p>Please note: Code can always read a file from the same
   89    * directory it's in (or a subdirectory of that directory); it does not
   90    * need explicit permission to do so.
   91    *
   92    * @see java.security.Permission
   93    * @see java.security.Permissions
   94    * @see java.security.PermissionCollection
   95    *
   96    *
   97    * @author Marianne Mueller
   98    * @author Roland Schemers
   99    * @since 1.2
  100    *
  101    * @serial exclude
  102    */
  103   
  104   public final class FilePermission extends Permission implements Serializable {
  105   
  106       /**
  107        * Execute action.
  108        */
  109       private final static int EXECUTE = 0x1;
  110       /**
  111        * Write action.
  112        */
  113       private final static int WRITE   = 0x2;
  114       /**
  115        * Read action.
  116        */
  117       private final static int READ    = 0x4;
  118       /**
  119        * Delete action.
  120        */
  121       private final static int DELETE  = 0x8;
  122       /**
  123        * Read link action.
  124        */
  125       private final static int READLINK    = 0x10;
  126   
  127       /**
  128        * All actions (read,write,execute,delete,readlink)
  129        */
  130       private final static int ALL     = READ|WRITE|EXECUTE|DELETE|READLINK;
  131       /**
  132        * No actions.
  133        */
  134       private final static int NONE    = 0x0;
  135   
  136       // the actions mask
  137       private transient int mask;
  138   
  139       // does path indicate a directory? (wildcard or recursive)
  140       private transient boolean directory;
  141   
  142       // is it a recursive directory specification?
  143       private transient boolean recursive;
  144   
  145       /**
  146        * the actions string.
  147        *
  148        * @serial
  149        */
  150       private String actions; // Left null as long as possible, then
  151                               // created and re-used in the getAction function.
  152   
  153       // canonicalized dir path. In the case of
  154       // directories, it is the name "/blah/*" or "/blah/-" without
  155       // the last character (the "*" or "-").
  156   
  157       private transient String cpath;
  158   
  159       // static Strings used by init(int mask)
  160       private static final char RECURSIVE_CHAR = '-';
  161       private static final char WILD_CHAR = '*';
  162   
  163   /*
  164       public String toString()
  165       {
  166           StringBuffer sb = new StringBuffer();
  167           sb.append("***\n");
  168           sb.append("cpath = "+cpath+"\n");
  169           sb.append("mask = "+mask+"\n");
  170           sb.append("actions = "+getActions()+"\n");
  171           sb.append("directory = "+directory+"\n");
  172           sb.append("recursive = "+recursive+"\n");
  173           sb.append("***\n");
  174           return sb.toString();
  175       }
  176   */
  177   
  178       private static final long serialVersionUID = 7930732926638008763L;
  179   
  180       /**
  181        * initialize a FilePermission object. Common to all constructors.
  182        * Also called during de-serialization.
  183        *
  184        * @param mask the actions mask to use.
  185        *
  186        */
  187       private void init(int mask)
  188       {
  189   
  190           if ((mask & ALL) != mask)
  191                   throw new IllegalArgumentException("invalid actions mask");
  192   
  193           if (mask == NONE)
  194                   throw new IllegalArgumentException("invalid actions mask");
  195   
  196           if ((cpath = getName()) == null)
  197                   throw new NullPointerException("name can't be null");
  198   
  199           this.mask = mask;
  200   
  201           if (cpath.equals("<<ALL FILES>>")) {
  202               directory = true;
  203               recursive = true;
  204               cpath = "";
  205               return;
  206           }
  207   
  208           // store only the canonical cpath if possible
  209           cpath = AccessController.doPrivileged(new PrivilegedAction<String>() {
  210               public String run() {
  211                   try {
  212                       String path = cpath;
  213                       if (cpath.endsWith("*")) {
  214                           // call getCanonicalPath with a path with wildcard character
  215                           // replaced to avoid calling it with paths that are
  216                           // intended to match all entries in a directory
  217                           path = path.substring(0, path.length()-1) + "-";
  218                           path = new File(path).getCanonicalPath();
  219                           return path.substring(0, path.length()-1) + "*";
  220                       } else {
  221                           return new File(path).getCanonicalPath();
  222                       }
  223                   } catch (IOException ioe) {
  224                       return cpath;
  225                   }
  226               }
  227           });
  228   
  229           int len = cpath.length();
  230           char last = ((len > 0) ? cpath.charAt(len - 1) : 0);
  231   
  232           if (last == RECURSIVE_CHAR &&
  233               cpath.charAt(len - 2) == File.separatorChar) {
  234               directory = true;
  235               recursive = true;
  236               cpath = cpath.substring(0, --len);
  237           } else if (last == WILD_CHAR &&
  238               cpath.charAt(len - 2) == File.separatorChar) {
  239               directory = true;
  240               //recursive = false;
  241               cpath = cpath.substring(0, --len);
  242           } else {
  243               // overkill since they are initialized to false, but
  244               // commented out here to remind us...
  245               //directory = false;
  246               //recursive = false;
  247           }
  248   
  249           // XXX: at this point the path should be absolute. die if it isn't?
  250       }
  251   
  252       /**
  253        * Creates a new FilePermission object with the specified actions.
  254        * <i>path</i> is the pathname of a file or directory, and <i>actions</i>
  255        * contains a comma-separated list of the desired actions granted on the
  256        * file or directory. Possible actions are
  257        * "read", "write", "execute", "delete", and "readlink".
  258        *
  259        * <p>A pathname that ends in "/*" (where "/" is
  260        * the file separator character, <code>File.separatorChar</code>)
  261        * indicates all the files and directories contained in that directory.
  262        * A pathname that ends with "/-" indicates (recursively) all files and
  263        * subdirectories contained in that directory. The special pathname
  264        * "&lt;&lt;ALL FILES&gt;&gt;" matches any file.
  265        *
  266        * <p>A pathname consisting of a single "*" indicates all the files
  267        * in the current directory, while a pathname consisting of a single "-"
  268        * indicates all the files in the current directory and
  269        * (recursively) all files and subdirectories contained in the current
  270        * directory.
  271        *
  272        * <p>A pathname containing an empty string represents an empty path.
  273        *
  274        * @param path the pathname of the file/directory.
  275        * @param actions the action string.
  276        *
  277        * @throws IllegalArgumentException
  278        *          If actions is <code>null</code>, empty or contains an action
  279        *          other than the specified possible actions.
  280        */
  281   
  282       public FilePermission(String path, String actions)
  283       {
  284           super(path);
  285           init(getMask(actions));
  286       }
  287   
  288       /**
  289        * Creates a new FilePermission object using an action mask.
  290        * More efficient than the FilePermission(String, String) constructor.
  291        * Can be used from within
  292        * code that needs to create a FilePermission object to pass into the
  293        * <code>implies</code> method.
  294        *
  295        * @param path the pathname of the file/directory.
  296        * @param mask the action mask to use.
  297        */
  298   
  299       // package private for use by the FilePermissionCollection add method
  300       FilePermission(String path, int mask)
  301       {
  302           super(path);
  303           init(mask);
  304       }
  305   
  306       /**
  307        * Checks if this FilePermission object "implies" the specified permission.
  308        * <P>
  309        * More specifically, this method returns true if:<p>
  310        * <ul>
  311        * <li> <i>p</i> is an instanceof FilePermission,<p>
  312        * <li> <i>p</i>'s actions are a proper subset of this
  313        * object's actions, and <p>
  314        * <li> <i>p</i>'s pathname is implied by this object's
  315        *      pathname. For example, "/tmp/*" implies "/tmp/foo", since
  316        *      "/tmp/*" encompasses all files in the "/tmp" directory,
  317        *      including the one named "foo".
  318        * </ul>
  319        *
  320        * @param p the permission to check against.
  321        *
  322        * @return <code>true</code> if the specified permission is not
  323        *                  <code>null</code> and is implied by this object,
  324        *                  <code>false</code> otherwise.
  325        */
  326       public boolean implies(Permission p) {
  327           if (!(p instanceof FilePermission))
  328               return false;
  329   
  330           FilePermission that = (FilePermission) p;
  331   
  332           // we get the effective mask. i.e., the "and" of this and that.
  333           // They must be equal to that.mask for implies to return true.
  334   
  335           return ((this.mask & that.mask) == that.mask) && impliesIgnoreMask(that);
  336       }
  337   
  338       /**
  339        * Checks if the Permission's actions are a proper subset of the
  340        * this object's actions. Returns the effective mask iff the
  341        * this FilePermission's path also implies that FilePermission's path.
  342        *
  343        * @param that the FilePermission to check against.
  344        * @param exact return immediately if the masks are not equal
  345        * @return the effective mask
  346        */
  347       boolean impliesIgnoreMask(FilePermission that) {
  348           if (this.directory) {
  349               if (this.recursive) {
  350                   // make sure that.path is longer then path so
  351                   // something like /foo/- does not imply /foo
  352                   if (that.directory) {
  353                       return (that.cpath.length() >= this.cpath.length()) &&
  354                               that.cpath.startsWith(this.cpath);
  355                   }  else {
  356                       return ((that.cpath.length() > this.cpath.length()) &&
  357                           that.cpath.startsWith(this.cpath));
  358                   }
  359               } else {
  360                   if (that.directory) {
  361                       // if the permission passed in is a directory
  362                       // specification, make sure that a non-recursive
  363                       // permission (i.e., this object) can't imply a recursive
  364                       // permission.
  365                       if (that.recursive)
  366                           return false;
  367                       else
  368                           return (this.cpath.equals(that.cpath));
  369                   } else {
  370                       int last = that.cpath.lastIndexOf(File.separatorChar);
  371                       if (last == -1)
  372                           return false;
  373                       else {
  374                           // this.cpath.equals(that.cpath.substring(0, last+1));
  375                           // Use regionMatches to avoid creating new string
  376                           return (this.cpath.length() == (last + 1)) &&
  377                               this.cpath.regionMatches(0, that.cpath, 0, last+1);
  378                       }
  379                   }
  380               }
  381           } else if (that.directory) {
  382               // if this is NOT recursive/wildcarded,
  383               // do not let it imply a recursive/wildcarded permission
  384               return false;
  385           } else {
  386               return (this.cpath.equals(that.cpath));
  387           }
  388       }
  389   
  390       /**
  391        * Checks two FilePermission objects for equality. Checks that <i>obj</i> is
  392        * a FilePermission, and has the same pathname and actions as this object.
  393        * <P>
  394        * @param obj the object we are testing for equality with this object.
  395        * @return <code>true</code> if obj is a FilePermission, and has the same
  396        *          pathname and actions as this FilePermission object,
  397        *          <code>false</code> otherwise.
  398        */
  399       public boolean equals(Object obj) {
  400           if (obj == this)
  401               return true;
  402   
  403           if (! (obj instanceof FilePermission))
  404               return false;
  405   
  406           FilePermission that = (FilePermission) obj;
  407   
  408           return (this.mask == that.mask) &&
  409               this.cpath.equals(that.cpath) &&
  410               (this.directory == that.directory) &&
  411               (this.recursive == that.recursive);
  412       }
  413   
  414       /**
  415        * Returns the hash code value for this object.
  416        *
  417        * @return a hash code value for this object.
  418        */
  419   
  420       public int hashCode() {
  421           return this.cpath.hashCode();
  422       }
  423   
  424       /**
  425        * Converts an actions String to an actions mask.
  426        *
  427        * @param action the action string.
  428        * @return the actions mask.
  429        */
  430       private static int getMask(String actions) {
  431   
  432           int mask = NONE;
  433   
  434           // Null action valid?
  435           if (actions == null) {
  436               return mask;
  437           }
  438           // Check against use of constants (used heavily within the JDK)
  439           if (actions == SecurityConstants.FILE_READ_ACTION) {
  440               return READ;
  441           } else if (actions == SecurityConstants.FILE_WRITE_ACTION) {
  442               return WRITE;
  443           } else if (actions == SecurityConstants.FILE_EXECUTE_ACTION) {
  444               return EXECUTE;
  445           } else if (actions == SecurityConstants.FILE_DELETE_ACTION) {
  446               return DELETE;
  447           } else if (actions == SecurityConstants.FILE_READLINK_ACTION) {
  448               return READLINK;
  449           }
  450   
  451           char[] a = actions.toCharArray();
  452   
  453           int i = a.length - 1;
  454           if (i < 0)
  455               return mask;
  456   
  457           while (i != -1) {
  458               char c;
  459   
  460               // skip whitespace
  461               while ((i!=-1) && ((c = a[i]) == ' ' ||
  462                                  c == '\r' ||
  463                                  c == '\n' ||
  464                                  c == '\f' ||
  465                                  c == '\t'))
  466                   i--;
  467   
  468               // check for the known strings
  469               int matchlen;
  470   
  471               if (i >= 3 && (a[i-3] == 'r' || a[i-3] == 'R') &&
  472                             (a[i-2] == 'e' || a[i-2] == 'E') &&
  473                             (a[i-1] == 'a' || a[i-1] == 'A') &&
  474                             (a[i] == 'd' || a[i] == 'D'))
  475               {
  476                   matchlen = 4;
  477                   mask |= READ;
  478   
  479               } else if (i >= 4 && (a[i-4] == 'w' || a[i-4] == 'W') &&
  480                                    (a[i-3] == 'r' || a[i-3] == 'R') &&
  481                                    (a[i-2] == 'i' || a[i-2] == 'I') &&
  482                                    (a[i-1] == 't' || a[i-1] == 'T') &&
  483                                    (a[i] == 'e' || a[i] == 'E'))
  484               {
  485                   matchlen = 5;
  486                   mask |= WRITE;
  487   
  488               } else if (i >= 6 && (a[i-6] == 'e' || a[i-6] == 'E') &&
  489                                    (a[i-5] == 'x' || a[i-5] == 'X') &&
  490                                    (a[i-4] == 'e' || a[i-4] == 'E') &&
  491                                    (a[i-3] == 'c' || a[i-3] == 'C') &&
  492                                    (a[i-2] == 'u' || a[i-2] == 'U') &&
  493                                    (a[i-1] == 't' || a[i-1] == 'T') &&
  494                                    (a[i] == 'e' || a[i] == 'E'))
  495               {
  496                   matchlen = 7;
  497                   mask |= EXECUTE;
  498   
  499               } else if (i >= 5 && (a[i-5] == 'd' || a[i-5] == 'D') &&
  500                                    (a[i-4] == 'e' || a[i-4] == 'E') &&
  501                                    (a[i-3] == 'l' || a[i-3] == 'L') &&
  502                                    (a[i-2] == 'e' || a[i-2] == 'E') &&
  503                                    (a[i-1] == 't' || a[i-1] == 'T') &&
  504                                    (a[i] == 'e' || a[i] == 'E'))
  505               {
  506                   matchlen = 6;
  507                   mask |= DELETE;
  508   
  509               } else if (i >= 7 && (a[i-7] == 'r' || a[i-7] == 'R') &&
  510                                    (a[i-6] == 'e' || a[i-6] == 'E') &&
  511                                    (a[i-5] == 'a' || a[i-5] == 'A') &&
  512                                    (a[i-4] == 'd' || a[i-4] == 'D') &&
  513                                    (a[i-3] == 'l' || a[i-3] == 'L') &&
  514                                    (a[i-2] == 'i' || a[i-2] == 'I') &&
  515                                    (a[i-1] == 'n' || a[i-1] == 'N') &&
  516                                    (a[i] == 'k' || a[i] == 'K'))
  517               {
  518                   matchlen = 8;
  519                   mask |= READLINK;
  520   
  521               } else {
  522                   // parse error
  523                   throw new IllegalArgumentException(
  524                           "invalid permission: " + actions);
  525               }
  526   
  527               // make sure we didn't just match the tail of a word
  528               // like "ackbarfaccept".  Also, skip to the comma.
  529               boolean seencomma = false;
  530               while (i >= matchlen && !seencomma) {
  531                   switch(a[i-matchlen]) {
  532                   case ',':
  533                       seencomma = true;
  534                       /*FALLTHROUGH*/
  535                   case ' ': case '\r': case '\n':
  536                   case '\f': case '\t':
  537                       break;
  538                   default:
  539                       throw new IllegalArgumentException(
  540                               "invalid permission: " + actions);
  541                   }
  542                   i--;
  543               }
  544   
  545               // point i at the location of the comma minus one (or -1).
  546               i -= matchlen;
  547           }
  548   
  549           return mask;
  550       }
  551   
  552       /**
  553        * Return the current action mask. Used by the FilePermissionCollection.
  554        *
  555        * @return the actions mask.
  556        */
  557   
  558       int getMask() {
  559           return mask;
  560       }
  561   
  562       /**
  563        * Return the canonical string representation of the actions.
  564        * Always returns present actions in the following order:
  565        * read, write, execute, delete, readlink.
  566        *
  567        * @return the canonical string representation of the actions.
  568        */
  569       private static String getActions(int mask)
  570       {
  571           StringBuilder sb = new StringBuilder();
  572           boolean comma = false;
  573   
  574           if ((mask & READ) == READ) {
  575               comma = true;
  576               sb.append("read");
  577           }
  578   
  579           if ((mask & WRITE) == WRITE) {
  580               if (comma) sb.append(',');
  581               else comma = true;
  582               sb.append("write");
  583           }
  584   
  585           if ((mask & EXECUTE) == EXECUTE) {
  586               if (comma) sb.append(',');
  587               else comma = true;
  588               sb.append("execute");
  589           }
  590   
  591           if ((mask & DELETE) == DELETE) {
  592               if (comma) sb.append(',');
  593               else comma = true;
  594               sb.append("delete");
  595           }
  596   
  597           if ((mask & READLINK) == READLINK) {
  598               if (comma) sb.append(',');
  599               else comma = true;
  600               sb.append("readlink");
  601           }
  602   
  603           return sb.toString();
  604       }
  605   
  606       /**
  607        * Returns the "canonical string representation" of the actions.
  608        * That is, this method always returns present actions in the following order:
  609        * read, write, execute, delete, readlink. For example, if this FilePermission
  610        * object allows both write and read actions, a call to <code>getActions</code>
  611        * will return the string "read,write".
  612        *
  613        * @return the canonical string representation of the actions.
  614        */
  615       public String getActions()
  616       {
  617           if (actions == null)
  618               actions = getActions(this.mask);
  619   
  620           return actions;
  621       }
  622   
  623   
  624       /**
  625        * Returns a new PermissionCollection object for storing FilePermission
  626        * objects.
  627        * <p>
  628        * FilePermission objects must be stored in a manner that allows them
  629        * to be inserted into the collection in any order, but that also enables the
  630        * PermissionCollection <code>implies</code>
  631        * method to be implemented in an efficient (and consistent) manner.
  632        *
  633        * <p>For example, if you have two FilePermissions:
  634        * <OL>
  635        * <LI>  <code>"/tmp/-", "read"</code>
  636        * <LI>  <code>"/tmp/scratch/foo", "write"</code>
  637        * </OL>
  638        *
  639        * <p>and you are calling the <code>implies</code> method with the FilePermission:
  640        *
  641        * <pre>
  642        *   "/tmp/scratch/foo", "read,write",
  643        * </pre>
  644        *
  645        * then the <code>implies</code> function must
  646        * take into account both the "/tmp/-" and "/tmp/scratch/foo"
  647        * permissions, so the effective permission is "read,write",
  648        * and <code>implies</code> returns true. The "implies" semantics for
  649        * FilePermissions are handled properly by the PermissionCollection object
  650        * returned by this <code>newPermissionCollection</code> method.
  651        *
  652        * @return a new PermissionCollection object suitable for storing
  653        * FilePermissions.
  654        */
  655   
  656       public PermissionCollection newPermissionCollection() {
  657           return new FilePermissionCollection();
  658       }
  659   
  660       /**
  661        * WriteObject is called to save the state of the FilePermission
  662        * to a stream. The actions are serialized, and the superclass
  663        * takes care of the name.
  664        */
  665       private void writeObject(ObjectOutputStream s)
  666           throws IOException
  667       {
  668           // Write out the actions. The superclass takes care of the name
  669           // call getActions to make sure actions field is initialized
  670           if (actions == null)
  671               getActions();
  672           s.defaultWriteObject();
  673       }
  674   
  675       /**
  676        * readObject is called to restore the state of the FilePermission from
  677        * a stream.
  678        */
  679       private void readObject(ObjectInputStream s)
  680            throws IOException, ClassNotFoundException
  681       {
  682           // Read in the actions, then restore everything else by calling init.
  683           s.defaultReadObject();
  684           init(getMask(actions));
  685       }
  686   }
  687   
  688   /**
  689    * A FilePermissionCollection stores a set of FilePermission permissions.
  690    * FilePermission objects
  691    * must be stored in a manner that allows them to be inserted in any
  692    * order, but enable the implies function to evaluate the implies
  693    * method.
  694    * For example, if you have two FilePermissions:
  695    * <OL>
  696    * <LI> "/tmp/-", "read"
  697    * <LI> "/tmp/scratch/foo", "write"
  698    * </OL>
  699    * And you are calling the implies function with the FilePermission:
  700    * "/tmp/scratch/foo", "read,write", then the implies function must
  701    * take into account both the /tmp/- and /tmp/scratch/foo
  702    * permissions, so the effective permission is "read,write".
  703    *
  704    * @see java.security.Permission
  705    * @see java.security.Permissions
  706    * @see java.security.PermissionCollection
  707    *
  708    *
  709    * @author Marianne Mueller
  710    * @author Roland Schemers
  711    *
  712    * @serial include
  713    *
  714    */
  715   
  716   final class FilePermissionCollection extends PermissionCollection
  717   implements Serializable {
  718   
  719       // Not serialized; see serialization section at end of class
  720       private transient List<Permission> perms;
  721   
  722       /**
  723        * Create an empty FilePermissions object.
  724        *
  725        */
  726   
  727       public FilePermissionCollection() {
  728           perms = new ArrayList<>();
  729       }
  730   
  731       /**
  732        * Adds a permission to the FilePermissions. The key for the hash is
  733        * permission.path.
  734        *
  735        * @param permission the Permission object to add.
  736        *
  737        * @exception IllegalArgumentException - if the permission is not a
  738        *                                       FilePermission
  739        *
  740        * @exception SecurityException - if this FilePermissionCollection object
  741        *                                has been marked readonly
  742        */
  743   
  744       public void add(Permission permission)
  745       {
  746           if (! (permission instanceof FilePermission))
  747               throw new IllegalArgumentException("invalid permission: "+
  748                                                  permission);
  749           if (isReadOnly())
  750               throw new SecurityException(
  751                   "attempt to add a Permission to a readonly PermissionCollection");
  752   
  753           synchronized (this) {
  754               perms.add(permission);
  755           }
  756       }
  757   
  758       /**
  759        * Check and see if this set of permissions implies the permissions
  760        * expressed in "permission".
  761        *
  762        * @param p the Permission object to compare
  763        *
  764        * @return true if "permission" is a proper subset of a permission in
  765        * the set, false if not.
  766        */
  767   
  768       public boolean implies(Permission permission)
  769       {
  770           if (! (permission instanceof FilePermission))
  771                   return false;
  772   
  773           FilePermission fp = (FilePermission) permission;
  774   
  775           int desired = fp.getMask();
  776           int effective = 0;
  777           int needed = desired;
  778   
  779           synchronized (this) {
  780               int len = perms.size();
  781               for (int i = 0; i < len; i++) {
  782                   FilePermission x = (FilePermission) perms.get(i);
  783                   if (((needed & x.getMask()) != 0) && x.impliesIgnoreMask(fp)) {
  784                       effective |=  x.getMask();
  785                       if ((effective & desired) == desired)
  786                           return true;
  787                       needed = (desired ^ effective);
  788                   }
  789               }
  790           }
  791           return false;
  792       }
  793   
  794       /**
  795        * Returns an enumeration of all the FilePermission objects in the
  796        * container.
  797        *
  798        * @return an enumeration of all the FilePermission objects.
  799        */
  800   
  801       public Enumeration elements() {
  802           // Convert Iterator into Enumeration
  803           synchronized (this) {
  804               return Collections.enumeration(perms);
  805           }
  806       }
  807   
  808       private static final long serialVersionUID = 2202956749081564585L;
  809   
  810       // Need to maintain serialization interoperability with earlier releases,
  811       // which had the serializable field:
  812       //    private Vector permissions;
  813   
  814       /**
  815        * @serialField permissions java.util.Vector
  816        *     A list of FilePermission objects.
  817        */
  818       private static final ObjectStreamField[] serialPersistentFields = {
  819           new ObjectStreamField("permissions", Vector.class),
  820       };
  821   
  822       /**
  823        * @serialData "permissions" field (a Vector containing the FilePermissions).
  824        */
  825       /*
  826        * Writes the contents of the perms field out as a Vector for
  827        * serialization compatibility with earlier releases.
  828        */
  829       private void writeObject(ObjectOutputStream out) throws IOException {
  830           // Don't call out.defaultWriteObject()
  831   
  832           // Write out Vector
  833           Vector<Permission> permissions = new Vector<>(perms.size());
  834           synchronized (this) {
  835               permissions.addAll(perms);
  836           }
  837   
  838           ObjectOutputStream.PutField pfields = out.putFields();
  839           pfields.put("permissions", permissions);
  840           out.writeFields();
  841       }
  842   
  843       /*
  844        * Reads in a Vector of FilePermissions and saves them in the perms field.
  845        */
  846       @SuppressWarnings("unchecked")
  847       private void readObject(ObjectInputStream in) throws IOException,
  848       ClassNotFoundException {
  849           // Don't call defaultReadObject()
  850   
  851           // Read in serialized fields
  852           ObjectInputStream.GetField gfields = in.readFields();
  853   
  854           // Get the one we want
  855           Vector<Permission> permissions = (Vector<Permission>)gfields.get("permissions", null);
  856           perms = new ArrayList<>(permissions.size());
  857           perms.addAll(permissions);
  858       }
  859   }

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