1 /* |
1 /* |
2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
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 |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this |
7 * published by the Free Software Foundation. Oracle designates this |
25 |
25 |
26 package java.io; |
26 package java.io; |
27 |
27 |
28 import java.security.*; |
28 import java.security.*; |
29 import java.util.Enumeration; |
29 import java.util.Enumeration; |
30 import java.util.List; |
30 import java.util.StringJoiner; |
31 import java.util.ArrayList; |
|
32 import java.util.Vector; |
31 import java.util.Vector; |
33 import java.util.Collections; |
32 import java.util.concurrent.ConcurrentHashMap; |
34 import java.util.StringJoiner; |
|
35 import sun.security.util.SecurityConstants; |
33 import sun.security.util.SecurityConstants; |
36 |
34 |
37 /** |
35 /** |
38 * This class represents access to a file or directory. A FilePermission consists |
36 * 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. |
37 * of a pathname and a set of actions valid for that pathname. |
286 * <code>implies</code> method. |
284 * <code>implies</code> method. |
287 * |
285 * |
288 * @param path the pathname of the file/directory. |
286 * @param path the pathname of the file/directory. |
289 * @param mask the action mask to use. |
287 * @param mask the action mask to use. |
290 */ |
288 */ |
291 |
|
292 // package private for use by the FilePermissionCollection add method |
289 // package private for use by the FilePermissionCollection add method |
293 FilePermission(String path, int mask) { |
290 FilePermission(String path, int mask) { |
294 super(path); |
291 super(path); |
295 init(mask); |
292 init(mask); |
296 } |
293 } |
313 * |
310 * |
314 * @return <code>true</code> if the specified permission is not |
311 * @return <code>true</code> if the specified permission is not |
315 * <code>null</code> and is implied by this object, |
312 * <code>null</code> and is implied by this object, |
316 * <code>false</code> otherwise. |
313 * <code>false</code> otherwise. |
317 */ |
314 */ |
|
315 @Override |
318 public boolean implies(Permission p) { |
316 public boolean implies(Permission p) { |
319 if (!(p instanceof FilePermission)) |
317 if (!(p instanceof FilePermission)) |
320 return false; |
318 return false; |
321 |
319 |
322 FilePermission that = (FilePermission) p; |
320 FilePermission that = (FilePermission) p; |
385 * @param obj the object we are testing for equality with this object. |
383 * @param obj the object we are testing for equality with this object. |
386 * @return <code>true</code> if obj is a FilePermission, and has the same |
384 * @return <code>true</code> if obj is a FilePermission, and has the same |
387 * pathname and actions as this FilePermission object, |
385 * pathname and actions as this FilePermission object, |
388 * <code>false</code> otherwise. |
386 * <code>false</code> otherwise. |
389 */ |
387 */ |
|
388 @Override |
390 public boolean equals(Object obj) { |
389 public boolean equals(Object obj) { |
391 if (obj == this) |
390 if (obj == this) |
392 return true; |
391 return true; |
393 |
392 |
394 if (! (obj instanceof FilePermission)) |
393 if (! (obj instanceof FilePermission)) |
585 * object allows both write and read actions, a call to <code>getActions</code> |
585 * object allows both write and read actions, a call to <code>getActions</code> |
586 * will return the string "read,write". |
586 * will return the string "read,write". |
587 * |
587 * |
588 * @return the canonical string representation of the actions. |
588 * @return the canonical string representation of the actions. |
589 */ |
589 */ |
|
590 @Override |
590 public String getActions() { |
591 public String getActions() { |
591 if (actions == null) |
592 if (actions == null) |
592 actions = getActions(this.mask); |
593 actions = getActions(this.mask); |
593 |
594 |
594 return actions; |
595 return actions; |
687 |
689 |
688 final class FilePermissionCollection extends PermissionCollection |
690 final class FilePermissionCollection extends PermissionCollection |
689 implements Serializable |
691 implements Serializable |
690 { |
692 { |
691 // Not serialized; see serialization section at end of class |
693 // Not serialized; see serialization section at end of class |
692 private transient List<Permission> perms; |
694 private transient ConcurrentHashMap<String, Permission> perms; |
693 |
695 |
694 /** |
696 /** |
695 * Create an empty FilePermissionCollection object. |
697 * Create an empty FilePermissionCollection object. |
696 */ |
698 */ |
697 public FilePermissionCollection() { |
699 public FilePermissionCollection() { |
698 perms = new ArrayList<>(); |
700 perms = new ConcurrentHashMap<>(); |
699 } |
701 } |
700 |
702 |
701 /** |
703 /** |
702 * Adds a permission to the FilePermissionCollection. The key for the hash is |
704 * Adds a permission to the FilePermissionCollection. The key for the hash is |
703 * permission.path. |
705 * permission.path. |
708 * FilePermission |
710 * FilePermission |
709 * |
711 * |
710 * @exception SecurityException - if this FilePermissionCollection object |
712 * @exception SecurityException - if this FilePermissionCollection object |
711 * has been marked readonly |
713 * has been marked readonly |
712 */ |
714 */ |
|
715 @Override |
713 public void add(Permission permission) { |
716 public void add(Permission permission) { |
714 if (! (permission instanceof FilePermission)) |
717 if (! (permission instanceof FilePermission)) |
715 throw new IllegalArgumentException("invalid permission: "+ |
718 throw new IllegalArgumentException("invalid permission: "+ |
716 permission); |
719 permission); |
717 if (isReadOnly()) |
720 if (isReadOnly()) |
718 throw new SecurityException( |
721 throw new SecurityException( |
719 "attempt to add a Permission to a readonly PermissionCollection"); |
722 "attempt to add a Permission to a readonly PermissionCollection"); |
720 |
723 |
721 synchronized (this) { |
724 FilePermission fp = (FilePermission)permission; |
722 perms.add(permission); |
725 |
723 } |
726 // Add permission to map if it is absent, or replace with new |
|
727 // permission if applicable. NOTE: cannot use lambda for |
|
728 // remappingFunction parameter until JDK-8076596 is fixed. |
|
729 perms.merge(fp.getName(), fp, |
|
730 new java.util.function.BiFunction<>() { |
|
731 @Override |
|
732 public Permission apply(Permission existingVal, |
|
733 Permission newVal) { |
|
734 int oldMask = ((FilePermission)existingVal).getMask(); |
|
735 int newMask = ((FilePermission)newVal).getMask(); |
|
736 if (oldMask != newMask) { |
|
737 int effective = oldMask | newMask; |
|
738 if (effective == newMask) { |
|
739 return newVal; |
|
740 } |
|
741 if (effective != oldMask) { |
|
742 return new FilePermission(fp.getName(), effective); |
|
743 } |
|
744 } |
|
745 return existingVal; |
|
746 } |
|
747 } |
|
748 ); |
724 } |
749 } |
725 |
750 |
726 /** |
751 /** |
727 * Check and see if this set of permissions implies the permissions |
752 * Check and see if this set of permissions implies the permissions |
728 * expressed in "permission". |
753 * expressed in "permission". |
730 * @param permission the Permission object to compare |
755 * @param permission the Permission object to compare |
731 * |
756 * |
732 * @return true if "permission" is a proper subset of a permission in |
757 * @return true if "permission" is a proper subset of a permission in |
733 * the set, false if not. |
758 * the set, false if not. |
734 */ |
759 */ |
|
760 @Override |
735 public boolean implies(Permission permission) { |
761 public boolean implies(Permission permission) { |
736 if (! (permission instanceof FilePermission)) |
762 if (! (permission instanceof FilePermission)) |
737 return false; |
763 return false; |
738 |
764 |
739 FilePermission fp = (FilePermission) permission; |
765 FilePermission fperm = (FilePermission) permission; |
740 |
766 |
741 int desired = fp.getMask(); |
767 int desired = fperm.getMask(); |
742 int effective = 0; |
768 int effective = 0; |
743 int needed = desired; |
769 int needed = desired; |
744 |
770 |
745 synchronized (this) { |
771 for (Permission perm : perms.values()) { |
746 int len = perms.size(); |
772 FilePermission fp = (FilePermission)perm; |
747 for (int i = 0; i < len; i++) { |
773 if (((needed & fp.getMask()) != 0) && fp.impliesIgnoreMask(fperm)) { |
748 FilePermission x = (FilePermission) perms.get(i); |
774 effective |= fp.getMask(); |
749 if (((needed & x.getMask()) != 0) && x.impliesIgnoreMask(fp)) { |
775 if ((effective & desired) == desired) { |
750 effective |= x.getMask(); |
776 return true; |
751 if ((effective & desired) == desired) |
|
752 return true; |
|
753 needed = (desired ^ effective); |
|
754 } |
777 } |
|
778 needed = (desired ^ effective); |
755 } |
779 } |
756 } |
780 } |
757 return false; |
781 return false; |
758 } |
782 } |
759 |
783 |
761 * Returns an enumeration of all the FilePermission objects in the |
785 * Returns an enumeration of all the FilePermission objects in the |
762 * container. |
786 * container. |
763 * |
787 * |
764 * @return an enumeration of all the FilePermission objects. |
788 * @return an enumeration of all the FilePermission objects. |
765 */ |
789 */ |
|
790 @Override |
766 public Enumeration<Permission> elements() { |
791 public Enumeration<Permission> elements() { |
767 // Convert Iterator into Enumeration |
792 return perms.elements(); |
768 synchronized (this) { |
|
769 return Collections.enumeration(perms); |
|
770 } |
|
771 } |
793 } |
772 |
794 |
773 private static final long serialVersionUID = 2202956749081564585L; |
795 private static final long serialVersionUID = 2202956749081564585L; |
774 |
796 |
775 // Need to maintain serialization interoperability with earlier releases, |
797 // Need to maintain serialization interoperability with earlier releases, |
793 */ |
815 */ |
794 private void writeObject(ObjectOutputStream out) throws IOException { |
816 private void writeObject(ObjectOutputStream out) throws IOException { |
795 // Don't call out.defaultWriteObject() |
817 // Don't call out.defaultWriteObject() |
796 |
818 |
797 // Write out Vector |
819 // Write out Vector |
798 Vector<Permission> permissions = new Vector<>(perms.size()); |
820 Vector<Permission> permissions = new Vector<>(perms.values()); |
799 synchronized (this) { |
|
800 permissions.addAll(perms); |
|
801 } |
|
802 |
821 |
803 ObjectOutputStream.PutField pfields = out.putFields(); |
822 ObjectOutputStream.PutField pfields = out.putFields(); |
804 pfields.put("permissions", permissions); |
823 pfields.put("permissions", permissions); |
805 out.writeFields(); |
824 out.writeFields(); |
806 } |
825 } |
817 ObjectInputStream.GetField gfields = in.readFields(); |
836 ObjectInputStream.GetField gfields = in.readFields(); |
818 |
837 |
819 // Get the one we want |
838 // Get the one we want |
820 @SuppressWarnings("unchecked") |
839 @SuppressWarnings("unchecked") |
821 Vector<Permission> permissions = (Vector<Permission>)gfields.get("permissions", null); |
840 Vector<Permission> permissions = (Vector<Permission>)gfields.get("permissions", null); |
822 perms = new ArrayList<>(permissions.size()); |
841 perms = new ConcurrentHashMap<>(permissions.size()); |
823 perms.addAll(permissions); |
842 for (Permission perm : permissions) { |
|
843 perms.put(perm.getName(), perm); |
|
844 } |
824 } |
845 } |
825 } |
846 } |