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/10 18:56:31 UTC

svn commit: r1549910 - in /hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src: main/java/org/apache/hadoop/fs/ main/java/org/apache/hadoop/fs/permission/ main/java/org/apache/hadoop/fs/viewfs/ test/java/org/apache/hadoop/fs/ test/...

Author: cnauroth
Date: Tue Dec 10 17:56:30 2013
New Revision: 1549910

URL: http://svn.apache.org/r1549910
Log:
HDFS-5594. FileSystem API for ACLs. Contributed by Chris Nauroth.

Added:
    hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/Acl.java
    hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntry.java
    hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntryScope.java
    hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntryType.java
    hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclReadFlag.java
    hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclStatus.java
    hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclWriteFlag.java
    hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/permission/TestAcl.java
Modified:
    hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileSystem.java
    hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FilterFileSystem.java
    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/viewfs/ChRootedFileSystem.java
    hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java
    hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestHarFileSystem.java
    hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestChRootedFileSystem.java
    hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFileSystemDelegation.java

Modified: hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileSystem.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileSystem.java?rev=1549910&r1=1549909&r2=1549910&view=diff
==============================================================================
--- hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileSystem.java (original)
+++ hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileSystem.java Tue Dec 10 17:56:30 2013
@@ -25,8 +25,6 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.security.PrivilegedExceptionAction;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -40,7 +38,6 @@ import java.util.ServiceLoader;
 import java.util.Set;
 import java.util.Stack;
 import java.util.TreeSet;
-import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicLong;
 
 import org.apache.commons.logging.Log;
@@ -51,6 +48,10 @@ import org.apache.hadoop.conf.Configurat
 import org.apache.hadoop.conf.Configured;
 import org.apache.hadoop.fs.Options.ChecksumOpt;
 import org.apache.hadoop.fs.Options.Rename;
+import org.apache.hadoop.fs.permission.AclEntry;
+import org.apache.hadoop.fs.permission.AclReadFlag;
+import org.apache.hadoop.fs.permission.AclStatus;
+import org.apache.hadoop.fs.permission.AclWriteFlag;
 import org.apache.hadoop.fs.permission.FsPermission;
 import org.apache.hadoop.io.MultipleIOException;
 import org.apache.hadoop.io.Text;
@@ -2269,6 +2270,96 @@ public abstract class FileSystem extends
         + " doesn't support deleteSnapshot");
   }
   
+  /**
+   * Modifies ACL entries of files and directories.  This method can add new ACL
+   * entries or modify the permissions on existing ACL entries.  All existing
+   * ACL entries that are not specified in this call are retained without
+   * changes.  (Modifications are merged into the current ACL.)
+   *
+   * @param path Path to modify
+   * @param aclSpec List<AclEntry> describing modifications
+   * @param flags EnumSet<AclWriteFlag> containing flags (such as recursive)
+   * @throws IOException if an ACL could not be modified
+   */
+  public void modifyAclEntries(Path path, List<AclEntry> aclSpec,
+      EnumSet<AclWriteFlag> flags) throws IOException {
+    throw new UnsupportedOperationException(getClass().getSimpleName()
+        + " doesn't support modifyAclEntries");
+  }
+
+  /**
+   * Removes ACL entries from files and directories.  Other ACL entries are
+   * retained.
+   *
+   * @param path Path to modify
+   * @param aclSpec List<AclEntry> describing entries to remove
+   * @param flags EnumSet<AclWriteFlag> containing flags (such as recursive)
+   * @throws IOException if an ACL could not be modified
+   */
+  public void removeAclEntries(Path path, List<AclEntry> aclSpec,
+      EnumSet<AclWriteFlag> flags) throws IOException {
+    throw new UnsupportedOperationException(getClass().getSimpleName()
+        + " doesn't support removeAclEntries");
+  }
+
+  /**
+   * Removes all default ACL entries from files and directories.
+   *
+   * @param path Path to modify
+   * @param flags EnumSet<AclWriteFlag> containing flags (such as recursive)
+   * @throws IOException if an ACL could not be modified
+   */
+  public void removeDefaultAcl(Path path, EnumSet<AclWriteFlag> flags)
+      throws IOException {
+    throw new UnsupportedOperationException(getClass().getSimpleName()
+        + " doesn't support removeDefaultAcl");
+  }
+
+  /**
+   * Removes all but the base ACL entries of files and directories.  The entries
+   * for user, group, and others are retained for compatibility with permission
+   * bits.
+   *
+   * @param path Path to modify
+   * @param flags EnumSet<AclWriteFlag> containing flags (such as recursive)
+   * @throws IOException if an ACL could not be removed
+   */
+  public void removeAcl(Path path, EnumSet<AclWriteFlag> flags)
+      throws IOException {
+    throw new UnsupportedOperationException(getClass().getSimpleName()
+        + " doesn't support removeAcl");
+  }
+
+  /**
+   * Fully replaces ACL of files and directories, discarding all existing
+   * entries.
+   *
+   * @param path Path to modify
+   * @param aclSpec List<AclEntry> describing modifications, must include entries
+   *   for user, group, and others for compatibility with permission bits.
+   * @param flags EnumSet<AclWriteFlag> containing flags (such as recursive)
+   * @throws IOException if an ACL could not be modified
+   */
+  public void setAcl(Path path, List<AclEntry> aclSpec,
+      EnumSet<AclWriteFlag> flags) throws IOException {
+    throw new UnsupportedOperationException(getClass().getSimpleName()
+        + " doesn't support setAcl");
+  }
+
+  /**
+   * Gets the ACLs of files and directories.
+   *
+   * @param path Path to get
+   * @param flags EnumSet<AclReadFlag> containing flags (such as recursive)
+   * @return RemoteIterator<AclStatus> which returns each AclStatus
+   * @throws IOException if an ACL could not be read
+   */
+  public RemoteIterator<AclStatus> listAclStatus(Path path,
+      EnumSet<AclReadFlag> flags) throws IOException {
+    throw new UnsupportedOperationException(getClass().getSimpleName()
+        + " doesn't support listAclStatus");
+  }
+
   // making it volatile to be able to do a double checked locking
   private volatile static boolean FILE_SYSTEMS_LOADED = false;
 

Modified: hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FilterFileSystem.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FilterFileSystem.java?rev=1549910&r1=1549909&r2=1549910&view=diff
==============================================================================
--- hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FilterFileSystem.java (original)
+++ hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FilterFileSystem.java Tue Dec 10 17:56:30 2013
@@ -22,9 +22,14 @@ import java.io.*;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.EnumSet;
+import java.util.List;
 import org.apache.hadoop.classification.InterfaceAudience;
 import org.apache.hadoop.classification.InterfaceStability;
 import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.permission.AclEntry;
+import org.apache.hadoop.fs.permission.AclReadFlag;
+import org.apache.hadoop.fs.permission.AclStatus;
+import org.apache.hadoop.fs.permission.AclWriteFlag;
 import org.apache.hadoop.fs.permission.FsPermission;
 import org.apache.hadoop.fs.ContentSummary;
 import org.apache.hadoop.fs.Options.ChecksumOpt;
@@ -507,4 +512,40 @@ public class FilterFileSystem extends Fi
       throws IOException {
     fs.deleteSnapshot(path, snapshotName);
   }
+
+  @Override
+  public void modifyAclEntries(Path path, List<AclEntry> aclSpec,
+      EnumSet<AclWriteFlag> flags) throws IOException {
+    fs.modifyAclEntries(path, aclSpec, flags);
+  }
+
+  @Override
+  public void removeAclEntries(Path path, List<AclEntry> aclSpec,
+      EnumSet<AclWriteFlag> flags) throws IOException {
+    fs.removeAclEntries(path, aclSpec, flags);
+  }
+
+  @Override
+  public void removeDefaultAcl(Path path, EnumSet<AclWriteFlag> flags)
+      throws IOException {
+    fs.removeDefaultAcl(path, flags);
+  }
+
+  @Override
+  public void removeAcl(Path path, EnumSet<AclWriteFlag> flags)
+      throws IOException {
+    fs.removeAcl(path, flags);
+  }
+
+  @Override
+  public void setAcl(Path path, List<AclEntry> aclSpec,
+      EnumSet<AclWriteFlag> flags) throws IOException {
+    fs.setAcl(path, aclSpec, flags);
+  }
+
+  @Override
+  public RemoteIterator<AclStatus> listAclStatus(Path path,
+      EnumSet<AclReadFlag> flags) throws IOException {
+    return fs.listAclStatus(path, flags);
+  }
 }

Added: hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/Acl.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/Acl.java?rev=1549910&view=auto
==============================================================================
--- hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/Acl.java (added)
+++ hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/Acl.java Tue Dec 10 17:56:30 2013
@@ -0,0 +1,141 @@
+/**
+ * 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.Collections;
+import java.util.List;
+
+import com.google.common.base.Objects;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+
+/**
+ * Defines an Access Control List, which is a set of rules for enforcement of
+ * permissions on a file or directory.  An Acl contains a set of multiple
+ * {@link AclEntry} instances.  The ACL entries define the permissions enforced
+ * for different classes of users: owner, named user, owning group, named group
+ * and others.  The Acl also contains additional flags associated with the file,
+ * such as the sticky bit.  Acl instances are immutable.  Use a {@link Builder}
+ * to create a new instance.
+ */
+@InterfaceAudience.Public
+@InterfaceStability.Evolving
+public class Acl {
+  private final List<AclEntry> entries;
+  private final boolean stickyBit;
+
+  /**
+   * Returns the sticky bit.
+   *
+   * @return boolean sticky bit
+   */
+  public boolean getStickyBit() {
+    return stickyBit;
+  }
+
+  /**
+   * Returns the list of all ACL entries, ordered by their natural ordering.
+   * The list is unmodifiable.
+   *
+   * @return List<AclEntry> unmodifiable ordered list of all ACL entries
+   */
+  public List<AclEntry> getEntries() {
+    return entries;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (o == null) {
+      return false;
+    }
+    if (getClass() != o.getClass()) {
+      return false;
+    }
+    Acl other = (Acl)o;
+    return Objects.equal(entries, other.entries) &&
+      Objects.equal(stickyBit, other.stickyBit);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hashCode(entries, stickyBit);
+  }
+
+  @Override
+  public String toString() {
+    return new StringBuilder()
+      .append("entries: ").append(entries)
+      .append(", stickyBit: ").append(stickyBit)
+      .toString();
+  }
+
+  /**
+   * Builder for creating new Acl instances.
+   */
+  public static class Builder {
+    private List<AclEntry> entries = new ArrayList<AclEntry>();
+    private boolean stickyBit = false;
+
+    /**
+     * Adds an ACL entry.
+     *
+     * @param entry AclEntry entry to add
+     * @return Builder this builder, for call chaining
+     */
+    public Builder addEntry(AclEntry entry) {
+      entries.add(entry);
+      return this;
+    }
+
+    /**
+     * Sets sticky bit.  If this method is not called, then the builder assumes
+     * false.
+     *
+     * @param stickyBit boolean sticky bit
+     * @return Builder this builder, for call chaining
+     */
+    public Builder setStickyBit(boolean stickyBit) {
+      this.stickyBit = stickyBit;
+      return this;
+    }
+
+    /**
+     * Builds a new Acl populated with the set properties.
+     *
+     * @return Acl new Acl
+     */
+    public Acl build() {
+      return new Acl(entries, stickyBit);
+    }
+  }
+
+  /**
+   * Private constructor.
+   *
+   * @param entries List<AclEntry> list of all ACL entries
+   * @param boolean sticky bit
+   */
+  private Acl(List<AclEntry> entries, boolean stickyBit) {
+    List<AclEntry> entriesCopy = new ArrayList<AclEntry>(entries);
+    Collections.sort(entriesCopy);
+    this.entries = Collections.unmodifiableList(entriesCopy);
+    this.stickyBit = stickyBit;
+  }
+}

Added: hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntry.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/AclEntry.java?rev=1549910&view=auto
==============================================================================
--- hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntry.java (added)
+++ hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntry.java Tue Dec 10 17:56:30 2013
@@ -0,0 +1,216 @@
+/**
+ * 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 static org.apache.hadoop.fs.permission.AclEntryScope.*;
+import static org.apache.hadoop.fs.permission.AclEntryType.*;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ComparisonChain;
+import com.google.common.collect.Ordering;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+
+/**
+ * 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).  The natural ordering for entries within an ACL is:
+ * <ol>
+ * <li>owner entry (unnamed user)</li>
+ * <li>all named user entries (internal ordering undefined)</li>
+ * <li>owning group entry (unnamed group)</li>
+ * <li>all named group entries (internal ordering undefined)</li>
+ * <li>other entry</li>
+ * </ol>
+ * All access ACL entries sort ahead of all default ACL entries.  AclEntry
+ * instances are immutable.  Use a {@link Builder} to create a new instance.
+ */
+@InterfaceAudience.Public
+@InterfaceStability.Evolving
+public class AclEntry implements Comparable<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 int compareTo(AclEntry other) {
+    return ComparisonChain.start()
+      .compare(scope, other.scope, Ordering.explicit(ACCESS, DEFAULT))
+      .compare(type, other.type, Ordering.explicit(USER, GROUP, MASK, OTHER))
+      .compare(name, other.name, Ordering.natural().nullsFirst())
+      .result();
+  }
+
+  @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;
+  }
+}

Added: hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntryScope.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/AclEntryScope.java?rev=1549910&view=auto
==============================================================================
--- hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntryScope.java (added)
+++ hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntryScope.java Tue Dec 10 17:56:30 2013
@@ -0,0 +1,42 @@
+/**
+ * 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 org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+
+/**
+ * Specifies the scope or intended usage of an ACL entry.
+ */
+@InterfaceAudience.Public
+@InterfaceStability.Evolving
+public enum AclEntryScope {
+  /**
+   * An ACL entry that is inspected during permission checks to enforce
+   * permissions.
+   */
+  ACCESS,
+
+  /**
+   * An ACL entry to be applied to a directory's children that do not otherwise
+   * have their own ACL defined.  Unlike an access ACL entry, a default ACL
+   * entry is not inspected as part of permission enforcement on the directory
+   * that owns it.
+   */
+  DEFAULT
+}

Added: hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntryType.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/AclEntryType.java?rev=1549910&view=auto
==============================================================================
--- hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntryType.java (added)
+++ hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntryType.java Tue Dec 10 17:56:30 2013
@@ -0,0 +1,58 @@
+/**
+ * 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 org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+
+/**
+ * Specifies the type of an ACL entry.
+ */
+@InterfaceAudience.Public
+@InterfaceStability.Evolving
+public enum AclEntryType {
+  /**
+   * An ACL entry applied to a specific user.  These ACL entries can be unnamed,
+   * which applies to the file owner, or named, which applies to the specific
+   * named user.
+   */
+  USER,
+
+  /**
+   * An ACL entry applied to a specific group.  These ACL entries can be
+   * unnamed, which applies to the file's group, or named, which applies to the
+   * specific named group.
+   */
+  GROUP,
+
+  /**
+   * An ACL mask entry.  Mask entries are unnamed.  During permission checks,
+   * the mask entry interacts with all ACL entries that are members of the group
+   * class.  This consists of all named user entries, the unnamed group entry,
+   * and all named group entries.  For each such entry, any permissions that are
+   * absent from the mask entry are removed from the effective permissions used
+   * during the permission check.
+   */
+  MASK,
+
+  /**
+   * An ACL entry that applies to all other users that were not covered by one
+   * of the more specific ACL entry types.
+   */
+  OTHER
+}

Added: hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclReadFlag.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/AclReadFlag.java?rev=1549910&view=auto
==============================================================================
--- hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclReadFlag.java (added)
+++ hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclReadFlag.java Tue Dec 10 17:56:30 2013
@@ -0,0 +1,34 @@
+/**
+ * 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 org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+
+/**
+ * Flags that control behavior of operations for reading ACL information.
+ */
+@InterfaceAudience.Public
+@InterfaceStability.Evolving
+public enum AclReadFlag {
+  /**
+   * Read ACLs for all files and directories recursively in the sub-tree of the
+   * specified path.
+   */
+  RECURSIVE
+}

Added: hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclStatus.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/AclStatus.java?rev=1549910&view=auto
==============================================================================
--- hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclStatus.java (added)
+++ hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclStatus.java Tue Dec 10 17:56:30 2013
@@ -0,0 +1,182 @@
+/**
+ * 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 com.google.common.base.Objects;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.fs.Path;
+
+/**
+ * An AclStatus represents an association of a specific file {@link Path} with
+ * an {@link Acl}.  AclStatus instances are immutable.  Use a {@link Builder} to
+ * create a new instance.
+ */
+@InterfaceAudience.Public
+@InterfaceStability.Evolving
+public class AclStatus {
+  private final Path file;
+  private final String owner;
+  private final String group;
+  private final Acl acl;
+
+  /**
+   * Returns the file associated to this ACL.
+   *
+   * @return Path file associated to this ACL
+   */
+  public Path getFile() {
+    return file;
+  }
+
+  /**
+   * Returns the file owner.
+   *
+   * @return String file owner
+   */
+  public String getOwner() {
+    return owner;
+  }
+
+  /**
+   * Returns the file group.
+   *
+   * @return String file group
+   */
+  public String getGroup() {
+    return group;
+  }
+
+  /**
+   * Returns the ACL.
+   *
+   * @return Acl the ACL
+   */
+  public Acl getAcl() {
+    return acl;
+  }
+
+  @Override
+  public boolean equals(Object o) {
+    if (o == null) {
+      return false;
+    }
+    if (getClass() != o.getClass()) {
+      return false;
+    }
+    AclStatus other = (AclStatus)o;
+    return Objects.equal(file, other.file) &&
+      Objects.equal(owner, other.owner) &&
+      Objects.equal(group, other.group) &&
+      Objects.equal(acl, other.acl);
+  }
+
+  @Override
+  public int hashCode() {
+    return Objects.hashCode(file, owner, group, acl);
+  }
+
+  @Override
+  public String toString() {
+    return new StringBuilder()
+      .append("file: ").append(file)
+      .append(", owner: ").append(owner)
+      .append(", group: ").append(group)
+      .append(", acl: {").append(acl).append('}')
+      .toString();
+  }
+
+  /**
+   * Builder for creating new Acl instances.
+   */
+  public static class Builder {
+    private Path file;
+    private String owner;
+    private String group;
+    private Acl acl;
+
+    /**
+     * Sets the file associated to this ACL.
+     *
+     * @param file Path file associated to this ACL
+     * @return Builder this builder, for call chaining
+     */
+    public Builder setFile(Path file) {
+      this.file = file;
+      return this;
+    }
+
+    /**
+     * Sets the file owner.
+     *
+     * @param owner String file owner
+     * @return Builder this builder, for call chaining
+     */
+    public Builder setOwner(String owner) {
+      this.owner = owner;
+      return this;
+    }
+
+    /**
+     * Sets the file group.
+     *
+     * @param group String file group
+     * @return Builder this builder, for call chaining
+     */
+    public Builder setGroup(String group) {
+      this.group = group;
+      return this;
+    }
+
+    /**
+     * Sets the ACL.
+     *
+     * @param acl Acl the ACL
+     * @return Builder this builder, for call chaining
+     */
+    public Builder setAcl(Acl acl) {
+      this.acl = acl;
+      return this;
+    }
+
+    /**
+     * Builds a new Acl populated with the set properties.
+     *
+     * @return Acl new Acl
+     */
+    public AclStatus build() {
+      return new AclStatus(file, owner, group, acl);
+    }
+  }
+
+  /**
+   * Private constructor.
+   *
+   * @param file Path file associated to this ACL
+   * @param owner String file owner
+   * @param group String file group
+   * @param acl Acl the ACL
+   */
+  private AclStatus(Path file, String owner, String group, Acl acl) {
+    this.file = file;
+    this.owner = owner;
+    this.group = group;
+    this.acl = acl;
+  }
+}

Added: hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclWriteFlag.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/AclWriteFlag.java?rev=1549910&view=auto
==============================================================================
--- hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclWriteFlag.java (added)
+++ hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclWriteFlag.java Tue Dec 10 17:56:30 2013
@@ -0,0 +1,34 @@
+/**
+ * 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 org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+
+/**
+ * Flags that control behavior of operations for writing ACL information.
+ */
+@InterfaceAudience.Public
+@InterfaceStability.Evolving
+public enum AclWriteFlag {
+  /**
+   * Modify ACLs for all files and directories recursively in the sub-tree of
+   * the specified path.
+   */
+  RECURSIVE
+}

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=1549910&r1=1549909&r2=1549910&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 Tue Dec 10 17:56:30 2013
@@ -23,8 +23,8 @@ import org.apache.hadoop.classification.
 /**
  * File system actions, e.g. read, write, etc.
  */
-@InterfaceAudience.LimitedPrivate({"HDFS"})
-@InterfaceStability.Unstable
+@InterfaceAudience.Public
+@InterfaceStability.Stable
 public enum FsAction {
   // POSIX style
   NONE("---"),

Modified: hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ChRootedFileSystem.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ChRootedFileSystem.java?rev=1549910&r1=1549909&r2=1549910&view=diff
==============================================================================
--- hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ChRootedFileSystem.java (original)
+++ hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ChRootedFileSystem.java Tue Dec 10 17:56:30 2013
@@ -20,6 +20,7 @@ import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.net.URI;
 import java.util.EnumSet;
+import java.util.List;
 
 import org.apache.hadoop.classification.InterfaceAudience;
 import org.apache.hadoop.classification.InterfaceStability;
@@ -36,6 +37,11 @@ import org.apache.hadoop.fs.FilterFileSy
 import org.apache.hadoop.fs.FsServerDefaults;
 import org.apache.hadoop.fs.FsStatus;
 import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.fs.RemoteIterator;
+import org.apache.hadoop.fs.permission.AclEntry;
+import org.apache.hadoop.fs.permission.AclReadFlag;
+import org.apache.hadoop.fs.permission.AclStatus;
+import org.apache.hadoop.fs.permission.AclWriteFlag;
 import org.apache.hadoop.fs.permission.FsPermission;
 import org.apache.hadoop.util.Progressable;
 
@@ -279,6 +285,42 @@ class ChRootedFileSystem extends FilterF
   }
   
   @Override
+  public void modifyAclEntries(Path path, List<AclEntry> aclSpec,
+      EnumSet<AclWriteFlag> flags) throws IOException {
+    super.modifyAclEntries(fullPath(path), aclSpec, flags);
+  }
+
+  @Override
+  public void removeAclEntries(Path path, List<AclEntry> aclSpec,
+      EnumSet<AclWriteFlag> flags) throws IOException {
+    super.removeAclEntries(fullPath(path), aclSpec, flags);
+  }
+
+  @Override
+  public void removeDefaultAcl(Path path, EnumSet<AclWriteFlag> flags)
+      throws IOException {
+    super.removeDefaultAcl(fullPath(path), flags);
+  }
+
+  @Override
+  public void removeAcl(Path path, EnumSet<AclWriteFlag> flags)
+      throws IOException {
+    super.removeAcl(fullPath(path), flags);
+  }
+
+  @Override
+  public void setAcl(Path path, List<AclEntry> aclSpec,
+      EnumSet<AclWriteFlag> flags) throws IOException {
+    super.setAcl(fullPath(path), aclSpec, flags);
+  }
+
+  @Override
+  public RemoteIterator<AclStatus> listAclStatus(Path path,
+      EnumSet<AclReadFlag> flags) throws IOException {
+    return super.listAclStatus(fullPath(path), flags);
+  }
+
+  @Override
   public Path resolvePath(final Path p) throws IOException {
     return super.resolvePath(fullPath(p));
   }

Modified: hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java?rev=1549910&r1=1549909&r2=1549910&view=diff
==============================================================================
--- hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java (original)
+++ hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java Tue Dec 10 17:56:30 2013
@@ -47,7 +47,12 @@ import org.apache.hadoop.fs.FsConstants;
 import org.apache.hadoop.fs.FsServerDefaults;
 import org.apache.hadoop.fs.InvalidPathException;
 import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.fs.RemoteIterator;
 import org.apache.hadoop.fs.UnsupportedFileSystemException;
+import org.apache.hadoop.fs.permission.AclEntry;
+import org.apache.hadoop.fs.permission.AclReadFlag;
+import org.apache.hadoop.fs.permission.AclStatus;
+import org.apache.hadoop.fs.permission.AclWriteFlag;
 import org.apache.hadoop.fs.permission.FsPermission;
 import org.apache.hadoop.fs.viewfs.InodeTree.INode;
 import org.apache.hadoop.fs.viewfs.InodeTree.INodeLink;
@@ -474,6 +479,54 @@ public class ViewFileSystem extends File
   }
 
   @Override
+  public void modifyAclEntries(Path path, List<AclEntry> aclSpec,
+      EnumSet<AclWriteFlag> flags) throws IOException {
+    InodeTree.ResolveResult<FileSystem> res =
+      fsState.resolve(getUriPath(path), true);
+    res.targetFileSystem.modifyAclEntries(res.remainingPath, aclSpec, flags);
+  }
+
+  @Override
+  public void removeAclEntries(Path path, List<AclEntry> aclSpec,
+      EnumSet<AclWriteFlag> flags) throws IOException {
+    InodeTree.ResolveResult<FileSystem> res =
+      fsState.resolve(getUriPath(path), true);
+    res.targetFileSystem.removeAclEntries(res.remainingPath, aclSpec, flags);
+  }
+
+  @Override
+  public void removeDefaultAcl(Path path, EnumSet<AclWriteFlag> flags)
+      throws IOException {
+    InodeTree.ResolveResult<FileSystem> res =
+      fsState.resolve(getUriPath(path), true);
+    res.targetFileSystem.removeDefaultAcl(res.remainingPath, flags);
+  }
+
+  @Override
+  public void removeAcl(Path path, EnumSet<AclWriteFlag> flags)
+      throws IOException {
+    InodeTree.ResolveResult<FileSystem> res =
+      fsState.resolve(getUriPath(path), true);
+    res.targetFileSystem.removeAcl(res.remainingPath, flags);
+  }
+
+  @Override
+  public void setAcl(Path path, List<AclEntry> aclSpec,
+      EnumSet<AclWriteFlag> flags) throws IOException {
+    InodeTree.ResolveResult<FileSystem> res =
+      fsState.resolve(getUriPath(path), true);
+    res.targetFileSystem.setAcl(res.remainingPath, aclSpec, flags);
+  }
+
+  @Override
+  public RemoteIterator<AclStatus> listAclStatus(Path path,
+      EnumSet<AclReadFlag> flags) throws IOException {
+    InodeTree.ResolveResult<FileSystem> res =
+      fsState.resolve(getUriPath(path), true);
+    return res.targetFileSystem.listAclStatus(res.remainingPath, flags);
+  }
+
+  @Override
   public void setVerifyChecksum(final boolean verifyChecksum) { 
     List<InodeTree.MountPoint<FileSystem>> mountPoints = 
         fsState.getMountPoints();

Modified: hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestHarFileSystem.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestHarFileSystem.java?rev=1549910&r1=1549909&r2=1549910&view=diff
==============================================================================
--- hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestHarFileSystem.java (original)
+++ hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestHarFileSystem.java Tue Dec 10 17:56:30 2013
@@ -21,6 +21,10 @@ package org.apache.hadoop.fs;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.permission.AclEntry;
+import org.apache.hadoop.fs.permission.AclReadFlag;
+import org.apache.hadoop.fs.permission.AclStatus;
+import org.apache.hadoop.fs.permission.AclWriteFlag;
 import org.apache.hadoop.fs.permission.FsPermission;
 import org.apache.hadoop.security.Credentials;
 import org.apache.hadoop.security.token.Token;
@@ -33,6 +37,7 @@ import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.util.EnumSet;
 import java.util.Iterator;
+import java.util.List;
 
 import static org.apache.hadoop.fs.Options.ChecksumOpt;
 import static org.apache.hadoop.fs.Options.CreateOpts;
@@ -165,6 +170,18 @@ public class TestHarFileSystem {
         String snapshotNewName) throws IOException;
     public void deleteSnapshot(Path path, String snapshotName)
         throws IOException;
+    public void modifyAclEntries(Path path, List<AclEntry> aclSpec,
+        EnumSet<AclWriteFlag> flags) throws IOException;
+    public void removeAclEntries(Path path, List<AclEntry> aclSpec,
+        EnumSet<AclWriteFlag> flags) throws IOException;
+    public void removeDefaultAcl(Path path, EnumSet<AclWriteFlag> flags)
+        throws IOException;
+    public void removeAcl(Path path, EnumSet<AclWriteFlag> flags)
+        throws IOException;
+    public void setAcl(Path path, List<AclEntry> aclSpec,
+        EnumSet<AclWriteFlag> flags) throws IOException;
+    public RemoteIterator<AclStatus> listAclStatus(Path path,
+        EnumSet<AclReadFlag> flags) throws IOException;
   }
 
   @Test

Added: hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/permission/TestAcl.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/permission/TestAcl.java?rev=1549910&view=auto
==============================================================================
--- hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/permission/TestAcl.java (added)
+++ hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/permission/TestAcl.java Tue Dec 10 17:56:30 2013
@@ -0,0 +1,291 @@
+/**
+ * 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 static org.junit.Assert.*;
+
+import java.util.List;
+
+import org.junit.Test;
+
+import org.apache.hadoop.fs.Path;
+
+/**
+ * Tests covering basic functionality of the ACL objects.
+ */
+public class TestAcl {
+  private static final Acl ACL1, ACL2, ACL3, ACL4;
+  private static final AclEntry ENTRY1, ENTRY2, ENTRY3, ENTRY4, ENTRY5, ENTRY6,
+    ENTRY7, ENTRY8, ENTRY9, ENTRY10, ENTRY11, ENTRY12, ENTRY13;
+  private static final AclStatus STATUS1, STATUS2, STATUS3;
+
+  static {
+    // named user
+    AclEntry.Builder aclEntryBuilder = new AclEntry.Builder()
+      .setType(AclEntryType.USER)
+      .setName("user1")
+      .setPermission(FsAction.ALL);
+    ENTRY1 = aclEntryBuilder.build();
+    ENTRY2 = aclEntryBuilder.build();
+    // named group
+    ENTRY3 = new AclEntry.Builder()
+      .setType(AclEntryType.GROUP)
+      .setName("group2")
+      .setPermission(FsAction.READ_WRITE)
+      .build();
+    // default other
+    ENTRY4 = new AclEntry.Builder()
+      .setType(AclEntryType.OTHER)
+      .setPermission(FsAction.NONE)
+      .setScope(AclEntryScope.DEFAULT)
+      .build();
+    // owner
+    ENTRY5 = new AclEntry.Builder()
+      .setType(AclEntryType.USER)
+      .setPermission(FsAction.ALL)
+      .build();
+    // default named group
+    ENTRY6 = new AclEntry.Builder()
+      .setType(AclEntryType.GROUP)
+      .setName("group3")
+      .setPermission(FsAction.READ_WRITE)
+      .setScope(AclEntryScope.DEFAULT)
+      .build();
+    // other
+    ENTRY7 = new AclEntry.Builder()
+      .setType(AclEntryType.OTHER)
+      .setPermission(FsAction.NONE)
+      .build();
+    // default named user
+    ENTRY8 = new AclEntry.Builder()
+      .setType(AclEntryType.USER)
+      .setName("user3")
+      .setPermission(FsAction.ALL)
+      .setScope(AclEntryScope.DEFAULT)
+      .build();
+    // mask
+    ENTRY9 = new AclEntry.Builder()
+      .setType(AclEntryType.MASK)
+      .setPermission(FsAction.READ)
+      .build();
+    // default mask
+    ENTRY10 = new AclEntry.Builder()
+      .setType(AclEntryType.MASK)
+      .setPermission(FsAction.READ_EXECUTE)
+      .setScope(AclEntryScope.DEFAULT)
+      .build();
+    // group
+    ENTRY11 = new AclEntry.Builder()
+      .setType(AclEntryType.GROUP)
+      .setPermission(FsAction.READ)
+      .build();
+    // default group
+    ENTRY12 = new AclEntry.Builder()
+      .setType(AclEntryType.GROUP)
+      .setPermission(FsAction.READ)
+      .setScope(AclEntryScope.DEFAULT)
+      .build();
+    // default owner
+    ENTRY13 = new AclEntry.Builder()
+      .setType(AclEntryType.USER)
+      .setPermission(FsAction.ALL)
+      .setScope(AclEntryScope.DEFAULT)
+      .build();
+
+    Acl.Builder aclBuilder = new Acl.Builder()
+      .addEntry(ENTRY1)
+      .addEntry(ENTRY3)
+      .addEntry(ENTRY4);
+    ACL1 = aclBuilder.build();
+    ACL2 = aclBuilder.build();
+    ACL3 = new Acl.Builder()
+      .setStickyBit(true)
+      .build();
+
+    AclStatus.Builder aclStatusBuilder = new AclStatus.Builder()
+      .setFile(new Path("file1"))
+      .setOwner("owner1")
+      .setGroup("group1")
+      .setAcl(ACL1);
+    STATUS1 = aclStatusBuilder.build();
+    STATUS2 = aclStatusBuilder.build();
+    STATUS3 = new AclStatus.Builder()
+      .setFile(new Path("file2"))
+      .setOwner("owner2")
+      .setGroup("group2")
+      .setAcl(ACL3)
+      .build();
+
+    ACL4 = new Acl.Builder()
+      .addEntry(ENTRY1)
+      .addEntry(ENTRY3)
+      .addEntry(ENTRY4)
+      .addEntry(ENTRY5)
+      .addEntry(ENTRY6)
+      .addEntry(ENTRY7)
+      .addEntry(ENTRY8)
+      .addEntry(ENTRY9)
+      .addEntry(ENTRY10)
+      .addEntry(ENTRY11)
+      .addEntry(ENTRY12)
+      .addEntry(ENTRY13)
+      .build();
+  }
+
+  @Test
+  public void testAclEquals() {
+    assertNotSame(ACL1, ACL2);
+    assertNotSame(ACL1, ACL3);
+    assertNotSame(ACL2, ACL3);
+    assertEquals(ACL1, ACL1);
+    assertEquals(ACL2, ACL2);
+    assertEquals(ACL1, ACL2);
+    assertEquals(ACL2, ACL1);
+    assertFalse(ACL1.equals(ACL3));
+    assertFalse(ACL2.equals(ACL3));
+    assertFalse(ACL1.equals(null));
+    assertFalse(ACL1.equals(new Object()));
+  }
+
+  @Test
+  public void testAclHashCode() {
+    assertEquals(ACL1.hashCode(), ACL2.hashCode());
+    assertFalse(ACL1.hashCode() == ACL3.hashCode());
+  }
+
+  @Test
+  public void testAclEntriesImmutable() {
+    AclEntry entry = new AclEntry.Builder().build();
+    List<AclEntry> entries = ACL1.getEntries();
+    try {
+      entries.add(entry);
+      fail("expected adding ACL entry to fail");
+    } catch (UnsupportedOperationException e) {
+      // expected
+    }
+  }
+
+  @Test
+  public void testEntryEquals() {
+    assertNotSame(ENTRY1, ENTRY2);
+    assertNotSame(ENTRY1, ENTRY3);
+    assertNotSame(ENTRY1, ENTRY4);
+    assertNotSame(ENTRY2, ENTRY3);
+    assertNotSame(ENTRY2, ENTRY4);
+    assertNotSame(ENTRY3, ENTRY4);
+    assertEquals(ENTRY1, ENTRY1);
+    assertEquals(ENTRY2, ENTRY2);
+    assertEquals(ENTRY1, ENTRY2);
+    assertEquals(ENTRY2, ENTRY1);
+    assertFalse(ENTRY1.equals(ENTRY3));
+    assertFalse(ENTRY1.equals(ENTRY4));
+    assertFalse(ENTRY3.equals(ENTRY4));
+    assertFalse(ENTRY1.equals(null));
+    assertFalse(ENTRY1.equals(new Object()));
+  }
+
+  @Test
+  public void testEntryHashCode() {
+    assertEquals(ENTRY1.hashCode(), ENTRY2.hashCode());
+    assertFalse(ENTRY1.hashCode() == ENTRY3.hashCode());
+    assertFalse(ENTRY1.hashCode() == ENTRY4.hashCode());
+    assertFalse(ENTRY3.hashCode() == ENTRY4.hashCode());
+  }
+
+  @Test
+  public void testEntryNaturalOrdering() {
+    AclEntry expected[] = new AclEntry[] {
+      ENTRY5,  // owner
+      ENTRY1,  // named user
+      ENTRY11, // group
+      ENTRY3,  // named group
+      ENTRY9,  // mask
+      ENTRY7,  // other
+      ENTRY13, // default owner
+      ENTRY8,  // default named user
+      ENTRY12, // default group
+      ENTRY6,  // default named group
+      ENTRY10, // default mask
+      ENTRY4   // default other
+    };
+    List<AclEntry> actual = ACL4.getEntries();
+    assertNotNull(actual);
+    assertEquals(expected.length, actual.size());
+    for (int i = 0; i < expected.length; ++i) {
+      AclEntry expectedEntry = expected[i];
+      AclEntry actualEntry = actual.get(i);
+      assertEquals(
+        String.format("At position %d, expected = %s, actual = %s", i,
+          expectedEntry, actualEntry),
+        expectedEntry, actualEntry);
+    }
+  }
+
+  @Test
+  public void testEntryScopeIsAccessIfUnspecified() {
+    assertEquals(AclEntryScope.ACCESS, ENTRY1.getScope());
+    assertEquals(AclEntryScope.ACCESS, ENTRY2.getScope());
+    assertEquals(AclEntryScope.ACCESS, ENTRY3.getScope());
+    assertEquals(AclEntryScope.DEFAULT, ENTRY4.getScope());
+  }
+
+  @Test
+  public void testStatusEquals() {
+    assertNotSame(STATUS1, STATUS2);
+    assertNotSame(STATUS1, STATUS3);
+    assertNotSame(STATUS2, STATUS3);
+    assertEquals(STATUS1, STATUS1);
+    assertEquals(STATUS2, STATUS2);
+    assertEquals(STATUS1, STATUS2);
+    assertEquals(STATUS2, STATUS1);
+    assertFalse(STATUS1.equals(STATUS3));
+    assertFalse(STATUS2.equals(STATUS3));
+    assertFalse(STATUS1.equals(null));
+    assertFalse(STATUS1.equals(new Object()));
+  }
+
+  @Test
+  public void testStatusHashCode() {
+    assertEquals(STATUS1.hashCode(), STATUS2.hashCode());
+    assertFalse(STATUS1.hashCode() == STATUS3.hashCode());
+  }
+
+  @Test
+  public void testToString() {
+    assertEquals(
+      "entries: [user:user1:rwx, group:group2:rw-, default:other::---], stickyBit: false",
+      ACL1.toString());
+    assertEquals(
+      "entries: [user:user1:rwx, group:group2:rw-, default:other::---], stickyBit: false",
+      ACL2.toString());
+    assertEquals("entries: [], stickyBit: true", ACL3.toString());
+    assertEquals("user:user1:rwx", ENTRY1.toString());
+    assertEquals("user:user1:rwx", ENTRY2.toString());
+    assertEquals("group:group2:rw-", ENTRY3.toString());
+    assertEquals("default:other::---", ENTRY4.toString());
+    assertEquals(
+      "file: file1, owner: owner1, group: group1, acl: {entries: [user:user1:rwx, group:group2:rw-, default:other::---], stickyBit: false}",
+      STATUS1.toString());
+    assertEquals(
+      "file: file1, owner: owner1, group: group1, acl: {entries: [user:user1:rwx, group:group2:rw-, default:other::---], stickyBit: false}",
+      STATUS2.toString());
+    assertEquals(
+      "file: file2, owner: owner2, group: group2, acl: {entries: [], stickyBit: true}",
+      STATUS3.toString());
+  }
+}

Modified: hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestChRootedFileSystem.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestChRootedFileSystem.java?rev=1549910&r1=1549909&r2=1549910&view=diff
==============================================================================
--- hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestChRootedFileSystem.java (original)
+++ hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestChRootedFileSystem.java Tue Dec 10 17:56:30 2013
@@ -20,6 +20,9 @@ package org.apache.hadoop.fs.viewfs;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.net.URI;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
 
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FileStatus;
@@ -29,6 +32,9 @@ import org.apache.hadoop.fs.FileSystemTe
 import org.apache.hadoop.fs.FilterFileSystem;
 import org.apache.hadoop.fs.FsConstants;
 import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.fs.permission.AclEntry;
+import org.apache.hadoop.fs.permission.AclReadFlag;
+import org.apache.hadoop.fs.permission.AclWriteFlag;
 import org.apache.hadoop.fs.viewfs.ChRootedFileSystem;
 import org.junit.After;
 import org.junit.Assert;
@@ -354,6 +360,46 @@ public class TestChRootedFileSystem {
     new ChRootedFileSystem(chrootUri, conf);
   }
 
+  /**
+   * Tests that ChRootedFileSystem delegates calls for every ACL method to the
+   * underlying FileSystem with all Path arguments translated as required to
+   * enforce chroot.
+   */
+  @Test
+  public void testAclMethodsPathTranslation() throws IOException {
+    Configuration conf = new Configuration();
+    conf.setClass("fs.mockfs.impl", MockFileSystem.class, FileSystem.class);
+
+    URI chrootUri = URI.create("mockfs://foo/a/b");
+    ChRootedFileSystem chrootFs = new ChRootedFileSystem(chrootUri, conf);
+    FileSystem mockFs = ((FilterFileSystem)chrootFs.getRawFileSystem())
+        .getRawFileSystem();
+
+    Path chrootPath = new Path("/c");
+    Path rawPath = new Path("/a/b/c");
+    List<AclEntry> entries = Collections.emptyList();
+    EnumSet<AclWriteFlag> writeFlags = EnumSet.noneOf(AclWriteFlag.class);
+    EnumSet<AclReadFlag> readFlags = EnumSet.noneOf(AclReadFlag.class);
+
+    chrootFs.modifyAclEntries(chrootPath, entries, writeFlags);
+    verify(mockFs).modifyAclEntries(rawPath, entries, writeFlags);
+
+    chrootFs.removeAclEntries(chrootPath, entries, writeFlags);
+    verify(mockFs).removeAclEntries(rawPath, entries, writeFlags);
+
+    chrootFs.removeDefaultAcl(chrootPath, writeFlags);
+    verify(mockFs).removeDefaultAcl(rawPath, writeFlags);
+
+    chrootFs.removeAcl(chrootPath, writeFlags);
+    verify(mockFs).removeAcl(rawPath, writeFlags);
+
+    chrootFs.setAcl(chrootPath, entries, writeFlags);
+    verify(mockFs).setAcl(rawPath, entries, writeFlags);
+
+    chrootFs.listAclStatus(chrootPath, readFlags);
+    verify(mockFs).listAclStatus(rawPath, readFlags);
+  }
+
   static class MockFileSystem extends FilterFileSystem {
     MockFileSystem() {
       super(mock(FileSystem.class));
@@ -361,4 +407,4 @@ public class TestChRootedFileSystem {
     @Override
     public void initialize(URI name, Configuration conf) throws IOException {}
   }
-}
\ No newline at end of file
+}

Modified: hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFileSystemDelegation.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFileSystemDelegation.java?rev=1549910&r1=1549909&r2=1549910&view=diff
==============================================================================
--- hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFileSystemDelegation.java (original)
+++ hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFileSystemDelegation.java Tue Dec 10 17:56:30 2013
@@ -20,14 +20,22 @@ package org.apache.hadoop.fs.viewfs;
 
 import java.io.IOException;
 import java.net.URI;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.FileSystemTestHelper;
 import org.apache.hadoop.fs.FsConstants;
 import org.apache.hadoop.fs.LocalFileSystem;
 import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.fs.permission.AclEntry;
+import org.apache.hadoop.fs.permission.AclReadFlag;
+import org.apache.hadoop.fs.permission.AclWriteFlag;
+import org.apache.hadoop.fs.viewfs.TestChRootedFileSystem.MockFileSystem;
 import org.junit.*;
 import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
 
 /**
  * Verify that viewfs propagates certain methods to the underlying fs 
@@ -57,6 +65,15 @@ public class TestViewFileSystemDelegatio
     return fs;
   }
 
+  private static FileSystem setupMockFileSystem(Configuration conf, URI uri)
+      throws Exception {
+    String scheme = uri.getScheme();
+    conf.set("fs." + scheme + ".impl", MockFileSystem.class.getName());
+    FileSystem fs = FileSystem.get(uri, conf);
+    ConfigUtil.addLink(conf, "/mounts/" + scheme, uri);
+    return ((MockFileSystem)fs).getRawFileSystem();
+  }
+
   @Test
   public void testSanity() {
     assertEquals("fs1:/", fs1.getUri().toString());
@@ -69,6 +86,57 @@ public class TestViewFileSystemDelegatio
     checkVerifyChecksum(true);
   }
 
+  /**
+   * Tests that ViewFileSystem dispatches calls for every ACL method through the
+   * mount table to the correct underlying FileSystem with all Path arguments
+   * translated as required.
+   */
+  @Test
+  public void testAclMethods() throws Exception {
+    Configuration conf = ViewFileSystemTestSetup.createConfig();
+    FileSystem mockFs1 = setupMockFileSystem(conf, new URI("mockfs1:/"));
+    FileSystem mockFs2 = setupMockFileSystem(conf, new URI("mockfs2:/"));
+    FileSystem viewFs = FileSystem.get(FsConstants.VIEWFS_URI, conf);
+
+    Path viewFsPath1 = new Path("/mounts/mockfs1/a/b/c");
+    Path mockFsPath1 = new Path("/a/b/c");
+    Path viewFsPath2 = new Path("/mounts/mockfs2/d/e/f");
+    Path mockFsPath2 = new Path("/d/e/f");
+    List<AclEntry> entries = Collections.emptyList();
+    EnumSet<AclWriteFlag> writeFlags = EnumSet.noneOf(AclWriteFlag.class);
+    EnumSet<AclReadFlag> readFlags = EnumSet.noneOf(AclReadFlag.class);
+
+    viewFs.modifyAclEntries(viewFsPath1, entries, writeFlags);
+    verify(mockFs1).modifyAclEntries(mockFsPath1, entries, writeFlags);
+    viewFs.modifyAclEntries(viewFsPath2, entries, writeFlags);
+    verify(mockFs2).modifyAclEntries(mockFsPath2, entries, writeFlags);
+
+    viewFs.removeAclEntries(viewFsPath1, entries, writeFlags);
+    verify(mockFs1).removeAclEntries(mockFsPath1, entries, writeFlags);
+    viewFs.removeAclEntries(viewFsPath2, entries, writeFlags);
+    verify(mockFs2).removeAclEntries(mockFsPath2, entries, writeFlags);
+
+    viewFs.removeDefaultAcl(viewFsPath1, writeFlags);
+    verify(mockFs1).removeDefaultAcl(mockFsPath1, writeFlags);
+    viewFs.removeDefaultAcl(viewFsPath2, writeFlags);
+    verify(mockFs2).removeDefaultAcl(mockFsPath2, writeFlags);
+
+    viewFs.removeAcl(viewFsPath1, writeFlags);
+    verify(mockFs1).removeAcl(mockFsPath1, writeFlags);
+    viewFs.removeAcl(viewFsPath2, writeFlags);
+    verify(mockFs2).removeAcl(mockFsPath2, writeFlags);
+
+    viewFs.setAcl(viewFsPath1, entries, writeFlags);
+    verify(mockFs1).setAcl(mockFsPath1, entries, writeFlags);
+    viewFs.setAcl(viewFsPath2, entries, writeFlags);
+    verify(mockFs2).setAcl(mockFsPath2, entries, writeFlags);
+
+    viewFs.listAclStatus(viewFsPath1, readFlags);
+    verify(mockFs1).listAclStatus(mockFsPath1, readFlags);
+    viewFs.listAclStatus(viewFsPath2, readFlags);
+    verify(mockFs2).listAclStatus(mockFsPath2, readFlags);
+  }
+
   void checkVerifyChecksum(boolean flag) {
     viewFs.setVerifyChecksum(flag);
     assertEquals(flag, fs1.getVerifyChecksum());