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