| 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 */  | 
 | 
 | 
 | 
package java.io;  | 
 | 
 | 
 | 
import java.net.URI;  | 
 | 
import java.nio.file.InvalidPathException;  | 
 | 
import java.security.*;  | 
 | 
import java.util.Enumeration;  | 
 | 
import java.util.List;  | 
 | 
import java.util.ArrayList;  | 
 | 
import java.util.Vector;  | 
 | 
import java.util.Collections;  | 
 | 
 | 
 | 
import sun.nio.fs.DefaultFileSystemProvider;  | 
 | 
import sun.security.util.SecurityConstants;  | 
 | 
 | 
 | 
/**  | 
 | 
 * This class represents access to a file or directory.  A FilePermission consists  | 
 | 
 * of a pathname and a set of actions valid for that pathname.  | 
 | 
 * <P>  | 
 | 
 * Pathname is the pathname of the file or directory granted the specified  | 
 | 
 * actions. A pathname that ends in "/*" (where "/" is  | 
 | 
 * the file separator character, <code>File.separatorChar</code>) indicates  | 
 | 
 * all the files and directories contained in that directory. A pathname  | 
 | 
 * that ends with "/-" indicates (recursively) all files  | 
 | 
 * and subdirectories contained in that directory. Such a pathname is called  | 
 | 
 * a wildcard pathname. Otherwise, it's a simple pathname.  | 
 | 
 * <P>  | 
 | 
 * A pathname consisting of the special token {@literal "<<ALL FILES>>"} | 
 | 
 * matches <b>any</b> file.  | 
 | 
 * <P>  | 
 | 
 * Note: A pathname consisting of a single "*" indicates all the files  | 
 | 
 * in the current directory, while a pathname consisting of a single "-"  | 
 | 
 * indicates all the files in the current directory and  | 
 | 
 * (recursively) all files and subdirectories contained in the current  | 
 | 
 * directory.  | 
 | 
 * <P>  | 
 | 
 * The actions to be granted are passed to the constructor in a string containing  | 
 | 
 * a list of one or more comma-separated keywords. The possible keywords are  | 
 | 
 * "read", "write", "execute", "delete", and "readlink". Their meaning is  | 
 | 
 * defined as follows:  | 
 | 
 *  | 
 | 
 * <DL>  | 
 | 
 *    <DT> read <DD> read permission  | 
 | 
 *    <DT> write <DD> write permission  | 
 | 
 *    <DT> execute  | 
 | 
 *    <DD> execute permission. Allows <code>Runtime.exec</code> to  | 
 | 
 *         be called. Corresponds to <code>SecurityManager.checkExec</code>.  | 
 | 
 *    <DT> delete  | 
 | 
 *    <DD> delete permission. Allows <code>File.delete</code> to  | 
 | 
 *         be called. Corresponds to <code>SecurityManager.checkDelete</code>.  | 
 | 
 *    <DT> readlink  | 
 | 
 *    <DD> read link permission. Allows the target of a  | 
 | 
 *         <a href="../nio/file/package-summary.html#links">symbolic link</a>  | 
 | 
 *         to be read by invoking the {@link java.nio.file.Files#readSymbolicLink | 
 | 
 *         readSymbolicLink } method.  | 
 | 
 * </DL>  | 
 | 
 * <P>  | 
 | 
 * The actions string is converted to lowercase before processing.  | 
 | 
 * <P>  | 
 | 
 * Be careful when granting FilePermissions. Think about the implications  | 
 | 
 * of granting read and especially write access to various files and  | 
 | 
 * directories. The {@literal "<<ALL FILES>>"} permission with write action is | 
 | 
 * especially dangerous. This grants permission to write to the entire  | 
 | 
 * file system. One thing this effectively allows is replacement of the  | 
 | 
 * system binary, including the JVM runtime environment.  | 
 | 
 *  | 
 | 
 * <p>Please note: Code can always read a file from the same  | 
 | 
 * directory it's in (or a subdirectory of that directory); it does not  | 
 | 
 * need explicit permission to do so.  | 
 | 
 *  | 
 | 
 * @see java.security.Permission  | 
 | 
 * @see java.security.Permissions  | 
 | 
 * @see java.security.PermissionCollection  | 
 | 
 *  | 
 | 
 *  | 
 | 
 * @author Marianne Mueller  | 
 | 
 * @author Roland Schemers  | 
 | 
 * @since 1.2  | 
 | 
 *  | 
 | 
 * @serial exclude  | 
 | 
 */  | 
 | 
 | 
 | 
public final class FilePermission extends Permission implements Serializable { | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private final static int EXECUTE = 0x1;  | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private final static int WRITE   = 0x2;  | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private final static int READ    = 0x4;  | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private final static int DELETE  = 0x8;  | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private final static int READLINK    = 0x10;  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private final static int ALL     = READ|WRITE|EXECUTE|DELETE|READLINK;  | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private final static int NONE    = 0x0;  | 
 | 
 | 
 | 
      | 
 | 
    private transient int mask;  | 
 | 
 | 
 | 
      | 
 | 
    private transient boolean directory;  | 
 | 
 | 
 | 
      | 
 | 
    private transient boolean recursive;  | 
 | 
 | 
 | 
    /**  | 
 | 
     * the actions string.  | 
 | 
     *  | 
 | 
     * @serial  | 
 | 
     */  | 
 | 
    private String actions;   | 
 | 
                            // created and re-used in the getAction function.  | 
 | 
 | 
 | 
    // canonicalized dir path. In the case of  | 
 | 
    // directories, it is the name "/blah/*" or "/blah/-" without  | 
 | 
    // the last character (the "*" or "-").  | 
 | 
 | 
 | 
    private transient String cpath;  | 
 | 
 | 
 | 
    private transient boolean allFiles;   | 
 | 
    private transient boolean invalid;    | 
 | 
 | 
 | 
      | 
 | 
    private static final char RECURSIVE_CHAR = '-';  | 
 | 
    private static final char WILD_CHAR = '*';  | 
 | 
 | 
 | 
/*  | 
 | 
    public String toString()  | 
 | 
    { | 
 | 
        StringBuffer sb = new StringBuffer();  | 
 | 
        sb.append("***\n"); | 
 | 
        sb.append("cpath = "+cpath+"\n"); | 
 | 
        sb.append("mask = "+mask+"\n"); | 
 | 
        sb.append("actions = "+getActions()+"\n"); | 
 | 
        sb.append("directory = "+directory+"\n"); | 
 | 
        sb.append("recursive = "+recursive+"\n"); | 
 | 
        sb.append("***\n"); | 
 | 
        return sb.toString();  | 
 | 
    }  | 
 | 
*/  | 
 | 
 | 
 | 
    private static final long serialVersionUID = 7930732926638008763L;  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static final java.nio.file.FileSystem builtInFS =  | 
 | 
            DefaultFileSystemProvider.create()  | 
 | 
                    .getFileSystem(URI.create("file:///")); | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private void init(int mask) { | 
 | 
        if ((mask & ALL) != mask)  | 
 | 
                throw new IllegalArgumentException("invalid actions mask"); | 
 | 
 | 
 | 
        if (mask == NONE)  | 
 | 
                throw new IllegalArgumentException("invalid actions mask"); | 
 | 
 | 
 | 
        if ((cpath = getName()) == null)  | 
 | 
                throw new NullPointerException("name can't be null"); | 
 | 
 | 
 | 
        this.mask = mask;  | 
 | 
 | 
 | 
        if (cpath.equals("<<ALL FILES>>")) { | 
 | 
            allFiles = true;  | 
 | 
            directory = true;  | 
 | 
            recursive = true;  | 
 | 
            cpath = "";  | 
 | 
            return;  | 
 | 
        }  | 
 | 
 | 
 | 
        // Validate path by platform's default file system  | 
 | 
        // Note: this check does not apply during FilePermission  | 
 | 
          | 
 | 
        if (builtInFS != null) { | 
 | 
            try { | 
 | 
                String name = cpath.endsWith("*") ? | 
 | 
                        cpath.substring(0, cpath.length() - 1) + "-" : cpath;  | 
 | 
                builtInFS.getPath(new File(name).getPath());  | 
 | 
            } catch (InvalidPathException ipe) { | 
 | 
                invalid = true;  | 
 | 
                return;  | 
 | 
            }  | 
 | 
        }  | 
 | 
 | 
 | 
          | 
 | 
        cpath = AccessController.doPrivileged(new PrivilegedAction<String>() { | 
 | 
            public String run() { | 
 | 
                try { | 
 | 
                    String path = cpath;  | 
 | 
                    if (cpath.endsWith("*")) { | 
 | 
                        // call getCanonicalPath with a path with wildcard character  | 
 | 
                        // replaced to avoid calling it with paths that are  | 
 | 
                          | 
 | 
                        path = path.substring(0, path.length()-1) + "-";  | 
 | 
                        path = new File(path).getCanonicalPath();  | 
 | 
                        return path.substring(0, path.length()-1) + "*";  | 
 | 
                    } else { | 
 | 
                        return new File(path).getCanonicalPath();  | 
 | 
                    }  | 
 | 
                } catch (IOException ioe) { | 
 | 
                    return cpath;  | 
 | 
                }  | 
 | 
            }  | 
 | 
        });  | 
 | 
 | 
 | 
        int len = cpath.length();  | 
 | 
        char last = ((len > 0) ? cpath.charAt(len - 1) : 0);  | 
 | 
 | 
 | 
        if (last == RECURSIVE_CHAR &&  | 
 | 
            cpath.charAt(len - 2) == File.separatorChar) { | 
 | 
            directory = true;  | 
 | 
            recursive = true;  | 
 | 
            cpath = cpath.substring(0, --len);  | 
 | 
        } else if (last == WILD_CHAR &&  | 
 | 
            cpath.charAt(len - 2) == File.separatorChar) { | 
 | 
            directory = true;  | 
 | 
              | 
 | 
            cpath = cpath.substring(0, --len);  | 
 | 
        } else { | 
 | 
            // overkill since they are initialized to false, but  | 
 | 
            // commented out here to remind us...  | 
 | 
            //directory = false;  | 
 | 
            //recursive = false;  | 
 | 
        }  | 
 | 
 | 
 | 
        // XXX: at this point the path should be absolute. die if it isn't?  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public FilePermission(String path, String actions) { | 
 | 
        super(path);  | 
 | 
        init(getMask(actions));  | 
 | 
    }  | 
 | 
 | 
 | 
    /**  | 
 | 
     * Creates a new FilePermission object using an action mask.  | 
 | 
     * More efficient than the FilePermission(String, String) constructor.  | 
 | 
     * Can be used from within  | 
 | 
     * code that needs to create a FilePermission object to pass into the  | 
 | 
     * <code>implies</code> method.  | 
 | 
     *  | 
 | 
     * @param path the pathname of the file/directory.  | 
 | 
     * @param mask the action mask to use.  | 
 | 
     */  | 
 | 
 | 
 | 
      | 
 | 
    FilePermission(String path, int mask) { | 
 | 
        super(path);  | 
 | 
        init(mask);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public boolean implies(Permission p) { | 
 | 
        if (!(p instanceof FilePermission))  | 
 | 
            return false;  | 
 | 
 | 
 | 
        FilePermission that = (FilePermission) p;  | 
 | 
 | 
 | 
        // we get the effective mask. i.e., the "and" of this and that.  | 
 | 
        // They must be equal to that.mask for implies to return true.  | 
 | 
 | 
 | 
        return ((this.mask & that.mask) == that.mask) && impliesIgnoreMask(that);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    boolean impliesIgnoreMask(FilePermission that) { | 
 | 
        if (this == that) { | 
 | 
            return true;  | 
 | 
        }  | 
 | 
        if (allFiles) { | 
 | 
            return true;  | 
 | 
        }  | 
 | 
        if (this.invalid || that.invalid) { | 
 | 
            return false;  | 
 | 
        }  | 
 | 
        if (that.allFiles) { | 
 | 
            return false;  | 
 | 
        }  | 
 | 
        if (this.directory) { | 
 | 
            if (this.recursive) { | 
 | 
                // make sure that.path is longer then path so  | 
 | 
                  | 
 | 
                if (that.directory) { | 
 | 
                    return (that.cpath.length() >= this.cpath.length()) &&  | 
 | 
                            that.cpath.startsWith(this.cpath);  | 
 | 
                }  else { | 
 | 
                    return ((that.cpath.length() > this.cpath.length()) &&  | 
 | 
                        that.cpath.startsWith(this.cpath));  | 
 | 
                }  | 
 | 
            } else { | 
 | 
                if (that.directory) { | 
 | 
                    // if the permission passed in is a directory  | 
 | 
                    // specification, make sure that a non-recursive  | 
 | 
                    // permission (i.e., this object) can't imply a recursive  | 
 | 
                      | 
 | 
                    if (that.recursive)  | 
 | 
                        return false;  | 
 | 
                    else  | 
 | 
                        return (this.cpath.equals(that.cpath));  | 
 | 
                } else { | 
 | 
                    int last = that.cpath.lastIndexOf(File.separatorChar);  | 
 | 
                    if (last == -1)  | 
 | 
                        return false;  | 
 | 
                    else { | 
 | 
                        // this.cpath.equals(that.cpath.substring(0, last+1));  | 
 | 
                          | 
 | 
                        return (this.cpath.length() == (last + 1)) &&  | 
 | 
                            this.cpath.regionMatches(0, that.cpath, 0, last+1);  | 
 | 
                    }  | 
 | 
                }  | 
 | 
            }  | 
 | 
        } else if (that.directory) { | 
 | 
            // if this is NOT recursive/wildcarded,  | 
 | 
              | 
 | 
            return false;  | 
 | 
        } else { | 
 | 
            return (this.cpath.equals(that.cpath));  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public boolean equals(Object obj) { | 
 | 
        if (obj == this)  | 
 | 
            return true;  | 
 | 
 | 
 | 
        if (! (obj instanceof FilePermission))  | 
 | 
            return false;  | 
 | 
 | 
 | 
        FilePermission that = (FilePermission) obj;  | 
 | 
 | 
 | 
        if (this.invalid || that.invalid) { | 
 | 
            return false;  | 
 | 
        }  | 
 | 
        return (this.mask == that.mask) &&  | 
 | 
            (this.allFiles == that.allFiles) &&  | 
 | 
            this.cpath.equals(that.cpath) &&  | 
 | 
            (this.directory == that.directory) &&  | 
 | 
            (this.recursive == that.recursive);  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public int hashCode() { | 
 | 
        return 0;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static int getMask(String actions) { | 
 | 
        int mask = NONE;  | 
 | 
 | 
 | 
          | 
 | 
        if (actions == null) { | 
 | 
            return mask;  | 
 | 
        }  | 
 | 
 | 
 | 
        // Use object identity comparison against known-interned strings for  | 
 | 
          | 
 | 
        if (actions == SecurityConstants.FILE_READ_ACTION) { | 
 | 
            return READ;  | 
 | 
        } else if (actions == SecurityConstants.FILE_WRITE_ACTION) { | 
 | 
            return WRITE;  | 
 | 
        } else if (actions == SecurityConstants.FILE_EXECUTE_ACTION) { | 
 | 
            return EXECUTE;  | 
 | 
        } else if (actions == SecurityConstants.FILE_DELETE_ACTION) { | 
 | 
            return DELETE;  | 
 | 
        } else if (actions == SecurityConstants.FILE_READLINK_ACTION) { | 
 | 
            return READLINK;  | 
 | 
        }  | 
 | 
 | 
 | 
        char[] a = actions.toCharArray();  | 
 | 
 | 
 | 
        int i = a.length - 1;  | 
 | 
        if (i < 0)  | 
 | 
            return mask;  | 
 | 
 | 
 | 
        while (i != -1) { | 
 | 
            char c;  | 
 | 
 | 
 | 
              | 
 | 
            while ((i!=-1) && ((c = a[i]) == ' ' ||  | 
 | 
                               c == '\r' ||  | 
 | 
                               c == '\n' ||  | 
 | 
                               c == '\f' ||  | 
 | 
                               c == '\t'))  | 
 | 
                i--;  | 
 | 
 | 
 | 
              | 
 | 
            int matchlen;  | 
 | 
 | 
 | 
            if (i >= 3 && (a[i-3] == 'r' || a[i-3] == 'R') &&  | 
 | 
                          (a[i-2] == 'e' || a[i-2] == 'E') &&  | 
 | 
                          (a[i-1] == 'a' || a[i-1] == 'A') &&  | 
 | 
                          (a[i] == 'd' || a[i] == 'D'))  | 
 | 
            { | 
 | 
                matchlen = 4;  | 
 | 
                mask |= READ;  | 
 | 
 | 
 | 
            } else if (i >= 4 && (a[i-4] == 'w' || a[i-4] == 'W') &&  | 
 | 
                                 (a[i-3] == 'r' || a[i-3] == 'R') &&  | 
 | 
                                 (a[i-2] == 'i' || a[i-2] == 'I') &&  | 
 | 
                                 (a[i-1] == 't' || a[i-1] == 'T') &&  | 
 | 
                                 (a[i] == 'e' || a[i] == 'E'))  | 
 | 
            { | 
 | 
                matchlen = 5;  | 
 | 
                mask |= WRITE;  | 
 | 
 | 
 | 
            } else if (i >= 6 && (a[i-6] == 'e' || a[i-6] == 'E') &&  | 
 | 
                                 (a[i-5] == 'x' || a[i-5] == 'X') &&  | 
 | 
                                 (a[i-4] == 'e' || a[i-4] == 'E') &&  | 
 | 
                                 (a[i-3] == 'c' || a[i-3] == 'C') &&  | 
 | 
                                 (a[i-2] == 'u' || a[i-2] == 'U') &&  | 
 | 
                                 (a[i-1] == 't' || a[i-1] == 'T') &&  | 
 | 
                                 (a[i] == 'e' || a[i] == 'E'))  | 
 | 
            { | 
 | 
                matchlen = 7;  | 
 | 
                mask |= EXECUTE;  | 
 | 
 | 
 | 
            } else if (i >= 5 && (a[i-5] == 'd' || a[i-5] == 'D') &&  | 
 | 
                                 (a[i-4] == 'e' || a[i-4] == 'E') &&  | 
 | 
                                 (a[i-3] == 'l' || a[i-3] == 'L') &&  | 
 | 
                                 (a[i-2] == 'e' || a[i-2] == 'E') &&  | 
 | 
                                 (a[i-1] == 't' || a[i-1] == 'T') &&  | 
 | 
                                 (a[i] == 'e' || a[i] == 'E'))  | 
 | 
            { | 
 | 
                matchlen = 6;  | 
 | 
                mask |= DELETE;  | 
 | 
 | 
 | 
            } else if (i >= 7 && (a[i-7] == 'r' || a[i-7] == 'R') &&  | 
 | 
                                 (a[i-6] == 'e' || a[i-6] == 'E') &&  | 
 | 
                                 (a[i-5] == 'a' || a[i-5] == 'A') &&  | 
 | 
                                 (a[i-4] == 'd' || a[i-4] == 'D') &&  | 
 | 
                                 (a[i-3] == 'l' || a[i-3] == 'L') &&  | 
 | 
                                 (a[i-2] == 'i' || a[i-2] == 'I') &&  | 
 | 
                                 (a[i-1] == 'n' || a[i-1] == 'N') &&  | 
 | 
                                 (a[i] == 'k' || a[i] == 'K'))  | 
 | 
            { | 
 | 
                matchlen = 8;  | 
 | 
                mask |= READLINK;  | 
 | 
 | 
 | 
            } else { | 
 | 
                  | 
 | 
                throw new IllegalArgumentException(  | 
 | 
                        "invalid permission: " + actions);  | 
 | 
            }  | 
 | 
 | 
 | 
            // make sure we didn't just match the tail of a word  | 
 | 
              | 
 | 
            boolean seencomma = false;  | 
 | 
            while (i >= matchlen && !seencomma) { | 
 | 
                switch(a[i-matchlen]) { | 
 | 
                case ',':  | 
 | 
                    seencomma = true;  | 
 | 
                    break;  | 
 | 
                case ' ': case '\r': case '\n':  | 
 | 
                case '\f': case '\t':  | 
 | 
                    break;  | 
 | 
                default:  | 
 | 
                    throw new IllegalArgumentException(  | 
 | 
                            "invalid permission: " + actions);  | 
 | 
                }  | 
 | 
                i--;  | 
 | 
            }  | 
 | 
 | 
 | 
              | 
 | 
            i -= matchlen;  | 
 | 
        }  | 
 | 
 | 
 | 
        return mask;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    int getMask() { | 
 | 
        return mask;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static String getActions(int mask) { | 
 | 
        StringBuilder sb = new StringBuilder();  | 
 | 
        boolean comma = false;  | 
 | 
 | 
 | 
        if ((mask & READ) == READ) { | 
 | 
            comma = true;  | 
 | 
            sb.append("read"); | 
 | 
        }  | 
 | 
 | 
 | 
        if ((mask & WRITE) == WRITE) { | 
 | 
            if (comma) sb.append(','); | 
 | 
            else comma = true;  | 
 | 
            sb.append("write"); | 
 | 
        }  | 
 | 
 | 
 | 
        if ((mask & EXECUTE) == EXECUTE) { | 
 | 
            if (comma) sb.append(','); | 
 | 
            else comma = true;  | 
 | 
            sb.append("execute"); | 
 | 
        }  | 
 | 
 | 
 | 
        if ((mask & DELETE) == DELETE) { | 
 | 
            if (comma) sb.append(','); | 
 | 
            else comma = true;  | 
 | 
            sb.append("delete"); | 
 | 
        }  | 
 | 
 | 
 | 
        if ((mask & READLINK) == READLINK) { | 
 | 
            if (comma) sb.append(','); | 
 | 
            else comma = true;  | 
 | 
            sb.append("readlink"); | 
 | 
        }  | 
 | 
 | 
 | 
        return sb.toString();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public String getActions() { | 
 | 
        if (actions == null)  | 
 | 
            actions = getActions(this.mask);  | 
 | 
 | 
 | 
        return actions;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public PermissionCollection newPermissionCollection() { | 
 | 
        return new FilePermissionCollection();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private void writeObject(ObjectOutputStream s)  | 
 | 
        throws IOException  | 
 | 
    { | 
 | 
        // Write out the actions. The superclass takes care of the name  | 
 | 
          | 
 | 
        if (actions == null)  | 
 | 
            getActions();  | 
 | 
        s.defaultWriteObject();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private void readObject(ObjectInputStream s)  | 
 | 
         throws IOException, ClassNotFoundException  | 
 | 
    { | 
 | 
          | 
 | 
        s.defaultReadObject();  | 
 | 
        init(getMask(actions));  | 
 | 
    }  | 
 | 
}  | 
 | 
 | 
 | 
/**  | 
 | 
 * A FilePermissionCollection stores a set of FilePermission permissions.  | 
 | 
 * FilePermission objects  | 
 | 
 * must be stored in a manner that allows them to be inserted in any  | 
 | 
 * order, but enable the implies function to evaluate the implies  | 
 | 
 * method.  | 
 | 
 * For example, if you have two FilePermissions:  | 
 | 
 * <OL>  | 
 | 
 * <LI> "/tmp/-", "read"  | 
 | 
 * <LI> "/tmp/scratch/foo", "write"  | 
 | 
 * </OL>  | 
 | 
 * And you are calling the implies function with the FilePermission:  | 
 | 
 * "/tmp/scratch/foo", "read,write", then the implies function must  | 
 | 
 * take into account both the /tmp/- and /tmp/scratch/foo  | 
 | 
 * permissions, so the effective permission is "read,write".  | 
 | 
 *  | 
 | 
 * @see java.security.Permission  | 
 | 
 * @see java.security.Permissions  | 
 | 
 * @see java.security.PermissionCollection  | 
 | 
 *  | 
 | 
 *  | 
 | 
 * @author Marianne Mueller  | 
 | 
 * @author Roland Schemers  | 
 | 
 *  | 
 | 
 * @serial include  | 
 | 
 *  | 
 | 
 */  | 
 | 
 | 
 | 
final class FilePermissionCollection extends PermissionCollection  | 
 | 
    implements Serializable  | 
 | 
{ | 
 | 
      | 
 | 
    private transient List<Permission> perms;  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    public FilePermissionCollection() { | 
 | 
        perms = new ArrayList<>();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public void add(Permission permission) { | 
 | 
        if (! (permission instanceof FilePermission))  | 
 | 
            throw new IllegalArgumentException("invalid permission: "+ | 
 | 
                                               permission);  | 
 | 
        if (isReadOnly())  | 
 | 
            throw new SecurityException(  | 
 | 
                "attempt to add a Permission to a readonly PermissionCollection");  | 
 | 
 | 
 | 
        synchronized (this) { | 
 | 
            perms.add(permission);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public boolean implies(Permission permission) { | 
 | 
        if (! (permission instanceof FilePermission))  | 
 | 
            return false;  | 
 | 
 | 
 | 
        FilePermission fp = (FilePermission) permission;  | 
 | 
 | 
 | 
        int desired = fp.getMask();  | 
 | 
        int effective = 0;  | 
 | 
        int needed = desired;  | 
 | 
 | 
 | 
        synchronized (this) { | 
 | 
            int len = perms.size();  | 
 | 
            for (int i = 0; i < len; i++) { | 
 | 
                FilePermission x = (FilePermission) perms.get(i);  | 
 | 
                if (((needed & x.getMask()) != 0) && x.impliesIgnoreMask(fp)) { | 
 | 
                    effective |=  x.getMask();  | 
 | 
                    if ((effective & desired) == desired)  | 
 | 
                        return true;  | 
 | 
                    needed = (desired ^ effective);  | 
 | 
                }  | 
 | 
            }  | 
 | 
        }  | 
 | 
        return false;  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    public Enumeration<Permission> elements() { | 
 | 
          | 
 | 
        synchronized (this) { | 
 | 
            return Collections.enumeration(perms);  | 
 | 
        }  | 
 | 
    }  | 
 | 
 | 
 | 
    private static final long serialVersionUID = 2202956749081564585L;  | 
 | 
 | 
 | 
    // Need to maintain serialization interoperability with earlier releases,  | 
 | 
    // which had the serializable field:  | 
 | 
    //    private Vector permissions;  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private static final ObjectStreamField[] serialPersistentFields = { | 
 | 
        new ObjectStreamField("permissions", Vector.class), | 
 | 
    };  | 
 | 
 | 
 | 
    /**  | 
 | 
     * @serialData "permissions" field (a Vector containing the FilePermissions).  | 
 | 
     */  | 
 | 
      | 
 | 
 | 
 | 
 | 
 | 
     */  | 
 | 
    private void writeObject(ObjectOutputStream out) throws IOException { | 
 | 
        // Don't call out.defaultWriteObject()  | 
 | 
 | 
 | 
          | 
 | 
        Vector<Permission> permissions = new Vector<>(perms.size());  | 
 | 
        synchronized (this) { | 
 | 
            permissions.addAll(perms);  | 
 | 
        }  | 
 | 
 | 
 | 
        ObjectOutputStream.PutField pfields = out.putFields();  | 
 | 
        pfields.put("permissions", permissions); | 
 | 
        out.writeFields();  | 
 | 
    }  | 
 | 
 | 
 | 
      | 
 | 
 | 
 | 
     */  | 
 | 
    private void readObject(ObjectInputStream in)  | 
 | 
        throws IOException, ClassNotFoundException  | 
 | 
    { | 
 | 
        // Don't call defaultReadObject()  | 
 | 
 | 
 | 
          | 
 | 
        ObjectInputStream.GetField gfields = in.readFields();  | 
 | 
 | 
 | 
          | 
 | 
        @SuppressWarnings("unchecked") | 
 | 
        Vector<Permission> permissions = (Vector<Permission>)gfields.get("permissions", null); | 
 | 
        perms = new ArrayList<>(permissions.size());  | 
 | 
        for (Permission perm : permissions) { | 
 | 
            perms.add(perm);  | 
 | 
        }  | 
 | 
    }  | 
 | 
}  |