You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by cn...@apache.org on 2013/12/27 21:41:17 UTC
svn commit: r1553735 - in
/hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src:
main/java/org/apache/hadoop/fs/permission/
main/java/org/apache/hadoop/fs/shell/ test/java/org/apache/hadoop/fs/shell/
Author: cnauroth
Date: Fri Dec 27 20:41:16 2013
New Revision: 1553735
URL: http://svn.apache.org/r1553735
Log:
HADOOP-10187. add getfacl and setfacl with minimal support for getting and setting ACLs. Contributed by Vinay.
Added:
hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/AclCommands.java
hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/TestAclCommands.java
Modified:
hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/FsAction.java
hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/FsCommand.java
Modified: hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/FsAction.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/FsAction.java?rev=1553735&r1=1553734&r2=1553735&view=diff
==============================================================================
--- hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/FsAction.java (original)
+++ hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/FsAction.java Fri Dec 27 20:41:16 2013
@@ -69,4 +69,21 @@ public enum FsAction {
public FsAction not() {
return vals[7 - ordinal()];
}
+
+ /**
+ * Get the FsAction enum for String representation of permissions
+ *
+ * @param permission
+ * 3-character string representation of permission. ex: rwx
+ * @return Returns FsAction enum if the corresponding FsAction exists for permission.
+ * Otherwise returns null
+ */
+ public static FsAction getFsAction(String permission) {
+ for (FsAction fsAction : vals) {
+ if (fsAction.SYMBOL.equals(permission)) {
+ return fsAction;
+ }
+ }
+ return null;
+ }
}
Added: hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/AclCommands.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/AclCommands.java?rev=1553735&view=auto
==============================================================================
--- hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/AclCommands.java (added)
+++ hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/AclCommands.java Fri Dec 27 20:41:16 2013
@@ -0,0 +1,232 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.fs.shell;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.hadoop.HadoopIllegalArgumentException;
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.fs.permission.AclEntry;
+import org.apache.hadoop.fs.permission.AclEntryScope;
+import org.apache.hadoop.fs.permission.AclEntryType;
+import org.apache.hadoop.fs.permission.AclStatus;
+import org.apache.hadoop.fs.permission.FsAction;
+import org.apache.hadoop.util.StringUtils;
+
+/**
+ * Acl related operations
+ */
+@InterfaceAudience.Private
+@InterfaceStability.Evolving
+class AclCommands extends FsCommand {
+ private static String GET_FACL = "getfacl";
+ private static String SET_FACL = "setfacl";
+
+ public static void registerCommands(CommandFactory factory) {
+ factory.addClass(GetfaclCommand.class, "-" + GET_FACL);
+ factory.addClass(SetfaclCommand.class, "-" + SET_FACL);
+ }
+
+ /**
+ * Implementing the '-getfacl' command for the the FsShell.
+ */
+ public static class GetfaclCommand extends FsCommand {
+ public static String NAME = GET_FACL;
+ public static String USAGE = "[-R] <path>";
+ public static String DESCRIPTION = "Displays the Access Control Lists"
+ + " (ACLs) of files and directories. If a directory has a default ACL,"
+ + " then getfacl also displays the default ACL.\n"
+ + "-R: List the ACLs of all files and directories recursively.\n"
+ + "<path>: File or directory to list.\n";
+
+ @Override
+ protected void processOptions(LinkedList<String> args) throws IOException {
+ CommandFormat cf = new CommandFormat(0, Integer.MAX_VALUE, "R");
+ cf.parse(args);
+ setRecursive(cf.getOpt("R"));
+ if (args.isEmpty()) {
+ throw new HadoopIllegalArgumentException("<path> is missing");
+ }
+ if (args.size() > 1) {
+ throw new HadoopIllegalArgumentException("Too many arguments");
+ }
+ }
+
+ @Override
+ protected void processPath(PathData item) throws IOException {
+ AclStatus aclStatus = item.fs.getAclStatus(item.path);
+ out.println("# file: " + item.path);
+ out.println("# owner: " + aclStatus.getOwner());
+ out.println("# group: " + aclStatus.getGroup());
+ List<AclEntry> entries = aclStatus.getEntries();
+ if (aclStatus.isStickyBit()) {
+ String stickyFlag = "T";
+ for (AclEntry aclEntry : entries) {
+ if (aclEntry.getType() == AclEntryType.OTHER
+ && aclEntry.getScope() == AclEntryScope.ACCESS
+ && aclEntry.getPermission().implies(FsAction.EXECUTE)) {
+ stickyFlag = "t";
+ break;
+ }
+ }
+ out.println("# flags: --" + stickyFlag);
+ }
+ for (AclEntry entry : entries) {
+ out.println(entry);
+ }
+ }
+ }
+
+ /**
+ * Implementing the '-setfacl' command for the the FsShell.
+ */
+ public static class SetfaclCommand extends FsCommand {
+ public static String NAME = SET_FACL;
+ public static String USAGE = "[-R] [{-b|-k} {-m|-x <acl_spec>} <path>]"
+ + "|[--set <acl_spec> <path>]";
+ public static String DESCRIPTION = "Sets Access Control Lists (ACLs)"
+ + " of files and directories.\n"
+ + "Options:\n"
+ + "-b :Remove all but the base ACL entries. The entries for user,"
+ + " group and others are retained for compatibility with permission "
+ + "bits.\n"
+ + "-k :Remove the default ACL.\n"
+ + "-R :Apply operations to all files and directories recursively.\n"
+ + "-m :Modify ACL. New entries are added to the ACL, and existing"
+ + " entries are retained.\n"
+ + "-x :Remove specified ACL entries. Other ACL entries are retained.\n"
+ + "--set :Fully replace the ACL, discarding all existing entries."
+ + " The <acl_spec> must include entries for user, group, and others"
+ + " for compatibility with permission bits.\n"
+ + "<acl_spec>: Comma separated list of ACL entries.\n"
+ + "<path>: File or directory to modify.\n";
+
+ private static final String DEFAULT = "default";
+
+ Path path = null;
+ CommandFormat cf = new CommandFormat(0, Integer.MAX_VALUE, "b", "k", "R",
+ "m", "x", "-set");
+ List<AclEntry> aclEntries = null;
+
+ @Override
+ protected void processOptions(LinkedList<String> args) throws IOException {
+ cf.parse(args);
+ setRecursive(cf.getOpt("R"));
+ // Mix of remove and modify acl flags are not allowed
+ boolean bothRemoveOptions = cf.getOpt("b") && cf.getOpt("k");
+ boolean bothModifyOptions = cf.getOpt("m") && cf.getOpt("x");
+ boolean oneRemoveOption = cf.getOpt("b") || cf.getOpt("k");
+ boolean oneModifyOption = cf.getOpt("m") || cf.getOpt("x");
+ boolean setOption = cf.getOpt("-set");
+ if ((bothRemoveOptions || bothModifyOptions)
+ || (oneRemoveOption && oneModifyOption)
+ || (setOption && (oneRemoveOption || oneModifyOption))) {
+ throw new HadoopIllegalArgumentException(
+ "Specified flags contains both remove and modify flags");
+ }
+
+ // Only -m, -x and --set expects <acl_spec>
+ if (oneModifyOption || setOption) {
+ if (args.size() < 2) {
+ throw new HadoopIllegalArgumentException("<acl_spec> is missing");
+ }
+ aclEntries = parseAclSpec(args.removeFirst());
+ }
+
+ if (args.isEmpty()) {
+ throw new HadoopIllegalArgumentException("<path> is missing");
+ }
+ if (args.size() > 1) {
+ throw new HadoopIllegalArgumentException("Too many arguments");
+ }
+ path = new Path(args.removeFirst());
+ }
+
+ @Override
+ protected void processPath(PathData item) throws IOException {
+ if (cf.getOpt("b")) {
+ item.fs.removeAcl(item.path);
+ } else if (cf.getOpt("k")) {
+ item.fs.removeDefaultAcl(item.path);
+ } else if (cf.getOpt("m")) {
+ item.fs.modifyAclEntries(item.path, aclEntries);
+ } else if (cf.getOpt("x")) {
+ item.fs.removeAclEntries(item.path, aclEntries);
+ } else if (cf.getOpt("-set")) {
+ item.fs.setAcl(path, aclEntries);
+ }
+ }
+
+ /**
+ * Parse the aclSpec and returns the list of AclEntry objects.
+ *
+ * @param aclSpec
+ * @return
+ */
+ private List<AclEntry> parseAclSpec(String aclSpec) {
+ List<AclEntry> aclEntries = new ArrayList<AclEntry>();
+ Collection<String> aclStrings = StringUtils.getStringCollection(aclSpec,
+ ",");
+ for (String aclStr : aclStrings) {
+ AclEntry.Builder builder = new AclEntry.Builder();
+ // Here "::" represent one empty string.
+ // StringUtils.getStringCollection() will ignore this.
+ String[] split = aclSpec.split(":");
+ if (split.length != 3
+ && !(split.length == 4 && DEFAULT.equals(split[0]))) {
+ throw new HadoopIllegalArgumentException("Invalid <aclSpec> : "
+ + aclStr);
+ }
+ int index = 0;
+ if (split.length == 4) {
+ assert DEFAULT.equals(split[0]);
+ // default entry
+ index++;
+ builder.setScope(AclEntryScope.DEFAULT);
+ }
+ String type = split[index++];
+ AclEntryType aclType = null;
+ try {
+ aclType = Enum.valueOf(AclEntryType.class, type.toUpperCase());
+ builder.setType(aclType);
+ } catch (IllegalArgumentException iae) {
+ throw new HadoopIllegalArgumentException(
+ "Invalid type of acl in <aclSpec> :" + aclStr);
+ }
+
+ builder.setName(split[index++]);
+
+ String permission = split[index++];
+ FsAction fsAction = FsAction.getFsAction(permission);
+ if (null == fsAction) {
+ throw new HadoopIllegalArgumentException(
+ "Invalid permission in <aclSpec> : " + aclStr);
+ }
+ builder.setPermission(fsAction);
+ aclEntries.add(builder.build());
+ }
+ return aclEntries;
+ }
+ }
+}
Modified: hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/FsCommand.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/FsCommand.java?rev=1553735&r1=1553734&r2=1553735&view=diff
==============================================================================
--- hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/FsCommand.java (original)
+++ hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/FsCommand.java Fri Dec 27 20:41:16 2013
@@ -43,6 +43,7 @@ abstract public class FsCommand extends
* @param factory where to register the class
*/
public static void registerCommands(CommandFactory factory) {
+ factory.registerCommands(AclCommands.class);
factory.registerCommands(CopyCommands.class);
factory.registerCommands(Count.class);
factory.registerCommands(Delete.class);
Added: hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/TestAclCommands.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/TestAclCommands.java?rev=1553735&view=auto
==============================================================================
--- hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/TestAclCommands.java (added)
+++ hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/TestAclCommands.java Fri Dec 27 20:41:16 2013
@@ -0,0 +1,65 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.hadoop.fs.shell;
+
+import static org.junit.Assert.assertFalse;
+
+import java.io.IOException;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.FsShell;
+import org.apache.hadoop.util.ToolRunner;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestAclCommands {
+
+ private Configuration conf = null;
+
+ @Before
+ public void setup() throws IOException {
+ conf = new Configuration();
+ }
+
+ @Test
+ public void testGetfaclValidations() throws Exception {
+ assertFalse("getfacl should fail without path",
+ 0 == runCommand(new String[] { "-getfacl" }));
+ assertFalse("getfacl should fail with extra argument",
+ 0 == runCommand(new String[] { "-getfacl", "/test", "extraArg" }));
+ }
+
+ @Test
+ public void testSetfaclValidations() throws Exception {
+ assertFalse("setfacl should fail without path",
+ 0 == runCommand(new String[] { "-setfacl" }));
+ assertFalse("setfacl should fail without aclSpec",
+ 0 == runCommand(new String[] { "-setfacl", "-m", "/path" }));
+ assertFalse("setfacl should fail with conflicting options",
+ 0 == runCommand(new String[] { "-setfacl", "-m", "/path" }));
+ assertFalse("setfacl should fail with extra arguments",
+ 0 == runCommand(new String[] { "-setfacl", "/path", "extra" }));
+ assertFalse("setfacl should fail with extra arguments",
+ 0 == runCommand(new String[] { "-setfacl", "--set",
+ "default:user::rwx", "/path", "extra" }));
+ }
+
+ private int runCommand(String[] commands) throws Exception {
+ return ToolRunner.run(conf, new FsShell(), commands);
+ }
+}