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 2014/02/19 19:34:54 UTC

svn commit: r1569870 - in /hadoop/common/trunk/hadoop-common-project/hadoop-common: ./ src/main/docs/ src/main/java/ src/main/java/org/apache/hadoop/fs/ src/main/java/org/apache/hadoop/fs/permission/ src/main/java/org/apache/hadoop/fs/shell/ src/main/j...

Author: cnauroth
Date: Wed Feb 19 18:34:52 2014
New Revision: 1569870

URL: http://svn.apache.org/r1569870
Log:
Merge HDFS-4685 to trunk.

Added:
    hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntry.java
      - copied unchanged from r1569863, hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntry.java
    hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntryScope.java
      - copied unchanged from r1569863, hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntryScope.java
    hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntryType.java
      - copied unchanged from r1569863, hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclEntryType.java
    hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclStatus.java
      - copied unchanged from r1569863, hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/AclStatus.java
    hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/AclCommands.java
      - copied unchanged from r1569863, hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/AclCommands.java
    hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/permission/TestAcl.java
      - copied unchanged from r1569863, hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/permission/TestAcl.java
    hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/TestAclCommands.java
      - copied unchanged from r1569863, hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/shell/TestAclCommands.java
Modified:
    hadoop/common/trunk/hadoop-common-project/hadoop-common/CHANGES.txt   (contents, props changed)
    hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/docs/   (props changed)
    hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/   (props changed)
    hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileSystem.java
    hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FilterFileSystem.java
    hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/RawLocalFileSystem.java
    hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/FsAction.java
    hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/FsCommand.java
    hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/Ls.java
    hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ChRootedFileSystem.java
    hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java
    hadoop/common/trunk/hadoop-common-project/hadoop-common/src/site/apt/FileSystemShell.apt.vm
    hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/core/   (props changed)
    hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestHarFileSystem.java
    hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/permission/TestFsPermission.java
    hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestChRootedFileSystem.java
    hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFileSystemDelegation.java

Modified: hadoop/common/trunk/hadoop-common-project/hadoop-common/CHANGES.txt
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/CHANGES.txt?rev=1569870&r1=1569869&r2=1569870&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/CHANGES.txt (original)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/CHANGES.txt Wed Feb 19 18:34:52 2014
@@ -8,6 +8,9 @@ Trunk (Unreleased)
     FSDataOutputStream.sync() and Syncable.sync().  (szetszwo)
 
   NEW FEATURES
+
+    HADOOP-10184. Hadoop Common changes required to support HDFS ACLs. (See
+    breakdown of tasks below for features and contributors)
     
   IMPROVEMENTS
 
@@ -295,6 +298,34 @@ Trunk (Unreleased)
 
     HADOOP-10044 Improve the javadoc of rpc code (sanjay Radia)
 
+  BREAKDOWN OF HADOOP-10184 SUBTASKS AND RELATED JIRAS
+
+    HADOOP-10185. FileSystem API for ACLs. (cnauroth)
+
+    HADOOP-10186. Remove AclReadFlag and AclWriteFlag in FileSystem API.
+    (Haohui Mai via cnauroth)
+
+    HADOOP-10187. FsShell CLI: add getfacl and setfacl with minimal support for
+    getting and setting ACLs. (Vinay via cnauroth)
+
+    HADOOP-10192. FileSystem#getAclStatus has incorrect JavaDocs. (cnauroth)
+
+    HADOOP-10220. Add ACL indicator bit to FsPermission. (cnauroth)
+
+    HADOOP-10241. Clean up output of FsShell getfacl. (Chris Nauroth via wheat9)
+
+    HADOOP-10213. Fix bugs parsing ACL spec in FsShell setfacl.
+    (Vinay via cnauroth)
+
+    HADOOP-10277. setfacl -x fails to parse ACL spec if trying to remove the
+    mask entry. (Vinay via cnauroth)
+
+    HADOOP-10270. getfacl does not display effective permissions of masked
+    entries. (cnauroth)
+
+    HADOOP-10344. Fix TestAclCommands after merging HADOOP-10338 patch.
+    (cnauroth)
+
   OPTIMIZATIONS
 
     HADOOP-7761. Improve the performance of raw comparisons. (todd)

Propchange: hadoop/common/trunk/hadoop-common-project/hadoop-common/CHANGES.txt
------------------------------------------------------------------------------
  Merged /hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/CHANGES.txt:r1547224-1569863

Propchange: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/docs/
------------------------------------------------------------------------------
  Merged /hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/docs:r1547224-1569863

Propchange: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/
------------------------------------------------------------------------------
  Merged /hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/main/java:r1547224-1569863

Modified: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileSystem.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileSystem.java?rev=1569870&r1=1569869&r2=1569870&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileSystem.java (original)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FileSystem.java Wed Feb 19 18:34:52 2014
@@ -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,8 @@ 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.AclStatus;
 import org.apache.hadoop.fs.permission.FsPermission;
 import org.apache.hadoop.io.MultipleIOException;
 import org.apache.hadoop.io.Text;
@@ -2269,6 +2268,88 @@ 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
+   * @throws IOException if an ACL could not be modified
+   */
+  public void modifyAclEntries(Path path, List<AclEntry> aclSpec)
+      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
+   * @throws IOException if an ACL could not be modified
+   */
+  public void removeAclEntries(Path path, List<AclEntry> aclSpec)
+      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
+   * @throws IOException if an ACL could not be modified
+   */
+  public void removeDefaultAcl(Path path)
+      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
+   * @throws IOException if an ACL could not be removed
+   */
+  public void removeAcl(Path path)
+      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.
+   * @throws IOException if an ACL could not be modified
+   */
+  public void setAcl(Path path, List<AclEntry> aclSpec) throws IOException {
+    throw new UnsupportedOperationException(getClass().getSimpleName()
+        + " doesn't support setAcl");
+  }
+
+  /**
+   * Gets the ACL of a file or directory.
+   *
+   * @param path Path to get
+   * @return AclStatus describing the ACL of the file or directory
+   * @throws IOException if an ACL could not be read
+   */
+  public AclStatus getAclStatus(Path path) throws IOException {
+    throw new UnsupportedOperationException(getClass().getSimpleName()
+        + " doesn't support getAclStatus");
+  }
+
   // making it volatile to be able to do a double checked locking
   private volatile static boolean FILE_SYSTEMS_LOADED = false;
 

Modified: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FilterFileSystem.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FilterFileSystem.java?rev=1569870&r1=1569869&r2=1569870&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FilterFileSystem.java (original)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/FilterFileSystem.java Wed Feb 19 18:34:52 2014
@@ -22,9 +22,13 @@ 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.AclStatus;
 import org.apache.hadoop.fs.permission.FsPermission;
 import org.apache.hadoop.fs.ContentSummary;
 import org.apache.hadoop.fs.Options.ChecksumOpt;
@@ -507,4 +511,36 @@ public class FilterFileSystem extends Fi
       throws IOException {
     fs.deleteSnapshot(path, snapshotName);
   }
+
+  @Override
+  public void modifyAclEntries(Path path, List<AclEntry> aclSpec)
+      throws IOException {
+    fs.modifyAclEntries(path, aclSpec);
+  }
+
+  @Override
+  public void removeAclEntries(Path path, List<AclEntry> aclSpec)
+      throws IOException {
+    fs.removeAclEntries(path, aclSpec);
+  }
+
+  @Override
+  public void removeDefaultAcl(Path path) throws IOException {
+    fs.removeDefaultAcl(path);
+  }
+
+  @Override
+  public void removeAcl(Path path) throws IOException {
+    fs.removeAcl(path);
+  }
+
+  @Override
+  public void setAcl(Path path, List<AclEntry> aclSpec) throws IOException {
+    fs.setAcl(path, aclSpec);
+  }
+
+  @Override
+  public AclStatus getAclStatus(Path path) throws IOException {
+    return fs.getAclStatus(path);
+  }
 }

Modified: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/RawLocalFileSystem.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/RawLocalFileSystem.java?rev=1569870&r1=1569869&r2=1569870&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/RawLocalFileSystem.java (original)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/RawLocalFileSystem.java Wed Feb 19 18:34:52 2014
@@ -569,9 +569,6 @@ public class RawLocalFileSystem extends 
         //expected format
         //-rw-------    1 username groupname ...
         String permission = t.nextToken();
-        if (permission.length() > 10) { //files with ACLs might have a '+'
-          permission = permission.substring(0, 10);
-        }
         setPermission(FsPermission.valueOf(permission));
         t.nextToken();
 

Modified: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/FsAction.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/FsAction.java?rev=1569870&r1=1569869&r2=1569870&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/FsAction.java (original)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/permission/FsAction.java Wed Feb 19 18:34:52 2014
@@ -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("---"),
@@ -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;
+  }
 }

Modified: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/FsCommand.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/FsCommand.java?rev=1569870&r1=1569869&r2=1569870&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/FsCommand.java (original)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/FsCommand.java Wed Feb 19 18:34:52 2014
@@ -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);

Modified: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/Ls.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/Ls.java?rev=1569870&r1=1569869&r2=1569870&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/Ls.java (original)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/Ls.java Wed Feb 19 18:34:52 2014
@@ -19,15 +19,22 @@
 package org.apache.hadoop.fs.shell;
 
 import java.io.IOException;
+import java.net.URI;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.LinkedList;
+import java.util.Set;
 import org.apache.hadoop.util.StringUtils;
 
 import org.apache.hadoop.classification.InterfaceAudience;
 import org.apache.hadoop.classification.InterfaceStability;
 import org.apache.hadoop.fs.FileStatus;
+import org.apache.hadoop.fs.FileSystem;
 import org.apache.hadoop.fs.Path;
+import org.apache.hadoop.ipc.RemoteException;
+import org.apache.hadoop.ipc.RpcNoSuchMethodException;
+
+import com.google.common.collect.Sets;
 
 /**
  * Get a listing of all files in that match the file patterns.
@@ -60,11 +67,14 @@ class Ls extends FsCommand {
   protected static final SimpleDateFormat dateFormat = 
     new SimpleDateFormat("yyyy-MM-dd HH:mm");
 
-  protected int maxRepl = 3, maxLen = 10, maxOwner = 0, maxGroup = 0;
+  protected int maxPerm = 9, maxRepl = 3, maxLen = 10, maxOwner = 0,
+    maxGroup = 0;
   protected String lineFormat;
   protected boolean dirRecurse;
 
   protected boolean humanReadable = false;
+  private Set<URI> aclNotSupportedFsSet = Sets.newHashSet();
+
   protected String formatSize(long size) {
     return humanReadable
       ? StringUtils.TraditionalBinaryPrefix.long2String(size, "", 1)
@@ -107,7 +117,7 @@ class Ls extends FsCommand {
     FileStatus stat = item.stat;
     String line = String.format(lineFormat,
         (stat.isDirectory() ? "d" : "-"),
-        stat.getPermission(),
+        stat.getPermission() + (hasAcl(item) ? "+" : ""),
         (stat.isFile() ? stat.getReplication() : "-"),
         stat.getOwner(),
         stat.getGroup(),
@@ -125,6 +135,7 @@ class Ls extends FsCommand {
   private void adjustColumnWidths(PathData items[]) {
     for (PathData item : items) {
       FileStatus stat = item.stat;
+      maxPerm  = maxLength(maxPerm, stat.getPermission());
       maxRepl  = maxLength(maxRepl, stat.getReplication());
       maxLen   = maxLength(maxLen, stat.getLen());
       maxOwner = maxLength(maxOwner, stat.getOwner());
@@ -132,7 +143,7 @@ class Ls extends FsCommand {
     }
 
     StringBuilder fmt = new StringBuilder();
-    fmt.append("%s%s "); // permission string
+    fmt.append("%s%-" + maxPerm + "s "); // permission string
     fmt.append("%"  + maxRepl  + "s ");
     // Do not use '%-0s' as a formatting conversion, since it will throw a
     // a MissingFormatWidthException if it is used in String.format().
@@ -144,6 +155,49 @@ class Ls extends FsCommand {
     lineFormat = fmt.toString();
   }
 
+  /**
+   * Calls getAclStatus to determine if the given item has an ACL.  For
+   * compatibility, this method traps errors caused by the RPC method missing
+   * from the server side.  This would happen if the client was connected to an
+   * old NameNode that didn't have the ACL APIs.  This method also traps the
+   * case of the client-side FileSystem not implementing the ACL APIs.
+   * FileSystem instances that do not support ACLs are remembered.  This
+   * prevents the client from sending multiple failing RPC calls during a
+   * recursive ls.
+   *
+   * @param item PathData item to check
+   * @return boolean true if item has an ACL
+   * @throws IOException if there is a failure
+   */
+  private boolean hasAcl(PathData item) throws IOException {
+    FileSystem fs = item.fs;
+    if (aclNotSupportedFsSet.contains(fs.getUri())) {
+      // This FileSystem failed to run the ACL API in an earlier iteration.
+      return false;
+    }
+    try {
+      return !fs.getAclStatus(item.path).getEntries().isEmpty();
+    } catch (RemoteException e) {
+      // If this is a RpcNoSuchMethodException, then the client is connected to
+      // an older NameNode that doesn't support ACLs.  Keep going.
+      IOException e2 = e.unwrapRemoteException(RpcNoSuchMethodException.class);
+      if (!(e2 instanceof RpcNoSuchMethodException)) {
+        throw e;
+      }
+    } catch (IOException e) {
+      // The NameNode supports ACLs, but they are not enabled.  Keep going.
+      String message = e.getMessage();
+      if (message != null && !message.contains("ACLs has been disabled")) {
+        throw e;
+      }
+    } catch (UnsupportedOperationException e) {
+      // The underlying FileSystem doesn't implement ACLs.  Keep going.
+    }
+    // Remember that this FileSystem cannot support ACLs.
+    aclNotSupportedFsSet.add(fs.getUri());
+    return false;
+  }
+
   private int maxLength(int n, Object value) {
     return Math.max(n, (value != null) ? String.valueOf(value).length() : 0);
   }

Modified: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ChRootedFileSystem.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ChRootedFileSystem.java?rev=1569870&r1=1569869&r2=1569870&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ChRootedFileSystem.java (original)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ChRootedFileSystem.java Wed Feb 19 18:34:52 2014
@@ -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,8 @@ 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.permission.AclEntry;
+import org.apache.hadoop.fs.permission.AclStatus;
 import org.apache.hadoop.fs.permission.FsPermission;
 import org.apache.hadoop.util.Progressable;
 
@@ -277,7 +280,39 @@ class ChRootedFileSystem extends FilterF
       throws IOException {
     super.setTimes(fullPath(f), mtime, atime);
   }
-  
+
+  @Override
+  public void modifyAclEntries(Path path, List<AclEntry> aclSpec)
+      throws IOException {
+    super.modifyAclEntries(fullPath(path), aclSpec);
+  }
+
+  @Override
+  public void removeAclEntries(Path path, List<AclEntry> aclSpec)
+      throws IOException {
+    super.removeAclEntries(fullPath(path), aclSpec);
+  }
+
+  @Override
+  public void removeDefaultAcl(Path path) throws IOException {
+    super.removeDefaultAcl(fullPath(path));
+  }
+
+  @Override
+  public void removeAcl(Path path) throws IOException {
+    super.removeAcl(fullPath(path));
+  }
+
+  @Override
+  public void setAcl(Path path, List<AclEntry> aclSpec) throws IOException {
+    super.setAcl(fullPath(path), aclSpec);
+  }
+
+  @Override
+  public AclStatus getAclStatus(Path path) throws IOException {
+    return super.getAclStatus(fullPath(path));
+  }
+
   @Override
   public Path resolvePath(final Path p) throws IOException {
     return super.resolvePath(fullPath(p));

Modified: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java?rev=1569870&r1=1569869&r2=1569870&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java (original)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/viewfs/ViewFileSystem.java Wed Feb 19 18:34:52 2014
@@ -28,7 +28,6 @@ import java.util.EnumSet;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-import java.util.StringTokenizer;
 import java.util.Map.Entry;
 
 import org.apache.hadoop.classification.InterfaceAudience;
@@ -45,9 +44,10 @@ import org.apache.hadoop.fs.FileStatus;
 import org.apache.hadoop.fs.FileSystem;
 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.UnsupportedFileSystemException;
+import org.apache.hadoop.fs.permission.AclEntry;
+import org.apache.hadoop.fs.permission.AclStatus;
 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 +474,52 @@ public class ViewFileSystem extends File
   }
 
   @Override
+  public void modifyAclEntries(Path path, List<AclEntry> aclSpec)
+      throws IOException {
+    InodeTree.ResolveResult<FileSystem> res = fsState.resolve(getUriPath(path),
+        true);
+    res.targetFileSystem.modifyAclEntries(res.remainingPath, aclSpec);
+  }
+
+  @Override
+  public void removeAclEntries(Path path, List<AclEntry> aclSpec)
+      throws IOException {
+    InodeTree.ResolveResult<FileSystem> res = fsState.resolve(getUriPath(path),
+        true);
+    res.targetFileSystem.removeAclEntries(res.remainingPath, aclSpec);
+  }
+
+  @Override
+  public void removeDefaultAcl(Path path)
+      throws IOException {
+    InodeTree.ResolveResult<FileSystem> res =
+      fsState.resolve(getUriPath(path), true);
+    res.targetFileSystem.removeDefaultAcl(res.remainingPath);
+  }
+
+  @Override
+  public void removeAcl(Path path)
+      throws IOException {
+    InodeTree.ResolveResult<FileSystem> res =
+      fsState.resolve(getUriPath(path), true);
+    res.targetFileSystem.removeAcl(res.remainingPath);
+  }
+
+  @Override
+  public void setAcl(Path path, List<AclEntry> aclSpec) throws IOException {
+    InodeTree.ResolveResult<FileSystem> res =
+      fsState.resolve(getUriPath(path), true);
+    res.targetFileSystem.setAcl(res.remainingPath, aclSpec);
+  }
+
+  @Override
+  public AclStatus getAclStatus(Path path) throws IOException {
+    InodeTree.ResolveResult<FileSystem> res =
+      fsState.resolve(getUriPath(path), true);
+    return res.targetFileSystem.getAclStatus(res.remainingPath);
+  }
+
+  @Override
   public void setVerifyChecksum(final boolean verifyChecksum) { 
     List<InodeTree.MountPoint<FileSystem>> mountPoints = 
         fsState.getMountPoints();

Modified: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/site/apt/FileSystemShell.apt.vm
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/site/apt/FileSystemShell.apt.vm?rev=1569870&r1=1569869&r2=1569870&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/site/apt/FileSystemShell.apt.vm (original)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/site/apt/FileSystemShell.apt.vm Wed Feb 19 18:34:52 2014
@@ -231,6 +231,29 @@ get
 
    Returns 0 on success and -1 on error.
 
+getfacl
+
+   Usage: <<<hdfs dfs -getfacl [-R] <path> >>>
+
+   Displays the Access Control Lists (ACLs) of files and directories. If a
+   directory has a default ACL, then getfacl also displays the default ACL.
+
+   Options:
+
+     * -R: List the ACLs of all files and directories recursively.
+
+     * <path>: File or directory to list.
+
+   Examples:
+
+     * <<<hdfs dfs -getfacl /file>>>
+
+     * <<<hdfs dfs -getfacl -R /dir>>>
+
+   Exit Code:
+
+   Returns 0 on success and non-zero on error.
+
 getmerge
 
    Usage: <<<hdfs dfs -getmerge <src> <localdst> [addnl]>>>
@@ -379,6 +402,54 @@ rmr
 
    Returns 0 on success and -1 on error.
 
+setfacl
+
+   Usage: <<<hdfs dfs -setfacl [-R] [{-b|-k} {-m|-x <acl_spec>} <path>]|[--set <acl_spec> <path>] >>>
+
+   Sets Access Control Lists (ACLs) of files and directories.
+
+   Options:
+
+     * -b: Remove all but the base ACL entries. The entries for user, group and
+       others are retained for compatibility with permission bits.
+
+     * -k: Remove the default ACL.
+
+     * -R: Apply operations to all files and directories recursively.
+
+     * -m: Modify ACL. New entries are added to the ACL, and existing entries
+       are retained.
+
+     * -x: Remove specified ACL entries. Other ACL entries are retained.
+
+     * --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.
+
+     * <acl_spec>: Comma separated list of ACL entries.
+
+     * <path>: File or directory to modify.
+
+   Examples:
+
+      * <<<hdfs dfs -setfacl -m user:hadoop:rw- /file>>>
+
+      * <<<hdfs dfs -setfacl -x user:hadoop /file>>>
+
+      * <<<hdfs dfs -setfacl -b /file>>>
+
+      * <<<hdfs dfs -setfacl -k /dir>>>
+
+      * <<<hdfs dfs -setfacl --set user::rw-,user:hadoop:rw-,group::r--,other::r-- /file>>>
+
+      * <<<hdfs dfs -setfacl -R -m user:hadoop:r-x /dir>>>
+
+      * <<<hdfs dfs -setfacl -m default:user:hadoop:r-x /dir>>>
+
+   Exit Code:
+
+   Returns 0 on success and non-zero on error.
+
 setrep
 
    Usage: <<<hdfs dfs -setrep [-R] [-w] <numReplicas> <path> >>>

Propchange: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/core/
------------------------------------------------------------------------------
  Merged /hadoop/common/branches/HDFS-4685/hadoop-common-project/hadoop-common/src/test/core:r1547224-1569863

Modified: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestHarFileSystem.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestHarFileSystem.java?rev=1569870&r1=1569869&r2=1569870&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestHarFileSystem.java (original)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/TestHarFileSystem.java Wed Feb 19 18:34:52 2014
@@ -21,6 +21,8 @@ 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.AclStatus;
 import org.apache.hadoop.fs.permission.FsPermission;
 import org.apache.hadoop.security.Credentials;
 import org.apache.hadoop.security.token.Token;
@@ -33,6 +35,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 +168,20 @@ public class TestHarFileSystem {
         String snapshotNewName) throws IOException;
     public void deleteSnapshot(Path path, String snapshotName)
         throws IOException;
+
+    public void modifyAclEntries(Path path, List<AclEntry> aclSpec)
+        throws IOException;
+
+    public void removeAclEntries(Path path, List<AclEntry> aclSpec)
+        throws IOException;
+
+    public void removeDefaultAcl(Path path) throws IOException;
+
+    public void removeAcl(Path path) throws IOException;
+
+    public void setAcl(Path path, List<AclEntry> aclSpec) throws IOException;
+
+    public AclStatus getAclStatus(Path path) throws IOException;
   }
 
   @Test

Modified: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/permission/TestFsPermission.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/permission/TestFsPermission.java?rev=1569870&r1=1569869&r2=1569870&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/permission/TestFsPermission.java (original)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/permission/TestFsPermission.java Wed Feb 19 18:34:52 2014
@@ -54,7 +54,7 @@ public class TestFsPermission extends Te
    * the expected values back out for all combinations
    */
   public void testConvertingPermissions() {
-    for(short s = 0; s < 01777; s++) {
+    for(short s = 0; s <= 01777; s++) {
       assertEquals(s, new FsPermission(s).toShort());
     }
 
@@ -64,10 +64,12 @@ public class TestFsPermission extends Te
       for(FsAction u : FsAction.values()) {
         for(FsAction g : FsAction.values()) {
           for(FsAction o : FsAction.values()) {
+            // Cover constructor with sticky bit.
             FsPermission f = new FsPermission(u, g, o, sb);
             assertEquals(s, f.toShort());
             FsPermission f2 = new FsPermission(f);
             assertEquals(s, f2.toShort());
+
             s++;
           }
         }
@@ -75,48 +77,57 @@ public class TestFsPermission extends Te
     }
   }
 
-  public void testStickyBitToString() {
-    // Check that every permission has its sticky bit represented correctly
-    for(boolean sb : new boolean [] { false, true }) {
-      for(FsAction u : FsAction.values()) {
-        for(FsAction g : FsAction.values()) {
-          for(FsAction o : FsAction.values()) {
+  public void testSpecialBitsToString() {
+    for (boolean sb : new boolean[] { false, true }) {
+      for (FsAction u : FsAction.values()) {
+        for (FsAction g : FsAction.values()) {
+          for (FsAction o : FsAction.values()) {
             FsPermission f = new FsPermission(u, g, o, sb);
-            if(f.getStickyBit() && f.getOtherAction().implies(EXECUTE))
-              assertEquals('t', f.toString().charAt(8));
-            else if(f.getStickyBit() && !f.getOtherAction().implies(EXECUTE))
-              assertEquals('T', f.toString().charAt(8));
-            else if(!f.getStickyBit()  && f.getOtherAction().implies(EXECUTE))
-              assertEquals('x', f.toString().charAt(8));
+            String fString = f.toString();
+
+            // Check that sticky bit is represented correctly.
+            if (f.getStickyBit() && f.getOtherAction().implies(EXECUTE))
+              assertEquals('t', fString.charAt(8));
+            else if (f.getStickyBit() && !f.getOtherAction().implies(EXECUTE))
+              assertEquals('T', fString.charAt(8));
+            else if (!f.getStickyBit() && f.getOtherAction().implies(EXECUTE))
+              assertEquals('x', fString.charAt(8));
             else
-              assertEquals('-', f.toString().charAt(8));
+              assertEquals('-', fString.charAt(8));
+
+            assertEquals(9, fString.length());
           }
         }
+
       }
     }
   }
 
   public void testFsPermission() {
-      String symbolic = "-rwxrwxrwx";
-      StringBuilder b = new StringBuilder("-123456789");
-
-      for(int i = 0; i < (1<<9); i++) {
-        for(int j = 1; j < 10; j++) {
-          b.setCharAt(j, '-');
-        }
-        String binary = Integer.toBinaryString(i);
+    String symbolic = "-rwxrwxrwx";
 
-        int len = binary.length();
-        for(int j = 0; j < len; j++) {
-          if (binary.charAt(j) == '1') {
-            int k = 9 - (len - 1 - j);
-            b.setCharAt(k, symbolic.charAt(k));
-          }
+    for(int i = 0; i < (1 << 10); i++) {
+      StringBuilder b = new StringBuilder("----------");
+      String binary = String.format("%11s", Integer.toBinaryString(i));
+      String permBinary = binary.substring(2, binary.length());
+
+      int len = permBinary.length();
+      for(int j = 0; j < len; j++) {
+        if (permBinary.charAt(j) == '1') {
+          int k = 9 - (len - 1 - j);
+          b.setCharAt(k, symbolic.charAt(k));
         }
+      }
 
-        assertEquals(i, FsPermission.valueOf(b.toString()).toShort());
+      // Check for sticky bit.
+      if (binary.charAt(1) == '1') {
+        char replacement = b.charAt(9) == 'x' ? 't' : 'T';
+        b.setCharAt(9, replacement);
       }
+
+      assertEquals(i, FsPermission.valueOf(b.toString()).toShort());
     }
+  }
 
   public void testUMaskParser() throws IOException {
     Configuration conf = new Configuration();

Modified: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestChRootedFileSystem.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestChRootedFileSystem.java?rev=1569870&r1=1569869&r2=1569870&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestChRootedFileSystem.java (original)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestChRootedFileSystem.java Wed Feb 19 18:34:52 2014
@@ -20,6 +20,8 @@ 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.List;
 
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.fs.FileStatus;
@@ -29,6 +31,7 @@ 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.viewfs.ChRootedFileSystem;
 import org.junit.After;
 import org.junit.Assert;
@@ -354,6 +357,44 @@ 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();
+
+    chrootFs.modifyAclEntries(chrootPath, entries);
+    verify(mockFs).modifyAclEntries(rawPath, entries);
+
+    chrootFs.removeAclEntries(chrootPath, entries);
+    verify(mockFs).removeAclEntries(rawPath, entries);
+
+    chrootFs.removeDefaultAcl(chrootPath);
+    verify(mockFs).removeDefaultAcl(rawPath);
+
+    chrootFs.removeAcl(chrootPath);
+    verify(mockFs).removeAcl(rawPath);
+
+    chrootFs.setAcl(chrootPath, entries);
+    verify(mockFs).setAcl(rawPath, entries);
+
+    chrootFs.getAclStatus(chrootPath);
+    verify(mockFs).getAclStatus(rawPath);
+  }
+
   static class MockFileSystem extends FilterFileSystem {
     MockFileSystem() {
       super(mock(FileSystem.class));
@@ -361,4 +402,4 @@ public class TestChRootedFileSystem {
     @Override
     public void initialize(URI name, Configuration conf) throws IOException {}
   }
-}
\ No newline at end of file
+}

Modified: hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFileSystemDelegation.java
URL: http://svn.apache.org/viewvc/hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFileSystemDelegation.java?rev=1569870&r1=1569869&r2=1569870&view=diff
==============================================================================
--- hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFileSystemDelegation.java (original)
+++ hadoop/common/trunk/hadoop-common-project/hadoop-common/src/test/java/org/apache/hadoop/fs/viewfs/TestViewFileSystemDelegation.java Wed Feb 19 18:34:52 2014
@@ -20,14 +20,19 @@ package org.apache.hadoop.fs.viewfs;
 
 import java.io.IOException;
 import java.net.URI;
+import java.util.Collections;
+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.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 +62,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 +83,55 @@ 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();
+
+    viewFs.modifyAclEntries(viewFsPath1, entries);
+    verify(mockFs1).modifyAclEntries(mockFsPath1, entries);
+    viewFs.modifyAclEntries(viewFsPath2, entries);
+    verify(mockFs2).modifyAclEntries(mockFsPath2, entries);
+
+    viewFs.removeAclEntries(viewFsPath1, entries);
+    verify(mockFs1).removeAclEntries(mockFsPath1, entries);
+    viewFs.removeAclEntries(viewFsPath2, entries);
+    verify(mockFs2).removeAclEntries(mockFsPath2, entries);
+
+    viewFs.removeDefaultAcl(viewFsPath1);
+    verify(mockFs1).removeDefaultAcl(mockFsPath1);
+    viewFs.removeDefaultAcl(viewFsPath2);
+    verify(mockFs2).removeDefaultAcl(mockFsPath2);
+
+    viewFs.removeAcl(viewFsPath1);
+    verify(mockFs1).removeAcl(mockFsPath1);
+    viewFs.removeAcl(viewFsPath2);
+    verify(mockFs2).removeAcl(mockFsPath2);
+
+    viewFs.setAcl(viewFsPath1, entries);
+    verify(mockFs1).setAcl(mockFsPath1, entries);
+    viewFs.setAcl(viewFsPath2, entries);
+    verify(mockFs2).setAcl(mockFsPath2, entries);
+
+    viewFs.getAclStatus(viewFsPath1);
+    verify(mockFs1).getAclStatus(mockFsPath1);
+    viewFs.getAclStatus(viewFsPath2);
+    verify(mockFs2).getAclStatus(mockFsPath2);
+  }
+
   void checkVerifyChecksum(boolean flag) {
     viewFs.setVerifyChecksum(flag);
     assertEquals(flag, fs1.getVerifyChecksum());