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