| /** |
| * 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.permission; |
| |
| 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, |
| * mask, or other), an optional name (referring to a specific user or group), a |
| * set of permissions (any combination of read, write and execute), and a scope |
| * (access or default). AclEntry instances are immutable. Use a {@link Builder} |
| * to create a new instance. |
| */ |
| @InterfaceAudience.Public |
| @InterfaceStability.Evolving |
| public class AclEntry { |
| private final AclEntryType type; |
| private final String name; |
| private final FsAction permission; |
| private final AclEntryScope scope; |
| |
| /** |
| * Returns the ACL entry type. |
| * |
| * @return AclEntryType ACL entry type |
| */ |
| public AclEntryType getType() { |
| return type; |
| } |
| |
| /** |
| * Returns the optional ACL entry name. |
| * |
| * @return String ACL entry name, or null if undefined |
| */ |
| public String getName() { |
| return name; |
| } |
| |
| /** |
| * Returns the set of permissions in the ACL entry. |
| * |
| * @return FsAction set of permissions in the ACL entry |
| */ |
| public FsAction getPermission() { |
| return permission; |
| } |
| |
| /** |
| * Returns the scope of the ACL entry. |
| * |
| * @return AclEntryScope scope of the ACL entry |
| */ |
| public AclEntryScope getScope() { |
| return scope; |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| if (o == null) { |
| return false; |
| } |
| if (getClass() != o.getClass()) { |
| return false; |
| } |
| AclEntry other = (AclEntry)o; |
| return Objects.equal(type, other.type) && |
| Objects.equal(name, other.name) && |
| Objects.equal(permission, other.permission) && |
| Objects.equal(scope, other.scope); |
| } |
| |
| @Override |
| public int hashCode() { |
| return Objects.hashCode(type, name, permission, scope); |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder sb = new StringBuilder(); |
| if (scope == AclEntryScope.DEFAULT) { |
| sb.append("default:"); |
| } |
| if (type != null) { |
| sb.append(type.toString().toLowerCase()); |
| } |
| sb.append(':'); |
| if (name != null) { |
| sb.append(name); |
| } |
| sb.append(':'); |
| if (permission != null) { |
| sb.append(permission.SYMBOL); |
| } |
| return sb.toString(); |
| } |
| |
| /** |
| * Builder for creating new AclEntry instances. |
| */ |
| public static class Builder { |
| private AclEntryType type; |
| private String name; |
| private FsAction permission; |
| private AclEntryScope scope = AclEntryScope.ACCESS; |
| |
| /** |
| * Sets the ACL entry type. |
| * |
| * @param type AclEntryType ACL entry type |
| * @return Builder this builder, for call chaining |
| */ |
| public Builder setType(AclEntryType type) { |
| this.type = type; |
| return this; |
| } |
| |
| /** |
| * Sets the optional ACL entry name. |
| * |
| * @param name String optional ACL entry name |
| * @return Builder this builder, for call chaining |
| */ |
| public Builder setName(String name) { |
| this.name = name; |
| return this; |
| } |
| |
| /** |
| * Sets the set of permissions in the ACL entry. |
| * |
| * @param permission FsAction set of permissions in the ACL entry |
| * @return Builder this builder, for call chaining |
| */ |
| public Builder setPermission(FsAction permission) { |
| this.permission = permission; |
| return this; |
| } |
| |
| /** |
| * Sets the scope of the ACL entry. If this method is not called, then the |
| * builder assumes {@link AclEntryScope#ACCESS}. |
| * |
| * @param scope AclEntryScope scope of the ACL entry |
| * @return Builder this builder, for call chaining |
| */ |
| public Builder setScope(AclEntryScope scope) { |
| this.scope = scope; |
| return this; |
| } |
| |
| /** |
| * Builds a new AclEntry populated with the set properties. |
| * |
| * @return AclEntry new AclEntry |
| */ |
| public AclEntry build() { |
| return new AclEntry(type, name, permission, scope); |
| } |
| } |
| |
| /** |
| * Private constructor. |
| * |
| * @param type AclEntryType ACL entry type |
| * @param name String optional ACL entry name |
| * @param permission FsAction set of permissions in the ACL entry |
| * @param scope AclEntryScope scope of the ACL entry |
| */ |
| private AclEntry(AclEntryType type, String name, FsAction permission, AclEntryScope scope) { |
| this.type = type; |
| this.name = name; |
| 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.<br> |
| * But for removeAcl operation it will be false. i.e. AclSpec should |
| * not contain permissions.<br> |
| * Example: "user:foo,group:bar" |
| * @return Returns list of {@link AclEntry} parsed |
| */ |
| public static List<AclEntry> parseAclSpec(String aclSpec, |
| boolean includePermission) { |
| List<AclEntry> aclEntries = new ArrayList<AclEntry>(); |
| Collection<String> aclStrings = StringUtils.getStringCollection(aclSpec, |
| ","); |
| for (String aclStr : aclStrings) { |
| AclEntry aclEntry = parseAclEntry(aclStr, includePermission); |
| aclEntries.add(aclEntry); |
| } |
| return aclEntries; |
| } |
| |
| /** |
| * Parses a string representation of an ACL into a AclEntry object.<br> |
| * |
| * @param aclStr |
| * String representation of an ACL.<br> |
| * Example: "user:foo:rw-" |
| * @param includePermission |
| * for setAcl operations this will be true. i.e. Acl should include |
| * permissions.<br> |
| * But for removeAcl operation it will be false. i.e. Acl should not |
| * contain permissions.<br> |
| * Example: "user:foo,group:bar,mask::" |
| * @return Returns an {@link AclEntry} object |
| */ |
| public static AclEntry parseAclEntry(String aclStr, |
| boolean includePermission) { |
| AclEntry.Builder builder = new AclEntry.Builder(); |
| // Here "::" represent one empty string. |
| // StringUtils.getStringCollection() will ignore this. |
| String[] split = aclStr.split(":"); |
| |
| if (split.length == 0) { |
| throw new HadoopIllegalArgumentException("Invalid <aclSpec> : " + aclStr); |
| } |
| int index = 0; |
| if ("default".equals(split[0])) { |
| // default entry |
| index++; |
| builder.setScope(AclEntryScope.DEFAULT); |
| } |
| |
| if (split.length <= index) { |
| throw new HadoopIllegalArgumentException("Invalid <aclSpec> : " + aclStr); |
| } |
| |
| AclEntryType aclType = null; |
| try { |
| aclType = Enum.valueOf(AclEntryType.class, split[index].toUpperCase()); |
| builder.setType(aclType); |
| index++; |
| } catch (IllegalArgumentException iae) { |
| throw new HadoopIllegalArgumentException( |
| "Invalid type of acl in <aclSpec> :" + aclStr); |
| } |
| |
| if (split.length > index) { |
| String name = split[index]; |
| if (!name.isEmpty()) { |
| builder.setName(name); |
| } |
| index++; |
| } |
| |
| if (includePermission) { |
| if (split.length < index) { |
| throw new HadoopIllegalArgumentException("Invalid <aclSpec> : " |
| + aclStr); |
| } |
| String permission = split[index]; |
| FsAction fsAction = FsAction.getFsAction(permission); |
| if (null == fsAction) { |
| throw new HadoopIllegalArgumentException( |
| "Invalid permission in <aclSpec> : " + aclStr); |
| } |
| builder.setPermission(fsAction); |
| index++; |
| } |
| |
| if (split.length > index) { |
| throw new HadoopIllegalArgumentException("Invalid <aclSpec> : " + aclStr); |
| } |
| AclEntry aclEntry = builder.build(); |
| return aclEntry; |
| } |
| } |