diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntry.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntry.java
index 3d57e06d47..7de6115955 100644
--- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntry.java
+++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntry.java
@@ -17,12 +17,16 @@
*/
package org.apache.hadoop.fs.permission;
-import static org.apache.hadoop.fs.permission.AclEntryScope.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
import com.google.common.base.Objects;
+import org.apache.hadoop.HadoopIllegalArgumentException;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.util.StringUtils;
/**
* Defines a single entry in an ACL. An ACL entry has a type (user, group,
@@ -193,4 +197,74 @@ private AclEntry(AclEntryType type, String name, FsAction permission, AclEntrySc
this.permission = permission;
this.scope = scope;
}
+
+ /**
+ * Parses a string representation of an ACL spec into a list of AclEntry
+ * objects. Example: "user::rwx,user:foo:rw-,group::r--,other::---"
+ *
+ * @param aclSpec
+ * String representation of an ACL spec.
+ * @param includePermission
+ * for setAcl operations this will be true. i.e. AclSpec should
+ * include permissions.
+ * But for removeAcl operation it will be false. i.e. AclSpec should
+ * not contain permissions.
+ * Example: "user:foo,group:bar"
+ * @return Returns list of AclEntries parsed
+ */
+ public static List parseAclSpec(String aclSpec,
+ boolean includePermission) {
+ List aclEntries = new ArrayList();
+ Collection 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 = aclStr.split(":");
+ int expectedAclSpecLength = 2;
+ if (includePermission) {
+ expectedAclSpecLength = 3;
+ }
+ if (split.length != expectedAclSpecLength
+ && !(split.length == expectedAclSpecLength + 1 && "default"
+ .equals(split[0]))) {
+ throw new HadoopIllegalArgumentException("Invalid : "
+ + aclStr);
+ }
+ int index = 0;
+ if (split.length == expectedAclSpecLength + 1) {
+ 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 :" + aclStr);
+ }
+
+ String name = split[index++];
+ if (!name.isEmpty()) {
+ builder.setName(name);
+ }
+
+ if (expectedAclSpecLength == 3) {
+ String permission = split[index++];
+ FsAction fsAction = FsAction.getFsAction(permission);
+ if (null == fsAction) {
+ throw new HadoopIllegalArgumentException(
+ "Invalid permission in : " + aclStr);
+ }
+ builder.setPermission(fsAction);
+ }
+ aclEntries.add(builder.build());
+ }
+ return aclEntries;
+ }
}
diff --git a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/AclCommands.java b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/AclCommands.java
index cb83027f51..67f5cc0d0d 100644
--- a/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/AclCommands.java
+++ b/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/AclCommands.java
@@ -18,8 +18,6 @@
package org.apache.hadoop.fs.shell;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -27,14 +25,12 @@
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.fs.permission.FsPermission;
-import org.apache.hadoop.util.StringUtils;
/**
* Acl related operations
@@ -201,9 +197,6 @@ public static class SetfaclCommand extends FsCommand {
+ ": Comma separated list of ACL entries.\n"
+ ": 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 aclEntries = null;
@@ -230,7 +223,7 @@ protected void processOptions(LinkedList args) throws IOException {
if (args.size() < 2) {
throw new HadoopIllegalArgumentException(" is missing");
}
- aclEntries = parseAclSpec(args.removeFirst());
+ aclEntries = AclEntry.parseAclSpec(args.removeFirst(), !cf.getOpt("x"));
}
if (args.isEmpty()) {
@@ -239,7 +232,6 @@ protected void processOptions(LinkedList args) throws IOException {
if (args.size() > 1) {
throw new HadoopIllegalArgumentException("Too many arguments");
}
- path = new Path(args.removeFirst());
}
@Override
@@ -253,59 +245,8 @@ protected void processPath(PathData item) throws IOException {
} else if (cf.getOpt("x")) {
item.fs.removeAclEntries(item.path, aclEntries);
} else if (cf.getOpt("-set")) {
- item.fs.setAcl(path, aclEntries);
+ item.fs.setAcl(item.path, aclEntries);
}
}
-
- /**
- * Parse the aclSpec and returns the list of AclEntry objects.
- *
- * @param aclSpec
- * @return
- */
- private List parseAclSpec(String aclSpec) {
- List aclEntries = new ArrayList();
- Collection 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 : "
- + 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 :" + aclStr);
- }
-
- builder.setName(split[index++]);
-
- String permission = split[index++];
- FsAction fsAction = FsAction.getFsAction(permission);
- if (null == fsAction) {
- throw new HadoopIllegalArgumentException(
- "Invalid permission in : " + aclStr);
- }
- builder.setPermission(fsAction);
- aclEntries.add(builder.build());
- }
- return aclEntries;
- }
}
}
diff --git a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/TestAclCommands.java b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/TestAclCommands.java
index d0137e2472..6de7351187 100644
--- a/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/TestAclCommands.java
+++ b/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/TestAclCommands.java
@@ -17,12 +17,18 @@
*/
package org.apache.hadoop.fs.shell;
-import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.*;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FsShell;
+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.FsAction;
import org.apache.hadoop.util.ToolRunner;
import org.junit.Before;
import org.junit.Test;
@@ -57,6 +63,37 @@ public void testSetfaclValidations() throws Exception {
assertFalse("setfacl should fail with extra arguments",
0 == runCommand(new String[] { "-setfacl", "--set",
"default:user::rwx", "/path", "extra" }));
+ assertFalse("setfacl should fail with permissions for -x",
+ 0 == runCommand(new String[] { "-setfacl", "-x", "user:user1:rwx",
+ "/path" }));
+ assertFalse("setfacl should fail with permissions for -x",
+ 0 == runCommand(new String[] { "-setfacl", "-m",
+ "", "/path" }));
+ }
+
+ @Test
+ public void testMultipleAclSpecParsing() throws Exception {
+ List parsedList = AclEntry.parseAclSpec(
+ "group::rwx,user:user1:rwx,user:user2:rw-,group:group1:rw-,default:group:group1:rw-", true);
+
+ AclEntry basicAcl = new AclEntry.Builder().setType(AclEntryType.GROUP)
+ .setPermission(FsAction.ALL).build();
+ AclEntry user1Acl = new AclEntry.Builder().setType(AclEntryType.USER)
+ .setPermission(FsAction.ALL).setName("user1").build();
+ AclEntry user2Acl = new AclEntry.Builder().setType(AclEntryType.USER)
+ .setPermission(FsAction.READ_WRITE).setName("user2").build();
+ AclEntry group1Acl = new AclEntry.Builder().setType(AclEntryType.GROUP)
+ .setPermission(FsAction.READ_WRITE).setName("group1").build();
+ AclEntry defaultAcl = new AclEntry.Builder().setType(AclEntryType.GROUP)
+ .setPermission(FsAction.READ_WRITE).setName("group1")
+ .setScope(AclEntryScope.DEFAULT).build();
+ List expectedList = new ArrayList();
+ expectedList.add(basicAcl);
+ expectedList.add(user1Acl);
+ expectedList.add(user2Acl);
+ expectedList.add(group1Acl);
+ expectedList.add(defaultAcl);
+ assertEquals("Parsed Acl not correct", expectedList, parsedList);
}
private int runCommand(String[] commands) throws Exception {
diff --git a/hadoop-hdfs-project/hadoop-hdfs/CHANGES-HDFS-4685.txt b/hadoop-hdfs-project/hadoop-hdfs/CHANGES-HDFS-4685.txt
index 747c540457..ddbf93346e 100644
--- a/hadoop-hdfs-project/hadoop-hdfs/CHANGES-HDFS-4685.txt
+++ b/hadoop-hdfs-project/hadoop-hdfs/CHANGES-HDFS-4685.txt
@@ -45,3 +45,6 @@ HDFS-4685 (Unreleased)
HDFS-5739. ACL RPC must allow null name or unspecified permissions in ACL
entries. (cnauroth)
+
+ HADOOP-10213. Fix bugs parsing ACL spec in FsShell setfacl.
+ (Vinay via cnauroth)