1 /* 2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.io; 27 28 import java.security.*; 29 import java.util.Enumeration; 30 import java.util.List; 31 import java.util.ArrayList; 32 import java.util.Vector; 33 import java.util.Collections; 34 import java.util.StringJoiner; 35 import sun.security.util.SecurityConstants; 36 37 /** 38 * This class represents access to a file or directory. A FilePermission consists 39 * of a pathname and a set of actions valid for that pathname. 40 * <P> 41 * Pathname is the pathname of the file or directory granted the specified 42 * actions. A pathname that ends in "/*" (where "/" is 43 * the file separator character, <code>File.separatorChar</code>) indicates 44 * all the files and directories contained in that directory. A pathname 45 * that ends with "/-" indicates (recursively) all files 46 * and subdirectories contained in that directory. A pathname consisting of 47 * the special token "<<ALL FILES>>" matches <b>any</b> file. 48 * <P> 49 * Note: A pathname consisting of a single "*" indicates all the files 50 * in the current directory, while a pathname consisting of a single "-" 51 * indicates all the files in the current directory and 52 * (recursively) all files and subdirectories contained in the current 53 * directory. 54 * <P> 55 * The actions to be granted are passed to the constructor in a string containing 56 * a list of one or more comma-separated keywords. The possible keywords are 57 * "read", "write", "execute", "delete", and "readlink". Their meaning is 58 * defined as follows: 59 * 60 * <DL> 61 * <DT> read <DD> read permission 62 * <DT> write <DD> write permission 63 * <DT> execute 64 * <DD> execute permission. Allows <code>Runtime.exec</code> to 65 * be called. Corresponds to <code>SecurityManager.checkExec</code>. 66 * <DT> delete 67 * <DD> delete permission. Allows <code>File.delete</code> to 68 * be called. Corresponds to <code>SecurityManager.checkDelete</code>. 69 * <DT> readlink 70 * <DD> read link permission. Allows the target of a 71 * <a href="../nio/file/package-summary.html#links">symbolic link</a> 72 * to be read by invoking the {@link java.nio.file.Files#readSymbolicLink 73 * readSymbolicLink } method. 74 * </DL> 75 * <P> 76 * The actions string is converted to lowercase before processing. 77 * <P> 78 * Be careful when granting FilePermissions. Think about the implications 79 * of granting read and especially write access to various files and 80 * directories. The "<<ALL FILES>>" permission with write action is 81 * especially dangerous. This grants permission to write to the entire 82 * file system. One thing this effectively allows is replacement of the 83 * system binary, including the JVM runtime environment. 84 * 85 * <p>Please note: Code can always read a file from the same 86 * directory it's in (or a subdirectory of that directory); it does not 87 * need explicit permission to do so. 88 * 89 * @see java.security.Permission 90 * @see java.security.Permissions 91 * @see java.security.PermissionCollection 92 * 93 * 94 * @author Marianne Mueller 95 * @author Roland Schemers 96 * @since 1.2 97 * 98 * @serial exclude 99 */ 100 101 public final class FilePermission extends Permission implements Serializable { 102 103 /** 104 * Execute action. 105 */ 106 private final static int EXECUTE = 0x1; 107 /** 108 * Write action. 109 */ 110 private final static int WRITE = 0x2; 111 /** 112 * Read action. 113 */ 114 private final static int READ = 0x4; 115 /** 116 * Delete action. 117 */ 118 private final static int DELETE = 0x8; 119 /** 120 * Read link action. 121 */ 122 private final static int READLINK = 0x10; 123 124 /** 125 * All actions (read,write,execute,delete,readlink) 126 */ 127 private final static int ALL = READ|WRITE|EXECUTE|DELETE|READLINK; 128 /** 129 * No actions. 130 */ 131 private final static int NONE = 0x0; 132 133 // the actions mask 134 private transient int mask; 135 136 // does path indicate a directory? (wildcard or recursive) 137 private transient boolean directory; 138 139 // is it a recursive directory specification? 140 private transient boolean recursive; 141 142 /** 143 * the actions string. 144 * 145 * @serial 146 */ 147 private String actions; // Left null as long as possible, then 148 // created and re-used in the getAction function. 149 150 // Flags to assist in lazy setting. 151 // Are directory and recursive set? 152 private transient boolean dir_rec_set = false; 153 154 // canonicalized dir path. In the case of 155 // directories, it is the name "/blah/*" or "/blah/-" without 156 // the last character (the "*" or "-"). 157 158 private transient String cpath; 159 160 // static Strings used by init(int mask) 161 private static final char RECURSIVE_CHAR = '-'; 162 private static final char WILD_CHAR = '*'; 163 164 /* 165 public String toString() 166 { 167 StringBuffer sb = new StringBuffer(); 168 sb.append("***\n"); 169 sb.append("cpath = "+cpath+"\n"); 170 sb.append("mask = "+mask+"\n"); 171 sb.append("actions = "+getActions()+"\n"); 172 sb.append("directory = "+directory+"\n"); 173 sb.append("recursive = "+recursive+"\n"); 174 sb.append("***\n"); 175 return sb.toString(); 176 } 177 */ 178 179 private static final long serialVersionUID = 7930732926638008763L; 180 181 /** 182 * initialize a FilePermission object. Common to all constructors. 183 * Also called during de-serialization. 184 * 185 * @param mask the actions mask to use. 186 * 187 */ 188 private void init(int mask) { 189 if ((mask & ALL) != mask) 190 throw new IllegalArgumentException("invalid actions mask"); 191 192 if (mask == NONE) 193 throw new IllegalArgumentException("invalid actions mask"); 194 195 if (getName() == null) 196 throw new NullPointerException("name can't be null"); 197 198 this.mask = mask; 199 } 200 201 /* 202 * Sets the directory and recursive flag, and does partial processing of the 203 * path name. 204 */ 205 private void get_dir_rec() { 206 207 cpath = getName(); 208 209 if (cpath.equals("<<ALL FILES>>")) { 210 directory = true; 211 recursive = true; 212 cpath = ""; 213 dir_rec_set = true; 214 return; 215 } 216 217 // store only the canonical cpath if possible 218 cpath = AccessController.doPrivileged(new PrivilegedAction<String>() { 219 public String run() { 220 try { 221 String path = cpath; 222 if (cpath.endsWith("*")) { 223 // call getCanonicalPath with a path with wildcard character 224 // replaced to avoid calling it with paths that are 225 // intended to match all entries in a directory 226 path = path.substring(0, path.length()-1) + "-"; 227 path = new File(path).getCanonicalPath(); 228 return path.substring(0, path.length()-1) + "*"; 229 } else { 230 return new File(path).getCanonicalPath(); 231 } 232 } catch (IOException ioe) { 233 return cpath; 234 } 235 } 236 }); 237 238 int len = cpath.length(); 239 char last = ((len > 0) ? cpath.charAt(len - 1) : 0); 240 241 if (last == RECURSIVE_CHAR && 242 (len == 1 || cpath.charAt(len - 2) == File.separatorChar)) { 243 directory = true; 244 recursive = true; 245 cpath = cpath.substring(0, --len); 246 } else if (last == WILD_CHAR && 247 (len == 1 || cpath.charAt(len - 2) == File.separatorChar)) { 248 directory = true; 249 //recursive = false; 250 cpath = cpath.substring(0, --len); 251 } else { 252 // overkill since they are initialized to false, but 253 // commented out here to remind us... 254 //directory = false; 255 //recursive = false; 256 } 257 258 // XXX: at this point the path should be absolute. die if it isn't? 259 dir_rec_set = true; 260 } 261 262 /** 263 * Creates a new FilePermission object with the specified actions. 264 * <i>path</i> is the pathname of a file or directory, and <i>actions</i> 265 * contains a comma-separated list of the desired actions granted on the 266 * file or directory. Possible actions are 267 * "read", "write", "execute", "delete", and "readlink". 268 * 269 * <p>A pathname that ends in "/*" (where "/" is 270 * the file separator character, <code>File.separatorChar</code>) 271 * indicates all the files and directories contained in that directory. 272 * A pathname that ends with "/-" indicates (recursively) all files and 273 * subdirectories contained in that directory. The special pathname 274 * "<<ALL FILES>>" matches any file. 275 * 276 * <p>A pathname consisting of a single "*" indicates all the files 277 * in the current directory, while a pathname consisting of a single "-" 278 * indicates all the files in the current directory and 279 * (recursively) all files and subdirectories contained in the current 280 * directory. 281 * 282 * <p>A pathname containing an empty string represents an empty path. 283 * 284 * @param path the pathname of the file/directory. 285 * @param actions the action string. 286 * 287 * @throws IllegalArgumentException 288 * If actions is <code>null</code>, empty or contains an action 289 * other than the specified possible actions. 290 */ 291 public FilePermission(String path, String actions) { 292 super(path); 293 init(getMask(actions)); 294 } 295 296 /** 297 * Creates a new FilePermission object using an action mask. 298 * More efficient than the FilePermission(String, String) constructor. 299 * Can be used from within 300 * code that needs to create a FilePermission object to pass into the 301 * <code>implies</code> method. 302 * 303 * @param path the pathname of the file/directory. 304 * @param mask the action mask to use. 305 */ 306 307 // package private for use by the FilePermissionCollection add method 308 FilePermission(String path, int mask) { 309 super(path); 310 init(mask); 311 } 312 313 /** 314 * Checks if this FilePermission object "implies" the specified permission. 315 * <P> 316 * More specifically, this method returns true if: 317 * <ul> 318 * <li> <i>p</i> is an instanceof FilePermission, 319 * <li> <i>p</i>'s actions are a proper subset of this 320 * object's actions, and 321 * <li> <i>p</i>'s pathname is implied by this object's 322 * pathname. For example, "/tmp/*" implies "/tmp/foo", since 323 * "/tmp/*" encompasses all files in the "/tmp" directory, 324 * including the one named "foo". 325 * </ul> 326 * 327 * @param p the permission to check against. 328 * 329 * @return <code>true</code> if the specified permission is not 330 * <code>null</code> and is implied by this object, 331 * <code>false</code> otherwise. 332 */ 333 public boolean implies(Permission p) { 334 if (!(p instanceof FilePermission)) 335 return false; 336 337 FilePermission that = (FilePermission) p; 338 339 // we get the effective mask. i.e., the "and" of this and that. 340 // They must be equal to that.mask for implies to return true. 341 342 return ((this.mask & that.mask) == that.mask) && impliesIgnoreMask(that); 343 } 344 345 /** 346 * Checks if the Permission's actions are a proper subset of the 347 * this object's actions. Returns the effective mask iff the 348 * this FilePermission's path also implies that FilePermission's path. 349 * 350 * @param that the FilePermission to check against. 351 * @return the effective mask 352 */ 353 boolean impliesIgnoreMask(FilePermission that) { 354 if (this.getName().equals("<<ALL FILES>>")) 355 return true; 356 if (!this.dir_rec_set) this.get_dir_rec(); 357 if (!that.dir_rec_set) that.get_dir_rec(); 358 if (this.directory) { 359 if (this.recursive) { 360 // make sure that.path is longer then path so 361 // something like /foo/- does not imply /foo 362 if (that.directory) { 363 return (that.cpath.length() >= this.cpath.length()) && 364 that.cpath.startsWith(this.cpath); 365 } else { 366 return ((that.cpath.length() > this.cpath.length()) && 367 that.cpath.startsWith(this.cpath)); 368 } 369 } else { 370 if (that.directory) { 371 // if the permission passed in is a directory 372 // specification, make sure that a non-recursive 373 // permission (i.e., this object) can't imply a recursive 374 // permission. 375 if (that.recursive) 376 return false; 377 else 378 return (this.cpath.equals(that.cpath)); 379 } else { 380 int last = that.cpath.lastIndexOf(File.separatorChar); 381 if (last == -1) 382 return false; 383 else { 384 // this.cpath.equals(that.cpath.substring(0, last+1)); 385 // Use regionMatches to avoid creating new string 386 return (this.cpath.length() == (last + 1)) && 387 this.cpath.regionMatches(0, that.cpath, 0, last+1); 388 } 389 } 390 } 391 } else if (that.directory) { 392 // if this is NOT recursive/wildcarded, 393 // do not let it imply a recursive/wildcarded permission 394 return false; 395 } else { 396 return (this.cpath.equals(that.cpath)); 397 } 398 } 399 400 /** 401 * Checks two FilePermission objects for equality. Checks that <i>obj</i> is 402 * a FilePermission, and has the same pathname and actions as this object. 403 * 404 * @param obj the object we are testing for equality with this object. 405 * @return <code>true</code> if obj is a FilePermission, and has the same 406 * pathname and actions as this FilePermission object, 407 * <code>false</code> otherwise. 408 */ 409 public boolean equals(Object obj) { 410 if (obj == this) 411 return true; 412 413 if (! (obj instanceof FilePermission)) 414 return false; 415 416 FilePermission that = (FilePermission) obj; 417 418 if (!this.dir_rec_set) this.get_dir_rec(); 419 if (!that.dir_rec_set) that.get_dir_rec(); 420 return (this.mask == that.mask) && 421 this.cpath.equals(that.cpath) && 422 (this.directory == that.directory) && 423 (this.recursive == that.recursive); 424 } 425 426 /** 427 * Returns the hash code value for this object. 428 * 429 * @return a hash code value for this object. 430 */ 431 public int hashCode() { 432 return 0; 433 } 434 435 /** 436 * Converts an actions String to an actions mask. 437 * 438 * @param actions the action string. 439 * @return the actions mask. 440 */ 441 private static int getMask(String actions) { 442 int mask = NONE; 443 444 // Null action valid? 445 if (actions == null) { 446 return mask; 447 } 448 449 // Use object identity comparison against known-interned strings for 450 // performance benefit (these values are used heavily within the JDK). 451 if (actions == SecurityConstants.FILE_READ_ACTION) { 452 return READ; 453 } else if (actions == SecurityConstants.FILE_WRITE_ACTION) { 454 return WRITE; 455 } else if (actions == SecurityConstants.FILE_EXECUTE_ACTION) { 456 return EXECUTE; 457 } else if (actions == SecurityConstants.FILE_DELETE_ACTION) { 458 return DELETE; 459 } else if (actions == SecurityConstants.FILE_READLINK_ACTION) { 460 return READLINK; 461 } 462 463 char[] a = actions.toCharArray(); 464 465 int i = a.length - 1; 466 if (i < 0) 467 return mask; 468 469 while (i != -1) { 470 char c; 471 472 // skip whitespace 473 while ((i!=-1) && ((c = a[i]) == ' ' || 474 c == '\r' || 475 c == '\n' || 476 c == '\f' || 477 c == '\t')) 478 i--; 479 480 // check for the known strings 481 int matchlen; 482 483 if (i >= 3 && (a[i-3] == 'r' || a[i-3] == 'R') && 484 (a[i-2] == 'e' || a[i-2] == 'E') && 485 (a[i-1] == 'a' || a[i-1] == 'A') && 486 (a[i] == 'd' || a[i] == 'D')) 487 { 488 matchlen = 4; 489 mask |= READ; 490 491 } else if (i >= 4 && (a[i-4] == 'w' || a[i-4] == 'W') && 492 (a[i-3] == 'r' || a[i-3] == 'R') && 493 (a[i-2] == 'i' || a[i-2] == 'I') && 494 (a[i-1] == 't' || a[i-1] == 'T') && 495 (a[i] == 'e' || a[i] == 'E')) 496 { 497 matchlen = 5; 498 mask |= WRITE; 499 500 } else if (i >= 6 && (a[i-6] == 'e' || a[i-6] == 'E') && 501 (a[i-5] == 'x' || a[i-5] == 'X') && 502 (a[i-4] == 'e' || a[i-4] == 'E') && 503 (a[i-3] == 'c' || a[i-3] == 'C') && 504 (a[i-2] == 'u' || a[i-2] == 'U') && 505 (a[i-1] == 't' || a[i-1] == 'T') && 506 (a[i] == 'e' || a[i] == 'E')) 507 { 508 matchlen = 7; 509 mask |= EXECUTE; 510 511 } else if (i >= 5 && (a[i-5] == 'd' || a[i-5] == 'D') && 512 (a[i-4] == 'e' || a[i-4] == 'E') && 513 (a[i-3] == 'l' || a[i-3] == 'L') && 514 (a[i-2] == 'e' || a[i-2] == 'E') && 515 (a[i-1] == 't' || a[i-1] == 'T') && 516 (a[i] == 'e' || a[i] == 'E')) 517 { 518 matchlen = 6; 519 mask |= DELETE; 520 521 } else if (i >= 7 && (a[i-7] == 'r' || a[i-7] == 'R') && 522 (a[i-6] == 'e' || a[i-6] == 'E') && 523 (a[i-5] == 'a' || a[i-5] == 'A') && 524 (a[i-4] == 'd' || a[i-4] == 'D') && 525 (a[i-3] == 'l' || a[i-3] == 'L') && 526 (a[i-2] == 'i' || a[i-2] == 'I') && 527 (a[i-1] == 'n' || a[i-1] == 'N') && 528 (a[i] == 'k' || a[i] == 'K')) 529 { 530 matchlen = 8; 531 mask |= READLINK; 532 533 } else { 534 // parse error 535 throw new IllegalArgumentException( 536 "invalid permission: " + actions); 537 } 538 539 // make sure we didn't just match the tail of a word 540 // like "ackbarfaccept". Also, skip to the comma. 541 boolean seencomma = false; 542 while (i >= matchlen && !seencomma) { 543 switch(a[i-matchlen]) { 544 case ',': 545 seencomma = true; 546 break; 547 case ' ': case '\r': case '\n': 548 case '\f': case '\t': 549 break; 550 default: 551 throw new IllegalArgumentException( 552 "invalid permission: " + actions); 553 } 554 i--; 555 } 556 557 // point i at the location of the comma minus one (or -1). 558 i -= matchlen; 559 } 560 561 return mask; 562 } 563 564 /** 565 * Return the current action mask. Used by the FilePermissionCollection. 566 * 567 * @return the actions mask. 568 */ 569 int getMask() { 570 return mask; 571 } 572 573 /** 574 * Return the canonical string representation of the actions. 575 * Always returns present actions in the following order: 576 * read, write, execute, delete, readlink. 577 * 578 * @return the canonical string representation of the actions. 579 */ 580 private static String getActions(int mask) { 581 StringJoiner sj = new StringJoiner(","); 582 583 if ((mask & READ) == READ) { 584 sj.add("read"); 585 } 586 if ((mask & WRITE) == WRITE) { 587 sj.add("write"); 588 } 589 if ((mask & EXECUTE) == EXECUTE) { 590 sj.add("execute"); 591 } 592 if ((mask & DELETE) == DELETE) { 593 sj.add("delete"); 594 } 595 if ((mask & READLINK) == READLINK) { 596 sj.add("readlink"); 597 } 598 599 return sj.toString(); 600 } 601 602 /** 603 * Returns the "canonical string representation" of the actions. 604 * That is, this method always returns present actions in the following order: 605 * read, write, execute, delete, readlink. For example, if this FilePermission 606 * object allows both write and read actions, a call to <code>getActions</code> 607 * will return the string "read,write". 608 * 609 * @return the canonical string representation of the actions. 610 */ 611 public String getActions() { 612 if (actions == null) 613 actions = getActions(this.mask); 614 615 return actions; 616 } 617 618 /** 619 * Returns a new PermissionCollection object for storing FilePermission 620 * objects. 621 * <p> 622 * FilePermission objects must be stored in a manner that allows them 623 * to be inserted into the collection in any order, but that also enables the 624 * PermissionCollection <code>implies</code> 625 * method to be implemented in an efficient (and consistent) manner. 626 * 627 * <p>For example, if you have two FilePermissions: 628 * <OL> 629 * <LI> <code>"/tmp/-", "read"</code> 630 * <LI> <code>"/tmp/scratch/foo", "write"</code> 631 * </OL> 632 * 633 * <p>and you are calling the <code>implies</code> method with the FilePermission: 634 * 635 * <pre> 636 * "/tmp/scratch/foo", "read,write", 637 * </pre> 638 * 639 * then the <code>implies</code> function must 640 * take into account both the "/tmp/-" and "/tmp/scratch/foo" 641 * permissions, so the effective permission is "read,write", 642 * and <code>implies</code> returns true. The "implies" semantics for 643 * FilePermissions are handled properly by the PermissionCollection object 644 * returned by this <code>newPermissionCollection</code> method. 645 * 646 * @return a new PermissionCollection object suitable for storing 647 * FilePermissions. 648 */ 649 public PermissionCollection newPermissionCollection() { 650 return new FilePermissionCollection(); 651 } 652 653 /** 654 * WriteObject is called to save the state of the FilePermission 655 * to a stream. The actions are serialized, and the superclass 656 * takes care of the name. 657 */ 658 private void writeObject(ObjectOutputStream s) 659 throws IOException 660 { 661 // Write out the actions. The superclass takes care of the name 662 // call getActions to make sure actions field is initialized 663 if (actions == null) 664 getActions(); 665 s.defaultWriteObject(); 666 } 667 668 /** 669 * readObject is called to restore the state of the FilePermission from 670 * a stream. 671 */ 672 private void readObject(ObjectInputStream s) 673 throws IOException, ClassNotFoundException 674 { 675 // Read in the actions, then restore everything else by calling init. 676 s.defaultReadObject(); 677 init(getMask(actions)); 678 } 679 } 680 681 /** 682 * A FilePermissionCollection stores a set of FilePermission permissions. 683 * FilePermission objects 684 * must be stored in a manner that allows them to be inserted in any 685 * order, but enable the implies function to evaluate the implies 686 * method. 687 * For example, if you have two FilePermissions: 688 * <OL> 689 * <LI> "/tmp/-", "read" 690 * <LI> "/tmp/scratch/foo", "write" 691 * </OL> 692 * And you are calling the implies function with the FilePermission: 693 * "/tmp/scratch/foo", "read,write", then the implies function must 694 * take into account both the /tmp/- and /tmp/scratch/foo 695 * permissions, so the effective permission is "read,write". 696 * 697 * @see java.security.Permission 698 * @see java.security.Permissions 699 * @see java.security.PermissionCollection 700 * 701 * 702 * @author Marianne Mueller 703 * @author Roland Schemers 704 * 705 * @serial include 706 * 707 */ 708 709 final class FilePermissionCollection extends PermissionCollection 710 implements Serializable 711 { 712 // Not serialized; see serialization section at end of class 713 private transient List<Permission> perms; 714 715 /** 716 * Create an empty FilePermissionCollection object. 717 */ 718 public FilePermissionCollection() { 719 perms = new ArrayList<>(); 720 } 721 722 /** 723 * Adds a permission to the FilePermissionCollection. The key for the hash is 724 * permission.path. 725 * 726 * @param permission the Permission object to add. 727 * 728 * @exception IllegalArgumentException - if the permission is not a 729 * FilePermission 730 * 731 * @exception SecurityException - if this FilePermissionCollection object 732 * has been marked readonly 733 */ 734 public void add(Permission permission) { 735 if (! (permission instanceof FilePermission)) 736 throw new IllegalArgumentException("invalid permission: "+ 737 permission); 738 if (isReadOnly()) 739 throw new SecurityException( 740 "attempt to add a Permission to a readonly PermissionCollection"); 741 742 synchronized (this) { 743 perms.add(permission); 744 } 745 } 746 747 /** 748 * Check and see if this set of permissions implies the permissions 749 * expressed in "permission". 750 * 751 * @param permission the Permission object to compare 752 * 753 * @return true if "permission" is a proper subset of a permission in 754 * the set, false if not. 755 */ 756 public boolean implies(Permission permission) { 757 if (! (permission instanceof FilePermission)) 758 return false; 759 760 FilePermission fp = (FilePermission) permission; 761 762 int desired = fp.getMask(); 763 int effective = 0; 764 int needed = desired; 765 766 synchronized (this) { 767 int len = perms.size(); 768 for (int i = 0; i < len; i++) { 769 FilePermission x = (FilePermission) perms.get(i); 770 if (((needed & x.getMask()) != 0) && x.impliesIgnoreMask(fp)) { 771 effective |= x.getMask(); 772 if ((effective & desired) == desired) 773 return true; 774 needed = (desired ^ effective); 775 } 776 } 777 } 778 return false; 779 } 780 781 /** 782 * Returns an enumeration of all the FilePermission objects in the 783 * container. 784 * 785 * @return an enumeration of all the FilePermission objects. 786 */ 787 public Enumeration<Permission> elements() { 788 // Convert Iterator into Enumeration 789 synchronized (this) { 790 return Collections.enumeration(perms); 791 } 792 } 793 794 private static final long serialVersionUID = 2202956749081564585L; 795 796 // Need to maintain serialization interoperability with earlier releases, 797 // which had the serializable field: 798 // private Vector permissions; 799 800 /** 801 * @serialField permissions java.util.Vector 802 * A list of FilePermission objects. 803 */ 804 private static final ObjectStreamField[] serialPersistentFields = { 805 new ObjectStreamField("permissions", Vector.class), 806 }; 807 808 /** 809 * @serialData "permissions" field (a Vector containing the FilePermissions). 810 */ 811 /* 812 * Writes the contents of the perms field out as a Vector for 813 * serialization compatibility with earlier releases. 814 */ 815 private void writeObject(ObjectOutputStream out) throws IOException { 816 // Don't call out.defaultWriteObject() 817 818 // Write out Vector 819 Vector<Permission> permissions = new Vector<>(perms.size()); 820 synchronized (this) { 821 permissions.addAll(perms); 822 } 823 824 ObjectOutputStream.PutField pfields = out.putFields(); 825 pfields.put("permissions", permissions); 826 out.writeFields(); 827 } 828 829 /* 830 * Reads in a Vector of FilePermissions and saves them in the perms field. 831 */ 832 private void readObject(ObjectInputStream in) 833 throws IOException, ClassNotFoundException 834 { 835 // Don't call defaultReadObject() 836 837 // Read in serialized fields 838 ObjectInputStream.GetField gfields = in.readFields(); 839 840 // Get the one we want 841 @SuppressWarnings("unchecked") 842 Vector<Permission> permissions = (Vector<Permission>)gfields.get("permissions", null); 843 perms = new ArrayList<>(permissions.size()); 844 perms.addAll(permissions); 845 } 846 }