HDFS-5594. FileSystem API for ACLs. Contributed by Chris Nauroth.
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/HDFS-4685@1549910 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
aff5be250a
commit
b4d8aabe6b
|
@ -25,8 +25,6 @@ import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.security.PrivilegedExceptionAction;
|
import java.security.PrivilegedExceptionAction;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
@ -40,7 +38,6 @@ import java.util.ServiceLoader;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
|
@ -51,6 +48,10 @@ import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.conf.Configured;
|
import org.apache.hadoop.conf.Configured;
|
||||||
import org.apache.hadoop.fs.Options.ChecksumOpt;
|
import org.apache.hadoop.fs.Options.ChecksumOpt;
|
||||||
import org.apache.hadoop.fs.Options.Rename;
|
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.fs.permission.FsPermission;
|
||||||
import org.apache.hadoop.io.MultipleIOException;
|
import org.apache.hadoop.io.MultipleIOException;
|
||||||
import org.apache.hadoop.io.Text;
|
import org.apache.hadoop.io.Text;
|
||||||
|
@ -2269,6 +2270,96 @@ public abstract class FileSystem extends Configured implements Closeable {
|
||||||
+ " doesn't support deleteSnapshot");
|
+ " 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
|
// making it volatile to be able to do a double checked locking
|
||||||
private volatile static boolean FILE_SYSTEMS_LOADED = false;
|
private volatile static boolean FILE_SYSTEMS_LOADED = false;
|
||||||
|
|
||||||
|
|
|
@ -22,9 +22,14 @@ import java.io.*;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.classification.InterfaceStability;
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
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.permission.FsPermission;
|
||||||
import org.apache.hadoop.fs.ContentSummary;
|
import org.apache.hadoop.fs.ContentSummary;
|
||||||
import org.apache.hadoop.fs.Options.ChecksumOpt;
|
import org.apache.hadoop.fs.Options.ChecksumOpt;
|
||||||
|
@ -507,4 +512,40 @@ public class FilterFileSystem extends FileSystem {
|
||||||
throws IOException {
|
throws IOException {
|
||||||
fs.deleteSnapshot(path, snapshotName);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
|
@ -23,8 +23,8 @@ import org.apache.hadoop.classification.InterfaceStability;
|
||||||
/**
|
/**
|
||||||
* File system actions, e.g. read, write, etc.
|
* File system actions, e.g. read, write, etc.
|
||||||
*/
|
*/
|
||||||
@InterfaceAudience.LimitedPrivate({"HDFS"})
|
@InterfaceAudience.Public
|
||||||
@InterfaceStability.Unstable
|
@InterfaceStability.Stable
|
||||||
public enum FsAction {
|
public enum FsAction {
|
||||||
// POSIX style
|
// POSIX style
|
||||||
NONE("---"),
|
NONE("---"),
|
||||||
|
|
|
@ -20,6 +20,7 @@ import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.classification.InterfaceStability;
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
|
@ -36,6 +37,11 @@ import org.apache.hadoop.fs.FilterFileSystem;
|
||||||
import org.apache.hadoop.fs.FsServerDefaults;
|
import org.apache.hadoop.fs.FsServerDefaults;
|
||||||
import org.apache.hadoop.fs.FsStatus;
|
import org.apache.hadoop.fs.FsStatus;
|
||||||
import org.apache.hadoop.fs.Path;
|
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.fs.permission.FsPermission;
|
||||||
import org.apache.hadoop.util.Progressable;
|
import org.apache.hadoop.util.Progressable;
|
||||||
|
|
||||||
|
@ -278,6 +284,42 @@ class ChRootedFileSystem extends FilterFileSystem {
|
||||||
super.setTimes(fullPath(f), mtime, atime);
|
super.setTimes(fullPath(f), mtime, atime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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
|
@Override
|
||||||
public Path resolvePath(final Path p) throws IOException {
|
public Path resolvePath(final Path p) throws IOException {
|
||||||
return super.resolvePath(fullPath(p));
|
return super.resolvePath(fullPath(p));
|
||||||
|
|
|
@ -47,7 +47,12 @@ import org.apache.hadoop.fs.FsConstants;
|
||||||
import org.apache.hadoop.fs.FsServerDefaults;
|
import org.apache.hadoop.fs.FsServerDefaults;
|
||||||
import org.apache.hadoop.fs.InvalidPathException;
|
import org.apache.hadoop.fs.InvalidPathException;
|
||||||
import org.apache.hadoop.fs.Path;
|
import org.apache.hadoop.fs.Path;
|
||||||
|
import org.apache.hadoop.fs.RemoteIterator;
|
||||||
import org.apache.hadoop.fs.UnsupportedFileSystemException;
|
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.permission.FsPermission;
|
||||||
import org.apache.hadoop.fs.viewfs.InodeTree.INode;
|
import org.apache.hadoop.fs.viewfs.InodeTree.INode;
|
||||||
import org.apache.hadoop.fs.viewfs.InodeTree.INodeLink;
|
import org.apache.hadoop.fs.viewfs.InodeTree.INodeLink;
|
||||||
|
@ -473,6 +478,54 @@ public class ViewFileSystem extends FileSystem {
|
||||||
res.targetFileSystem.setTimes(res.remainingPath, mtime, atime);
|
res.targetFileSystem.setTimes(res.remainingPath, mtime, atime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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
|
@Override
|
||||||
public void setVerifyChecksum(final boolean verifyChecksum) {
|
public void setVerifyChecksum(final boolean verifyChecksum) {
|
||||||
List<InodeTree.MountPoint<FileSystem>> mountPoints =
|
List<InodeTree.MountPoint<FileSystem>> mountPoints =
|
||||||
|
|
|
@ -21,6 +21,10 @@ package org.apache.hadoop.fs;
|
||||||
import org.apache.commons.logging.Log;
|
import org.apache.commons.logging.Log;
|
||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
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.permission.FsPermission;
|
||||||
import org.apache.hadoop.security.Credentials;
|
import org.apache.hadoop.security.Credentials;
|
||||||
import org.apache.hadoop.security.token.Token;
|
import org.apache.hadoop.security.token.Token;
|
||||||
|
@ -33,6 +37,7 @@ import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import static org.apache.hadoop.fs.Options.ChecksumOpt;
|
import static org.apache.hadoop.fs.Options.ChecksumOpt;
|
||||||
import static org.apache.hadoop.fs.Options.CreateOpts;
|
import static org.apache.hadoop.fs.Options.CreateOpts;
|
||||||
|
@ -165,6 +170,18 @@ public class TestHarFileSystem {
|
||||||
String snapshotNewName) throws IOException;
|
String snapshotNewName) throws IOException;
|
||||||
public void deleteSnapshot(Path path, String snapshotName)
|
public void deleteSnapshot(Path path, String snapshotName)
|
||||||
throws IOException;
|
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
|
@Test
|
||||||
|
|
|
@ -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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,6 +20,9 @@ package org.apache.hadoop.fs.viewfs;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
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.conf.Configuration;
|
||||||
import org.apache.hadoop.fs.FileStatus;
|
import org.apache.hadoop.fs.FileStatus;
|
||||||
|
@ -29,6 +32,9 @@ import org.apache.hadoop.fs.FileSystemTestHelper;
|
||||||
import org.apache.hadoop.fs.FilterFileSystem;
|
import org.apache.hadoop.fs.FilterFileSystem;
|
||||||
import org.apache.hadoop.fs.FsConstants;
|
import org.apache.hadoop.fs.FsConstants;
|
||||||
import org.apache.hadoop.fs.Path;
|
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.apache.hadoop.fs.viewfs.ChRootedFileSystem;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
@ -354,6 +360,46 @@ public class TestChRootedFileSystem {
|
||||||
new ChRootedFileSystem(chrootUri, conf);
|
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 {
|
static class MockFileSystem extends FilterFileSystem {
|
||||||
MockFileSystem() {
|
MockFileSystem() {
|
||||||
super(mock(FileSystem.class));
|
super(mock(FileSystem.class));
|
||||||
|
|
|
@ -20,14 +20,22 @@ package org.apache.hadoop.fs.viewfs;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
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.conf.Configuration;
|
||||||
import org.apache.hadoop.fs.FileSystem;
|
import org.apache.hadoop.fs.FileSystem;
|
||||||
import org.apache.hadoop.fs.FileSystemTestHelper;
|
import org.apache.hadoop.fs.FileSystemTestHelper;
|
||||||
import org.apache.hadoop.fs.FsConstants;
|
import org.apache.hadoop.fs.FsConstants;
|
||||||
import org.apache.hadoop.fs.LocalFileSystem;
|
import org.apache.hadoop.fs.LocalFileSystem;
|
||||||
import org.apache.hadoop.fs.Path;
|
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 org.junit.*;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify that viewfs propagates certain methods to the underlying fs
|
* Verify that viewfs propagates certain methods to the underlying fs
|
||||||
|
@ -57,6 +65,15 @@ public class TestViewFileSystemDelegation { //extends ViewFileSystemTestSetup {
|
||||||
return fs;
|
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
|
@Test
|
||||||
public void testSanity() {
|
public void testSanity() {
|
||||||
assertEquals("fs1:/", fs1.getUri().toString());
|
assertEquals("fs1:/", fs1.getUri().toString());
|
||||||
|
@ -69,6 +86,57 @@ public class TestViewFileSystemDelegation { //extends ViewFileSystemTestSetup {
|
||||||
checkVerifyChecksum(true);
|
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) {
|
void checkVerifyChecksum(boolean flag) {
|
||||||
viewFs.setVerifyChecksum(flag);
|
viewFs.setVerifyChecksum(flag);
|
||||||
assertEquals(flag, fs1.getVerifyChecksum());
|
assertEquals(flag, fs1.getVerifyChecksum());
|
||||||
|
|
|
@ -7,6 +7,7 @@ HDFS-4685 (Unreleased)
|
||||||
NEW FEATURES
|
NEW FEATURES
|
||||||
|
|
||||||
IMPROVEMENTS
|
IMPROVEMENTS
|
||||||
|
HDFS-5594. FileSystem API for ACLs. (cnauroth)
|
||||||
|
|
||||||
OPTIMIZATIONS
|
OPTIMIZATIONS
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue