FileDocCategorySizeDatePackage
FilePermission.javaAPI DocJava SE 5 API24191Fri Aug 26 14:56:58 BST 2005java.io

FilePermission

public final class FilePermission extends Permission implements Serializable
This class represents access to a file or directory. A FilePermission consists of a pathname and a set of actions valid for that pathname.

Pathname is the pathname of the file or directory granted the specified actions. A pathname that ends in "/*" (where "/" is the file separator character, File.separatorChar) 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. A pathname consisting of the special token "<<ALL FILES>>" matches any file.

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.

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", and "delete". Their meaning is defined as follows:

read
read permission
write
write permission
execute
execute permission. Allows Runtime.exec to be called. Corresponds to SecurityManager.checkExec.
delete
delete permission. Allows File.delete to be called. Corresponds to SecurityManager.checkDelete.

The actions string is converted to lowercase before processing.

Be careful when granting FilePermissions. Think about the implications of granting read and especially write access to various files and directories. The "<<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.

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
version
1.76 04/01/12
author
Marianne Mueller
author
Roland Schemers
since
1.2
serial
exclude

Fields Summary
private static final int
EXECUTE
Execute action.
private static final int
WRITE
Write action.
private static final int
READ
Read action.
private static final int
DELETE
Delete action.
private static final int
ALL
All actions (read,write,execute,delete)
private static final int
NONE
No actions.
private transient int
mask
private transient boolean
directory
private transient boolean
recursive
private String
actions
the actions string.
private transient String
cpath
private static final char
RECURSIVE_CHAR
private static final char
WILD_CHAR
private static final long
serialVersionUID
Constructors Summary
public FilePermission(String path, String actions)
Creates a new FilePermission object with the specified actions. path is the pathname of a file or directory, and actions contains a comma-separated list of the desired actions granted on the file or directory. Possible actions are "read", "write", "execute", and "delete".

A pathname that ends in "/*" (where "/" is the file separator character, File.separatorChar) indicates a directory and all the files contained in that directory. A pathname that ends with "/-" indicates a directory and (recursively) all files and subdirectories contained in that directory. The special pathname "<<ALL FILES>>" matches all files.

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.

param
path the pathname of the file/directory.
param
actions the action string.

	super(path);
	init(getMask(actions));
    
FilePermission(String path, int mask)
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 implies method.

param
path the pathname of the file/directory.
param
mask the action mask to use.

	super(path);
	init(mask);
    
Methods Summary
public booleanequals(java.lang.Object obj)
Checks two FilePermission objects for equality. Checks that obj is a FilePermission, and has the same pathname and actions as this object.

param
obj the object we are testing for equality with this object.
return
true if obj is a FilePermission, and has the same pathname and actions as this FilePermission object.

	if (obj == this)
	    return true;

	if (! (obj instanceof FilePermission))
	    return false;

	FilePermission that = (FilePermission) obj;

	return (this.mask == that.mask) && 
	    this.cpath.equals(that.cpath) &&
	    (this.directory == that.directory) &&
	    (this.recursive == that.recursive);
    
private static java.lang.StringgetActions(int mask)
Return the canonical string representation of the actions. Always returns present actions in the following order: read, write, execute, delete.

return
the canonical string representation of the actions.

	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");
	}

	return sb.toString();
    
public java.lang.StringgetActions()
Returns the "canonical string representation" of the actions. That is, this method always returns present actions in the following order: read, write, execute, delete. For example, if this FilePermission object allows both write and read actions, a call to getActions will return the string "read,write".

return
the canonical string representation of the actions.

	if (actions == null)
	    actions = getActions(this.mask);

	return actions;
    
private static intgetMask(java.lang.String actions)
Converts an actions String to an actions mask.

param
action the action string.
return
the actions mask.


	int mask = NONE;

	// Null action valid?
	if (actions == null) {
	    return mask;
	}
	// Check against use of constants (used heavily within the JDK)
	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;
	}
	
	char[] a = actions.toCharArray();

	int i = a.length - 1;
	if (i < 0)
	    return mask;

	while (i != -1) {
	    char c;

	    // skip whitespace
	    while ((i!=-1) && ((c = a[i]) == ' " ||
			       c == '\r" ||
			       c == '\n" ||
			       c == '\f" ||
			       c == '\t"))
		i--;

	    // check for the known strings
	    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 {
		// parse error
		throw new IllegalArgumentException(
			"invalid permission: " + actions);
	    }

	    // make sure we didn't just match the tail of a word
	    // like "ackbarfaccept".  Also, skip to the comma.
	    boolean seencomma = false;
	    while (i >= matchlen && !seencomma) {
		switch(a[i-matchlen]) {
		case ',":
		    seencomma = true;
		    /*FALLTHROUGH*/
		case ' ": case '\r": case '\n":
		case '\f": case '\t":
		    break;
		default:
		    throw new IllegalArgumentException(
			    "invalid permission: " + actions);
		}
		i--;
	    }

	    // point i at the location of the comma minus one (or -1).
	    i -= matchlen;
	}

	return mask;
    
intgetMask()
Return the current action mask. Used by the FilePermissionCollection.

return
the actions mask.

	return mask;
    
public inthashCode()
Returns the hash code value for this object.

return
a hash code value for this object.

	return this.cpath.hashCode();
    
public booleanimplies(java.security.Permission p)
Checks if this FilePermission object "implies" the specified permission.

More specifically, this method returns true if:

  • p is an instanceof FilePermission,

  • p's actions are a proper subset of this object's actions, and

  • p's pathname is implied by this object's pathname. For example, "/tmp/*" implies "/tmp/foo", since "/tmp/*" encompasses the "/tmp" directory and all files in that directory, including the one named "foo".

param
p the permission to check against.
return
true if the specified permission is implied by this object, false if not.

	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);
    
booleanimpliesIgnoreMask(java.io.FilePermission that)
Checks if the Permission's actions are a proper subset of the this object's actions. Returns the effective mask iff the this FilePermission's path also implies that FilePermission's path.

param
that the FilePermission to check against.
param
exact return immediately if the masks are not equal
return
the effective mask

	if (this.directory) {
	    if (this.recursive) {
		// make sure that.path is longer then path so
		// something like /foo/- does not imply /foo
		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
		    // permission.
		    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));
			// Use regionMatches to avoid creating new string

			return (this.cpath.length() == (last + 1)) &&
			    this.cpath.regionMatches(0, that.cpath, 0, last+1);
		    }
		}
	    }
	} else {
	    return (this.cpath.equals(that.cpath));
	}
    
private voidinit(int mask)
initialize a FilePermission object. Common to all constructors. Also called during de-serialization.

param
mask the actions mask to use.


                            
        
    

	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>>")) {
	    directory = true;
	    recursive = true;
	    cpath = "";
	    return;
	}

	int len = cpath.length();
	char last = ((len > 0) ? cpath.charAt(len - 1) : 0);

	if (last == RECURSIVE_CHAR &&
	    (len == 1 || cpath.charAt(len - 2) == File.separatorChar)) {
	    directory = true;
	    recursive = true;
	    cpath = cpath.substring(0, --len);
	} else if (last == WILD_CHAR &&
	    (len == 1 || cpath.charAt(len - 2) == File.separatorChar)) {
	    directory = true;
	    //recursive = false;
	    cpath = cpath.substring(0, --len);
	} else {
	    // overkill since they are initialized to false, but 
	    // commented out here to remind us...
	    //directory = false;
	    //recursive = false;
	}

	if (len == 0) {
	    cpath = (String) java.security.AccessController.doPrivileged(
		       new sun.security.action.GetPropertyAction("user.dir"));
	}

	// store only the canonical cpath if possible

	// need a doPrivileged block as getCanonicalPath
	// might attempt to access user.dir to turn a relative
	// path into an absolute path.
	cpath = (String) 
	    AccessController.doPrivileged(
			new java.security.PrivilegedAction() {
	    public Object run() {
		try {
		    File file = new File(cpath);
		    String canonical_path = file.getCanonicalPath();
		    int ln;
		    if (directory && 
	  		((ln=canonical_path.length()) == 0 ||
			canonical_path.charAt(ln - 1) != File.separatorChar)) {
			return canonical_path + File.separator;
		    } else {
			return canonical_path;
		    }
		} catch (IOException ioe) {
		    // ignore if we can't canonicalize path?
		}
		return cpath;
	    }
	});

	// XXX: at this point the path should be absolute. die if it isn't?
    
public java.security.PermissionCollectionnewPermissionCollection()
Returns a new PermissionCollection object for storing FilePermission objects.

FilePermission objects must be stored in a manner that allows them to be inserted into the collection in any order, but that also enables the PermissionCollection implies method to be implemented in an efficient (and consistent) manner.

For example, if you have two FilePermissions:

  1. "/tmp/-", "read"
  2. "/tmp/scratch/foo", "write"

and you are calling the implies method 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", and implies returns true. The "implies" semantics for FilePermissions are handled properly by the PermissionCollection object returned by this newPermissionCollection method.

return
a new PermissionCollection object suitable for storing FilePermissions.

	return new FilePermissionCollection();
    
private voidreadObject(java.io.ObjectInputStream s)
readObject is called to restore the state of the FilePermission from a stream.

	// Read in the actions, then restore everything else by calling init.
	s.defaultReadObject();
	init(getMask(actions));
    
private voidwriteObject(java.io.ObjectOutputStream s)
WriteObject is called to save the state of the FilePermission to a stream. The actions are serialized, and the superclass takes care of the name.

	// Write out the actions. The superclass takes care of the name
	// call getActions to make sure actions field is initialized
	if (actions == null)
	    getActions();
	s.defaultWriteObject();