home *** CD-ROM | disk | FTP | other *** search
/ Java 1.2 How-To / JavaHowTo.iso / 3rdParty / jbuilder / unsupported / JDK1.2beta3 / SOURCE / SRC.ZIP / java / io / FilePermission.java < prev    next >
Encoding:
Java Source  |  1998-03-20  |  18.9 KB  |  643 lines

  1. /*
  2.  * @(#)FilePermission.java    1.50 98/03/18
  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.  * a directory and all the files contained in that directory. A pathname
  30.  * that ends with "/-" indicates a directory and (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 zero 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.  *
  58.  * @see java.security.Permission
  59.  * @see java.security.Permissions
  60.  * @see java.security.PermissionCollection
  61.  *
  62.  * @version 1.50 98/03/18
  63.  *
  64.  * @author Marianne Mueller
  65.  * @author Roland Schemers
  66.  */
  67.  
  68. public final class FilePermission extends Permission implements Serializable {
  69.  
  70.     /** use serialVersionUID from JDK 1.2 for interoperability */
  71.     private static final long serialVersionUID = -3107630564271172646L;
  72.  
  73.     /**
  74.      * Execute action.
  75.      */
  76.     private final static int EXECUTE = 0x1;
  77.     /**
  78.      * Write action.
  79.      */
  80.     private final static int WRITE   = 0x2;
  81.     /**
  82.      * Read action.
  83.      */
  84.     private final static int READ    = 0x4;
  85.     /**
  86.      * Delete action.
  87.      */
  88.     private final static int DELETE  = 0x8;
  89.  
  90.     /**
  91.      * All actions (read,write,execute,delete)
  92.      */
  93.     private final static int ALL     = READ|WRITE|EXECUTE|DELETE;
  94.     /**
  95.      * No actions.
  96.      */
  97.     private final static int NONE    = 0x0;
  98.  
  99.     // the actions mask
  100.     private int mask;
  101.  
  102.     // does path indicate a directory? (wildcard or recursive)
  103.     private boolean directory;
  104.  
  105.     // is it a recursive directory specification?
  106.     private boolean recursive;
  107.  
  108.     // the actions string. Left null as long as possible, then
  109.     // created and re-used in the getAction function.
  110.  
  111.     private String actions;
  112.  
  113.     // canonicalized dir path. In the case of
  114.     // directories, it is the name "/blah/*" or "/blah/-" without
  115.     // the last character (the "*" or "-").
  116.  
  117.     private String cpath;
  118.  
  119.     // static Strings used by init(int mask)
  120.     private static final String RECURSIVE = "-";
  121.     private static final String WILD = "*";
  122.     private static final String SEP_RECURSIVE = File.separator+RECURSIVE;
  123.     private static final String SEP_WILD = File.separator+WILD;
  124.  
  125. /*
  126.     public String toString()
  127.     {
  128.         StringBuffer sb = new StringBuffer();
  129.     sb.append("***\n");
  130.     sb.append("cpath = "+cpath+"\n");
  131.     sb.append("mask = "+mask+"\n");
  132.     sb.append("actions = "+getActions()+"\n");
  133.     sb.append("directory = "+directory+"\n");
  134.     sb.append("recursive = "+recursive+"\n");
  135.     sb.append("***\n");
  136.     return sb.toString();
  137.     }
  138. */
  139.  
  140.     /**
  141.      * initialize a FilePermission object. Common to all constructors.
  142.      * Also called during de-serialization.
  143.      *
  144.      * @param mask the actions mask to use.
  145.      *
  146.      */
  147.  
  148.     private void init(int mask) 
  149.     {
  150.  
  151.     if ((mask & ALL) != mask) 
  152.         throw new IllegalArgumentException("invalid actions mask");
  153.  
  154.     if (mask == NONE) 
  155.         throw new IllegalArgumentException("invalid actions mask");
  156.  
  157.     if (getName() == null) 
  158.         throw new IllegalArgumentException("name can't be null");
  159.  
  160.     this.mask = mask;
  161.  
  162.     cpath = getName();
  163.  
  164.     if (cpath.equals("<<ALL FILES>>")) {
  165.         directory = true;
  166.         recursive = true;
  167.         cpath = "";
  168.         return;
  169.     }
  170.  
  171.     if (cpath.endsWith(SEP_RECURSIVE) || cpath.equals(RECURSIVE)) {
  172.         directory = true;
  173.         recursive = true;
  174.         cpath = cpath.substring(0, cpath.length()-1);
  175.     } else if (cpath.endsWith(SEP_WILD) || cpath.equals(WILD)) {
  176.         directory = true;
  177.         //recursive = false;
  178.         cpath = cpath.substring(0, cpath.length()-1);
  179.     } else {
  180.         // overkill since they are initialized to false, but 
  181.         // commented out here to remind us...
  182.         //directory = false;
  183.         //recursive = false;
  184.     }
  185.  
  186.     if (cpath.equals("")) {
  187.         try {
  188.         AccessController.beginPrivileged();
  189.         cpath = System.getProperty("user.dir");
  190.         } finally {
  191.         AccessController.endPrivileged();
  192.         }
  193.     }
  194.  
  195.     File file = new File(cpath);
  196.  
  197.     // store only the canonical cpath
  198.     try {
  199.         // need a beginPrivileged block as getCanonicalPath
  200.         // might attempt to access user.dir to turn a relative
  201.         // path into an absolute path.
  202.         AccessController.beginPrivileged();
  203.         String canonical_path = file.getCanonicalPath();
  204.         if (directory && (!canonical_path.endsWith(File.separator))) {
  205.         cpath = canonical_path + File.separator;
  206.         } else {
  207.         cpath = canonical_path;
  208.         }
  209.         
  210.     } catch (IOException ioe) {
  211.         // ignore if we can't canonicalize path?
  212.     } finally {
  213.         AccessController.endPrivileged();
  214.     }
  215.  
  216.     // XXX: at this point the path should be absolute. die if it isn't?
  217.     }
  218.  
  219.     /**
  220.      * Creates a new FilePermission object with the specified actions.
  221.      * <i>path</i> is the pathname of a
  222.      * file or directory, and <i>actions</i> contains a comma-separated list of the
  223.      * desired actions granted on the file or directory. Possible actions are
  224.      * "read", "write", "execute", and "delete". 
  225.      * 
  226.      * <p>A pathname that ends in "/*" (where "/" is
  227.      * the file separator character, <code>File.separatorChar</code>) indicates
  228.      * a directory and all the files contained in that directory. A pathname
  229.      * that ends with "/-" indicates a directory and (recursively) all files
  230.      * and subdirectories contained in that directory. The special pathname
  231.      * "<<ALL FILES>>" matches all files.
  232.      * 
  233.      * <p>A pathname consisting of a single "*" indicates all the files
  234.      * in the current directory, while a pathname consisting of a single "-" 
  235.      * indicates all the files in the current directory and
  236.      * (recursively) all files and subdirectories contained in the current 
  237.      * directory.
  238.      * 
  239.      * @param path the pathname of the file/directory.
  240.      * @param actions the action string.
  241.      */
  242.  
  243.     public FilePermission(String path, String actions) 
  244.     {
  245.     super(path);
  246.     init(getMask(actions));
  247.     }
  248.  
  249.     /**
  250.      * Creates a new FilePermission object using an action mask.
  251.      * More efficient than the FilePermission(String, String) constructor.
  252.      * Can be used from within
  253.      * code that needs to create a FilePermission object to pass into the 
  254.      * <code>implies</code> method. 
  255.      *
  256.      * @param path the pathname of the file/directory.
  257.      * @param mask the action mask to use.
  258.      */
  259.  
  260.     // package private for use by the FilePermissionCollection add method
  261.     FilePermission(String path, int mask) 
  262.     {
  263.     super(path);
  264.     init(mask);
  265.     }
  266.  
  267.     /**
  268.      * Checks if this FilePermission object "implies" the specified permission.
  269.      * <P>
  270.      * More specifically, this method returns true if:<p>
  271.      * <ul>
  272.      * <li> <i>p</i> is an instanceof FilePermission,<p>
  273.      * <li> <i>p</i>'s actions are a proper subset of this
  274.      * object's actions, and <p>
  275.      * <li> <i>p</i>'s pathname is implied by this object's
  276.      *      pathname. For example, "/tmp/*" implies "/tmp/foo", since
  277.      *      "/tmp/*" encompasses the "/tmp" directory and all files in that
  278.      *      directory, including the one named "foo".
  279.      * </ul>
  280.      * @param p the permission to check against.
  281.      *
  282.      * @return true if the specified permission is implied by this object,
  283.      * false if not.  
  284.      */
  285.     public boolean implies(Permission p) {
  286.     if (!(p instanceof FilePermission))
  287.         return false;
  288.  
  289.     FilePermission that = (FilePermission) p;
  290.  
  291.     // we get the effective mask. i.e., the "and" of this and that.
  292.     // They must be equal to that.mask for implies to return true.
  293.  
  294.     return ((this.mask & that.mask) == that.mask) && impliesIgnoreMask(that);
  295.     }
  296.  
  297.     /**
  298.      * Checks if the Permission's actions are a proper subset of the
  299.      * this object's actions. Returns the effective mask iff the
  300.      * this FilePermission's path also implies that FilePermission's path.
  301.      * 
  302.      * @param that the FilePermission to check against.
  303.      * @param exact return immediatly if the masks are not equal
  304.      * @return the effective mask
  305.      */
  306.     boolean impliesIgnoreMask(FilePermission that) {
  307.     if (this.directory) {
  308.         if (this.recursive) {
  309.         // make sure that.path is longer then path so
  310.         // something like /foo/- does not imply /foo
  311.         if (that.directory) {
  312.             return (that.cpath.length() >= this.cpath.length()) &&
  313.                 that.cpath.startsWith(this.cpath);
  314.         }  else {
  315.             return ((that.cpath.length() > this.cpath.length()) &&
  316.                 that.cpath.startsWith(this.cpath));
  317.         }
  318.         } else {
  319.         if (that.directory) {
  320.             // if the permission passed in is a directory
  321.             // specification, make sure that a non-recursive
  322.             // permission (i.e., this object) can't imply a recursive
  323.             // permission.
  324.             if (that.recursive)
  325.             return false;
  326.             else 
  327.             return (this.cpath.equals(that.cpath));
  328.         } else {
  329.             int last = that.cpath.lastIndexOf(File.separatorChar);
  330.             if (last == -1) 
  331.             return false;
  332.             else {
  333.             String base = that.cpath.substring(0, last+1);
  334.             return (this.cpath.equals(base));
  335.             }
  336.         }
  337.         }
  338.     } else {
  339.         return (this.cpath.equals(that.cpath));
  340.     }
  341.     }
  342.  
  343.     /**
  344.      * Checks two FilePermission objects for equality. Checks that <i>obj</i> is
  345.      * a FilePermission, and has the same pathname and actions as this object.
  346.      * <P>
  347.      * @param obj the object we are testing for equality with this object.
  348.      * @return true if obj is a FilePermission, and has the same pathname and
  349.      * actions as this FilePermission object.
  350.      */
  351.     public boolean equals(Object obj) {
  352.     if (obj == this)
  353.         return true;
  354.  
  355.     if (! (obj instanceof FilePermission))
  356.         return false;
  357.  
  358.     FilePermission that = (FilePermission) obj;
  359.  
  360.     return (this.mask == that.mask) && 
  361.         this.cpath.equals(that.cpath) &&
  362.         (this.directory == that.directory) &&
  363.         (this.recursive == that.recursive);
  364.     }
  365.  
  366.     /**
  367.      * Returns the hash code value for this object.
  368.      * The hash code used is the hash code of the pathname, that is, 
  369.      * <code>getName().hashCode()</code>, where <code>getName</code> is
  370.      * from the Permission superclass.
  371.      * 
  372.      * @return a hash code value for this object.
  373.      */
  374.  
  375.     public int hashCode() {
  376.     return this.cpath.hashCode();
  377.     }
  378.  
  379.     /**
  380.      * Converts an actions String to an actions mask.
  381.      *
  382.      * @param action the action string.
  383.      * @return the actions mask.
  384.      */
  385.  
  386.     private static int getMask(String actions) {
  387.  
  388.     int mask = NONE;
  389.  
  390.     if (actions == null) {
  391.         return mask;
  392.     }
  393.  
  394.     actions = actions.toLowerCase();
  395.         StringTokenizer st = new StringTokenizer(actions,",");
  396.         while (st.hasMoreTokens()) {
  397.         String token = st.nextToken().trim();
  398.         if (token.equals("read"))
  399.         mask |= READ;
  400.         else if (token.equals("write"))
  401.         mask |= WRITE;
  402.         else if (token.equals("execute"))
  403.         mask |= EXECUTE;
  404.         else if (token.equals("delete"))
  405.         mask |= DELETE;
  406.         else 
  407.         throw new IllegalArgumentException("invalid permission: "+token);
  408.         }
  409.     return mask;
  410.     }
  411.  
  412.     /**
  413.      * Return the current action mask. Used by the FilePermissionCollection.
  414.      *
  415.      * @return the actions mask.
  416.      */
  417.  
  418.     int getMask() {
  419.     return mask;
  420.     }
  421.  
  422.     /**
  423.      * Return the canonical string representation of the actions.
  424.      * Always returns present actions in the following order: 
  425.      * read, write, execute, delete.
  426.      *
  427.      * @return the canonical string representation of the actions.
  428.      */
  429.     private static String getActions(int mask)
  430.     {
  431.     StringBuffer sb = new StringBuffer();
  432.         boolean comma = false;
  433.  
  434.     if ((mask & READ) == READ) {
  435.         comma = true;
  436.         sb.append("read");
  437.     }
  438.  
  439.     if ((mask & WRITE) == WRITE) {
  440.         if (comma) sb.append(',');
  441.             else comma = true;
  442.         sb.append("write");
  443.     }
  444.  
  445.     if ((mask & EXECUTE) == EXECUTE) {
  446.         if (comma) sb.append(',');
  447.             else comma = true;
  448.         sb.append("execute");
  449.     }
  450.  
  451.     if ((mask & DELETE) == DELETE) {
  452.         if (comma) sb.append(',');
  453.             else comma = true;
  454.         sb.append("delete");
  455.     }
  456.  
  457.     return sb.toString();
  458.     }
  459.  
  460.     /**
  461.      * Returns the "canonical string representation" of the actions.
  462.      * That is, this method always returns present actions in the following order: 
  463.      * read, write, execute, delete. For example, if this FilePermission object
  464.      * allows both write and read actions, a call to <code>getActions</code>
  465.      * will return the string "read,write".
  466.      *
  467.      * @return the canonical string representation of the actions.
  468.      */
  469.     public String getActions()
  470.     {
  471.     if (actions == null)
  472.         actions = getActions(this.mask);
  473.  
  474.     return actions;
  475.     }
  476.  
  477.  
  478.     /**
  479.      * Returns a new PermissionCollection object for storing FilePermission 
  480.      * objects.
  481.      * <p>
  482.      * FilePermission objects must be stored in a manner that allows them 
  483.      * to be inserted into the collection in any order, but that also enables the 
  484.      * PermissionCollection <code>implies</code>
  485.      * method to be implemented in an efficient (and consistent) manner.
  486.      * 
  487.      * <p>For example, if you have two FilePermissions:
  488.      * <OL>
  489.      * <LI>  <code>"/tmp/-", "read"</code>
  490.      * <LI>  <code>"/tmp/scratch/foo", "write"</code>
  491.      * </OL>
  492.      * 
  493.      * <p>and you are calling the <code>implies</code> method with the FilePermission: 
  494.      * 
  495.      * <pre>
  496.      *   "/tmp/scratch/foo", "read,write", 
  497.      * </pre>
  498.      * 
  499.      * then the <code>implies</code> function must
  500.      * take into account both the "/tmp/-" and "/tmp/scratch/foo"
  501.      * permissions, so the effective permission is "read,write",
  502.      * and <code>implies</code> returns true. The "implies" semantics for 
  503.      * FilePermissions are handled properly by the PermissionCollection object
  504.      * returned by this <code>newPermissionCollection</code> method.
  505.      *
  506.      * @return a new PermissionCollection object suitable for storing 
  507.      * FilePermissions.
  508.      */
  509.  
  510.     public PermissionCollection newPermissionCollection() {
  511.     return new FilePermissionCollection();
  512.     }
  513.  
  514.     /**
  515.      * WriteObject is called to save the state of the FilePermission 
  516.      * to a stream. Only the mask is serialized since we want to
  517.      * recalculate the other values when the contents are restored.
  518.      */
  519.     private synchronized void writeObject(java.io.ObjectOutputStream s)
  520.         throws IOException
  521.     {
  522.     // Write out the mask. The superclass takes care of the name
  523.     s.writeInt(mask);
  524.     }
  525.  
  526.     /**
  527.      * readObject is called to restore the state of the FilePermission from
  528.      * a stream.
  529.      */
  530.     private synchronized void readObject(java.io.ObjectInputStream s)
  531.          throws IOException, ClassNotFoundException
  532.     {
  533.     // Read in the mask, then restore everything else by calling init.
  534.     mask = s.readInt();
  535.     init(mask);
  536.     }
  537. }
  538.  
  539. /**
  540.  * A FilePermissionCollection stores a set of FilePermission permissions. 
  541.  * FilePermission objects
  542.  * must be stored in a manner that allows them to be inserted in any
  543.  * order, but enable the implies function to evaluate the implies
  544.  * method.
  545.  * For example, if you have two FilePermissions:
  546.  * <OL>
  547.  * <LI> "/tmp/-", "read"
  548.  * <LI> "/tmp/scratch/foo", "write"
  549.  * </OL>
  550.  * And you are calling the implies function with the FilePermission: 
  551.  * "/tmp/scratch/foo", "read,write", then the implies function must
  552.  * take into account both the /tmp/- and /tmp/scratch/foo
  553.  * permissions, so the effective permission is "read,write".
  554.  * 
  555.  * @see java.security.Permission
  556.  * @see java.security.Permissions
  557.  * @see java.security.PermissionCollection
  558.  *
  559.  * @version 1.50 98/03/18
  560.  *
  561.  * @author Marianne Mueller
  562.  * @author Roland Schemers
  563.  */
  564.  
  565. final class FilePermissionCollection extends PermissionCollection
  566. implements Serializable {
  567.     /** use serialVersionUID from JDK 1.2 for interoperability */
  568.     private static final long serialVersionUID = 2202956749081564585L;
  569.  
  570.     private Vector permissions;
  571.  
  572.     /**
  573.      * Create an empty FilePermissions object.
  574.      *
  575.      */
  576.  
  577.     public FilePermissionCollection() {
  578.     permissions = new Vector();
  579.     }
  580.  
  581.     /**
  582.      * Adds a permission to the FilePermissions. The key for the hash is
  583.      * permission.path.
  584.      *
  585.      * @param permission the Permission object to add.
  586.      */
  587.  
  588.     public void add(Permission permission)
  589.     {
  590.     if (! (permission instanceof FilePermission))
  591.         throw new IllegalArgumentException("invalid permission: "+
  592.                            permission);
  593.     permissions.addElement(permission);
  594.     }
  595.  
  596.     /**
  597.      * Check and see if this set of permissions implies the permissions 
  598.      * expressed in "permission".
  599.      *
  600.      * @param p the Permission object to compare
  601.      *
  602.      * @return true if "permission" is a proper subset of a permission in 
  603.      * the set, false if not.
  604.      */
  605.  
  606.     public boolean implies(Permission permission) 
  607.     {
  608.     if (! (permission instanceof FilePermission))
  609.            return false;
  610.  
  611.     FilePermission fp = (FilePermission) permission;
  612.  
  613.     int desired = fp.getMask();
  614.     int effective = 0;
  615.     int needed = desired;
  616.  
  617.     Enumeration e = permissions.elements();
  618.     
  619.     while (e.hasMoreElements()) {
  620.         FilePermission x = (FilePermission) e.nextElement();
  621.         if (((needed & x.getMask()) != 0) && x.impliesIgnoreMask(fp)) {
  622.         effective |=  x.getMask();
  623.         if ((effective & desired) == desired)
  624.             return true;
  625.         needed = (desired ^ effective);
  626.         }
  627.     }
  628.     return false;
  629.     }
  630.  
  631.     /**
  632.      * Returns an enumeration of all the FilePermission objects in the 
  633.      * container.
  634.      *
  635.      * @return an enumeration of all the FilePermission objects.
  636.      */
  637.  
  638.     public Enumeration elements()
  639.     {
  640.     return permissions.elements();
  641.     }
  642. }
  643.