2 * @(#)ACL.java 2.0 04/18/2001
4 * Copyright (c) 2001 International Business Machines Corp.
7 * This software has been released under the terms of the IBM Public
8 * License. For details, see the LICENSE file in the top-level source
9 * directory or online at http://www.openafs.org/dl/license10.html
11 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
12 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
13 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
14 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
15 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
16 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
17 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
18 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
19 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
20 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 package org.openafs.jafs;
26 import java.io.Serializable;
27 import java.util.ArrayList;
28 import java.util.StringTokenizer;
31 * An abstract representation of AFS file and directory pathnames.
33 * This class is an extension of the standard Java File class with file-based
34 * manipulation methods overridden by integrated AFS native methods.
36 * @version 2.0, 04/18/2001 - Completely revised class for efficiency.
39 public class ACL implements Serializable, Comparable
41 private ACL.Entry[] positiveEntries;
42 private ACL.Entry[] negativeEntries;
46 public ACL(String path) throws AFSException
48 int numberPositiveEntries = 0;
49 int numberNegativeEntries = 0;
55 StringTokenizer st = new StringTokenizer(getACLString(path), "\n\t");
57 buffer = st.nextToken();
58 numberPositiveEntries = new Integer(buffer).intValue();
59 positiveEntries = new ACL.Entry[numberPositiveEntries];
61 buffer = st.nextToken();
62 numberNegativeEntries = new Integer(buffer).intValue();
63 negativeEntries = new ACL.Entry[numberNegativeEntries];
65 for(int i = 0; i < numberPositiveEntries; i++)
67 aclEntry = new ACL.Entry();
68 aclEntry.setUser(st.nextToken());
69 aclEntry.setPermissions(new Integer(st.nextToken()).intValue());
70 positiveEntries[i] = aclEntry;
73 for(int i = 0; i < numberNegativeEntries; i++)
75 aclEntry = new ACL.Entry();
76 aclEntry.setUser(st.nextToken());
77 aclEntry.setPermissions(new Integer(st.nextToken()).intValue());
78 negativeEntries[i] = aclEntry;
81 public int getEntryCount()
83 return positiveEntries.length + positiveEntries.length;
85 public String getPath()
89 public ACL.Entry[] getPositiveEntries()
91 return positiveEntries;
93 public void addPositiveEntry(ACL.Entry entry) throws AFSException
95 int n = positiveEntries.length;
96 ACL.Entry[] e = new ACL.Entry[n + 1];
97 System.arraycopy(positiveEntries, 0, e, 0, n);
100 setACLString(path, getFormattedString());
102 public void setPositiveEntries(ACL.Entry[] entries) throws AFSException
104 this.positiveEntries = entries;
105 setACLString(path, getFormattedString());
107 public ACL.Entry[] getNegativeEntries()
109 return negativeEntries;
111 public void addNegativeEntry(ACL.Entry entry) throws AFSException
113 int n = negativeEntries.length;
114 ACL.Entry[] e = new ACL.Entry[n + 1];
115 System.arraycopy(negativeEntries, 0, e, 0, n);
118 setACLString(path, getFormattedString());
120 public void setNegativeEntries(ACL.Entry[] entries) throws AFSException
122 this.negativeEntries = entries;
123 setACLString(path, getFormattedString());
126 public void flush() throws AFSException
128 setACLString(path, getFormattedString());
131 private ACL.Entry[] getNonEmptyEntries(ACL.Entry[] entries)
133 ArrayList response = new ArrayList(entries.length);
134 for (int i = 0; i < entries.length; i++)
136 boolean isNonEmpty = entries[i].canRead() ||
137 entries[i].canLookup() ||
138 entries[i].canWrite() ||
139 entries[i].canInsert() ||
140 entries[i].canDelete() ||
141 entries[i].canLock() ||
142 entries[i].canAdmin();
143 if (isNonEmpty) response.add(entries[i]);
145 if (response.size() == entries.length) return entries;
146 return (ACL.Entry[])response.toArray(new ACL.Entry[response.size()]);
149 private void entriesToString(ACL.Entry[] entries, StringBuffer response)
151 for (int i = 0; i < entries.length; i++)
153 this.entryToString((ACL.Entry)entries[i], response);
157 private void entryToString(ACL.Entry entry, StringBuffer response)
159 response.append(entry.getUser() + '\t' + entry.getPermissionsMask() + '\n');
163 * Returns a ViceIoctl formatted String representation of this
166 * @return a ViceIoctl formatted String representation of this
169 private String getFormattedString()
171 StringBuffer out = null;
172 ACL.Entry[] nonEmptyPos = this.getNonEmptyEntries(this.getPositiveEntries());
173 ACL.Entry[] nonEmptyNeg = this.getNonEmptyEntries(this.getNegativeEntries());
175 out = new StringBuffer(nonEmptyPos.length + "\n" + nonEmptyNeg.length + "\n");
176 this.entriesToString(nonEmptyPos, out);
177 this.entriesToString(nonEmptyNeg, out);
179 return out.toString();
182 /////////////// custom override methods ////////////////////
185 * Compares two ACL objects respective to their paths and does not
186 * factor any other attribute. Alphabetic case is significant in
189 * @param acl The ACL object to be compared to this ACL
192 * @return Zero if the argument is equal to this ACL's path, a
193 * value less than zero if this ACL's path is
194 * lexicographically less than the argument, or a value greater
195 * than zero if this ACL's path is lexicographically
196 * greater than the argument
198 public int compareTo(ACL acl)
200 return this.getPath().compareTo(acl.getPath());
204 * Comparable interface method.
206 * @see #compareTo(ACL)
208 public int compareTo(Object obj)
210 return compareTo((ACL)obj);
214 * Tests whether two <code>ACL</code> objects are equal, based on their
215 * paths and permission bits.
217 * @param acl the ACL to test
218 * @return whether the specifed ACL is the same as this ACL
220 public boolean equals( ACL acl )
222 return ( (this.getPath().equals(acl.getPath())) &&
223 (positiveEntries.equals(acl.getPositiveEntries())) &&
224 (negativeEntries.equals(acl.getNegativeEntries())) );
228 * Returns a String representation of this <CODE>ACL</CODE>
230 * @return a String representation of this <CODE>ACL</CODE>
232 public String toString()
234 ACL.Entry[] nonEmptyPos = this.getNonEmptyEntries(this.getPositiveEntries());
235 ACL.Entry[] nonEmptyNeg = this.getNonEmptyEntries(this.getNegativeEntries());
237 StringBuffer out = new StringBuffer("ACL for ");
240 out.append("Positive Entries:\n");
241 for (int i = 0; i < nonEmptyPos.length; i++) {
243 out.append(nonEmptyPos[i].toString());
245 if (nonEmptyNeg.length > 0) {
246 out.append("Negative Entries:\n");
247 for (int i = 0; i < nonEmptyNeg.length; i++) {
249 out.append(nonEmptyNeg[i].toString());
253 return out.toString();
256 /////////////// native methods ////////////////////
259 * Returns a formatted String representing the ACL for the specified path.
261 * The string format is in the form of a ViceIoctl and is as follows:
262 * printf("%d\n%d\n", positiveEntriesCount, negativeEntriesCount);
263 * printf("%s\t%d\n", userOrGroupName, rightsMask);
265 * @param path the directory path
266 * @returns a formatted String representing the ACL for the specified path.
267 * @throws an AFSException if an AFS or JNI exception is encountered.
269 private native String getACLString(String path) throws AFSException;
272 * Sets the ACL in the file system according to this abstract representation.
274 * @param path the directory path
275 * @param aclString string representation of ACL to be set
276 * @throws an AFSException if an AFS or JNI exception is encountered.
278 private native void setACLString(String path, String aclString) throws AFSException;
280 /*====================================================================*/
282 /*====================================================================*/
285 * AFS ACL Entry Class.
287 * <p> Documentation reference:
288 * <A HREF="http://www.transarc.com/Library/documentation/afs/3.6/unix/en_US/HTML/AdminGd/auagd020.htm#HDRWQ772">Managing Access Control Lists</A>
290 * @version 2.0, 04/18/2001 - Completely revised class for efficiency.
291 * @version 3.0, 05/01/2002 - Converted class to an inner class.
293 public static final class Entry implements Serializable
295 /** ACL Mask read constant */
296 public static final int READ = 1;
297 /** ACL Mask write constant */
298 public static final int WRITE = 2;
299 /** ACL Mask insert constant */
300 public static final int INSERT = 4;
301 /** ACL Mask lookup constant */
302 public static final int LOOKUP = 8;
303 /** ACL Mask delete constant */
304 public static final int DELETE = 16;
305 /** ACL Mask lock constant */
306 public static final int LOCK = 32;
307 /** ACL Mask administer constant */
308 public static final int ADMIN = 64;
310 private String username;
312 private boolean r = false;
313 private boolean l = false;
314 private boolean i = false;
315 private boolean d = false;
316 private boolean w = false;
317 private boolean k = false;
318 private boolean a = false;
321 * Constructs a new ACL entry with all permission bits set to <code>false</code>.
327 * Constructs a new ACL entry with all permission bits set to <code>false</code>
328 * and sets the associated user or group name.
330 * @param user The user or group name associated with this entry
332 public Entry(String user)
337 * Constructs a new ACL entry setting each permission bit to its appropriate
338 * value according to the <code>permissionsMask</code> specified.
347 * @param permissionsMask An integer representation of the permissoin
348 * rights of this entry
350 public Entry(int permissionsMask)
352 this.setPermissions(permissionsMask);
355 * Constructs a new ACL entry setting each permission bit to its appropriate
356 * value according to the <code>permissionsMask</code> specified
357 * and sets the associated user or group name.
367 * @param permissionsMask An integer representation of the permissoin
368 * rights of this entry
369 * @param user The username or group associated with this entry
371 public Entry(String user, int permissionsMask)
374 this.setPermissions(permissionsMask);
376 /*-------------------------------------------------------------------------*/
378 * Set this entry's permission bits according to the value of the
379 * <code>permissionsMask</code> specified.
381 * @see #getPermissionsMask
382 * @param permissionsMask An integer representation of the permissoin
383 * rights of this entry
385 public void setPermissions(int permissionsMask)
387 if ((permissionsMask & READ) != 0) {
390 if ((permissionsMask & LOOKUP) != 0) {
391 this.setLookup(true);
393 if ((permissionsMask & INSERT) != 0) {
394 this.setInsert(true);
396 if ((permissionsMask & DELETE) != 0) {
397 this.setDelete(true);
399 if ((permissionsMask & WRITE) != 0) {
402 if ((permissionsMask & LOCK) != 0) {
405 if ((permissionsMask & ADMIN) != 0) {
410 * Returns this entry's permission mask.
412 * <p> <B>Permission Mask</B><BR>
421 * <p> Any combination of the above mask values would equate to a valid combination of
422 * permission settings. For example, if the permission mask was <B>11</B>, the ACL permissions
423 * would be as follows: <code>read</code> (1), <code>write</code> (2), and <code>lookup</code> (8).<BR>
426 * @return An integer representation (mask) of the permissoin rights of this entry
428 public int getPermissionsMask()
430 int permissionsMask = 0;
431 if (canRead()) permissionsMask |= READ;
432 if (canWrite()) permissionsMask |= WRITE;
433 if (canInsert()) permissionsMask |= INSERT;
434 if (canLookup()) permissionsMask |= LOOKUP;
435 if (canDelete()) permissionsMask |= DELETE;
436 if (canLock()) permissionsMask |= LOCK;
437 if (canAdmin()) permissionsMask |= ADMIN;
438 return permissionsMask;
441 * Returns the user <B>or</B> group name associated with this ACL entry.
443 * @return String representation of the user or group name associated with this entry.
445 public String getUser()
450 * Sets the user <B>or</B> group name associated with this ACL entry.
452 * @param user representation of the user or group name associated with this entry.
454 public void setUser(String user)
459 * <IMG SRC="file.gif" ALT="File Permission" WIDTH="15" HEIGHT="15" BORDER="0"> Tests whether the ACL permits <code>read</code> access.
461 * <p> This permission enables a user to read the contents of files in the directory
462 * and to obtain complete status information for the files (read/retrieve the file
465 * <p><FONT COLOR="666699"><IMG SRC="file.gif" ALT="File Permission" WIDTH="15" HEIGHT="15" BORDER="0"> <U><B>File Permission</B></U></FONT><BR>
466 * This permission is meaningful with respect to files in
467 * a directory, rather than the directory itself or its subdirectories.
469 * <p> Documentation reference:
470 * <A HREF="http://www.transarc.com/Library/documentation/afs/3.6/unix/en_US/HTML/AdminGd/auagd020.htm#HDRWQ782">The AFS ACL Permissions</A>
472 * @return <code>true</code> if and only if the ACL permits <code>read</code> access of
473 * files; <code>false</code> otherwise
475 public boolean canRead()
480 * Sets the ACL permission to accomodate <code>read</code> access for files.
483 * @param flag boolean flag that denotes the permission bit for <code>read</code> access.
485 public void setRead(boolean flag)
490 * <IMG SRC="folder.gif" ALT="Directory Permission" WIDTH="15" HEIGHT="15" BORDER="0"> Tests whether the ACL permits lookup access.
492 * <p> This permission functions as something of a gate keeper for access to the directory
493 * and its files, because a user must have it in order to exercise any other permissions.
494 * In particular, a user must have this permission to access anything in the directory's
495 * subdirectories, even if the ACL on a subdirectory grants extensive permissions.
497 * <p> This permission enables a user to list the names of the files and subdirectories in
498 * the directory (this does not permit read access to its respective entries), obtain
499 * complete status information for the directory element itself, and examine the directory's
502 * <p> This permission does not enable a user to read the contents of a file in the
505 * <p> Similarly, this permission does not enable a user to lookup the contents of,
506 * obtain complete status information for, or examine the ACL of the subdirectory of
507 * the directory. Those operations require the <code>lookup</code> permission on the ACL
508 * of the subdirectory itself.
510 * <p><FONT COLOR="666699"><IMG SRC="folder.gif" ALT="Directory Permission" WIDTH="15" HEIGHT="15" BORDER="0"> <U><B>Directory Permission</B></U></FONT><BR>
511 * This permission is meaningful with respect to the
512 * directory itself. For example, the <code>insert</code> permission (see: {@link #canInsert})
513 * does not control addition of data to a file, but rather creation of a new file or
516 * <p> Documentation reference:
517 * <A HREF="http://www.transarc.com/Library/documentation/afs/3.6/unix/en_US/HTML/AdminGd/auagd020.htm#HDRWQ782">The AFS ACL Permissions</A>
519 * @return <code>true</code> if and only if the ACL permits <code>lookup</code> access for
520 * directories; <code>false</code> otherwise
522 public boolean canLookup()
527 * Sets the ACL permission to accomodate <code>lookup</code> access for directories.
530 * @param flag boolean flag that denotes the permission bit for <code>lookup</code> access.
532 public void setLookup(boolean flag)
537 * <IMG SRC="folder.gif" ALT="Directory Permission" WIDTH="15" HEIGHT="15" BORDER="0"> Tests whether the ACL permits <code>insert</code> access.
539 * <p> This permission enables a user to add new files to the directory, either by creating
540 * or copying, and to create new subdirectories. It does not extend into any subdirectories,
541 * which are protected by their own ACLs.
543 * <p><FONT COLOR="666699"><IMG SRC="folder.gif" ALT="Directory Permission" WIDTH="15" HEIGHT="15" BORDER="0"> <U><B>Directory Permission</B></U></FONT><BR>
544 * This permission is meaningful with respect to the
545 * directory itself. For example, the <code>insert</code> permission (see: {@link #canInsert})
546 * does not control addition of data to a file, but rather creation of a new file or
549 * <p> Documentation reference:
550 * <A HREF="http://www.transarc.com/Library/documentation/afs/3.6/unix/en_US/HTML/AdminGd/auagd020.htm#HDRWQ782">The AFS ACL Permissions</A>
552 * @return <code>true</code> if and only if the ACL permits <code>insert</code> access for
553 * directories; <code>false</code> otherwise
555 public boolean canInsert()
560 * Sets the ACL permission to accomodate <code>insert</code> access for directories.
563 * @param flag boolean flag that denotes the permission bit for <code>insert</code> access.
565 public void setInsert(boolean flag)
570 * <IMG SRC="folder.gif" ALT="Directory Permission" WIDTH="15" HEIGHT="15" BORDER="0"> Tests whether the ACL permits <code>delete</code> access.
572 * <p> This permission enables a user to remove files and subdirectories from the directory
573 * or move them into other directories (assuming that the user has the <code>insert</code>
574 * (see: {@link #canInsert}) permission on the ACL of the other directories).
576 * <p><FONT COLOR="666699"><IMG SRC="folder.gif" ALT="Directory Permission" WIDTH="15" HEIGHT="15" BORDER="0"> <U><B>Directory Permission</B></U></FONT><BR>
577 * This permission is meaningful with respect to the
578 * directory itself. For example, the <code>insert</code> permission (see: {@link #canInsert})
579 * does not control addition of data to a file, but rather creation of a new file or
582 * <p> Documentation reference:
583 * <A HREF="http://www.transarc.com/Library/documentation/afs/3.6/unix/en_US/HTML/AdminGd/auagd020.htm#HDRWQ782">The AFS ACL Permissions</A>
585 * @return <code>true</code> if and only if the ACL permits <code>delete</code> access for
586 * directories; <code>false</code> otherwise
588 public boolean canDelete()
593 * Sets the ACL permission to accomodate <code>delete</code> access for directories.
596 * @param flag boolean flag that denotes the permission bit for <code>delete</code> rights.
598 public void setDelete(boolean flag)
603 * <IMG SRC="file.gif" ALT="File Permission" WIDTH="15" HEIGHT="15" BORDER="0"> Tests whether the ACL permits <code>write</code> access.
605 * <p> This permission enables a user to modify the contents of files in the directory
606 * and to change their operating system specific mode bits.
608 * <p><FONT COLOR="666699"><IMG SRC="file.gif" ALT="File Permission" WIDTH="15" HEIGHT="15" BORDER="0"> <U><B>File Permission</B></U></FONT><BR>
609 * This permission is meaningful with respect to files in
610 * a directory, rather than the directory itself or its subdirectories.
612 * <p> Documentation reference:
613 * <A HREF="http://www.transarc.com/Library/documentation/afs/3.6/unix/en_US/HTML/AdminGd/auagd020.htm#HDRWQ782">The AFS ACL Permissions</A>
615 * @return <code>true</code> if and only if the ACL permits <code>write</code> access for
616 * files; <code>false</code> otherwise
618 public boolean canWrite()
623 * Sets the ACL permission to accomodate <code>write</code> access for files.
626 * @param flag boolean flag that denotes the permission bit for <code>write</code> access.
628 public void setWrite(boolean flag)
633 * <IMG SRC="file.gif" ALT="File Permission" WIDTH="15" HEIGHT="15" BORDER="0"> Tests whether the ACL permits the <code>lock</code> authority.
635 * <p> This permission enables the user to run programs that issue system calls to
636 * lock files in the directory.
638 * <p><FONT COLOR="666699"><IMG SRC="file.gif" ALT="File Permission" WIDTH="15" HEIGHT="15" BORDER="0"> <U><B>File Permission</B></U></FONT><BR>
639 * This permission is meaningful with respect to files in
640 * a directory, rather than the directory itself or its subdirectories.
642 * <p> Documentation reference:
643 * <A HREF="http://www.transarc.com/Library/documentation/afs/3.6/unix/en_US/HTML/AdminGd/auagd020.htm#HDRWQ782">The AFS ACL Permissions</A>
645 * @return <code>true</code> if and only if the ACL permits <code>lock</code> authority for
646 * files; <code>false</code> otherwise
648 public boolean canLock()
653 * Sets the ACL permission to accomodate <code>lock</code> access for files.
656 * @param flag boolean flag that denotes the permission bit for <code>lock</code> rights.
658 public void setLock(boolean flag)
663 * <IMG SRC="folder.gif" ALT="Directory Permission" WIDTH="15" HEIGHT="15" BORDER="0"> Tests whether the ACL permits <code>administer</code> access.
665 * <p> This permission enables a user to change the directory's ACL. Members of the
666 * <code>system:administrators</code> group implicitly have this permission on every
667 * directory (that is, even if that group does not appear on the ACL). Similarly, the
668 * owner of a directory implicitly has this permission on its ACL and those of all
669 * directories below it that he or she owns.
671 * <p><FONT COLOR="666699"><IMG SRC="folder.gif" ALT="Directory Permission" WIDTH="15" HEIGHT="15" BORDER="0"> <U><B>Directory Permission</B></U></FONT><BR>
672 * This permission is meaningful with respect to the
673 * directory itself. For example, the <code>insert</code> permission (see: {@link #canInsert})
674 * does not control addition of data to a file, but rather creation of a new file or
677 * <p> Documentation reference:
678 * <A HREF="http://www.transarc.com/Library/documentation/afs/3.6/unix/en_US/HTML/AdminGd/auagd020.htm#HDRWQ782">The AFS ACL Permissions</A>
680 * @return <code>true</code> if and only if the ACL permits <code>administer</code> access for
681 * directories; <code>false</code> otherwise
683 public boolean canAdmin()
688 * Sets the ACL permission to accomodate <code>administer</code> rights for directories.
691 * @param flag boolean flag that denotes the permission bit for <code>administer</code> rights.
693 public void setAdmin(boolean flag)
698 /////////////// custom override methods ////////////////////
701 * Tests whether two <code>ACL.Entry</code> objects are equal, based on associated
702 * username and permission bits.
704 * @param entry the ACL.Entry to test
705 * @return whether the specifed ACL.Entry is the same as this ACL.Entry
707 public boolean equals( ACL.Entry entry )
709 return ( (this.getUser().equals( entry.getUser() )) &&
710 (this.getPermissionsMask() == entry.getPermissionsMask()) );
714 * Returns a String representation of this <CODE>ACL.Entry</CODE>
716 * @return a String representation of this <CODE>ACL.Entry</CODE>
718 public String toString()
720 StringBuffer out = new StringBuffer(username);
722 if (r) out.append("r");
723 if (l) out.append("l");
724 if (i) out.append("i");
725 if (d) out.append("d");
726 if (w) out.append("w");
727 if (k) out.append("k");
728 if (a) out.append("a");
730 return out.toString();