001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2006-2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.types;
028 import org.opends.messages.Message;
029
030
031
032 import java.io.File;
033 import java.io.FileNotFoundException;
034 import java.lang.reflect.Method;
035
036 import org.opends.server.core.DirectoryServer;
037
038 import static org.opends.server.loggers.debug.DebugLogger.*;
039 import org.opends.server.loggers.debug.DebugTracer;
040 import static org.opends.messages.UtilityMessages.*;
041 import static org.opends.server.util.StaticUtils.*;
042
043
044
045 /**
046 * This class provides a mechanism for setting file permissions in a
047 * more abstract manner than is provided by the underlying operating
048 * system and/or filesystem. It uses a traditional UNIX-style rwx/ugo
049 * representation for the permissions and converts them as necessary
050 * to the scheme used by the underlying platform. It does not provide
051 * any mechanism for getting file permissions, nor does it provide any
052 * way of dealing with file ownership or ACLs.
053 * <BR><BR>
054 * Note that the mechanism used to perform this work on UNIX systems
055 * is based on executing the <CODE>chmod</CODE> command on the
056 * underlying system. This should be a safe operation because the
057 * Directory Server startup scripts should explicitly specify the PATH
058 * that should be used. Nevertheless, it is possible to prevent the
059 * server from using the <CODE>Runtime.exec</CODE> method by setting
060 * the <CODE>org.opends.server.DisableExec</CODE> system property with
061 * a value of "true".
062 */
063 @org.opends.server.types.PublicAPI(
064 stability=org.opends.server.types.StabilityLevel.VOLATILE,
065 mayInstantiate=true,
066 mayExtend=false,
067 mayInvoke=true)
068 public class FilePermission
069 {
070 /**
071 * The tracer object for the debug logger.
072 */
073 private static final DebugTracer TRACER = getTracer();
074
075
076
077
078 /**
079 * The bitmask that should be used for indicating whether a file is
080 * readable by its owner.
081 */
082 public static final int OWNER_READABLE = 0x0100;
083
084
085
086 /**
087 * The bitmask that should be used for indicating whether a file is
088 * writable by its owner.
089 */
090 public static final int OWNER_WRITABLE = 0x0080;
091
092
093
094 /**
095 * The bitmask that should be used for indicating whether a file is
096 * executable by its owner.
097 */
098 public static final int OWNER_EXECUTABLE = 0x0040;
099
100
101
102 /**
103 * The bitmask that should be used for indicating whether a file is
104 * readable by members of its group.
105 */
106 public static final int GROUP_READABLE = 0x0020;
107
108
109
110 /**
111 * The bitmask that should be used for indicating whether a file is
112 * writable by members of its group.
113 */
114 public static final int GROUP_WRITABLE = 0x0010;
115
116
117
118 /**
119 * The bitmask that should be used for indicating whether a file is
120 * executable by members of its group.
121 */
122 public static final int GROUP_EXECUTABLE = 0x0008;
123
124
125
126 /**
127 * The bitmask that should be used for indicating whether a file is
128 * readable by users other than the owner or group members.
129 */
130 public static final int OTHER_READABLE = 0x0004;
131
132
133
134 /**
135 * The bitmask that should be used for indicating whether a file is
136 * writable by users other than the owner or group members.
137 */
138 public static final int OTHER_WRITABLE = 0x0002;
139
140
141
142 /**
143 * The bitmask that should be used for indicating whether a file is
144 * executable by users other than the owner or group members.
145 */
146 public static final int OTHER_EXECUTABLE = 0x0001;
147
148
149
150 // Indicates whether to allow the use of exec for setting file
151 // permissions.
152 private static boolean allowExec;
153
154 // The method that may be used to specify whether a file is
155 // executable by its owner (and optionally others).
156 private static Method setExecutableMethod;
157
158 // The method that may be used to specify whether a file is readable
159 // by its owner (and optionally others).
160 private static Method setReadableMethod;
161
162 // The method that may be used to specify whether a file is wriable
163 // by its owner (and optionally others).
164 private static Method setWritableMethod;
165
166 // The encoded representation for this file permission.
167 private int encodedPermission;
168
169
170
171 static
172 {
173 // Iterate through the available methods and see if any of the
174 // Java 6 methods for dealing with permissions are available.
175 try
176 {
177 setExecutableMethod = null;
178 setReadableMethod = null;
179 setWritableMethod = null;
180
181 for (Method m : File.class.getMethods())
182 {
183 String name = m.getName();
184 Class[] argTypes = m.getParameterTypes();
185
186 if (name.equals("setExecutable") && (argTypes.length == 2))
187 {
188 setExecutableMethod = m;
189 }
190 else if (name.equals("setReadable") && (argTypes.length == 2))
191 {
192 setReadableMethod = m;
193 }
194 else if (name.equals("setWritable") && (argTypes.length == 2))
195 {
196 setWritableMethod = m;
197 }
198 }
199 }
200 catch (Exception e)
201 {
202 if (debugEnabled())
203 {
204 TRACER.debugCaught(DebugLogLevel.ERROR, e);
205 }
206 }
207
208
209 // Determine whether we should disable the ability to execute
210 // commands on the underlying system even if it could provide more
211 // control and capability.
212 allowExec = mayUseExec();
213 }
214
215
216
217 /**
218 * Creates a new file permission object with the provided encoded
219 * representation.
220 *
221 * @param encodedPermission The encoded representation for this
222 * file permission.
223 */
224 public FilePermission(int encodedPermission)
225 {
226 this.encodedPermission = encodedPermission;
227 }
228
229
230
231 /**
232 * Creates a new file permission with the specified rights for the
233 * file owner. Users other than the owner will not have any rights.
234 *
235 * @param ownerReadable Indicates whether the owner should have
236 * the read permission.
237 * @param ownerWritable Indicates whether the owner should have
238 * the write permission.
239 * @param ownerExecutable Indicates whether the owner should have
240 * the execute permission.
241 */
242 public FilePermission(boolean ownerReadable, boolean ownerWritable,
243 boolean ownerExecutable)
244 {
245 encodedPermission = 0x0000;
246
247 if (ownerReadable)
248 {
249 encodedPermission |= OWNER_READABLE;
250 }
251
252 if (ownerWritable)
253 {
254 encodedPermission |= OWNER_WRITABLE;
255 }
256
257 if (ownerExecutable)
258 {
259 encodedPermission |= OWNER_EXECUTABLE;
260 }
261 }
262
263
264
265 /**
266 * Creates a new file permission with the specified rights for the
267 * file owner, group members, and other users.
268 *
269 * @param ownerReadable Indicates whether the owner should have
270 * the read permission.
271 * @param ownerWritable Indicates whether the owner should have
272 * the write permission.
273 * @param ownerExecutable Indicates whether the owner should have
274 * the execute permission.
275 * @param groupReadable Indicates whether members of the file's
276 * group should have the read permission.
277 * @param groupWritable Indicates whether members of the file's
278 * group should have the write permission.
279 * @param groupExecutable Indicates whether members of the file's
280 * group should have the execute
281 * permission.
282 * @param otherReadable Indicates whether other users should
283 * have the read permission.
284 * @param otherWritable Indicates whether other users should
285 * have the write permission.
286 * @param otherExecutable Indicates whether other users should
287 * have the execute permission.
288 */
289 public FilePermission(boolean ownerReadable, boolean ownerWritable,
290 boolean ownerExecutable,
291 boolean groupReadable, boolean groupWritable,
292 boolean groupExecutable,
293 boolean otherReadable, boolean otherWritable,
294 boolean otherExecutable)
295 {
296 encodedPermission = 0x0000;
297
298 if (ownerReadable)
299 {
300 encodedPermission |= OWNER_READABLE;
301 }
302
303 if (ownerWritable)
304 {
305 encodedPermission |= OWNER_WRITABLE;
306 }
307
308 if (ownerExecutable)
309 {
310 encodedPermission |= OWNER_EXECUTABLE;
311 }
312
313 if (groupReadable)
314 {
315 encodedPermission |= GROUP_READABLE;
316 }
317
318 if (groupWritable)
319 {
320 encodedPermission |= GROUP_WRITABLE;
321 }
322
323 if (groupExecutable)
324 {
325 encodedPermission |= GROUP_EXECUTABLE;
326 }
327
328 if (otherReadable)
329 {
330 encodedPermission |= OTHER_READABLE;
331 }
332
333 if (otherWritable)
334 {
335 encodedPermission |= OTHER_WRITABLE;
336 }
337
338 if (otherExecutable)
339 {
340 encodedPermission |= OTHER_EXECUTABLE;
341 }
342 }
343
344
345
346 /**
347 * Indicates whether this file permission includes the owner read
348 * permission.
349 *
350 * @return <CODE>true</CODE> if this file permission includes the
351 * owner read permission, or <CODE>false</CODE> if not.
352 */
353 public boolean isOwnerReadable()
354 {
355 return ((encodedPermission & OWNER_READABLE) == OWNER_READABLE);
356 }
357
358
359
360 /**
361 * Indicates whether this file permission includes the owner write
362 * permission.
363 *
364 * @return <CODE>true</CODE> if this file permission includes the
365 * owner write permission, or <CODE>false</CODE> if not.
366 */
367 public boolean isOwnerWritable()
368 {
369 return ((encodedPermission & OWNER_WRITABLE) == OWNER_WRITABLE);
370 }
371
372
373
374 /**
375 * Indicates whether this file permission includes the owner execute
376 * permission.
377 *
378 * @return <CODE>true</CODE> if this file permission includes the
379 * owner execute permission, or <CODE>false</CODE> if not.
380 */
381 public boolean isOwnerExecutable()
382 {
383 return ((encodedPermission & OWNER_EXECUTABLE) ==
384 OWNER_EXECUTABLE);
385 }
386
387
388
389 /**
390 * Indicates whether this file permission includes the group read
391 * permission.
392 *
393 * @return <CODE>true</CODE> if this file permission includes the
394 * group read permission, or <CODE>false</CODE> if not.
395 */
396 public boolean isGroupReadable()
397 {
398 return ((encodedPermission & GROUP_READABLE) == GROUP_READABLE);
399 }
400
401
402
403 /**
404 * Indicates whether this file permission includes the group write
405 * permission.
406 *
407 * @return <CODE>true</CODE> if this file permission includes the
408 * group write permission, or <CODE>false</CODE> if not.
409 */
410 public boolean isGroupWritable()
411 {
412 return ((encodedPermission & GROUP_WRITABLE) == GROUP_WRITABLE);
413 }
414
415
416
417 /**
418 * Indicates whether this file permission includes the group execute
419 * permission.
420 *
421 * @return <CODE>true</CODE> if this file permission includes the
422 * group execute permission, or <CODE>false</CODE> if not.
423 */
424 public boolean isGroupExecutable()
425 {
426 return ((encodedPermission & GROUP_EXECUTABLE) ==
427 GROUP_EXECUTABLE);
428 }
429
430
431
432 /**
433 * Indicates whether this file permission includes the other read
434 * permission.
435 *
436 * @return <CODE>true</CODE> if this file permission includes the
437 * other read permission, or <CODE>false</CODE> if not.
438 */
439 public boolean isOtherReadable()
440 {
441 return ((encodedPermission & OTHER_READABLE) == OTHER_READABLE);
442 }
443
444
445
446 /**
447 * Indicates whether this file permission includes the other write
448 * permission.
449 *
450 * @return <CODE>true</CODE> if this file permission includes the
451 * other write permission, or <CODE>false</CODE> if not.
452 */
453 public boolean isOtherWritable()
454 {
455 return ((encodedPermission & OTHER_WRITABLE) == OTHER_WRITABLE);
456 }
457
458
459
460 /**
461 * Indicates whether this file permission includes the other execute
462 * permission.
463 *
464 * @return <CODE>true</CODE> if this file permission includes the
465 * other execute permission, or <CODE>false</CODE> if not.
466 */
467 public boolean isOtherExecutable()
468 {
469 return ((encodedPermission & OTHER_EXECUTABLE) ==
470 OTHER_EXECUTABLE);
471 }
472
473
474
475 /**
476 * Indicates whether the there is a mechanism available for setting
477 * permissions in the underlying filesystem on the current platform.
478 *
479 * @return <CODE>true</CODE> if there is a mechanism available for
480 * setting file permissions on the underlying system (e.g.,
481 * if the server is running in a Java 6 environment, or if
482 * this is a UNIX-based system and the use of exec is
483 * allowed), or <CODE>false</CODE> if no such mechanism is
484 * available.
485 */
486 public static boolean canSetPermissions()
487 {
488 if ((setReadableMethod != null) && (setWritableMethod != null) &&
489 (setExecutableMethod != null))
490 {
491 // It's a Java 6 environment, so we can always use that
492 // mechanism.
493 return true;
494 }
495
496 OperatingSystem os = DirectoryServer.getOperatingSystem();
497 if (allowExec && (os != null) && OperatingSystem.isUNIXBased(os))
498 {
499 // It's a UNIX-based system and we can exec the chmod utility.
500 return true;
501 }
502
503 // We have no way to set file permissions on this system.
504 return false;
505 }
506
507
508
509 /**
510 * Attempts to set the given permissions on the specified file. If
511 * the underlying platform does not allow the full level of
512 * granularity specified in the permissions, then an attempt will be
513 * made to set them as closely as possible to the provided
514 * permissions, erring on the side of security.
515 *
516 * @param f The file to which the permissions should be applied.
517 * @param p The permissions to apply to the file.
518 *
519 * @return <CODE>true</CODE> if the permissions (or the nearest
520 * equivalent) were successfully applied to the specified
521 * file, or <CODE>false</CODE> if was not possible to set
522 * the permissions on the current platform.
523 *
524 * @throws FileNotFoundException If the specified file does not
525 * exist.
526 *
527 * @throws DirectoryException If a problem occurs while trying to
528 * set the file permissions.
529 */
530 public static boolean setPermissions(File f, FilePermission p)
531 throws FileNotFoundException, DirectoryException
532 {
533 if (! f.exists())
534 {
535 Message message =
536 ERR_FILEPERM_SET_NO_SUCH_FILE.get(f.getAbsolutePath());
537 throw new FileNotFoundException(message.toString());
538 }
539
540
541 // If we're running Java 6, then we'll use the methods that Java
542 // provides. Even though it's potentially less fine-grained on a
543 // UNIX-based system, it is more efficient and doesn't require an
544 // external process.
545 if ((setReadableMethod != null) && (setWritableMethod != null) &&
546 (setExecutableMethod != null))
547 {
548 return setUsingJava(f, p);
549 }
550
551
552 // If it's a UNIX-based system, then try using the chmod command
553 // to set the permissions. Otherwise (or if that fails), then try
554 // to use the Java 6 API.
555 OperatingSystem os = DirectoryServer.getOperatingSystem();
556 if (allowExec && (os != null) && OperatingSystem.isUNIXBased(os))
557 {
558 return setUsingUNIX(f, p);
559 }
560
561 // FIXME -- Consider using cacls on Windows.
562
563
564 // We have no way to set file permissions on this system.
565 return false;
566 }
567
568
569
570 /**
571 * Attempts to set the specified permissions for the given file
572 * using the UNIX chmod command.
573 *
574 * @param f The file to which the permissions should be applied.
575 * @param p The permissions to apply to the file.
576 *
577 * @return <CODE>true</CODE> if the permissions were successfully
578 * updated, or <CODE>false</CODE> if not.
579 *
580 * @throws DirectoryException If an error occurs while trying to
581 * execute the chmod command.
582 */
583 private static boolean setUsingUNIX(File f, FilePermission p)
584 throws DirectoryException
585 {
586 String[] arguments =
587 {
588 toUNIXMode(p),
589 f.getAbsolutePath()
590 };
591
592 int exitCode;
593 try
594 {
595 exitCode = exec("chmod", arguments, null, null, null);
596 }
597 catch (Exception e)
598 {
599 if (debugEnabled())
600 {
601 TRACER.debugCaught(DebugLogLevel.ERROR, e);
602 }
603
604 Message message = ERR_FILEPERM_CANNOT_EXEC_CHMOD.get(
605 f.getAbsolutePath(), String.valueOf(e));
606 throw new DirectoryException(ResultCode.OTHER, message, e);
607 }
608
609 return (exitCode == 0);
610 }
611
612
613
614 /**
615 * Attempts to set the specified permissions for the given file
616 * using the Java 6 <CODE>FILE</CODE> API. Only the "owner" and
617 * "other" permissions will be preserved, since Java doesn't provide
618 * a way to set the group permissions directly.
619 *
620 * @param f The file to which the permissions should be applied.
621 * @param p The permissions to apply to the file.
622 *
623 * @return <CODE>true</CODE> if the permissions were successfully
624 * updated, or <CODE>false</CODE> if not.
625 *
626 * @throws DirectoryException If a problem occurs while attempting
627 * to update permissions.
628 */
629 private static boolean setUsingJava(File f, FilePermission p)
630 throws DirectoryException
631 {
632 // NOTE: Due to a very nasty behavior of the Java 6 API, if you
633 // want to want to grant a permission for the owner but not
634 // for anyone else, then you *must* remove it for everyone
635 // first, and then add it only for the owner. Otherwise,
636 // the other permissions will be left unchanged and if they
637 // had it before then they will still have it.
638
639 boolean anySuccessful = false;
640 boolean anyFailed = false;
641 boolean exceptionThrown = false;
642
643 // Take away read permission from everyone if necessary.
644 if (p.isOwnerReadable() && (! p.isOtherReadable()))
645 {
646 try
647 {
648 Boolean b =
649 (Boolean) setReadableMethod.invoke(f, false, false);
650 if (b.booleanValue())
651 {
652 anySuccessful = true;
653 }
654 else
655 {
656 if(!DirectoryServer.getOperatingSystem().equals(
657 OperatingSystem.WINDOWS))
658 {
659 // On Windows platforms, file readability permissions
660 // cannot be set to false. Do not consider this case
661 // a failure. http://java.sun.com/developer/
662 // technicalArticles/J2SE/Desktop/javase6/enhancements/
663 anyFailed = true;
664 }
665 }
666 }
667 catch (Exception e)
668 {
669 if (debugEnabled())
670 {
671 TRACER.debugCaught(DebugLogLevel.ERROR, e);
672 }
673 exceptionThrown = true;
674 }
675 }
676
677 // Grant the appropriate read permission.
678 try
679 {
680 boolean ownerOnly =
681 (p.isOwnerReadable() != p.isOtherReadable());
682
683 Boolean b = (Boolean)
684 setReadableMethod.invoke(f, p.isOwnerReadable(),
685 ownerOnly);
686 if (b.booleanValue())
687 {
688 anySuccessful = true;
689 }
690 else
691 {
692 if(!DirectoryServer.getOperatingSystem().equals(
693 OperatingSystem.WINDOWS) || p.isOwnerReadable())
694 {
695 // On Windows platforms, file readabilitys permissions
696 // cannot be set to false. Do not consider this case
697 // a failure. http://java.sun.com/developer/
698 // technicalArticles/J2SE/Desktop/javase6/enhancements/
699 anyFailed = true;
700 }
701 }
702 }
703 catch (Exception e)
704 {
705 if (debugEnabled())
706 {
707 TRACER.debugCaught(DebugLogLevel.ERROR, e);
708 }
709 exceptionThrown = true;
710 }
711
712
713 // Take away write permission from everyone if necessary.
714 if (p.isOwnerWritable() && (! p.isOtherWritable()))
715 {
716 try
717 {
718 Boolean b =
719 (Boolean) setWritableMethod.invoke(f, false, false);
720 if (b.booleanValue())
721 {
722 anySuccessful = true;
723 }
724 else
725 {
726 anyFailed = true;
727 }
728 }
729 catch (Exception e)
730 {
731 if (debugEnabled())
732 {
733 TRACER.debugCaught(DebugLogLevel.ERROR, e);
734 }
735 exceptionThrown = true;
736 }
737 }
738
739 // Grant the appropriate write permission.
740 try
741 {
742 boolean ownerOnly =
743 (p.isOwnerWritable() != p.isOtherWritable());
744
745 Boolean b = (Boolean)
746 setWritableMethod.invoke(f, p.isOwnerWritable(),
747 ownerOnly);
748 if (b.booleanValue())
749 {
750 anySuccessful = true;
751 }
752 else
753 {
754 anyFailed = true;
755 }
756 }
757 catch (Exception e)
758 {
759 if (debugEnabled())
760 {
761 TRACER.debugCaught(DebugLogLevel.ERROR, e);
762 }
763 exceptionThrown = true;
764 }
765
766
767 // Take away execute permission from everyone if necessary.
768 if (p.isOwnerExecutable() && (! p.isOtherExecutable()))
769 {
770 try
771 {
772 Boolean b =
773 (Boolean) setExecutableMethod.invoke(f, false, false);
774 if (b.booleanValue())
775 {
776 anySuccessful = true;
777 }
778 else
779 {
780 if(!DirectoryServer.getOperatingSystem().equals(
781 OperatingSystem.WINDOWS))
782 {
783 // On Windows platforms, file execute permissions
784 // cannot be set to false. Do not consider this case
785 // a failure. http://java.sun.com/developer/
786 // technicalArticles/J2SE/Desktop/javase6/enhancements/
787 anyFailed = true;
788 }
789 }
790 }
791 catch (Exception e)
792 {
793 if (debugEnabled())
794 {
795 TRACER.debugCaught(DebugLogLevel.ERROR, e);
796 }
797 exceptionThrown = true;
798 }
799 }
800
801 // Grant the appropriate execute permission.
802 try
803 {
804 boolean ownerOnly =
805 (p.isOwnerExecutable() != p.isOtherExecutable());
806
807 Boolean b = (Boolean)
808 setExecutableMethod.invoke(f, p.isOwnerExecutable(),
809 ownerOnly);
810 if (b.booleanValue())
811 {
812 anySuccessful = true;
813 }
814 else
815 {
816 if(!DirectoryServer.getOperatingSystem().equals(
817 OperatingSystem.WINDOWS) || p.isOwnerExecutable())
818 {
819 // On Windows platforms, file execute permissions
820 // cannot be set to false. Do not consider this case
821 // a failure. http://java.sun.com/developer/
822 // technicalArticles/J2SE/Desktop/javase6/enhancements/
823 anyFailed = true;
824 }
825 }
826 }
827 catch (Exception e)
828 {
829 if (debugEnabled())
830 {
831 TRACER.debugCaught(DebugLogLevel.ERROR, e);
832 }
833 exceptionThrown = true;
834 }
835
836
837 if (exceptionThrown)
838 {
839 // If an exception was thrown, we can't be sure whether or not
840 // any permissions were updated.
841 Message message =
842 ERR_FILEPERM_SET_JAVA_EXCEPTION.get(f.getAbsolutePath());
843 throw new DirectoryException(ResultCode.OTHER, message);
844 }
845 else if (anyFailed)
846 {
847 if (anySuccessful)
848 {
849 // Some of the file permissions may have been altered.
850 Message message = ERR_FILEPERM_SET_JAVA_FAILED_ALTERED.get(
851 f.getAbsolutePath());
852 throw new DirectoryException(ResultCode.OTHER, message);
853 }
854 else
855 {
856 // The file permissions should have been left intact.
857 Message message = ERR_FILEPERM_SET_JAVA_FAILED_UNALTERED.get(
858 f.getAbsolutePath());
859 throw new DirectoryException(ResultCode.OTHER, message);
860 }
861 }
862 else
863 {
864 return anySuccessful;
865 }
866 }
867
868
869
870 /**
871 * Retrieves a three-character string that is the UNIX mode for the
872 * provided file permission. Each character of the string will be a
873 * numeric digit from zero through seven.
874 *
875 * @param p The permission to retrieve as a UNIX mode string.
876 *
877 * @return The UNIX mode string for the provided permission.
878 */
879 public static String toUNIXMode(FilePermission p)
880 {
881 StringBuilder buffer = new StringBuilder(3);
882 toUNIXMode(buffer, p);
883 return buffer.toString();
884 }
885
886
887
888 /**
889 * Appends a three-character string that is the UNIX mode for the
890 * provided file permission to the given buffer. Each character of
891 * the string will be anumeric digit from zero through seven.
892 *
893 * @param buffer The buffer to which the mode string should be
894 * appended.
895 * @param p The permission to retrieve as a UNIX mode string.
896 */
897 public static void toUNIXMode(StringBuilder buffer,
898 FilePermission p)
899 {
900 byte modeByte = 0x00;
901 if (p.isOwnerReadable())
902 {
903 modeByte |= 0x04;
904 }
905 if (p.isOwnerWritable())
906 {
907 modeByte |= 0x02;
908 }
909 if (p.isOwnerExecutable())
910 {
911 modeByte |= 0x01;
912 }
913 buffer.append(String.valueOf(modeByte));
914
915 modeByte = 0x00;
916 if (p.isGroupReadable())
917 {
918 modeByte |= 0x04;
919 }
920 if (p.isGroupWritable())
921 {
922 modeByte |= 0x02;
923 }
924 if (p.isGroupExecutable())
925 {
926 modeByte |= 0x01;
927 }
928 buffer.append(String.valueOf(modeByte));
929
930 modeByte = 0x00;
931 if (p.isOtherReadable())
932 {
933 modeByte |= 0x04;
934 }
935 if (p.isOtherWritable())
936 {
937 modeByte |= 0x02;
938 }
939 if (p.isOtherExecutable())
940 {
941 modeByte |= 0x01;
942 }
943 buffer.append(String.valueOf(modeByte));
944 }
945
946
947
948 /**
949 * Decodes the provided string as a UNIX mode and retrieves the
950 * corresponding file permission. The mode string must contain
951 * three digits between zero and seven.
952 *
953 * @param modeString The string representation of the UNIX mode to
954 * decode.
955 *
956 * @return The file permission that is equivalent to the given UNIX
957 * mode.
958 *
959 * @throws DirectoryException If the provided string is not a
960 * valid three-digit UNIX mode.
961 */
962 public static FilePermission decodeUNIXMode(String modeString)
963 throws DirectoryException
964 {
965 if ((modeString == null) || (modeString.length() != 3))
966 {
967 Message message = ERR_FILEPERM_INVALID_UNIX_MODE_STRING.get(
968 String.valueOf(modeString));
969 throw new DirectoryException(ResultCode.OTHER, message);
970 }
971
972 int encodedPermission = 0x0000;
973 switch (modeString.charAt(0))
974 {
975 case '0':
976 break;
977 case '1':
978 encodedPermission |= OWNER_EXECUTABLE;
979 break;
980 case '2':
981 encodedPermission |= OWNER_WRITABLE;
982 break;
983 case '3':
984 encodedPermission |= OWNER_WRITABLE | OWNER_EXECUTABLE;
985 break;
986 case '4':
987 encodedPermission |= OWNER_READABLE;
988 break;
989 case '5':
990 encodedPermission |= OWNER_READABLE | OWNER_EXECUTABLE;
991 break;
992 case '6':
993 encodedPermission |= OWNER_READABLE | OWNER_WRITABLE;
994 break;
995 case '7':
996 encodedPermission |= OWNER_READABLE | OWNER_WRITABLE |
997 OWNER_EXECUTABLE;
998 break;
999 default:
1000 Message message = ERR_FILEPERM_INVALID_UNIX_MODE_STRING.get(
1001 String.valueOf(modeString));
1002 throw new DirectoryException(ResultCode.OTHER, message);
1003 }
1004
1005 switch (modeString.charAt(1))
1006 {
1007 case '0':
1008 break;
1009 case '1':
1010 encodedPermission |= GROUP_EXECUTABLE;
1011 break;
1012 case '2':
1013 encodedPermission |= GROUP_WRITABLE;
1014 break;
1015 case '3':
1016 encodedPermission |= GROUP_WRITABLE | GROUP_EXECUTABLE;
1017 break;
1018 case '4':
1019 encodedPermission |= GROUP_READABLE;
1020 break;
1021 case '5':
1022 encodedPermission |= GROUP_READABLE | GROUP_EXECUTABLE;
1023 break;
1024 case '6':
1025 encodedPermission |= GROUP_READABLE | GROUP_WRITABLE;
1026 break;
1027 case '7':
1028 encodedPermission |= GROUP_READABLE | GROUP_WRITABLE |
1029 GROUP_EXECUTABLE;
1030 break;
1031 default:
1032 Message message = ERR_FILEPERM_INVALID_UNIX_MODE_STRING.get(
1033 String.valueOf(modeString));
1034 throw new DirectoryException(ResultCode.OTHER, message);
1035 }
1036
1037 switch (modeString.charAt(2))
1038 {
1039 case '0':
1040 break;
1041 case '1':
1042 encodedPermission |= OTHER_EXECUTABLE;
1043 break;
1044 case '2':
1045 encodedPermission |= OTHER_WRITABLE;
1046 break;
1047 case '3':
1048 encodedPermission |= OTHER_WRITABLE | OTHER_EXECUTABLE;
1049 break;
1050 case '4':
1051 encodedPermission |= OTHER_READABLE;
1052 break;
1053 case '5':
1054 encodedPermission |= OTHER_READABLE | OTHER_EXECUTABLE;
1055 break;
1056 case '6':
1057 encodedPermission |= OTHER_READABLE | OTHER_WRITABLE;
1058 break;
1059 case '7':
1060 encodedPermission |= OTHER_READABLE | OTHER_WRITABLE |
1061 OTHER_EXECUTABLE;
1062 break;
1063 default:
1064 Message message = ERR_FILEPERM_INVALID_UNIX_MODE_STRING.get(
1065 String.valueOf(modeString));
1066 throw new DirectoryException(ResultCode.OTHER, message);
1067 }
1068
1069 return new FilePermission(encodedPermission);
1070 }
1071
1072
1073
1074 /**
1075 * Retrieves a string representation of this file permission.
1076 *
1077 * @return A string representation of this file permission.
1078 */
1079 public String toString()
1080 {
1081 StringBuilder buffer = new StringBuilder();
1082 toString(buffer);
1083 return buffer.toString();
1084 }
1085
1086
1087
1088 /**
1089 * Appends a string representation of this file permission to the
1090 * given buffer.
1091 *
1092 * @param buffer The buffer to which the data should be appended.
1093 */
1094 public void toString(StringBuilder buffer)
1095 {
1096 buffer.append("Owner=");
1097
1098 if (isOwnerReadable())
1099 {
1100 buffer.append("r");
1101 }
1102 if (isOwnerWritable())
1103 {
1104 buffer.append("w");
1105 }
1106 if (isOwnerExecutable())
1107 {
1108 buffer.append("x");
1109 }
1110 buffer.append(", Group=");
1111
1112 if (isGroupReadable())
1113 {
1114 buffer.append("r");
1115 }
1116 if (isGroupWritable())
1117 {
1118 buffer.append("w");
1119 }
1120 if (isGroupExecutable())
1121 {
1122 buffer.append("x");
1123 }
1124 buffer.append(", Other=");
1125
1126 if (isOtherReadable())
1127 {
1128 buffer.append("r");
1129 }
1130 if (isOtherWritable())
1131 {
1132 buffer.append("w");
1133 }
1134 if (isOtherExecutable())
1135 {
1136 buffer.append("x");
1137 }
1138 }
1139 }
1140