home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection Student Program / ADC Tools Sampler CD Disk 3 1999.iso / Metrowerks CodeWarrior / Java Support / Java_Source / Java2 / src / java / io / FilePermission.java < prev    next >
Encoding:
Java Source  |  1999-05-28  |  20.9 KB  |  721 lines  |  [TEXT/CWIE]

  1. /*
  2.  * @(#)FilePermission.java    1.56 98/09/28
  3.  *
  4.  * Copyright 1997, 1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  *
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.io;
  16.  
  17. import java.security.*;
  18. import java.util.Enumeration;
  19. import java.util.Vector;
  20. import java.util.StringTokenizer;
  21.  
  22. /**
  23.  * This class represents access to a file or directory.  A FilePermission consists
  24.  * of a pathname and a set of actions valid for that pathname.
  25.  * <P>
  26.  * Pathname is the pathname of the file or directory granted the specified
  27.  * actions. A pathname that ends in "/*" (where "/" is
  28.  * the file separator character, <code>File.separatorChar</code>) indicates
  29.  * all the files and directories contained in that directory. A pathname
  30.  * that ends with "/-" indicates (recursively) all files
  31.  * and subdirectories contained in that directory. A pathname consisting of
  32.  * the special token "<<ALL FILES>>" matches <bold>any</bold> file.
  33.  * <P>
  34.  * Note: A pathname consisting of a single "*" indicates all the files
  35.  * in the current directory, while a pathname consisting of a single "-" 
  36.  * indicates all the files in the current directory and
  37.  * (recursively) all files and subdirectories contained in the current 
  38.  * directory.
  39.  * <P>
  40.  * The actions to be granted are passed to the constructor in a string containing 
  41.  * a list of one or more comma-separated keywords. The possible keywords are
  42.  * "read", "write", "execute", and "delete". Their meaning is defined as follows:
  43.  * <P>
  44.  * <DL> 
  45.  *    <DT> read <DD> read permission
  46.  *    <DT> write <DD> write permission
  47.  *    <DT> execute 
  48.  *    <DD> execute permission. Allows <code>Runtime.exec</code> to
  49.  *         be called. Corresponds to <code>SecurityManager.checkExec</code>.
  50.  *    <DT> delete
  51.  *    <DD> delete permission. Allows <code>File.delete</code> to
  52.  *         be called. Corresponds to <code>SecurityManager.checkDelete</code>.
  53.  * </DL>
  54.  * <P>
  55.  * The actions string is converted to lowercase before processing.
  56.  * <P>
  57.  * Be careful when granting FilePermissions. Think about the implications 
  58.  * of granting read and especially write access to various files and 
  59.  * directories. The "<<ALL FILES>>" permission with write action is 
  60.  * especially dangerous. This grants permission to write to the entire 
  61.  * file system. One thing this effectively allows is replacement of the 
  62.  * system binary, including the JVM runtime environment.
  63.  * 
  64.  * <p>Please note: Code can always read a file from the same
  65.  * directory it's in (or a subdirectory of that directory); it does not
  66.  * need explicit permission to do so.
  67.  * 
  68.  * @see java.security.Permission
  69.  * @see java.security.Permissions
  70.  * @see java.security.PermissionCollection
  71.  *
  72.  * @version 1.56 99/03/26
  73.  *
  74.  * @author Marianne Mueller
  75.  * @author Roland Schemers
  76.  */
  77.  
  78. public final class FilePermission extends Permission implements Serializable {
  79.  
  80.     /**
  81.      * Execute action.
  82.      */
  83.     private final static int EXECUTE = 0x1;
  84.     /**
  85.      * Write action.
  86.      */
  87.     private final static int WRITE   = 0x2;
  88.     /**
  89.      * Read action.
  90.      */
  91.     private final static int READ    = 0x4;
  92.     /**
  93.      * Delete action.
  94.      */
  95.     private final static int DELETE  = 0x8;
  96.  
  97.     /**
  98.      * All actions (read,write,execute,delete)
  99.      */
  100.     private final static int ALL     = READ|WRITE|EXECUTE|DELETE;
  101.     /**
  102.      * No actions.
  103.      */
  104.     private final static int NONE    = 0x0;
  105.  
  106.     // the actions mask
  107.     private transient int mask;
  108.  
  109.     // does path indicate a directory? (wildcard or recursive)
  110.     private transient boolean directory;
  111.  
  112.     // is it a recursive directory specification?
  113.     private transient boolean recursive;
  114.  
  115.     /**
  116.      * the actions string. 
  117.      *
  118.      * @serial
  119.      */
  120.     private String actions; // Left null as long as possible, then
  121.                             // created and re-used in the getAction function.
  122.  
  123.     // canonicalized dir path. In the case of
  124.     // directories, it is the name "/blah/*" or "/blah/-" without
  125.     // the last character (the "*" or "-").
  126.  
  127.     private transient String cpath;
  128.  
  129.     // static Strings used by init(int mask)
  130.     private static final String RECURSIVE = "-";
  131.     private static final String WILD = "*";
  132.     private static final String SEP_RECURSIVE = File.separator+RECURSIVE;
  133.     private static final String SEP_WILD = File.separator+WILD;
  134.  
  135. /*
  136.     public String toString()
  137.     {
  138.         StringBuffer sb = new StringBuffer();
  139.     sb.append("***\n");
  140.     sb.append("cpath = "+cpath+"\n");
  141.     sb.append("mask = "+mask+"\n");
  142.     sb.append("actions = "+getActions()+"\n");
  143.     sb.append("directory = "+directory+"\n");
  144.     sb.append("recursive = "+recursive+"\n");
  145.     sb.append("***\n");
  146.     return sb.toString();
  147.     }
  148. */
  149.  
  150.     /**
  151.      * initialize a FilePermission object. Common to all constructors.
  152.      * Also called during de-serialization.
  153.      *
  154.      * @param mask the actions mask to use.
  155.      *
  156.      */
  157.  
  158.     private void init(int mask) 
  159.     {
  160.  
  161.     if ((mask & ALL) != mask) 
  162.         throw new IllegalArgumentException("invalid actions mask");
  163.  
  164.     if (mask == NONE) 
  165.         throw new IllegalArgumentException("invalid actions mask");
  166.  
  167.     if (getName() == null) 
  168.         throw new IllegalArgumentException("name can't be null");
  169.  
  170.     this.mask = mask;
  171.  
  172.     cpath = getName();
  173.  
  174.     if (cpath.equals("<<ALL FILES>>")) {
  175.         directory = true;
  176.         recursive = true;
  177.         cpath = "";
  178.         return;
  179.     }
  180.  
  181.     if (cpath.endsWith(SEP_RECURSIVE) || cpath.equals(RECURSIVE)) {
  182.         directory = true;
  183.         recursive = true;
  184.         cpath = cpath.substring(0, cpath.length()-1);
  185.     } else if (cpath.endsWith(SEP_WILD) || cpath.equals(WILD)) {
  186.         directory = true;
  187.         //recursive = false;
  188.         cpath = cpath.substring(0, cpath.length()-1);
  189.     } else {
  190.         // overkill since they are initialized to false, but 
  191.         // commented out here to remind us...
  192.         //directory = false;
  193.         //recursive = false;
  194.     }
  195.  
  196.     if (cpath.equals("")) {
  197.         cpath = (String) java.security.AccessController.doPrivileged(
  198.                new sun.security.action.GetPropertyAction("user.dir"));
  199.     }
  200.  
  201.     // store only the canonical cpath if possible
  202.  
  203.     // need a doPrivileged block as getCanonicalPath
  204.     // might attempt to access user.dir to turn a relative
  205.     // path into an absolute path.
  206.     cpath = (String) 
  207.         AccessController.doPrivileged(
  208.             new java.security.PrivilegedAction() {
  209.         public Object run() {
  210.         try {
  211.             File file = new File(cpath);
  212.             String canonical_path = file.getCanonicalPath();
  213.             if (directory && 
  214.             (!canonical_path.endsWith(File.separator))) {
  215.             return canonical_path + File.separator;
  216.             } else {
  217.             return canonical_path;
  218.             }
  219.         } catch (IOException ioe) {
  220.             // ignore if we can't canonicalize path?
  221.         }
  222.         return cpath;
  223.         }
  224.     });
  225.  
  226.     // XXX: at this point the path should be absolute. die if it isn't?
  227.     }
  228.  
  229.     /**
  230.      * Creates a new FilePermission object with the specified actions.
  231.      * <i>path</i> is the pathname of a
  232.      * file or directory, and <i>actions</i> contains a comma-separated list of the
  233.      * desired actions granted on the file or directory. Possible actions are
  234.      * "read", "write", "execute", and "delete". 
  235.      * 
  236.      * <p>A pathname that ends in "/*" (where "/" is
  237.      * the file separator character, <code>File.separatorChar</code>) indicates
  238.      * a directory and all the files contained in that directory. A pathname
  239.      * that ends with "/-" indicates a directory and (recursively) all files
  240.      * and subdirectories contained in that directory. The special pathname
  241.      * "<<ALL FILES>>" matches all files.
  242.      * 
  243.      * <p>A pathname consisting of a single "*" indicates all the files
  244.      * in the current directory, while a pathname consisting of a single "-" 
  245.      * indicates all the files in the current directory and
  246.      * (recursively) all files and subdirectories contained in the current 
  247.      * directory.
  248.      * 
  249.      * @param path the pathname of the file/directory.
  250.      * @param actions the action string.
  251.      */
  252.  
  253.     public FilePermission(String path, String actions) 
  254.     {
  255.     super(path);
  256.     init(getMask(actions));
  257.     }
  258.  
  259.     /**
  260.      * Creates a new FilePermission object using an action mask.
  261.      * More efficient than the FilePermission(String, String) constructor.
  262.      * Can be used from within
  263.      * code that needs to create a FilePermission object to pass into the 
  264.      * <code>implies</code> method. 
  265.      *
  266.      * @param path the pathname of the file/directory.
  267.      * @param mask the action mask to use.
  268.      */
  269.  
  270.     // package private for use by the FilePermissionCollection add method
  271.     FilePermission(String path, int mask) 
  272.     {
  273.     super(path);
  274.     init(mask);
  275.     }
  276.  
  277.     /**
  278.      * Checks if this FilePermission object "implies" the specified permission.
  279.      * <P>
  280.      * More specifically, this method returns true if:<p>
  281.      * <ul>
  282.      * <li> <i>p</i> is an instanceof FilePermission,<p>
  283.      * <li> <i>p</i>'s actions are a proper subset of this
  284.      * object's actions, and <p>
  285.      * <li> <i>p</i>'s pathname is implied by this object's
  286.      *      pathname. For example, "/tmp/*" implies "/tmp/foo", since
  287.      *      "/tmp/*" encompasses the "/tmp" directory and all files in that
  288.      *      directory, including the one named "foo".
  289.      * </ul>
  290.      * @param p the permission to check against.
  291.      *
  292.      * @return true if the specified permission is implied by this object,
  293.      * false if not.  
  294.      */
  295.     public boolean implies(Permission p) {
  296.     if (!(p instanceof FilePermission))
  297.         return false;
  298.  
  299.     FilePermission that = (FilePermission) p;
  300.  
  301.     // we get the effective mask. i.e., the "and" of this and that.
  302.     // They must be equal to that.mask for implies to return true.
  303.  
  304.     return ((this.mask & that.mask) == that.mask) && impliesIgnoreMask(that);
  305.     }
  306.  
  307.     /**
  308.      * Checks if the Permission's actions are a proper subset of the
  309.      * this object's actions. Returns the effective mask iff the
  310.      * this FilePermission's path also implies that FilePermission's path.
  311.      * 
  312.      * @param that the FilePermission to check against.
  313.      * @param exact return immediatly if the masks are not equal
  314.      * @return the effective mask
  315.      */
  316.     boolean impliesIgnoreMask(FilePermission that) {
  317.     if (this.directory) {
  318.         if (this.recursive) {
  319.         // make sure that.path is longer then path so
  320.         // something like /foo/- does not imply /foo
  321.         if (that.directory) {
  322.             return (that.cpath.length() >= this.cpath.length()) &&
  323.                 that.cpath.startsWith(this.cpath);
  324.         }  else {
  325.             return ((that.cpath.length() > this.cpath.length()) &&
  326.                 that.cpath.startsWith(this.cpath));
  327.         }
  328.         } else {
  329.         if (that.directory) {
  330.             // if the permission passed in is a directory
  331.             // specification, make sure that a non-recursive
  332.             // permission (i.e., this object) can't imply a recursive
  333.             // permission.
  334.             if (that.recursive)
  335.             return false;
  336.             else 
  337.             return (this.cpath.equals(that.cpath));
  338.         } else {
  339.             int last = that.cpath.lastIndexOf(File.separatorChar);
  340.             if (last == -1) 
  341.             return false;
  342.             else {
  343.             String base = that.cpath.substring(0, last+1);
  344.             return (this.cpath.equals(base));
  345.             }
  346.         }
  347.         }
  348.     } else {
  349.         return (this.cpath.equals(that.cpath));
  350.     }
  351.     }
  352.  
  353.     /**
  354.      * Checks two FilePermission objects for equality. Checks that <i>obj</i> is
  355.      * a FilePermission, and has the same pathname and actions as this object.
  356.      * <P>
  357.      * @param obj the object we are testing for equality with this object.
  358.      * @return true if obj is a FilePermission, and has the same pathname and
  359.      * actions as this FilePermission object.
  360.      */
  361.     public boolean equals(Object obj) {
  362.     if (obj == this)
  363.         return true;
  364.  
  365.     if (! (obj instanceof FilePermission))
  366.         return false;
  367.  
  368.     FilePermission that = (FilePermission) obj;
  369.  
  370.     return (this.mask == that.mask) && 
  371.         this.cpath.equals(that.cpath) &&
  372.         (this.directory == that.directory) &&
  373.         (this.recursive == that.recursive);
  374.     }
  375.  
  376.     /**
  377.      * Returns the hash code value for this object.
  378.      * 
  379.      * @return a hash code value for this object.
  380.      */
  381.  
  382.     public int hashCode() {
  383.     return this.cpath.hashCode();
  384.     }
  385.  
  386.     /**
  387.      * Converts an actions String to an actions mask.
  388.      *
  389.      * @param action the action string.
  390.      * @return the actions mask.
  391.      */
  392.     private static int getMask(String actions) {
  393.  
  394.     int mask = NONE;
  395.  
  396.     if (actions == null) {
  397.         return mask;
  398.     }
  399.  
  400.     char[] a = actions.toCharArray();
  401.  
  402.     int i = a.length - 1;
  403.     if (i < 0)
  404.         return mask;
  405.  
  406.     while (i != -1) {
  407.         char c;
  408.  
  409.         // skip whitespace
  410.         while ((i!=-1) && ((c = a[i]) == ' ' ||
  411.                    c == '\r' ||
  412.                    c == '\n' ||
  413.                    c == '\f' ||
  414.                    c == '\t'))
  415.         i--;
  416.  
  417.         // check for the known strings
  418.         int matchlen;
  419.  
  420.         if (i >= 3 && (a[i-3] == 'r' || a[i-3] == 'R') &&
  421.               (a[i-2] == 'e' || a[i-2] == 'E') &&
  422.               (a[i-1] == 'a' || a[i-1] == 'A') &&
  423.               (a[i] == 'd' || a[i] == 'D'))
  424.         {
  425.         matchlen = 4;
  426.         mask |= READ;
  427.  
  428.         } else if (i >= 4 && (a[i-4] == 'w' || a[i-4] == 'W') &&
  429.                  (a[i-3] == 'r' || a[i-3] == 'R') &&
  430.                  (a[i-2] == 'i' || a[i-2] == 'I') &&
  431.                  (a[i-1] == 't' || a[i-1] == 'T') &&
  432.                  (a[i] == 'e' || a[i] == 'E'))
  433.         {
  434.         matchlen = 5;
  435.         mask |= WRITE;
  436.  
  437.         } else if (i >= 6 && (a[i-6] == 'e' || a[i-6] == 'E') &&
  438.                          (a[i-5] == 'x' || a[i-5] == 'X') &&
  439.                  (a[i-4] == 'e' || a[i-4] == 'E') &&
  440.                  (a[i-3] == 'c' || a[i-3] == 'C') &&
  441.                  (a[i-2] == 'u' || a[i-2] == 'U') &&
  442.                  (a[i-1] == 't' || a[i-1] == 'T') &&
  443.                  (a[i] == 'e' || a[i] == 'E'))
  444.         {
  445.         matchlen = 7;
  446.         mask |= EXECUTE;
  447.  
  448.         } else if (i >= 5 && (a[i-5] == 'd' || a[i-5] == 'D') &&
  449.                  (a[i-4] == 'e' || a[i-4] == 'E') &&
  450.                  (a[i-3] == 'l' || a[i-3] == 'L') &&
  451.                  (a[i-2] == 'e' || a[i-2] == 'E') &&
  452.                  (a[i-1] == 't' || a[i-1] == 'T') &&
  453.                  (a[i] == 'e' || a[i] == 'E'))
  454.         {
  455.         matchlen = 6;
  456.         mask |= DELETE;
  457.  
  458.         } else {
  459.         // parse error
  460.         throw new IllegalArgumentException(
  461.             "invalid permission: " + actions);
  462.         }
  463.  
  464.         // make sure we didn't just match the tail of a word
  465.         // like "ackbarfaccept".  Also, skip to the comma.
  466.         boolean seencomma = false;
  467.         while (i >= matchlen && !seencomma) {
  468.         switch(a[i-matchlen]) {
  469.         case ',':
  470.             seencomma = true;
  471.             /*FALLTHROUGH*/
  472.         case ' ': case '\r': case '\n':
  473.         case '\f': case '\t':
  474.             break;
  475.         default:
  476.             throw new IllegalArgumentException(
  477.                 "invalid permission: " + actions);
  478.         }
  479.         i--;
  480.         }
  481.  
  482.         // point i at the location of the comma minus one (or -1).
  483.         i -= matchlen;
  484.     }
  485.  
  486.     return mask;
  487.     }
  488.  
  489.     /**
  490.      * Return the current action mask. Used by the FilePermissionCollection.
  491.      *
  492.      * @return the actions mask.
  493.      */
  494.  
  495.     int getMask() {
  496.     return mask;
  497.     }
  498.  
  499.     /**
  500.      * Return the canonical string representation of the actions.
  501.      * Always returns present actions in the following order: 
  502.      * read, write, execute, delete.
  503.      *
  504.      * @return the canonical string representation of the actions.
  505.      */
  506.     private static String getActions(int mask)
  507.     {
  508.     StringBuffer sb = new StringBuffer();
  509.         boolean comma = false;
  510.  
  511.     if ((mask & READ) == READ) {
  512.         comma = true;
  513.         sb.append("read");
  514.     }
  515.  
  516.     if ((mask & WRITE) == WRITE) {
  517.         if (comma) sb.append(',');
  518.             else comma = true;
  519.         sb.append("write");
  520.     }
  521.  
  522.     if ((mask & EXECUTE) == EXECUTE) {
  523.         if (comma) sb.append(',');
  524.             else comma = true;
  525.         sb.append("execute");
  526.     }
  527.  
  528.     if ((mask & DELETE) == DELETE) {
  529.         if (comma) sb.append(',');
  530.             else comma = true;
  531.         sb.append("delete");
  532.     }
  533.  
  534.     return sb.toString();
  535.     }
  536.  
  537.     /**
  538.      * Returns the "canonical string representation" of the actions.
  539.      * That is, this method always returns present actions in the following order: 
  540.      * read, write, execute, delete. For example, if this FilePermission object
  541.      * allows both write and read actions, a call to <code>getActions</code>
  542.      * will return the string "read,write".
  543.      *
  544.      * @return the canonical string representation of the actions.
  545.      */
  546.     public String getActions()
  547.     {
  548.     if (actions == null)
  549.         actions = getActions(this.mask);
  550.  
  551.     return actions;
  552.     }
  553.  
  554.  
  555.     /**
  556.      * Returns a new PermissionCollection object for storing FilePermission 
  557.      * objects.
  558.      * <p>
  559.      * FilePermission objects must be stored in a manner that allows them 
  560.      * to be inserted into the collection in any order, but that also enables the 
  561.      * PermissionCollection <code>implies</code>
  562.      * method to be implemented in an efficient (and consistent) manner.
  563.      * 
  564.      * <p>For example, if you have two FilePermissions:
  565.      * <OL>
  566.      * <LI>  <code>"/tmp/-", "read"</code>
  567.      * <LI>  <code>"/tmp/scratch/foo", "write"</code>
  568.      * </OL>
  569.      * 
  570.      * <p>and you are calling the <code>implies</code> method with the FilePermission: 
  571.      * 
  572.      * <pre>
  573.      *   "/tmp/scratch/foo", "read,write", 
  574.      * </pre>
  575.      * 
  576.      * then the <code>implies</code> function must
  577.      * take into account both the "/tmp/-" and "/tmp/scratch/foo"
  578.      * permissions, so the effective permission is "read,write",
  579.      * and <code>implies</code> returns true. The "implies" semantics for 
  580.      * FilePermissions are handled properly by the PermissionCollection object
  581.      * returned by this <code>newPermissionCollection</code> method.
  582.      *
  583.      * @return a new PermissionCollection object suitable for storing 
  584.      * FilePermissions.
  585.      */
  586.  
  587.     public PermissionCollection newPermissionCollection() {
  588.     return new FilePermissionCollection();
  589.     }
  590.  
  591.     /**
  592.      * WriteObject is called to save the state of the FilePermission 
  593.      * to a stream. The actions are serialized, and the superclass
  594.      * takes care of the name.
  595.      */
  596.     private synchronized void writeObject(java.io.ObjectOutputStream s)
  597.         throws IOException
  598.     {
  599.     // Write out the actions. The superclass takes care of the name
  600.     // call getActions to make sure actions field is initialized
  601.     if (actions == null)
  602.         getActions();
  603.     s.defaultWriteObject();
  604.     }
  605.  
  606.     /**
  607.      * readObject is called to restore the state of the FilePermission from
  608.      * a stream.
  609.      */
  610.     private synchronized void readObject(java.io.ObjectInputStream s)
  611.          throws IOException, ClassNotFoundException
  612.     {
  613.     // Read in the actions, then restore everything else by calling init.
  614.     s.defaultReadObject();
  615.     init(getMask(actions));
  616.     }
  617. }
  618.  
  619. /**
  620.  * A FilePermissionCollection stores a set of FilePermission permissions. 
  621.  * FilePermission objects
  622.  * must be stored in a manner that allows them to be inserted in any
  623.  * order, but enable the implies function to evaluate the implies
  624.  * method.
  625.  * For example, if you have two FilePermissions:
  626.  * <OL>
  627.  * <LI> "/tmp/-", "read"
  628.  * <LI> "/tmp/scratch/foo", "write"
  629.  * </OL>
  630.  * And you are calling the implies function with the FilePermission: 
  631.  * "/tmp/scratch/foo", "read,write", then the implies function must
  632.  * take into account both the /tmp/- and /tmp/scratch/foo
  633.  * permissions, so the effective permission is "read,write".
  634.  * 
  635.  * @see java.security.Permission
  636.  * @see java.security.Permissions
  637.  * @see java.security.PermissionCollection
  638.  *
  639.  * @version 1.56 99/03/26
  640.  *
  641.  * @author Marianne Mueller
  642.  * @author Roland Schemers
  643.  */
  644.  
  645. final class FilePermissionCollection extends PermissionCollection
  646. implements Serializable {
  647.  
  648.     private Vector permissions;
  649.  
  650.     /**
  651.      * Create an empty FilePermissions object.
  652.      *
  653.      */
  654.  
  655.     public FilePermissionCollection() {
  656.     permissions = new Vector();
  657.     }
  658.  
  659.     /**
  660.      * Adds a permission to the FilePermissions. The key for the hash is
  661.      * permission.path.
  662.      *
  663.      * @param permission the Permission object to add.
  664.      */
  665.  
  666.     public void add(Permission permission)
  667.     {
  668.     if (! (permission instanceof FilePermission))
  669.         throw new IllegalArgumentException("invalid permission: "+
  670.                            permission);
  671.     permissions.addElement(permission);
  672.     }
  673.  
  674.     /**
  675.      * Check and see if this set of permissions implies the permissions 
  676.      * expressed in "permission".
  677.      *
  678.      * @param p the Permission object to compare
  679.      *
  680.      * @return true if "permission" is a proper subset of a permission in 
  681.      * the set, false if not.
  682.      */
  683.  
  684.     public boolean implies(Permission permission) 
  685.     {
  686.     if (! (permission instanceof FilePermission))
  687.            return false;
  688.  
  689.     FilePermission fp = (FilePermission) permission;
  690.  
  691.     int desired = fp.getMask();
  692.     int effective = 0;
  693.     int needed = desired;
  694.  
  695.     Enumeration e = permissions.elements();
  696.     
  697.     while (e.hasMoreElements()) {
  698.         FilePermission x = (FilePermission) e.nextElement();
  699.         if (((needed & x.getMask()) != 0) && x.impliesIgnoreMask(fp)) {
  700.         effective |=  x.getMask();
  701.         if ((effective & desired) == desired)
  702.             return true;
  703.         needed = (desired ^ effective);
  704.         }
  705.     }
  706.     return false;
  707.     }
  708.  
  709.     /**
  710.      * Returns an enumeration of all the FilePermission objects in the 
  711.      * container.
  712.      *
  713.      * @return an enumeration of all the FilePermission objects.
  714.      */
  715.  
  716.     public Enumeration elements()
  717.     {
  718.     return permissions.elements();
  719.     }
  720. }
  721.