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