Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/sample/nio/file/Chmod.java
38829 views
/*1* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.2*3* Redistribution and use in source and binary forms, with or without4* modification, are permitted provided that the following conditions5* are met:6*7* - Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9*10* - Redistributions in binary form must reproduce the above copyright11* notice, this list of conditions and the following disclaimer in the12* documentation and/or other materials provided with the distribution.13*14* - Neither the name of Oracle nor the names of its15* contributors may be used to endorse or promote products derived16* from this software without specific prior written permission.17*18* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS19* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,20* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR21* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR22* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,23* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,24* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR25* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF26* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING27* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS28* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.29*/3031/*32* This source code is provided to illustrate the usage of a given feature33* or technique and has been deliberately simplified. Additional steps34* required for a production-quality application, such as security checks,35* input validation and proper error handling, might not be present in36* this sample code.37*/383940import java.nio.file.*;41import java.nio.file.attribute.*;42import static java.nio.file.attribute.PosixFilePermission.*;43import static java.nio.file.FileVisitResult.*;44import java.io.IOException;45import java.util.*;4647/**48* Sample code that changes the permissions of files in a similar manner to the49* chmod(1) program.50*/5152public class Chmod {5354/**55* Compiles a list of one or more <em>symbolic mode expressions</em> that56* may be used to change a set of file permissions. This method is57* intended for use where file permissions are required to be changed in58* a manner similar to the UNIX <i>chmod</i> program.59*60* <p> The {@code exprs} parameter is a comma separated list of expressions61* where each takes the form:62* <blockquote>63* <i>who operator</i> [<i>permissions</i>]64* </blockquote>65* where <i>who</i> is one or more of the characters {@code 'u'}, {@code 'g'},66* {@code 'o'}, or {@code 'a'} meaning the owner (user), group, others, or67* all (owner, group, and others) respectively.68*69* <p> <i>operator</i> is the character {@code '+'}, {@code '-'}, or {@code70* '='} signifying how permissions are to be changed. {@code '+'} means the71* permissions are added, {@code '-'} means the permissions are removed, and72* {@code '='} means the permissions are assigned absolutely.73*74* <p> <i>permissions</i> is a sequence of zero or more of the following:75* {@code 'r'} for read permission, {@code 'w'} for write permission, and76* {@code 'x'} for execute permission. If <i>permissions</i> is omitted77* when assigned absolutely, then the permissions are cleared for78* the owner, group, or others as identified by <i>who</i>. When omitted79* when adding or removing then the expression is ignored.80*81* <p> The following examples demonstrate possible values for the {@code82* exprs} parameter:83*84* <table border="0">85* <tr>86* <td> {@code u=rw} </td>87* <td> Sets the owner permissions to be read and write. </td>88* </tr>89* <tr>90* <td> {@code ug+w} </td>91* <td> Sets the owner write and group write permissions. </td>92* </tr>93* <tr>94* <td> {@code u+w,o-rwx} </td>95* <td> Sets the owner write, and removes the others read, others write96* and others execute permissions. </td>97* </tr>98* <tr>99* <td> {@code o=} </td>100* <td> Sets the others permission to none (others read, others write and101* others execute permissions are removed if set) </td>102* </tr>103* </table>104*105* @param exprs106* List of one or more <em>symbolic mode expressions</em>107*108* @return A {@code Changer} that may be used to changer a set of109* file permissions110*111* @throws IllegalArgumentException112* If the value of the {@code exprs} parameter is invalid113*/114public static Changer compile(String exprs) {115// minimum is who and operator (u= for example)116if (exprs.length() < 2)117throw new IllegalArgumentException("Invalid mode");118119// permissions that the changer will add or remove120final Set<PosixFilePermission> toAdd = new HashSet<PosixFilePermission>();121final Set<PosixFilePermission> toRemove = new HashSet<PosixFilePermission>();122123// iterate over each of expression modes124for (String expr: exprs.split(",")) {125// minimum of who and operator126if (expr.length() < 2)127throw new IllegalArgumentException("Invalid mode");128129int pos = 0;130131// who132boolean u = false;133boolean g = false;134boolean o = false;135boolean done = false;136for (;;) {137switch (expr.charAt(pos)) {138case 'u' : u = true; break;139case 'g' : g = true; break;140case 'o' : o = true; break;141case 'a' : u = true; g = true; o = true; break;142default : done = true;143}144if (done)145break;146pos++;147}148if (!u && !g && !o)149throw new IllegalArgumentException("Invalid mode");150151// get operator and permissions152char op = expr.charAt(pos++);153String mask = (expr.length() == pos) ? "" : expr.substring(pos);154155// operator156boolean add = (op == '+');157boolean remove = (op == '-');158boolean assign = (op == '=');159if (!add && !remove && !assign)160throw new IllegalArgumentException("Invalid mode");161162// who= means remove all163if (assign && mask.length() == 0) {164assign = false;165remove = true;166mask = "rwx";167}168169// permissions170boolean r = false;171boolean w = false;172boolean x = false;173for (int i=0; i<mask.length(); i++) {174switch (mask.charAt(i)) {175case 'r' : r = true; break;176case 'w' : w = true; break;177case 'x' : x = true; break;178default:179throw new IllegalArgumentException("Invalid mode");180}181}182183// update permissions set184if (add) {185if (u) {186if (r) toAdd.add(OWNER_READ);187if (w) toAdd.add(OWNER_WRITE);188if (x) toAdd.add(OWNER_EXECUTE);189}190if (g) {191if (r) toAdd.add(GROUP_READ);192if (w) toAdd.add(GROUP_WRITE);193if (x) toAdd.add(GROUP_EXECUTE);194}195if (o) {196if (r) toAdd.add(OTHERS_READ);197if (w) toAdd.add(OTHERS_WRITE);198if (x) toAdd.add(OTHERS_EXECUTE);199}200}201if (remove) {202if (u) {203if (r) toRemove.add(OWNER_READ);204if (w) toRemove.add(OWNER_WRITE);205if (x) toRemove.add(OWNER_EXECUTE);206}207if (g) {208if (r) toRemove.add(GROUP_READ);209if (w) toRemove.add(GROUP_WRITE);210if (x) toRemove.add(GROUP_EXECUTE);211}212if (o) {213if (r) toRemove.add(OTHERS_READ);214if (w) toRemove.add(OTHERS_WRITE);215if (x) toRemove.add(OTHERS_EXECUTE);216}217}218if (assign) {219if (u) {220if (r) toAdd.add(OWNER_READ);221else toRemove.add(OWNER_READ);222if (w) toAdd.add(OWNER_WRITE);223else toRemove.add(OWNER_WRITE);224if (x) toAdd.add(OWNER_EXECUTE);225else toRemove.add(OWNER_EXECUTE);226}227if (g) {228if (r) toAdd.add(GROUP_READ);229else toRemove.add(GROUP_READ);230if (w) toAdd.add(GROUP_WRITE);231else toRemove.add(GROUP_WRITE);232if (x) toAdd.add(GROUP_EXECUTE);233else toRemove.add(GROUP_EXECUTE);234}235if (o) {236if (r) toAdd.add(OTHERS_READ);237else toRemove.add(OTHERS_READ);238if (w) toAdd.add(OTHERS_WRITE);239else toRemove.add(OTHERS_WRITE);240if (x) toAdd.add(OTHERS_EXECUTE);241else toRemove.add(OTHERS_EXECUTE);242}243}244}245246// return changer247return new Changer() {248@Override249public Set<PosixFilePermission> change(Set<PosixFilePermission> perms) {250perms.addAll(toAdd);251perms.removeAll(toRemove);252return perms;253}254};255}256257/**258* A task that <i>changes</i> a set of {@link PosixFilePermission} elements.259*/260public interface Changer {261/**262* Applies the changes to the given set of permissions.263*264* @param perms265* The set of permissions to change266*267* @return The {@code perms} parameter268*/269Set<PosixFilePermission> change(Set<PosixFilePermission> perms);270}271272/**273* Changes the permissions of the file using the given Changer.274*/275static void chmod(Path file, Changer changer) {276try {277Set<PosixFilePermission> perms = Files.getPosixFilePermissions(file);278Files.setPosixFilePermissions(file, changer.change(perms));279} catch (IOException x) {280System.err.println(x);281}282}283284/**285* Changes the permission of each file and directory visited286*/287static class TreeVisitor implements FileVisitor<Path> {288private final Changer changer;289290TreeVisitor(Changer changer) {291this.changer = changer;292}293294@Override295public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {296chmod(dir, changer);297return CONTINUE;298}299300@Override301public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {302chmod(file, changer);303return CONTINUE;304}305306@Override307public FileVisitResult postVisitDirectory(Path dir, IOException exc) {308if (exc != null)309System.err.println("WARNING: " + exc);310return CONTINUE;311}312313@Override314public FileVisitResult visitFileFailed(Path file, IOException exc) {315System.err.println("WARNING: " + exc);316return CONTINUE;317}318}319320static void usage() {321System.err.println("java Chmod [-R] symbolic-mode-list file...");322System.exit(-1);323}324325public static void main(String[] args) throws IOException {326if (args.length < 2)327usage();328int argi = 0;329int maxDepth = 0;330if (args[argi].equals("-R")) {331if (args.length < 3)332usage();333argi++;334maxDepth = Integer.MAX_VALUE;335}336337// compile the symbolic mode expressions338Changer changer = compile(args[argi++]);339TreeVisitor visitor = new TreeVisitor(changer);340341Set<FileVisitOption> opts = Collections.emptySet();342while (argi < args.length) {343Path file = Paths.get(args[argi]);344Files.walkFileTree(file, opts, maxDepth, visitor);345argi++;346}347}348}349350351