FileDocCategorySizeDatePackage
FilePermission.javaAPI DocAndroid 1.5 API13755Wed May 06 22:41:04 BST 2009java.io

FilePermission

public final class FilePermission extends Permission implements Serializable
A permission for accessing a file or directory. The FilePermission is made up of a pathname and a set of actions which are valid for the pathname.

The {@code File.separatorChar} must be used in all pathnames when constructing a FilePermission. The following descriptions will assume the char is {@code /}. A pathname that ends in {@code /*} includes all the files and directories contained in that directory. If the pathname ends in {@code /-}, it includes all the files and directories in that directory recursively. The following pathnames have a special meaning:

  • "*": all files in the current directory;
  • "-": recursively all files and directories in the current directory;
  • "<<ALL FILES>>": any file and directory in the file system.
since
Android 1.0

Fields Summary
private static final long
serialVersionUID
private transient String
canonPath
private static final String[]
actionList
private String
actions
transient int
mask
private transient boolean
includeAll
private transient boolean
allDir
private transient boolean
allSubdir
Constructors Summary
public FilePermission(String path, String actions)
Constructs a new FilePermission with the path and actions specified.

param
path the pathname of the file or directory to apply the actions to.
param
actions the actions for the {@code path}. May be any combination of "read", "write", "execute" and "delete".
throws
IllegalArgumentException if {@code actions} is {@code null} or an empty string, or if it contains a string other than "read", "write", "execute" and "delete".
throws
NullPointerException if {@code path} is null.
since
Android 1.0


                                                                                                                                                                        
         
        super(path);
        init(path, actions);
    
Methods Summary
public booleanequals(java.lang.Object obj)
Indicates if this file permission is equal to another. The two are equal if {@code obj} is a FilePermission, they have the same path, and they have the same actions.

param
obj the object to check equality with.
return
{@code true} if this file permission is equal to {@code obj}, {@code false} otherwise.
since
Android 1.0

        if (obj instanceof FilePermission) {
            FilePermission fp = (FilePermission) obj;
            if (fp.actions != actions) {
                if (fp.actions == null || !fp.actions.equals(actions)) {
                    return false;
                }
            }

            /* Matching actions and both are <<ALL FILES>> ? */
            if (fp.includeAll || includeAll) {
                return fp.includeAll == includeAll;
            }
            return fp.canonPath.equals(canonPath);
        }
        return false;
    
public java.lang.StringgetActions()
Returns the actions associated with this file permission.

return
the actions associated with this file permission.
since
Android 1.0

        return actions;
    
private intgetMask(java.lang.String actionNames)
Returns the numerical representation of the argument.

param
actionNames the action names
return
the action mask

        int actionInt = 0, head = 0, tail = 0;
        do {
            tail = actionNames.indexOf(",", head); //$NON-NLS-1$
            String action = tail > 0 ? actionNames.substring(head, tail).trim()
                    : actionNames.substring(head).trim();
            if (action.equals("read")) { //$NON-NLS-1$
                actionInt |= 8;
            } else if (action.equals("write")) { //$NON-NLS-1$
                actionInt |= 4;
            } else if (action.equals("execute")) { //$NON-NLS-1$
                actionInt |= 2;
            } else if (action.equals("delete")) { //$NON-NLS-1$
                actionInt |= 1;
            } else {
                throw new IllegalArgumentException(Msg.getString(
                        "K006f", action)); //$NON-NLS-1$
            }
            head = tail + 1;
        } while (tail > 0);
        return actionInt;
    
public inthashCode()
Calculates the hash code value for this file permission.

return
the hash code value for this file permission.
since
Android 1.0

        return (canonPath == null ? getName().hashCode() : canonPath.hashCode())
                + mask;
    
public booleanimplies(java.security.Permission p)
Indicates whether the permission {@code p} is implied by this file permission. This is the case if {@code p} is an instance of {@code FilePermission}, if {@code p}'s actions are a subset of this file permission's actions and if {@code p}'s path is implied by this file permission's path.

param
p the permission to check.
return
{@code true} if the argument permission is implied by the receiver, and {@code false} if it is not.
since
Android 1.0

        int match = impliesMask(p);
        return match != 0 && match == ((FilePermission) p).mask;
    
intimpliesMask(java.security.Permission p)
Returns an int describing what masks are implied by a specific permission.

param
p the permission
return
the mask applied to the given permission

        if (!(p instanceof FilePermission)) {
            return 0;
        }
        FilePermission fp = (FilePermission) p;
        int matchedMask = mask & fp.mask;
        // Can't match any bits?
        if (matchedMask == 0) {
            return 0;
        }

        // Is this permission <<ALL FILES>>
        if (includeAll) {
            return matchedMask;
        }

        // We can't imply all files
        if (fp.includeAll) {
            return 0;
        }

        // Scan the length of p checking all match possibilities
        // \- implies everything except \
        int thisLength = canonPath.length();
        if (allSubdir && thisLength == 2
                && !fp.canonPath.equals(File.separator)) {
            return matchedMask;
        }
        // need /- to imply /-
        if (fp.allSubdir && !allSubdir) {
            return 0;
        }
        // need /- or /* to imply /*
        if (fp.allDir && !allSubdir && !allDir) {
            return 0;
        }

        boolean includeDir = false;
        int pLength = fp.canonPath.length();
        // do not compare the * or -
        if (allDir || allSubdir) {
            thisLength--;
        }
        if (fp.allDir || fp.allSubdir) {
            pLength--;
        }
        for (int i = 0; i < pLength; i++) {
            char pChar = fp.canonPath.charAt(i);
            // Is p longer than this permissions canonLength?
            if (i >= thisLength) {
                if (i == thisLength) {
                    // Is this permission include all? (must have matched up
                    // until this point).
                    if (allSubdir) {
                        return matchedMask;
                    }
                    // Is this permission include a dir? Continue the check
                    // afterwards.
                    if (allDir) {
                        includeDir = true;
                    }
                }
                // If not includeDir then is has to be a mismatch.
                if (!includeDir) {
                    return 0;
                }
                /**
                 * If we have * for this and find a separator it is invalid. IE:
                 * this is '/a/*' and p is '/a/b/c' we should fail on the
                 * separator after the b. Except for root, canonical paths do
                 * not end in a separator.
                 */
                if (pChar == File.separatorChar) {
                    return 0;
                }
            } else {
                // Are the characters matched?
                if (canonPath.charAt(i) != pChar) {
                    return 0;
                }
            }
        }
        // Must have matched up to this point or it's a valid file in an include
        // all directory
        if (pLength == thisLength) {
            if (allSubdir) {
                // /- implies /- or /*
                return fp.allSubdir || fp.allDir ? matchedMask : 0;
            }
            return allDir == fp.allDir ? matchedMask : 0;
        }
        return includeDir ? matchedMask : 0;
    
private voidinit(java.lang.String path, java.lang.String pathActions)

        if (pathActions == null || pathActions.equals("")) { //$NON-NLS-1$
            throw new IllegalArgumentException(Msg.getString("K006d")); //$NON-NLS-1$
        }
        this.actions = toCanonicalActionString(pathActions);

        if (path == null) {
            throw new NullPointerException(Msg.getString("K006e")); //$NON-NLS-1$
        }
        if (path.equals("<<ALL FILES>>")) { //$NON-NLS-1$
            includeAll = true;
        } else {
            canonPath = AccessController
                    .doPrivileged(new PrivilegedAction<String>() {
                        public String run() {
                            try {
                                return new File(path).getCanonicalPath();
                            } catch (IOException e) {
                                return path;
                            }
                        }
                    });
            if (path.equals("*") || path.endsWith(File.separator + "*")) { //$NON-NLS-1$ //$NON-NLS-2$
                allDir = true;
            }
            if (path.equals("-") || path.endsWith(File.separator + "-")) { //$NON-NLS-1$ //$NON-NLS-2$
                allSubdir = true;
            }
        }
    
public java.security.PermissionCollectionnewPermissionCollection()
Returns a new PermissionCollection in which to place FilePermission objects.

return
A new PermissionCollection object suitable for storing FilePermission objects.
since
Android 1.0

        return new FilePermissionCollection();
    
private voidreadObject(java.io.ObjectInputStream stream)

        stream.defaultReadObject();
        init(getName(), actions);
    
private java.lang.StringtoCanonicalActionString(java.lang.String action)
Returns the string representing this permission's actions. It must be of the form "read,write,execute,delete", all lower case and in the correct order if there is more than one action.

param
action the action name
return
the string representing this permission's actions

        actions = action.trim().toLowerCase();

        // get the numerical representation of the action list
        mask = getMask(actions);

        // convert the mask to a canonical action list.
        int len = actionList.length;
        // the test mask - shift the 1 to the leftmost position of the
        // actionList
        int highestBitMask = 1 << (len - 1);

        // if a bit of mask is set, append the corresponding action to result
        StringBuilder result = new StringBuilder();
        boolean addedItem = false;
        for (int i = 0; i < len; i++) {
            if ((highestBitMask & mask) != 0) {
                if (addedItem) {
                    result.append(","); //$NON-NLS-1$
                }
                result.append(actionList[i]);
                addedItem = true;
            }
            highestBitMask = highestBitMask >> 1;
        }
        return result.toString();
    
private voidwriteObject(java.io.ObjectOutputStream stream)

        stream.defaultWriteObject();