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