Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/sample/nio/file/AclEdit.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 java.io.IOException;43import java.util.*;44import java.util.regex.Pattern;4546/**47* Sample utility for editing a file's ACL.48*/4950public class AclEdit {5152// parse string as list of ACE permissions separated by /53static Set<AclEntryPermission> parsePermissions(String permsString) {54Set<AclEntryPermission> perms = new HashSet<AclEntryPermission>();55String[] result = permsString.split("/");56for (String s : result) {57if (s.equals(""))58continue;59try {60perms.add(AclEntryPermission.valueOf(s.toUpperCase()));61} catch (IllegalArgumentException x) {62System.err.format("Invalid permission '%s'\n", s);63System.exit(-1);64}65}66return perms;67}6869// parse string as list of ACE flags separated by /70static Set<AclEntryFlag> parseFlags(String flagsString) {71Set<AclEntryFlag> flags = new HashSet<AclEntryFlag>();72String[] result = flagsString.split("/");73for (String s : result) {74if (s.equals(""))75continue;76try {77flags.add(AclEntryFlag.valueOf(s.toUpperCase()));78} catch (IllegalArgumentException x) {79System.err.format("Invalid flag '%s'\n", s);80System.exit(-1);81}82}83return flags;84}8586// parse ACE type87static AclEntryType parseType(String typeString) {88// FIXME: support audit and alarm types in the future89if (typeString.equalsIgnoreCase("allow"))90return AclEntryType.ALLOW;91if (typeString.equalsIgnoreCase("deny"))92return AclEntryType.DENY;93System.err.format("Invalid type '%s'\n", typeString);94System.exit(-1);95return null; // keep compiler happy96}9798/**99* Parse string of the form:100* [user|group:]<username|groupname>:<perms>[:flags]:<allow|deny>101*/102static AclEntry parseAceString(String s,103UserPrincipalLookupService lookupService)104{105String[] result = s.split(":");106107// must have at least 3 components (username:perms:type)108if (result.length < 3)109usage();110111int index = 0;112int remaining = result.length;113114// optional first component can indicate user or group type115boolean isGroup = false;116if (result[index].equalsIgnoreCase("user") ||117result[index].equalsIgnoreCase("group"))118{119if (--remaining < 3)120usage();121isGroup = result[index++].equalsIgnoreCase("group");122}123124// user and permissions required125String userString = result[index++]; remaining--;126String permsString = result[index++]; remaining--;127128// flags are optional129String flagsString = "";130String typeString = null;131if (remaining == 1) {132typeString = result[index++];133} else {134if (remaining == 2) {135flagsString = result[index++];136typeString = result[index++];137} else {138usage();139}140}141142// lookup UserPrincipal143UserPrincipal user = null;144try {145user = (isGroup) ?146lookupService.lookupPrincipalByGroupName(userString) :147lookupService.lookupPrincipalByName(userString);148} catch (UserPrincipalNotFoundException x) {149System.err.format("Invalid %s '%s'\n",150((isGroup) ? "group" : "user"),151userString);152System.exit(-1);153} catch (IOException x) {154System.err.format("Lookup of '%s' failed: %s\n", userString, x);155System.exit(-1);156}157158// map string representation of permissions, flags, and type159Set<AclEntryPermission> perms = parsePermissions(permsString);160Set<AclEntryFlag> flags = parseFlags(flagsString);161AclEntryType type = parseType(typeString);162163// build the ACL entry164return AclEntry.newBuilder()165.setType(type)166.setPrincipal(user)167.setPermissions(perms).setFlags(flags).build();168}169170static void usage() {171System.err.println("usage: java AclEdit [ACL-operation] file");172System.err.println("");173System.err.println("Example 1: Prepends access control entry to the begining of the myfile's ACL");174System.err.println(" java AclEdit A+alice:read_data/read_attributes:allow myfile");175System.err.println("");176System.err.println("Example 2: Remove the entry at index 6 of myfile's ACL");177System.err.println(" java AclEdit A6- myfile");178System.err.println("");179System.err.println("Example 3: Replace the entry at index 2 of myfile's ACL");180System.err.println(" java AclEdit A2=bob:write_data/append_data:deny myfile");181System.exit(-1);182}183184static enum Action {185PRINT,186ADD,187REMOVE,188REPLACE;189}190191/**192* Main class: parses arguments and prints or edits ACL193*/194public static void main(String[] args) throws IOException {195Action action = null;196int index = -1;197String entryString = null;198199// parse arguments200if (args.length < 1 || args[0].equals("-help") || args[0].equals("-?"))201usage();202203if (args.length == 1) {204action = Action.PRINT;205} else {206String s = args[0];207208// A[index]+entry209if (Pattern.matches("^A[0-9]*\\+.*", s)) {210String[] result = s.split("\\+", 2);211if (result.length == 2) {212if (result[0].length() < 2) {213index = 0;214} else {215index = Integer.parseInt(result[0].substring(1));216}217entryString = result[1];218action = Action.ADD;219}220}221222// Aindex-223if (Pattern.matches("^A[0-9]+\\-", s)) {224String[] result = s.split("\\-", 2);225if (result.length == 2) {226index = Integer.parseInt(result[0].substring(1));227entryString = result[1];228action = Action.REMOVE;229}230}231232// Aindex=entry233if (Pattern.matches("^A[0-9]+=.*", s)) {234String[] result = s.split("=", 2);235if (result.length == 2) {236index = Integer.parseInt(result[0].substring(1));237entryString = result[1];238action = Action.REPLACE;239}240}241}242if (action == null)243usage();244245int fileArg = (action == Action.PRINT) ? 0 : 1;246Path file = Paths.get(args[fileArg]);247248// read file's ACL249AclFileAttributeView view =250Files.getFileAttributeView(file, AclFileAttributeView.class);251if (view == null) {252System.err.println("ACLs not supported on this platform");253System.exit(-1);254}255List<AclEntry> acl = view.getAcl();256257switch (action) {258// print ACL259case PRINT : {260for (int i=0; i<acl.size(); i++) {261System.out.format("%5d: %s\n", i, acl.get(i));262}263break;264}265266// add ACE to existing ACL267case ADD: {268AclEntry entry = parseAceString(entryString, file269.getFileSystem().getUserPrincipalLookupService());270if (index >= acl.size()) {271acl.add(entry);272} else {273acl.add(index, entry);274}275view.setAcl(acl);276break;277}278279// remove ACE280case REMOVE: {281if (index >= acl.size()) {282System.err.format("Index '%d' is invalid", index);283System.exit(-1);284}285acl.remove(index);286view.setAcl(acl);287break;288}289290// replace ACE291case REPLACE: {292if (index >= acl.size()) {293System.err.format("Index '%d' is invalid", index);294System.exit(-1);295}296AclEntry entry = parseAceString(entryString, file297.getFileSystem().getUserPrincipalLookupService());298acl.set(index, entry);299view.setAcl(acl);300break;301}302}303}304}305306307