Source for java.io.FilePermission

   1: /* FilePermission.java --
   2:    Copyright (C) 1998, 2000, 2003, 2004, 2005, 2006
   3:    Free Software Foundation, Inc.
   4: 
   5: This file is part of GNU Classpath.
   6: 
   7: GNU Classpath is free software; you can redistribute it and/or modify
   8: it under the terms of the GNU General Public License as published by
   9: the Free Software Foundation; either version 2, or (at your option)
  10: any later version.
  11: 
  12: GNU Classpath is distributed in the hope that it will be useful, but
  13: WITHOUT ANY WARRANTY; without even the implied warranty of
  14: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15: General Public License for more details.
  16: 
  17: You should have received a copy of the GNU General Public License
  18: along with GNU Classpath; see the file COPYING.  If not, write to the
  19: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  20: 02110-1301 USA.
  21: 
  22: Linking this library statically or dynamically with other modules is
  23: making a combined work based on this library.  Thus, the terms and
  24: conditions of the GNU General Public License cover the whole
  25: combination.
  26: 
  27: As a special exception, the copyright holders of this library give you
  28: permission to link this library with independent modules to produce an
  29: executable, regardless of the license terms of these independent
  30: modules, and to copy and distribute the resulting executable under
  31: terms of your choice, provided that you also meet, for each linked
  32: independent module, the terms and conditions of the license of that
  33: module.  An independent module is a module which is not derived from
  34: or based on this library.  If you modify this library, you may extend
  35: this exception to your version of the library, but you are not
  36: obligated to do so.  If you do not wish to do so, delete this
  37: exception statement from your version. */
  38: 
  39: 
  40: package java.io;
  41: 
  42: import java.security.Permission;
  43: 
  44: public final class FilePermission extends Permission implements Serializable
  45: {
  46:   private static final long serialVersionUID = 7930732926638008763L;
  47: 
  48:   private static final String ALL_FILES = "<<ALL FILES>>";
  49: 
  50:   private boolean readPerm = false;
  51:   private boolean writePerm = false;
  52:   private boolean executePerm = false;
  53:   private boolean deletePerm = false;
  54:   private final String actionsString;
  55: 
  56:   // Checks and caches the actions
  57:   private void checkPerms() throws IllegalArgumentException
  58:   {
  59:     String action;
  60:     int i = actionsString.indexOf(',');
  61:     int startI = 0;
  62:     while (i != -1) 
  63:       {
  64:         action = actionsString.substring(startI, i).trim().toLowerCase();
  65:         if (action.equals("read"))
  66:           readPerm = true;
  67:         else if (action.equals("write"))
  68:           writePerm = true;
  69:         else if (action.equals("execute"))
  70:           executePerm = true;
  71:         else if (action.equals("delete"))
  72:           deletePerm = true;
  73:     else
  74:       throw new IllegalArgumentException("Unknown action: " + action);
  75:       
  76:         startI = i + 1;
  77:         i = actionsString.indexOf(',', startI);
  78:       }
  79: 
  80:     action = actionsString.substring(startI).trim().toLowerCase();
  81:     if (action.equals("read"))
  82:       readPerm = true;
  83:     else if (action.equals("write"))
  84:       writePerm = true;
  85:     else if (action.equals("execute"))
  86:       executePerm = true;
  87:     else if (action.equals("delete"))
  88:       deletePerm = true;
  89:     else
  90:       throw new IllegalArgumentException("Unknown action: " + action);
  91:   }
  92: 
  93:   /**
  94:    * Create a new FilePermission.
  95:    *
  96:    * @param pathExpression an expression specifying the paths this
  97:    *        permission represents.
  98:    * @param actionsString a comma-separated list of the actions this
  99:    *        permission represents. The actions must be "read", "write",
 100:    *        "execute" and/or "delete".
 101:    */
 102:   public FilePermission(String pathExpression, String actionsString) 
 103:   {
 104:     // FIXME: what to do when the file string is malformed?
 105:     super(pathExpression);
 106:     if (pathExpression == null)
 107:       throw new NullPointerException("pathExpression");
 108:     if (actionsString == null)
 109:       throw new IllegalArgumentException("actionsString");
 110:     this.actionsString = actionsString;
 111:     checkPerms();
 112:   }
 113:   
 114:   /**
 115:    * Get the actions this FilePermission supports.
 116:    * @return the String representing the actions this FilePermission supports.
 117:    */
 118:   public String getActions() 
 119:   {
 120:     return actionsString;
 121:   }
 122: 
 123:   /**
 124:    * Get the hash code for this Object.<P>
 125:    * FilePermission's hash code is calculated as the exclusive or of the 
 126:    * target
 127:    * String's hash code and the action String's hash code.
 128:    * @specnote Sun did not specify how to calculate the hash code; 
 129:    * I made this up.
 130:    * @return the hash code for this Object.
 131:    */
 132:   public int hashCode() 
 133:   {
 134:     return getName().hashCode() ^ actionsString.hashCode();
 135:   }
 136: 
 137:   /**
 138:    * Check two FilePermissions for semantic equality.
 139:    * Two FilePermissions are exactly equivalent if they have identical path
 140:    * expressions and have exactly the same access permissions.
 141:    * @param o the Object to compare to.
 142:    * @return whether the Objects are semantically equivalent.
 143:    */
 144:   public boolean equals(Object o) 
 145:   {
 146:     if (! (o instanceof FilePermission))
 147:       return false;
 148:     FilePermission p = (FilePermission) o;
 149: 
 150:     String f1 = getName();
 151:     String f2 = p.getName();
 152: 
 153:     // Compare names, taking into account if they refer to a directory
 154:     // and one has a separator and the other does not.
 155:     if (f1.length() > 0 && f1.charAt(f1.length() - 1) == File.separatorChar) 
 156:       {
 157:         if (f2.length() > 0
 158:         && f2.charAt(f2.length() - 1) == File.separatorChar) 
 159:           {
 160:         if (! f2.equals(f1))
 161:           return false;
 162:           }
 163:         else
 164:           {
 165:         if (! f2.equals(f1.substring(0, f1.length() - 1)))
 166:           return false;
 167:           }
 168:       }
 169:     else
 170:       {
 171:         if (f2.length() > 0
 172:         && f2.charAt(f2.length() - 1) == File.separatorChar)
 173:           {
 174:         if (! f1.equals(f2.substring(0, f2.length() - 1)))
 175:           return false;
 176:           }
 177:         else
 178:           {
 179:         if (! f1.equals(f2))
 180:           return false;
 181:           }
 182:       }
 183:     return (readPerm == p.readPerm
 184:         && writePerm == p.writePerm
 185:         && executePerm == p.executePerm
 186:         && deletePerm == p.deletePerm);
 187:   }
 188: 
 189:   /**
 190:    * Check to see if this permission implies another.
 191:    * Permission A implies permission B if these things are all true:
 192:    * <OL>
 193:    * <LI>A and B are both FilePermissions.</LI>
 194:    * <LI>All possible files in B are included in A 
 195:    * (possibly more are in A).</LI>
 196:    * <LI>All actions B supports, A also supports.</LI>
 197:    * </OL>
 198:    * @param p the Permission to compare against.
 199:    * @return whether this Permission implies p
 200:    */
 201:   public boolean implies(Permission p) 
 202:   {
 203:     if (! (p instanceof FilePermission))
 204:       return false;
 205: 
 206:     String f1 = getName();
 207: 
 208:     if (f1.equals(ALL_FILES))
 209:       return true;
 210:     
 211:     FilePermission fp = (FilePermission) p;
 212:     String f2 = fp.getName();
 213: 
 214:     if (f2.equals(ALL_FILES))
 215:       return false;
 216: 
 217:     try
 218:       {
 219:     f1 = new File(f1).getCanonicalPath();
 220:     f2 = new File(f2).getCanonicalPath();
 221:       }
 222:     catch (IOException ioe)
 223:       {
 224:     return false;
 225:       }
 226: 
 227:     String sub1;
 228: 
 229:     switch (f1.charAt(f1.length() - 1))
 230:       {
 231:       case '*':
 232:     sub1 = f1.substring(0, f1.length() - 1); // chop off "*"
 233:     if (f2.length() <= sub1.length())
 234:       {
 235:         // If it's smaller, there is no way it could be part of
 236:         // this directory.  If it's the same (or length - 1), it
 237:         // could be the same directory but specifies access to
 238:         // the directory rather than the files in it.
 239:         return false;
 240:       } 
 241:     else if (f2.charAt(sub1.length() - 1) == File.separatorChar)
 242:       {
 243:         // Make sure the part before the "/" is the same.
 244:         if (! f2.substring(0, sub1.length()).equals(sub1))
 245:           return false;
 246:         // Make sure there are no subdirectories specified
 247:         // underneath this one.
 248:         if (f2.substring(sub1.length() + 1).indexOf(File.separatorChar)
 249:         != -1)
 250:           return false;
 251:       }
 252:     else
 253:       {
 254:         // Obviously not equal: f2 is either not a directory or
 255:         // is not the same directory (its name continues further
 256:         // than we want).
 257:         return false;
 258:       }
 259:     break;
 260:       case '-':
 261:     // Chop off "/-".
 262:     sub1 = f1.substring(0, f1.length() - 2);
 263:     if (f2.length() < sub1.length())
 264:       {
 265:         // If it's smaller, there is no way it could be part of
 266:         // this directory.
 267:         return false;
 268:       }
 269:     else if (f2.length() > sub1.length()
 270:          && f2.charAt(sub1.length()) != File.separatorChar)
 271:       return false;
 272:     else if (! f2.substring(0, sub1.length()).equals(sub1))
 273:       return false;
 274:     break;
 275: 
 276:       default:
 277:     if (!f1.equals(f2))
 278:       return false;
 279:     break;
 280:       }
 281: 
 282:     if (fp.readPerm && ! readPerm)
 283:       return false;
 284:     if (fp.writePerm && ! writePerm)
 285:       return false;
 286:     if (fp.executePerm && ! executePerm)
 287:       return false;
 288:     if (fp.deletePerm && ! deletePerm)
 289:       return false;
 290:     
 291:     return true;
 292:   }
 293: }