FilePermissionpublic final class FilePermission extends Permission implements SerializableThis 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. |
Fields Summary |
---|
private static final int | EXECUTEExecute action. | private static final int | WRITEWrite action. | private static final int | READRead action. | private static final int | DELETEDelete action. | private static final int | ALLAll actions (read,write,execute,delete) | private static final int | NONENo actions. | private transient int | mask | private transient boolean | directory | private transient boolean | recursive | private String | actionsthe 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 all the files and directories contained in that directory.
A pathname that ends with "/-" indicates (recursively) all files and
subdirectories contained in that directory. The special pathname
"<<ALL FILES>>" matches any file.
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.
A pathname containing an empty string represents an empty path.
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.
super(path);
init(mask);
|
Methods Summary |
---|
public boolean | equals(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.
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.String | getActions(int mask)Return the canonical string representation of the actions.
Always returns present actions in the following order:
read, write, execute, delete.
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.String | getActions()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".
if (actions == null)
actions = getActions(this.mask);
return actions;
| private static int | getMask(java.lang.String actions)Converts an actions String to an 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;
| int | getMask()Return the current action mask. Used by the FilePermissionCollection.
return mask;
| public int | hashCode()Returns the hash code value for this object.
return this.cpath.hashCode();
| public boolean | implies(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 all files in the "/tmp" directory,
including the one named "foo".
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(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.
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 if (that.directory) {
// if this is NOT recursive/wildcarded,
// do not let it imply a recursive/wildcarded permission
return false;
} else {
return (this.cpath.equals(that.cpath));
}
| private void | init(int mask)initialize a FilePermission object. Common to all constructors.
Also called during de-serialization.
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;
}
// store only the canonical cpath if possible
cpath = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
try {
return sun.security.provider.PolicyFile.canonPath(cpath);
} 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;
//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;
}
// XXX: at this point the path should be absolute. die if it isn't?
| public java.security.PermissionCollection | newPermissionCollection()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:
-
"/tmp/-", "read"
-
"/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 new FilePermissionCollection();
| private void | readObject(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 void | writeObject(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();
|
|