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 private static int getMask(String actions) { 427 428 int mask = NONE; 429 430 // Null action valid? 431 if (actions == null) { 432 return mask; 433 } 434 435 // Use object identity comparison against known-interned strings for 436 // performance benefit (these values are used heavily within the JDK). 437 if (actions == SecurityConstants.FILE_READ_ACTION) { 438 return READ; 439 } else if (actions == SecurityConstants.FILE_WRITE_ACTION) { 440 return WRITE; 441 } else if (actions == SecurityConstants.FILE_EXECUTE_ACTION) { 442 return EXECUTE; 443 } else if (actions == SecurityConstants.FILE_DELETE_ACTION) { 444 return DELETE; 445 } else if (actions == SecurityConstants.FILE_READLINK_ACTION) { 446 return READLINK; 447 } 448 449 char[] a = actions.toCharArray(); 450 451 int i = a.length - 1; 452 if (i < 0) 453 return mask; 454 455 while (i != -1) { 456 char c; 457 458 // skip whitespace 459 while ((i!=-1) && ((c = a[i]) == ' ' || 460 c == '\r' || 461 c == '\n' || 462 c == '\f' || 463 c == '\t')) 464 i--; 465 466 // check for the known strings 467 int matchlen; 468 469 if (i >= 3 && (a[i-3] == 'r' || a[i-3] == 'R') && 470 (a[i-2] == 'e' || a[i-2] == 'E') && 471 (a[i-1] == 'a' || a[i-1] == 'A') && 472 (a[i] == 'd' || a[i] == 'D')) 473 { 474 matchlen = 4; 475 mask |= READ; 476 477 } else if (i >= 4 && (a[i-4] == 'w' || a[i-4] == 'W') && 478 (a[i-3] == 'r' || a[i-3] == 'R') && 479 (a[i-2] == 'i' || a[i-2] == 'I') && 480 (a[i-1] == 't' || a[i-1] == 'T') && 481 (a[i] == 'e' || a[i] == 'E')) 482 { 483 matchlen = 5; 484 mask |= WRITE; 485 486 } else if (i >= 6 && (a[i-6] == 'e' || a[i-6] == 'E') && 487 (a[i-5] == 'x' || a[i-5] == 'X') && 488 (a[i-4] == 'e' || a[i-4] == 'E') && 489 (a[i-3] == 'c' || a[i-3] == 'C') && 490 (a[i-2] == 'u' || a[i-2] == 'U') && 491 (a[i-1] == 't' || a[i-1] == 'T') && 492 (a[i] == 'e' || a[i] == 'E')) 493 { 494 matchlen = 7; 495 mask |= EXECUTE; 496 497 } else if (i >= 5 && (a[i-5] == 'd' || a[i-5] == 'D') && 498 (a[i-4] == 'e' || a[i-4] == 'E') && 499 (a[i-3] == 'l' || a[i-3] == 'L') && 500 (a[i-2] == 'e' || a[i-2] == 'E') && 501 (a[i-1] == 't' || a[i-1] == 'T') && 502 (a[i] == 'e' || a[i] == 'E')) 503 { 504 matchlen = 6; 505 mask |= DELETE; 506 507 } else if (i >= 7 && (a[i-7] == 'r' || a[i-7] == 'R') && 508 (a[i-6] == 'e' || a[i-6] == 'E') && 509 (a[i-5] == 'a' || a[i-5] == 'A') && 510 (a[i-4] == 'd' || a[i-4] == 'D') && 511 (a[i-3] == 'l' || a[i-3] == 'L') && 512 (a[i-2] == 'i' || a[i-2] == 'I') && 513 (a[i-1] == 'n' || a[i-1] == 'N') && 514 (a[i] == 'k' || a[i] == 'K')) 515 { 516 matchlen = 8; 517 mask |= READLINK; 518 519 } else { 520 // parse error 521 throw new IllegalArgumentException( 522 "invalid permission: " + actions); 523 } 524 525 // make sure we didn't just match the tail of a word 526 // like "ackbarfaccept". Also, skip to the comma. 527 boolean seencomma = false; 528 while (i >= matchlen && !seencomma) { 529 switch(a[i-matchlen]) { 530 case ',': 531 seencomma = true; 532 break; 533 case ' ': case '\r': case '\n': 534 case '\f': case '\t': 535 break; 536 default: 537 throw new IllegalArgumentException( 538 "invalid permission: " + actions); 539 } 540 i--; 541 } 542 543 // point i at the location of the comma minus one (or -1). 544 i -= matchlen; 545 } 546 547 return mask; 548 } 549 550 /** 551 * Return the current action mask. Used by the FilePermissionCollection. 552 * 553 * @return the actions mask. 554 */ 555 556 int getMask() { 557 return mask; 558 } 559 560 /** 561 * Return the canonical string representation of the actions. 562 * Always returns present actions in the following order: 563 * read, write, execute, delete, readlink. 564 * 565 * @return the canonical string representation of the actions. 566 */ 567 private static String getActions(int mask) 568 { 569 StringBuilder sb = new StringBuilder(); 570 boolean comma = false; 571 572 if ((mask & READ) == READ) { 573 comma = true; 574 sb.append("read"); 575 } 576 577 if ((mask & WRITE) == WRITE) { 578 if (comma) sb.append(','); 579 else comma = true; 580 sb.append("write"); 581 } 582 583 if ((mask & EXECUTE) == EXECUTE) { 584 if (comma) sb.append(','); 585 else comma = true; 586 sb.append("execute"); 587 } 588 589 if ((mask & DELETE) == DELETE) { 590 if (comma) sb.append(','); 591 else comma = true; 592 sb.append("delete"); 593 } 594 595 if ((mask & READLINK) == READLINK) { 596 if (comma) sb.append(','); 597 else comma = true; 598 sb.append("readlink"); 599 } 600 601 return sb.toString(); 602 } 603 604 /** 605 * Returns the "canonical string representation" of the actions. 606 * That is, this method always returns present actions in the following order: 607 * read, write, execute, delete, readlink. For example, if this FilePermission 608 * object allows both write and read actions, a call to <code>getActions</code> 609 * will return the string "read,write". 610 * 611 * @return the canonical string representation of the actions. 612 */ 613 public String getActions() 614 { 615 if (actions == null) 616 actions = getActions(this.mask); 617 618 return actions; 619 } 620 621 622 /** 623 * Returns a new PermissionCollection object for storing FilePermission 624 * objects. 625 * <p> 626 * FilePermission objects must be stored in a manner that allows them 627 * to be inserted into the collection in any order, but that also enables the 628 * PermissionCollection <code>implies</code> 629 * method to be implemented in an efficient (and consistent) manner. 630 * 631 * <p>For example, if you have two FilePermissions: 632 * <OL> 633 * <LI> <code>"/tmp/-", "read"</code> 634 * <LI> <code>"/tmp/scratch/foo", "write"</code> 635 * </OL> 636 * 637 * <p>and you are calling the <code>implies</code> method with the FilePermission: 638 * 639 * <pre> 640 * "/tmp/scratch/foo", "read,write", 641 * </pre> 642 * 643 * then the <code>implies</code> function must 644 * take into account both the "/tmp/-" and "/tmp/scratch/foo" 645 * permissions, so the effective permission is "read,write", 646 * and <code>implies</code> returns true. The "implies" semantics for 647 * FilePermissions are handled properly by the PermissionCollection object 648 * returned by this <code>newPermissionCollection</code> method. 649 * 650 * @return a new PermissionCollection object suitable for storing 651 * FilePermissions. 652 */ 653 654 public PermissionCollection newPermissionCollection() { 655 return new FilePermissionCollection(); 656 } 657 658 /** 659 * WriteObject is called to save the state of the FilePermission 660 * to a stream. The actions are serialized, and the superclass 661 * takes care of the name. 662 */ 663 private void writeObject(ObjectOutputStream s) 664 throws IOException 665 { 666 // Write out the actions. The superclass takes care of the name 667 // call getActions to make sure actions field is initialized 668 if (actions == null) 669 getActions(); 670 s.defaultWriteObject(); 671 } 672 673 /** 674 * readObject is called to restore the state of the FilePermission from 675 * a stream. 676 */ 677 private void readObject(ObjectInputStream s) 678 throws IOException, ClassNotFoundException 679 { 680 // Read in the actions, then restore everything else by calling init. 681 s.defaultReadObject(); 682 init(getMask(actions)); 683 } 684 } 685 686 /** 687 * A FilePermissionCollection stores a set of FilePermission permissions. 688 * FilePermission objects 689 * must be stored in a manner that allows them to be inserted in any 690 * order, but enable the implies function to evaluate the implies 691 * method. 692 * For example, if you have two FilePermissions: 693 * <OL> 694 * <LI> "/tmp/-", "read" 695 * <LI> "/tmp/scratch/foo", "write" 696 * </OL> 697 * And you are calling the implies function with the FilePermission: 698 * "/tmp/scratch/foo", "read,write", then the implies function must 699 * take into account both the /tmp/- and /tmp/scratch/foo 700 * permissions, so the effective permission is "read,write". 701 * 702 * @see java.security.Permission 703 * @see java.security.Permissions 704 * @see java.security.PermissionCollection 705 * 706 * 707 * @author Marianne Mueller 708 * @author Roland Schemers 709 * 710 * @serial include 711 * 712 */ 713 714 final class FilePermissionCollection extends PermissionCollection 715 implements Serializable { 716 717 // Not serialized; see serialization section at end of class 718 private transient List<Permission> perms; 719 720 /** 721 * Create an empty FilePermissions object. 722 * 723 */ 724 725 public FilePermissionCollection() { 726 perms = new ArrayList<>(); 727 } 728 729 /** 730 * Adds a permission to the FilePermissions. The key for the hash is 731 * permission.path. 732 * 733 * @param permission the Permission object to add. 734 * 735 * @exception IllegalArgumentException - if the permission is not a 736 * FilePermission 737 * 738 * @exception SecurityException - if this FilePermissionCollection object 739 * has been marked readonly 740 */ 741 742 public void add(Permission permission) 743 { 744 if (! (permission instanceof FilePermission)) 745 throw new IllegalArgumentException("invalid permission: "+ 746 permission); 747 if (isReadOnly()) 748 throw new SecurityException( 749 "attempt to add a Permission to a readonly PermissionCollection"); 750 751 synchronized (this) { 752 perms.add(permission); 753 } 754 } 755 756 /** 757 * Check and see if this set of permissions implies the permissions 758 * expressed in "permission". 759 * 760 * @param p the Permission object to compare 761 * 762 * @return true if "permission" is a proper subset of a permission in 763 * the set, false if not. 764 */ 765 766 public boolean implies(Permission permission) 767 { 768 if (! (permission instanceof FilePermission)) 769 return false; 770 771 FilePermission fp = (FilePermission) permission; 772 773 int desired = fp.getMask(); 774 int effective = 0; 775 int needed = desired; 776 777 synchronized (this) { 778 int len = perms.size(); 779 for (int i = 0; i < len; i++) { 780 FilePermission x = (FilePermission) perms.get(i); 781 if (((needed & x.getMask()) != 0) && x.impliesIgnoreMask(fp)) { 782 effective |= x.getMask(); 783 if ((effective & desired) == desired) 784 return true; 785 needed = (desired ^ effective); 786 } 787 } 788 } 789 return false; 790 } 791 792 /** 793 * Returns an enumeration of all the FilePermission objects in the 794 * container. 795 * 796 * @return an enumeration of all the FilePermission objects. 797 */ 798 799 public Enumeration<Permission> elements() { 800 // Convert Iterator into Enumeration 801 synchronized (this) { 802 return Collections.enumeration(perms); 803 } 804 } 805 806 private static final long serialVersionUID = 2202956749081564585L; 807 808 // Need to maintain serialization interoperability with earlier releases, 809 // which had the serializable field: 810 // private Vector permissions; 811 812 /** 813 * @serialField permissions java.util.Vector 814 * A list of FilePermission objects. 815 */ 816 private static final ObjectStreamField[] serialPersistentFields = { 817 new ObjectStreamField("permissions", Vector.class), 818 }; 819 820 /** 821 * @serialData "permissions" field (a Vector containing the FilePermissions). 822 */ 823 /* 824 * Writes the contents of the perms field out as a Vector for 825 * serialization compatibility with earlier releases. 826 */ 827 private void writeObject(ObjectOutputStream out) throws IOException { 828 // Don't call out.defaultWriteObject() 829 830 // Write out Vector 831 Vector<Permission> permissions = new Vector<>(perms.size()); 832 synchronized (this) { 833 permissions.addAll(perms); 834 } 835 836 ObjectOutputStream.PutField pfields = out.putFields(); 837 pfields.put("permissions", permissions); 838 out.writeFields(); 839 } 840 841 /* 842 * Reads in a Vector of FilePermissions and saves them in the perms field. 843 */ 844 private void readObject(ObjectInputStream in) throws IOException, 845 ClassNotFoundException { 846 // Don't call defaultReadObject() 847 848 // Read in serialized fields 849 ObjectInputStream.GetField gfields = in.readFields(); 850 851 // Get the one we want 852 @SuppressWarnings("unchecked") 853 Vector<Permission> permissions = (Vector<Permission>)gfields.get("permissions", null); 854 perms = new ArrayList<>(permissions.size()); 855 perms.addAll(permissions); 856 } 857 }