HDFS-6962. ACL inheritance conflicts with umaskmode. Contributed by Chris Nauroth.
This commit is contained in:
parent
d37dc5d1b8
commit
f0d5382ff3
|
@ -46,6 +46,7 @@ import org.apache.hadoop.fs.Options.CreateOpts;
|
||||||
import org.apache.hadoop.fs.permission.AclEntry;
|
import org.apache.hadoop.fs.permission.AclEntry;
|
||||||
import org.apache.hadoop.fs.permission.AclStatus;
|
import org.apache.hadoop.fs.permission.AclStatus;
|
||||||
import org.apache.hadoop.fs.permission.FsAction;
|
import org.apache.hadoop.fs.permission.FsAction;
|
||||||
|
import org.apache.hadoop.fs.permission.FsCreateModes;
|
||||||
import org.apache.hadoop.fs.permission.FsPermission;
|
import org.apache.hadoop.fs.permission.FsPermission;
|
||||||
import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.FS_DEFAULT_NAME_KEY;
|
import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.FS_DEFAULT_NAME_KEY;
|
||||||
import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.FS_DEFAULT_NAME_DEFAULT;
|
import static org.apache.hadoop.fs.CommonConfigurationKeysPublic.FS_DEFAULT_NAME_DEFAULT;
|
||||||
|
@ -671,7 +672,7 @@ public class FileContext {
|
||||||
CreateOpts.Perms permOpt = CreateOpts.getOpt(CreateOpts.Perms.class, opts);
|
CreateOpts.Perms permOpt = CreateOpts.getOpt(CreateOpts.Perms.class, opts);
|
||||||
FsPermission permission = (permOpt != null) ? permOpt.getValue() :
|
FsPermission permission = (permOpt != null) ? permOpt.getValue() :
|
||||||
FILE_DEFAULT_PERM;
|
FILE_DEFAULT_PERM;
|
||||||
permission = permission.applyUMask(getUMask());
|
permission = FsCreateModes.applyUMask(permission, getUMask());
|
||||||
|
|
||||||
final CreateOpts[] updatedOpts =
|
final CreateOpts[] updatedOpts =
|
||||||
CreateOpts.setOpt(CreateOpts.perms(permission), opts);
|
CreateOpts.setOpt(CreateOpts.perms(permission), opts);
|
||||||
|
@ -717,8 +718,9 @@ public class FileContext {
|
||||||
ParentNotDirectoryException, UnsupportedFileSystemException,
|
ParentNotDirectoryException, UnsupportedFileSystemException,
|
||||||
IOException {
|
IOException {
|
||||||
final Path absDir = fixRelativePart(dir);
|
final Path absDir = fixRelativePart(dir);
|
||||||
final FsPermission absFerms = (permission == null ?
|
final FsPermission absFerms = FsCreateModes.applyUMask(
|
||||||
FsPermission.getDirDefault() : permission).applyUMask(getUMask());
|
permission == null ?
|
||||||
|
FsPermission.getDirDefault() : permission, getUMask());
|
||||||
new FSLinkResolver<Void>() {
|
new FSLinkResolver<Void>() {
|
||||||
@Override
|
@Override
|
||||||
public Void next(final AbstractFileSystem fs, final Path p)
|
public Void next(final AbstractFileSystem fs, final Path p)
|
||||||
|
|
|
@ -54,6 +54,7 @@ import org.apache.hadoop.fs.Options.Rename;
|
||||||
import org.apache.hadoop.fs.permission.AclEntry;
|
import org.apache.hadoop.fs.permission.AclEntry;
|
||||||
import org.apache.hadoop.fs.permission.AclStatus;
|
import org.apache.hadoop.fs.permission.AclStatus;
|
||||||
import org.apache.hadoop.fs.permission.FsAction;
|
import org.apache.hadoop.fs.permission.FsAction;
|
||||||
|
import org.apache.hadoop.fs.permission.FsCreateModes;
|
||||||
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;
|
||||||
|
@ -925,9 +926,9 @@ public abstract class FileSystem extends Configured implements Closeable {
|
||||||
long blockSize,
|
long blockSize,
|
||||||
Progressable progress
|
Progressable progress
|
||||||
) throws IOException {
|
) throws IOException {
|
||||||
return this.create(f, FsPermission.getFileDefault().applyUMask(
|
return this.create(f, FsCreateModes.applyUMask(
|
||||||
FsPermission.getUMask(getConf())), overwrite, bufferSize,
|
FsPermission.getFileDefault(), FsPermission.getUMask(getConf())),
|
||||||
replication, blockSize, progress);
|
overwrite, bufferSize, replication, blockSize, progress);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
/**
|
||||||
|
* 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.text.MessageFormat;
|
||||||
|
|
||||||
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class that stores both masked and unmasked create modes
|
||||||
|
* and is a drop-in replacement for masked permission.
|
||||||
|
*/
|
||||||
|
@InterfaceAudience.Public
|
||||||
|
@InterfaceStability.Evolving
|
||||||
|
public final class FsCreateModes extends FsPermission {
|
||||||
|
private final FsPermission unmasked;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create from unmasked mode and umask.
|
||||||
|
*
|
||||||
|
* If the mode is already an FsCreateModes object, return it.
|
||||||
|
*/
|
||||||
|
public static FsPermission applyUMask(FsPermission mode,
|
||||||
|
FsPermission umask) {
|
||||||
|
if (mode.getUnmasked() != null) {
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
return create(mode.applyUMask(umask), mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create from masked and unmasked modes.
|
||||||
|
*/
|
||||||
|
public static FsCreateModes create(FsPermission masked,
|
||||||
|
FsPermission unmasked) {
|
||||||
|
assert masked.getUnmasked() == null;
|
||||||
|
assert unmasked.getUnmasked() == null;
|
||||||
|
return new FsCreateModes(masked, unmasked);
|
||||||
|
}
|
||||||
|
|
||||||
|
private FsCreateModes(FsPermission masked, FsPermission unmasked) {
|
||||||
|
super(masked);
|
||||||
|
this.unmasked = unmasked;
|
||||||
|
assert masked.getUnmasked() == null;
|
||||||
|
assert unmasked.getUnmasked() == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FsPermission getMasked() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FsPermission getUnmasked() {
|
||||||
|
return unmasked;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return MessageFormat.format("'{' masked: {0}, unmasked: {1} '}'",
|
||||||
|
super.toString(), getUnmasked());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!super.equals(o)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
FsCreateModes that = (FsCreateModes) o;
|
||||||
|
return getUnmasked().equals(that.getUnmasked());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = super.hashCode();
|
||||||
|
result = 31 * result + getUnmasked().hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -137,6 +137,20 @@ public class FsPermission implements Writable {
|
||||||
fromShort(in.readShort());
|
fromShort(in.readShort());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get masked permission if exists.
|
||||||
|
*/
|
||||||
|
public FsPermission getMasked() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get unmasked permission if exists.
|
||||||
|
*/
|
||||||
|
public FsPermission getUnmasked() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create and initialize a {@link FsPermission} from {@link DataInput}.
|
* Create and initialize a {@link FsPermission} from {@link DataInput}.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* This package provides support for HDFS permission and ACL.
|
||||||
|
*/
|
||||||
|
@InterfaceAudience.Private
|
||||||
|
@InterfaceStability.Unstable
|
||||||
|
package org.apache.hadoop.fs.permission;
|
||||||
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
|
import org.apache.hadoop.classification.InterfaceStability;
|
|
@ -90,6 +90,7 @@ import org.apache.hadoop.fs.XAttrSetFlag;
|
||||||
import org.apache.hadoop.fs.permission.AclEntry;
|
import org.apache.hadoop.fs.permission.AclEntry;
|
||||||
import org.apache.hadoop.fs.permission.AclStatus;
|
import org.apache.hadoop.fs.permission.AclStatus;
|
||||||
import org.apache.hadoop.fs.permission.FsAction;
|
import org.apache.hadoop.fs.permission.FsAction;
|
||||||
|
import org.apache.hadoop.fs.permission.FsCreateModes;
|
||||||
import org.apache.hadoop.fs.permission.FsPermission;
|
import org.apache.hadoop.fs.permission.FsPermission;
|
||||||
import org.apache.hadoop.hdfs.NameNodeProxiesClient.ProxyAndInfo;
|
import org.apache.hadoop.hdfs.NameNodeProxiesClient.ProxyAndInfo;
|
||||||
import org.apache.hadoop.hdfs.client.HdfsClientConfigKeys;
|
import org.apache.hadoop.hdfs.client.HdfsClientConfigKeys;
|
||||||
|
@ -1160,14 +1161,14 @@ public class DFSClient implements java.io.Closeable, RemotePeerFactory,
|
||||||
if (permission == null) {
|
if (permission == null) {
|
||||||
permission = FsPermission.getFileDefault();
|
permission = FsPermission.getFileDefault();
|
||||||
}
|
}
|
||||||
return permission.applyUMask(dfsClientConf.getUMask());
|
return FsCreateModes.applyUMask(permission, dfsClientConf.getUMask());
|
||||||
}
|
}
|
||||||
|
|
||||||
private FsPermission applyUMaskDir(FsPermission permission) {
|
private FsPermission applyUMaskDir(FsPermission permission) {
|
||||||
if (permission == null) {
|
if (permission == null) {
|
||||||
permission = FsPermission.getDirDefault();
|
permission = FsPermission.getDirDefault();
|
||||||
}
|
}
|
||||||
return permission.applyUMask(dfsClientConf.getUMask());
|
return FsCreateModes.applyUMask(permission, dfsClientConf.getUMask());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -294,6 +294,10 @@ public class ClientNamenodeProtocolTranslatorPB implements
|
||||||
.setCreateParent(createParent)
|
.setCreateParent(createParent)
|
||||||
.setReplication(replication)
|
.setReplication(replication)
|
||||||
.setBlockSize(blockSize);
|
.setBlockSize(blockSize);
|
||||||
|
FsPermission unmasked = masked.getUnmasked();
|
||||||
|
if (unmasked != null) {
|
||||||
|
builder.setUnmasked(PBHelperClient.convert(unmasked));
|
||||||
|
}
|
||||||
builder.addAllCryptoProtocolVersion(
|
builder.addAllCryptoProtocolVersion(
|
||||||
PBHelperClient.convert(supportedVersions));
|
PBHelperClient.convert(supportedVersions));
|
||||||
CreateRequestProto req = builder.build();
|
CreateRequestProto req = builder.build();
|
||||||
|
@ -579,11 +583,15 @@ public class ClientNamenodeProtocolTranslatorPB implements
|
||||||
@Override
|
@Override
|
||||||
public boolean mkdirs(String src, FsPermission masked, boolean createParent)
|
public boolean mkdirs(String src, FsPermission masked, boolean createParent)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
MkdirsRequestProto req = MkdirsRequestProto.newBuilder()
|
MkdirsRequestProto.Builder builder = MkdirsRequestProto.newBuilder()
|
||||||
.setSrc(src)
|
.setSrc(src)
|
||||||
.setMasked(PBHelperClient.convert(masked))
|
.setMasked(PBHelperClient.convert(masked))
|
||||||
.setCreateParent(createParent).build();
|
.setCreateParent(createParent);
|
||||||
|
FsPermission unmasked = masked.getUnmasked();
|
||||||
|
if (unmasked != null) {
|
||||||
|
builder.setUnmasked(PBHelperClient.convert(unmasked));
|
||||||
|
}
|
||||||
|
MkdirsRequestProto req = builder.build();
|
||||||
try {
|
try {
|
||||||
return rpcProxy.mkdirs(null, req).getResult();
|
return rpcProxy.mkdirs(null, req).getResult();
|
||||||
} catch (ServiceException e) {
|
} catch (ServiceException e) {
|
||||||
|
|
|
@ -66,6 +66,7 @@ import org.apache.hadoop.fs.GlobalStorageStatistics;
|
||||||
import org.apache.hadoop.fs.GlobalStorageStatistics.StorageStatisticsProvider;
|
import org.apache.hadoop.fs.GlobalStorageStatistics.StorageStatisticsProvider;
|
||||||
import org.apache.hadoop.fs.RemoteIterator;
|
import org.apache.hadoop.fs.RemoteIterator;
|
||||||
import org.apache.hadoop.fs.StorageStatistics;
|
import org.apache.hadoop.fs.StorageStatistics;
|
||||||
|
import org.apache.hadoop.fs.permission.FsCreateModes;
|
||||||
import org.apache.hadoop.hdfs.DFSOpsCountStatistics;
|
import org.apache.hadoop.hdfs.DFSOpsCountStatistics;
|
||||||
import org.apache.hadoop.hdfs.DFSOpsCountStatistics.OpType;
|
import org.apache.hadoop.hdfs.DFSOpsCountStatistics.OpType;
|
||||||
import org.apache.hadoop.fs.MD5MD5CRC32FileChecksum;
|
import org.apache.hadoop.fs.MD5MD5CRC32FileChecksum;
|
||||||
|
@ -973,7 +974,8 @@ public class WebHdfsFileSystem extends FileSystem
|
||||||
if (permission == null) {
|
if (permission == null) {
|
||||||
permission = FsPermission.getDefault();
|
permission = FsPermission.getDefault();
|
||||||
}
|
}
|
||||||
return permission.applyUMask(FsPermission.getUMask(getConf()));
|
return FsCreateModes.applyUMask(permission,
|
||||||
|
FsPermission.getUMask(getConf()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private HdfsFileStatus getHdfsFileStatus(Path f) throws IOException {
|
private HdfsFileStatus getHdfsFileStatus(Path f) throws IOException {
|
||||||
|
@ -1025,8 +1027,10 @@ public class WebHdfsFileSystem extends FileSystem
|
||||||
statistics.incrementWriteOps(1);
|
statistics.incrementWriteOps(1);
|
||||||
storageStatistics.incrementOpCounter(OpType.MKDIRS);
|
storageStatistics.incrementOpCounter(OpType.MKDIRS);
|
||||||
final HttpOpParam.Op op = PutOpParam.Op.MKDIRS;
|
final HttpOpParam.Op op = PutOpParam.Op.MKDIRS;
|
||||||
|
final FsPermission modes = applyUMask(permission);
|
||||||
return new FsPathBooleanRunner(op, f,
|
return new FsPathBooleanRunner(op, f,
|
||||||
new PermissionParam(applyUMask(permission))
|
new PermissionParam(modes.getMasked()),
|
||||||
|
new UnmaskedPermissionParam(modes.getUnmasked())
|
||||||
).run();
|
).run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1313,9 +1317,11 @@ public class WebHdfsFileSystem extends FileSystem
|
||||||
statistics.incrementWriteOps(1);
|
statistics.incrementWriteOps(1);
|
||||||
storageStatistics.incrementOpCounter(OpType.CREATE);
|
storageStatistics.incrementOpCounter(OpType.CREATE);
|
||||||
|
|
||||||
|
final FsPermission modes = applyUMask(permission);
|
||||||
final HttpOpParam.Op op = PutOpParam.Op.CREATE;
|
final HttpOpParam.Op op = PutOpParam.Op.CREATE;
|
||||||
return new FsPathOutputStreamRunner(op, f, bufferSize,
|
return new FsPathOutputStreamRunner(op, f, bufferSize,
|
||||||
new PermissionParam(applyUMask(permission)),
|
new PermissionParam(modes.getMasked()),
|
||||||
|
new UnmaskedPermissionParam(modes.getUnmasked()),
|
||||||
new OverwriteParam(overwrite),
|
new OverwriteParam(overwrite),
|
||||||
new BufferSizeParam(bufferSize),
|
new BufferSizeParam(bufferSize),
|
||||||
new ReplicationParam(replication),
|
new ReplicationParam(replication),
|
||||||
|
@ -1331,9 +1337,11 @@ public class WebHdfsFileSystem extends FileSystem
|
||||||
statistics.incrementWriteOps(1);
|
statistics.incrementWriteOps(1);
|
||||||
storageStatistics.incrementOpCounter(OpType.CREATE_NON_RECURSIVE);
|
storageStatistics.incrementOpCounter(OpType.CREATE_NON_RECURSIVE);
|
||||||
|
|
||||||
|
final FsPermission modes = applyUMask(permission);
|
||||||
final HttpOpParam.Op op = PutOpParam.Op.CREATE;
|
final HttpOpParam.Op op = PutOpParam.Op.CREATE;
|
||||||
return new FsPathOutputStreamRunner(op, f, bufferSize,
|
return new FsPathOutputStreamRunner(op, f, bufferSize,
|
||||||
new PermissionParam(applyUMask(permission)),
|
new PermissionParam(modes.getMasked()),
|
||||||
|
new UnmaskedPermissionParam(modes.getUnmasked()),
|
||||||
new CreateFlagParam(flag),
|
new CreateFlagParam(flag),
|
||||||
new CreateParentParam(false),
|
new CreateParentParam(false),
|
||||||
new BufferSizeParam(bufferSize),
|
new BufferSizeParam(bufferSize),
|
||||||
|
|
|
@ -54,7 +54,7 @@ public class PermissionParam extends ShortParam {
|
||||||
* @param value the parameter value.
|
* @param value the parameter value.
|
||||||
*/
|
*/
|
||||||
public PermissionParam(final FsPermission value) {
|
public PermissionParam(final FsPermission value) {
|
||||||
super(DOMAIN, value == null? null: value.toShort(), null, null);
|
this(DOMAIN, value == null ? null : value.toShort(), null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -62,7 +62,12 @@ public class PermissionParam extends ShortParam {
|
||||||
* @param str a string representation of the parameter value.
|
* @param str a string representation of the parameter value.
|
||||||
*/
|
*/
|
||||||
public PermissionParam(final String str) {
|
public PermissionParam(final String str) {
|
||||||
super(DOMAIN, DOMAIN.parse(str), (short)0, (short)01777);
|
this(DOMAIN, DOMAIN.parse(str), (short)0, (short)01777);
|
||||||
|
}
|
||||||
|
|
||||||
|
PermissionParam(final Domain domain, final Short value, final Short min,
|
||||||
|
final Short max) {
|
||||||
|
super(domain, value, min, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
/**
|
||||||
|
* 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.hdfs.web.resources;
|
||||||
|
|
||||||
|
import org.apache.hadoop.fs.permission.FsPermission;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unmasked permission parameter, use a Short to represent a FsPermission.
|
||||||
|
*/
|
||||||
|
public class UnmaskedPermissionParam extends PermissionParam {
|
||||||
|
/** Parameter name. */
|
||||||
|
public static final String NAME = "unmaskedpermission";
|
||||||
|
|
||||||
|
private static final Domain DOMAIN = new Domain(NAME, 8);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
* @param value the parameter value.
|
||||||
|
*/
|
||||||
|
public UnmaskedPermissionParam(final FsPermission value) {
|
||||||
|
super(DOMAIN, value == null ? null : value.toShort(), null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
* @param str a string representation of the parameter value.
|
||||||
|
*/
|
||||||
|
public UnmaskedPermissionParam(final String str) {
|
||||||
|
super(DOMAIN, DOMAIN.parse(str), (short)0, (short)01777);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return NAME;
|
||||||
|
}
|
||||||
|
}
|
|
@ -79,6 +79,7 @@ message CreateRequestProto {
|
||||||
required uint32 replication = 6; // Short: Only 16 bits used
|
required uint32 replication = 6; // Short: Only 16 bits used
|
||||||
required uint64 blockSize = 7;
|
required uint64 blockSize = 7;
|
||||||
repeated CryptoProtocolVersionProto cryptoProtocolVersion = 8;
|
repeated CryptoProtocolVersionProto cryptoProtocolVersion = 8;
|
||||||
|
optional FsPermissionProto unmasked = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
message CreateResponseProto {
|
message CreateResponseProto {
|
||||||
|
@ -264,6 +265,7 @@ message MkdirsRequestProto {
|
||||||
required string src = 1;
|
required string src = 1;
|
||||||
required FsPermissionProto masked = 2;
|
required FsPermissionProto masked = 2;
|
||||||
required bool createParent = 3;
|
required bool createParent = 3;
|
||||||
|
optional FsPermissionProto unmasked = 4;
|
||||||
}
|
}
|
||||||
message MkdirsResponseProto {
|
message MkdirsResponseProto {
|
||||||
required bool result = 1;
|
required bool result = 1;
|
||||||
|
|
|
@ -259,6 +259,10 @@ public class DFSConfigKeys extends CommonConfigurationKeys {
|
||||||
public static final String DFS_PERMISSIONS_SUPERUSERGROUP_DEFAULT = "supergroup";
|
public static final String DFS_PERMISSIONS_SUPERUSERGROUP_DEFAULT = "supergroup";
|
||||||
public static final String DFS_NAMENODE_ACLS_ENABLED_KEY = "dfs.namenode.acls.enabled";
|
public static final String DFS_NAMENODE_ACLS_ENABLED_KEY = "dfs.namenode.acls.enabled";
|
||||||
public static final boolean DFS_NAMENODE_ACLS_ENABLED_DEFAULT = false;
|
public static final boolean DFS_NAMENODE_ACLS_ENABLED_DEFAULT = false;
|
||||||
|
public static final String DFS_NAMENODE_POSIX_ACL_INHERITANCE_ENABLED_KEY =
|
||||||
|
"dfs.namenode.posix.acl.inheritance.enabled";
|
||||||
|
public static final boolean
|
||||||
|
DFS_NAMENODE_POSIX_ACL_INHERITANCE_ENABLED_DEFAULT = false;
|
||||||
public static final String DFS_NAMENODE_XATTRS_ENABLED_KEY = "dfs.namenode.xattrs.enabled";
|
public static final String DFS_NAMENODE_XATTRS_ENABLED_KEY = "dfs.namenode.xattrs.enabled";
|
||||||
public static final boolean DFS_NAMENODE_XATTRS_ENABLED_DEFAULT = true;
|
public static final boolean DFS_NAMENODE_XATTRS_ENABLED_DEFAULT = true;
|
||||||
public static final String DFS_ADMIN = "dfs.cluster.administrators";
|
public static final String DFS_ADMIN = "dfs.cluster.administrators";
|
||||||
|
|
|
@ -25,6 +25,8 @@ 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.fs.BatchedRemoteIterator.BatchedEntries;
|
import org.apache.hadoop.fs.BatchedRemoteIterator.BatchedEntries;
|
||||||
|
import org.apache.hadoop.fs.permission.FsCreateModes;
|
||||||
|
import org.apache.hadoop.fs.permission.FsPermission;
|
||||||
import org.apache.hadoop.hdfs.AddBlockFlag;
|
import org.apache.hadoop.hdfs.AddBlockFlag;
|
||||||
import org.apache.hadoop.fs.ContentSummary;
|
import org.apache.hadoop.fs.ContentSummary;
|
||||||
import org.apache.hadoop.fs.CreateFlag;
|
import org.apache.hadoop.fs.CreateFlag;
|
||||||
|
@ -411,8 +413,12 @@ public class ClientNamenodeProtocolServerSideTranslatorPB implements
|
||||||
public CreateResponseProto create(RpcController controller,
|
public CreateResponseProto create(RpcController controller,
|
||||||
CreateRequestProto req) throws ServiceException {
|
CreateRequestProto req) throws ServiceException {
|
||||||
try {
|
try {
|
||||||
|
FsPermission masked = req.hasUnmasked() ?
|
||||||
|
FsCreateModes.create(PBHelperClient.convert(req.getMasked()),
|
||||||
|
PBHelperClient.convert(req.getUnmasked())) :
|
||||||
|
PBHelperClient.convert(req.getMasked());
|
||||||
HdfsFileStatus result = server.create(req.getSrc(),
|
HdfsFileStatus result = server.create(req.getSrc(),
|
||||||
PBHelperClient.convert(req.getMasked()), req.getClientName(),
|
masked, req.getClientName(),
|
||||||
PBHelperClient.convertCreateFlag(req.getCreateFlag()), req.getCreateParent(),
|
PBHelperClient.convertCreateFlag(req.getCreateFlag()), req.getCreateParent(),
|
||||||
(short) req.getReplication(), req.getBlockSize(),
|
(short) req.getReplication(), req.getBlockSize(),
|
||||||
PBHelperClient.convertCryptoProtocolVersions(
|
PBHelperClient.convertCryptoProtocolVersions(
|
||||||
|
@ -651,8 +657,12 @@ public class ClientNamenodeProtocolServerSideTranslatorPB implements
|
||||||
public MkdirsResponseProto mkdirs(RpcController controller,
|
public MkdirsResponseProto mkdirs(RpcController controller,
|
||||||
MkdirsRequestProto req) throws ServiceException {
|
MkdirsRequestProto req) throws ServiceException {
|
||||||
try {
|
try {
|
||||||
boolean result = server.mkdirs(req.getSrc(),
|
FsPermission masked = req.hasUnmasked() ?
|
||||||
PBHelperClient.convert(req.getMasked()), req.getCreateParent());
|
FsCreateModes.create(PBHelperClient.convert(req.getMasked()),
|
||||||
|
PBHelperClient.convert(req.getUnmasked())) :
|
||||||
|
PBHelperClient.convert(req.getMasked());
|
||||||
|
boolean result = server.mkdirs(req.getSrc(), masked,
|
||||||
|
req.getCreateParent());
|
||||||
return MkdirsResponseProto.newBuilder().setResult(result).build();
|
return MkdirsResponseProto.newBuilder().setResult(result).build();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new ServiceException(e);
|
throw new ServiceException(e);
|
||||||
|
|
|
@ -37,6 +37,7 @@ import org.apache.hadoop.hdfs.web.resources.OffsetParam;
|
||||||
import org.apache.hadoop.hdfs.web.resources.OverwriteParam;
|
import org.apache.hadoop.hdfs.web.resources.OverwriteParam;
|
||||||
import org.apache.hadoop.hdfs.web.resources.PermissionParam;
|
import org.apache.hadoop.hdfs.web.resources.PermissionParam;
|
||||||
import org.apache.hadoop.hdfs.web.resources.ReplicationParam;
|
import org.apache.hadoop.hdfs.web.resources.ReplicationParam;
|
||||||
|
import org.apache.hadoop.hdfs.web.resources.UnmaskedPermissionParam;
|
||||||
import org.apache.hadoop.hdfs.web.resources.UserParam;
|
import org.apache.hadoop.hdfs.web.resources.UserParam;
|
||||||
import org.apache.hadoop.security.SecurityUtil;
|
import org.apache.hadoop.security.SecurityUtil;
|
||||||
import org.apache.hadoop.security.token.Token;
|
import org.apache.hadoop.security.token.Token;
|
||||||
|
@ -108,6 +109,12 @@ class ParameterParser {
|
||||||
getFileFsPermission();
|
getFileFsPermission();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FsPermission unmaskedPermission() {
|
||||||
|
String value = param(UnmaskedPermissionParam.NAME);
|
||||||
|
return value == null ? null :
|
||||||
|
new UnmaskedPermissionParam(value).getFileFsPermission();
|
||||||
|
}
|
||||||
|
|
||||||
boolean overwrite() {
|
boolean overwrite() {
|
||||||
return new OverwriteParam(param(OverwriteParam.NAME)).getValue();
|
return new OverwriteParam(param(OverwriteParam.NAME)).getValue();
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,7 @@ import org.apache.commons.logging.LogFactory;
|
||||||
import org.apache.hadoop.conf.Configuration;
|
import org.apache.hadoop.conf.Configuration;
|
||||||
import org.apache.hadoop.fs.CreateFlag;
|
import org.apache.hadoop.fs.CreateFlag;
|
||||||
import org.apache.hadoop.fs.MD5MD5CRC32FileChecksum;
|
import org.apache.hadoop.fs.MD5MD5CRC32FileChecksum;
|
||||||
|
import org.apache.hadoop.fs.permission.FsCreateModes;
|
||||||
import org.apache.hadoop.fs.permission.FsPermission;
|
import org.apache.hadoop.fs.permission.FsPermission;
|
||||||
import org.apache.hadoop.hdfs.DFSClient;
|
import org.apache.hadoop.hdfs.DFSClient;
|
||||||
import org.apache.hadoop.hdfs.client.HdfsDataInputStream;
|
import org.apache.hadoop.hdfs.client.HdfsDataInputStream;
|
||||||
|
@ -187,7 +188,10 @@ public class WebHdfsHandler extends SimpleChannelInboundHandler<HttpRequest> {
|
||||||
final int bufferSize = params.bufferSize();
|
final int bufferSize = params.bufferSize();
|
||||||
final short replication = params.replication();
|
final short replication = params.replication();
|
||||||
final long blockSize = params.blockSize();
|
final long blockSize = params.blockSize();
|
||||||
final FsPermission permission = params.permission();
|
final FsPermission unmaskedPermission = params.unmaskedPermission();
|
||||||
|
final FsPermission permission = unmaskedPermission == null ?
|
||||||
|
params.permission() :
|
||||||
|
FsCreateModes.create(params.permission(), unmaskedPermission);
|
||||||
final boolean createParent = params.createParent();
|
final boolean createParent = params.createParent();
|
||||||
|
|
||||||
EnumSet<CreateFlag> flags = params.createFlag();
|
EnumSet<CreateFlag> flags = params.createFlag();
|
||||||
|
|
|
@ -73,11 +73,11 @@ public final class AclStorage {
|
||||||
*
|
*
|
||||||
* @param child INode newly created child
|
* @param child INode newly created child
|
||||||
*/
|
*/
|
||||||
public static void copyINodeDefaultAcl(INode child) {
|
public static boolean copyINodeDefaultAcl(INode child) {
|
||||||
INodeDirectory parent = child.getParent();
|
INodeDirectory parent = child.getParent();
|
||||||
AclFeature parentAclFeature = parent.getAclFeature();
|
AclFeature parentAclFeature = parent.getAclFeature();
|
||||||
if (parentAclFeature == null || !(child.isFile() || child.isDirectory())) {
|
if (parentAclFeature == null || !(child.isFile() || child.isDirectory())) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Split parent's entries into access vs. default.
|
// Split parent's entries into access vs. default.
|
||||||
|
@ -88,7 +88,7 @@ public final class AclStorage {
|
||||||
|
|
||||||
// The parent may have an access ACL but no default ACL. If so, exit.
|
// The parent may have an access ACL but no default ACL. If so, exit.
|
||||||
if (parentDefaultEntries.isEmpty()) {
|
if (parentDefaultEntries.isEmpty()) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pre-allocate list size for access entries to copy from parent.
|
// Pre-allocate list size for access entries to copy from parent.
|
||||||
|
@ -145,6 +145,7 @@ public final class AclStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
child.setPermission(newPerm);
|
child.setPermission(newPerm);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -219,7 +219,8 @@ class FSDirMkdirOp {
|
||||||
final INodeDirectory dir = new INodeDirectory(inodeId, name, permission,
|
final INodeDirectory dir = new INodeDirectory(inodeId, name, permission,
|
||||||
timestamp);
|
timestamp);
|
||||||
|
|
||||||
INodesInPath iip = fsd.addLastINode(parent, dir, true);
|
INodesInPath iip =
|
||||||
|
fsd.addLastINode(parent, dir, permission.getPermission(), true);
|
||||||
if (iip != null && aclEntries != null) {
|
if (iip != null && aclEntries != null) {
|
||||||
AclStorage.updateINodeAcl(dir, aclEntries, Snapshot.CURRENT_STATE_ID);
|
AclStorage.updateINodeAcl(dir, aclEntries, Snapshot.CURRENT_STATE_ID);
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,8 @@ class FSDirSymlinkOp {
|
||||||
final INodeSymlink symlink = new INodeSymlink(id, null, perm, mtime, atime,
|
final INodeSymlink symlink = new INodeSymlink(id, null, perm, mtime, atime,
|
||||||
target);
|
target);
|
||||||
symlink.setLocalName(localName);
|
symlink.setLocalName(localName);
|
||||||
return fsd.addINode(iip, symlink) != null ? symlink : null;
|
return fsd.addINode(iip, symlink, perm.getPermission()) != null ?
|
||||||
|
symlink : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -496,7 +496,8 @@ class FSDirWriteFileOp {
|
||||||
replication, preferredBlockSize, storagePolicyId, ecPolicy != null);
|
replication, preferredBlockSize, storagePolicyId, ecPolicy != null);
|
||||||
}
|
}
|
||||||
newNode.setLocalName(localName);
|
newNode.setLocalName(localName);
|
||||||
INodesInPath iip = fsd.addINode(existing, newNode);
|
INodesInPath iip = fsd.addINode(existing, newNode,
|
||||||
|
permissions.getPermission());
|
||||||
if (iip != null) {
|
if (iip != null) {
|
||||||
if (aclEntries != null) {
|
if (aclEntries != null) {
|
||||||
AclStorage.updateINodeAcl(newNode, aclEntries, CURRENT_STATE_ID);
|
AclStorage.updateINodeAcl(newNode, aclEntries, CURRENT_STATE_ID);
|
||||||
|
@ -594,7 +595,7 @@ class FSDirWriteFileOp {
|
||||||
modTime, modTime, replication, preferredBlockSize, ecPolicy != null);
|
modTime, modTime, replication, preferredBlockSize, ecPolicy != null);
|
||||||
newNode.setLocalName(localName);
|
newNode.setLocalName(localName);
|
||||||
newNode.toUnderConstruction(clientName, clientMachine);
|
newNode.toUnderConstruction(clientName, clientMachine);
|
||||||
newiip = fsd.addINode(existing, newNode);
|
newiip = fsd.addINode(existing, newNode, permissions.getPermission());
|
||||||
} finally {
|
} finally {
|
||||||
fsd.writeUnlock();
|
fsd.writeUnlock();
|
||||||
}
|
}
|
||||||
|
|
|
@ -168,6 +168,10 @@ public class FSDirectory implements Closeable {
|
||||||
* ACL-related operations.
|
* ACL-related operations.
|
||||||
*/
|
*/
|
||||||
private final boolean aclsEnabled;
|
private final boolean aclsEnabled;
|
||||||
|
/**
|
||||||
|
* Support for POSIX ACL inheritance. Not final for testing purpose.
|
||||||
|
*/
|
||||||
|
private boolean posixAclInheritanceEnabled;
|
||||||
private final boolean xattrsEnabled;
|
private final boolean xattrsEnabled;
|
||||||
private final int xattrMaxSize;
|
private final int xattrMaxSize;
|
||||||
|
|
||||||
|
@ -251,6 +255,10 @@ public class FSDirectory implements Closeable {
|
||||||
DFSConfigKeys.DFS_NAMENODE_ACLS_ENABLED_KEY,
|
DFSConfigKeys.DFS_NAMENODE_ACLS_ENABLED_KEY,
|
||||||
DFSConfigKeys.DFS_NAMENODE_ACLS_ENABLED_DEFAULT);
|
DFSConfigKeys.DFS_NAMENODE_ACLS_ENABLED_DEFAULT);
|
||||||
LOG.info("ACLs enabled? " + aclsEnabled);
|
LOG.info("ACLs enabled? " + aclsEnabled);
|
||||||
|
this.posixAclInheritanceEnabled = conf.getBoolean(
|
||||||
|
DFSConfigKeys.DFS_NAMENODE_POSIX_ACL_INHERITANCE_ENABLED_KEY,
|
||||||
|
DFSConfigKeys.DFS_NAMENODE_POSIX_ACL_INHERITANCE_ENABLED_DEFAULT);
|
||||||
|
LOG.info("POSIX ACL inheritance enabled? " + posixAclInheritanceEnabled);
|
||||||
this.xattrsEnabled = conf.getBoolean(
|
this.xattrsEnabled = conf.getBoolean(
|
||||||
DFSConfigKeys.DFS_NAMENODE_XATTRS_ENABLED_KEY,
|
DFSConfigKeys.DFS_NAMENODE_XATTRS_ENABLED_KEY,
|
||||||
DFSConfigKeys.DFS_NAMENODE_XATTRS_ENABLED_DEFAULT);
|
DFSConfigKeys.DFS_NAMENODE_XATTRS_ENABLED_DEFAULT);
|
||||||
|
@ -450,6 +458,18 @@ public class FSDirectory implements Closeable {
|
||||||
boolean isAclsEnabled() {
|
boolean isAclsEnabled() {
|
||||||
return aclsEnabled;
|
return aclsEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public boolean isPosixAclInheritanceEnabled() {
|
||||||
|
return posixAclInheritanceEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public void setPosixAclInheritanceEnabled(
|
||||||
|
boolean posixAclInheritanceEnabled) {
|
||||||
|
this.posixAclInheritanceEnabled = posixAclInheritanceEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
boolean isXattrsEnabled() {
|
boolean isXattrsEnabled() {
|
||||||
return xattrsEnabled;
|
return xattrsEnabled;
|
||||||
}
|
}
|
||||||
|
@ -952,16 +972,18 @@ public class FSDirectory implements Closeable {
|
||||||
* Add the given child to the namespace.
|
* Add the given child to the namespace.
|
||||||
* @param existing the INodesInPath containing all the ancestral INodes
|
* @param existing the INodesInPath containing all the ancestral INodes
|
||||||
* @param child the new INode to add
|
* @param child the new INode to add
|
||||||
|
* @param modes create modes
|
||||||
* @return a new INodesInPath instance containing the new child INode. Null
|
* @return a new INodesInPath instance containing the new child INode. Null
|
||||||
* if the adding fails.
|
* if the adding fails.
|
||||||
* @throws QuotaExceededException is thrown if it violates quota limit
|
* @throws QuotaExceededException is thrown if it violates quota limit
|
||||||
*/
|
*/
|
||||||
INodesInPath addINode(INodesInPath existing, INode child)
|
INodesInPath addINode(INodesInPath existing, INode child,
|
||||||
|
FsPermission modes)
|
||||||
throws QuotaExceededException, UnresolvedLinkException {
|
throws QuotaExceededException, UnresolvedLinkException {
|
||||||
cacheName(child);
|
cacheName(child);
|
||||||
writeLock();
|
writeLock();
|
||||||
try {
|
try {
|
||||||
return addLastINode(existing, child, true);
|
return addLastINode(existing, child, modes, true);
|
||||||
} finally {
|
} finally {
|
||||||
writeUnlock();
|
writeUnlock();
|
||||||
}
|
}
|
||||||
|
@ -1066,13 +1088,52 @@ public class FSDirectory implements Closeable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turn on HDFS-6962 POSIX ACL inheritance when the property
|
||||||
|
* {@link DFSConfigKeys#DFS_NAMENODE_POSIX_ACL_INHERITANCE_ENABLED_KEY} is
|
||||||
|
* true and a compatible client has sent both masked and unmasked create
|
||||||
|
* modes.
|
||||||
|
*
|
||||||
|
* @param child INode newly created child
|
||||||
|
* @param modes create modes
|
||||||
|
*/
|
||||||
|
private void copyINodeDefaultAcl(INode child, FsPermission modes) {
|
||||||
|
if (LOG.isDebugEnabled()) {
|
||||||
|
LOG.debug("child: {}, posixAclInheritanceEnabled: {}, modes: {}",
|
||||||
|
child, posixAclInheritanceEnabled, modes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (posixAclInheritanceEnabled && modes != null &&
|
||||||
|
modes.getUnmasked() != null) {
|
||||||
|
//
|
||||||
|
// HDFS-6962: POSIX ACL inheritance
|
||||||
|
//
|
||||||
|
child.setPermission(modes.getUnmasked());
|
||||||
|
if (!AclStorage.copyINodeDefaultAcl(child)) {
|
||||||
|
if (LOG.isDebugEnabled()) {
|
||||||
|
LOG.debug("{}: no parent default ACL to inherit", child);
|
||||||
|
}
|
||||||
|
child.setPermission(modes.getMasked());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//
|
||||||
|
// Old behavior before HDFS-6962
|
||||||
|
//
|
||||||
|
AclStorage.copyINodeDefaultAcl(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a child to the end of the path specified by INodesInPath.
|
* Add a child to the end of the path specified by INodesInPath.
|
||||||
|
* @param existing the INodesInPath containing all the ancestral INodes
|
||||||
|
* @param inode the new INode to add
|
||||||
|
* @param modes create modes
|
||||||
|
* @param checkQuota whether to check quota
|
||||||
* @return an INodesInPath instance containing the new INode
|
* @return an INodesInPath instance containing the new INode
|
||||||
*/
|
*/
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public INodesInPath addLastINode(INodesInPath existing, INode inode,
|
public INodesInPath addLastINode(INodesInPath existing, INode inode,
|
||||||
boolean checkQuota) throws QuotaExceededException {
|
FsPermission modes, boolean checkQuota) throws QuotaExceededException {
|
||||||
assert existing.getLastINode() != null &&
|
assert existing.getLastINode() != null &&
|
||||||
existing.getLastINode().isDirectory();
|
existing.getLastINode().isDirectory();
|
||||||
|
|
||||||
|
@ -1119,7 +1180,7 @@ public class FSDirectory implements Closeable {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
if (!isRename) {
|
if (!isRename) {
|
||||||
AclStorage.copyINodeDefaultAcl(inode);
|
copyINodeDefaultAcl(inode, modes);
|
||||||
}
|
}
|
||||||
addToInodeMap(inode);
|
addToInodeMap(inode);
|
||||||
}
|
}
|
||||||
|
@ -1128,7 +1189,8 @@ public class FSDirectory implements Closeable {
|
||||||
|
|
||||||
INodesInPath addLastINodeNoQuotaCheck(INodesInPath existing, INode i) {
|
INodesInPath addLastINodeNoQuotaCheck(INodesInPath existing, INode i) {
|
||||||
try {
|
try {
|
||||||
return addLastINode(existing, i, false);
|
// All callers do not have create modes to pass.
|
||||||
|
return addLastINode(existing, i, null, false);
|
||||||
} catch (QuotaExceededException e) {
|
} catch (QuotaExceededException e) {
|
||||||
NameNode.LOG.warn("FSDirectory.addChildNoQuotaCheck - unexpected", e);
|
NameNode.LOG.warn("FSDirectory.addChildNoQuotaCheck - unexpected", e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,8 @@ import org.apache.hadoop.fs.Options;
|
||||||
import org.apache.hadoop.fs.XAttr;
|
import org.apache.hadoop.fs.XAttr;
|
||||||
import org.apache.hadoop.fs.permission.AclStatus;
|
import org.apache.hadoop.fs.permission.AclStatus;
|
||||||
import org.apache.hadoop.fs.permission.FsAction;
|
import org.apache.hadoop.fs.permission.FsAction;
|
||||||
|
import org.apache.hadoop.fs.permission.FsCreateModes;
|
||||||
|
import org.apache.hadoop.fs.permission.FsPermission;
|
||||||
import org.apache.hadoop.hdfs.DFSUtil;
|
import org.apache.hadoop.hdfs.DFSUtil;
|
||||||
import org.apache.hadoop.hdfs.XAttrHelper;
|
import org.apache.hadoop.hdfs.XAttrHelper;
|
||||||
import org.apache.hadoop.hdfs.protocol.DatanodeInfo;
|
import org.apache.hadoop.hdfs.protocol.DatanodeInfo;
|
||||||
|
@ -324,6 +326,9 @@ public class NamenodeWebHdfsMethods {
|
||||||
final GroupParam group,
|
final GroupParam group,
|
||||||
@QueryParam(PermissionParam.NAME) @DefaultValue(PermissionParam.DEFAULT)
|
@QueryParam(PermissionParam.NAME) @DefaultValue(PermissionParam.DEFAULT)
|
||||||
final PermissionParam permission,
|
final PermissionParam permission,
|
||||||
|
@QueryParam(UnmaskedPermissionParam.NAME)
|
||||||
|
@DefaultValue(UnmaskedPermissionParam.DEFAULT)
|
||||||
|
final UnmaskedPermissionParam unmaskedPermission,
|
||||||
@QueryParam(OverwriteParam.NAME) @DefaultValue(OverwriteParam.DEFAULT)
|
@QueryParam(OverwriteParam.NAME) @DefaultValue(OverwriteParam.DEFAULT)
|
||||||
final OverwriteParam overwrite,
|
final OverwriteParam overwrite,
|
||||||
@QueryParam(BufferSizeParam.NAME) @DefaultValue(BufferSizeParam.DEFAULT)
|
@QueryParam(BufferSizeParam.NAME) @DefaultValue(BufferSizeParam.DEFAULT)
|
||||||
|
@ -362,11 +367,11 @@ public class NamenodeWebHdfsMethods {
|
||||||
final NoRedirectParam noredirect
|
final NoRedirectParam noredirect
|
||||||
) throws IOException, InterruptedException {
|
) throws IOException, InterruptedException {
|
||||||
return put(ugi, delegation, username, doAsUser, ROOT, op, destination,
|
return put(ugi, delegation, username, doAsUser, ROOT, op, destination,
|
||||||
owner, group, permission, overwrite, bufferSize, replication,
|
owner, group, permission, unmaskedPermission, overwrite, bufferSize,
|
||||||
blockSize, modificationTime, accessTime, renameOptions, createParent,
|
replication, blockSize, modificationTime, accessTime, renameOptions,
|
||||||
delegationTokenArgument, aclPermission, xattrName, xattrValue,
|
createParent, delegationTokenArgument, aclPermission, xattrName,
|
||||||
xattrSetFlag, snapshotName, oldSnapshotName, excludeDatanodes,
|
xattrValue, xattrSetFlag, snapshotName, oldSnapshotName,
|
||||||
createFlagParam, noredirect);
|
excludeDatanodes, createFlagParam, noredirect);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Handle HTTP PUT request. */
|
/** Handle HTTP PUT request. */
|
||||||
|
@ -393,6 +398,9 @@ public class NamenodeWebHdfsMethods {
|
||||||
final GroupParam group,
|
final GroupParam group,
|
||||||
@QueryParam(PermissionParam.NAME) @DefaultValue(PermissionParam.DEFAULT)
|
@QueryParam(PermissionParam.NAME) @DefaultValue(PermissionParam.DEFAULT)
|
||||||
final PermissionParam permission,
|
final PermissionParam permission,
|
||||||
|
@QueryParam(UnmaskedPermissionParam.NAME)
|
||||||
|
@DefaultValue(UnmaskedPermissionParam.DEFAULT)
|
||||||
|
final UnmaskedPermissionParam unmaskedPermission,
|
||||||
@QueryParam(OverwriteParam.NAME) @DefaultValue(OverwriteParam.DEFAULT)
|
@QueryParam(OverwriteParam.NAME) @DefaultValue(OverwriteParam.DEFAULT)
|
||||||
final OverwriteParam overwrite,
|
final OverwriteParam overwrite,
|
||||||
@QueryParam(BufferSizeParam.NAME) @DefaultValue(BufferSizeParam.DEFAULT)
|
@QueryParam(BufferSizeParam.NAME) @DefaultValue(BufferSizeParam.DEFAULT)
|
||||||
|
@ -432,10 +440,11 @@ public class NamenodeWebHdfsMethods {
|
||||||
) throws IOException, InterruptedException {
|
) throws IOException, InterruptedException {
|
||||||
|
|
||||||
init(ugi, delegation, username, doAsUser, path, op, destination, owner,
|
init(ugi, delegation, username, doAsUser, path, op, destination, owner,
|
||||||
group, permission, overwrite, bufferSize, replication, blockSize,
|
group, permission, unmaskedPermission, overwrite, bufferSize,
|
||||||
modificationTime, accessTime, renameOptions, delegationTokenArgument,
|
replication, blockSize, modificationTime, accessTime, renameOptions,
|
||||||
aclPermission, xattrName, xattrValue, xattrSetFlag, snapshotName,
|
delegationTokenArgument, aclPermission, xattrName, xattrValue,
|
||||||
oldSnapshotName, excludeDatanodes, createFlagParam, noredirect);
|
xattrSetFlag, snapshotName, oldSnapshotName, excludeDatanodes,
|
||||||
|
createFlagParam, noredirect);
|
||||||
|
|
||||||
return ugi.doAs(new PrivilegedExceptionAction<Response>() {
|
return ugi.doAs(new PrivilegedExceptionAction<Response>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -443,10 +452,11 @@ public class NamenodeWebHdfsMethods {
|
||||||
try {
|
try {
|
||||||
return put(ugi, delegation, username, doAsUser,
|
return put(ugi, delegation, username, doAsUser,
|
||||||
path.getAbsolutePath(), op, destination, owner, group,
|
path.getAbsolutePath(), op, destination, owner, group,
|
||||||
permission, overwrite, bufferSize, replication, blockSize,
|
permission, unmaskedPermission, overwrite, bufferSize,
|
||||||
modificationTime, accessTime, renameOptions, createParent,
|
replication, blockSize, modificationTime, accessTime,
|
||||||
delegationTokenArgument, aclPermission, xattrName, xattrValue,
|
renameOptions, createParent, delegationTokenArgument,
|
||||||
xattrSetFlag, snapshotName, oldSnapshotName, excludeDatanodes,
|
aclPermission, xattrName, xattrValue, xattrSetFlag,
|
||||||
|
snapshotName, oldSnapshotName, excludeDatanodes,
|
||||||
createFlagParam, noredirect);
|
createFlagParam, noredirect);
|
||||||
} finally {
|
} finally {
|
||||||
reset();
|
reset();
|
||||||
|
@ -466,6 +476,7 @@ public class NamenodeWebHdfsMethods {
|
||||||
final OwnerParam owner,
|
final OwnerParam owner,
|
||||||
final GroupParam group,
|
final GroupParam group,
|
||||||
final PermissionParam permission,
|
final PermissionParam permission,
|
||||||
|
final UnmaskedPermissionParam unmaskedPermission,
|
||||||
final OverwriteParam overwrite,
|
final OverwriteParam overwrite,
|
||||||
final BufferSizeParam bufferSize,
|
final BufferSizeParam bufferSize,
|
||||||
final ReplicationParam replication,
|
final ReplicationParam replication,
|
||||||
|
@ -495,8 +506,9 @@ public class NamenodeWebHdfsMethods {
|
||||||
{
|
{
|
||||||
final URI uri = redirectURI(namenode, ugi, delegation, username,
|
final URI uri = redirectURI(namenode, ugi, delegation, username,
|
||||||
doAsUser, fullpath, op.getValue(), -1L, blockSize.getValue(conf),
|
doAsUser, fullpath, op.getValue(), -1L, blockSize.getValue(conf),
|
||||||
exclDatanodes.getValue(), permission, overwrite, bufferSize,
|
exclDatanodes.getValue(), permission, unmaskedPermission,
|
||||||
replication, blockSize, createParent, createFlagParam);
|
overwrite, bufferSize, replication, blockSize, createParent,
|
||||||
|
createFlagParam);
|
||||||
if(!noredirectParam.getValue()) {
|
if(!noredirectParam.getValue()) {
|
||||||
return Response.temporaryRedirect(uri)
|
return Response.temporaryRedirect(uri)
|
||||||
.type(MediaType.APPLICATION_OCTET_STREAM).build();
|
.type(MediaType.APPLICATION_OCTET_STREAM).build();
|
||||||
|
@ -507,8 +519,11 @@ public class NamenodeWebHdfsMethods {
|
||||||
}
|
}
|
||||||
case MKDIRS:
|
case MKDIRS:
|
||||||
{
|
{
|
||||||
final boolean b = np.mkdirs(fullpath,
|
FsPermission masked = unmaskedPermission.getValue() == null ?
|
||||||
permission.getDirFsPermission(), true);
|
permission.getDirFsPermission() :
|
||||||
|
FsCreateModes.create(permission.getDirFsPermission(),
|
||||||
|
unmaskedPermission.getDirFsPermission());
|
||||||
|
final boolean b = np.mkdirs(fullpath, masked, true);
|
||||||
final String js = JsonUtil.toJsonString("boolean", b);
|
final String js = JsonUtil.toJsonString("boolean", b);
|
||||||
return Response.ok(js).type(MediaType.APPLICATION_JSON).build();
|
return Response.ok(js).type(MediaType.APPLICATION_JSON).build();
|
||||||
}
|
}
|
||||||
|
|
|
@ -457,7 +457,19 @@
|
||||||
</description>
|
</description>
|
||||||
</property>
|
</property>
|
||||||
|
|
||||||
<property>
|
<property>
|
||||||
|
<name>dfs.namenode.posix.acl.inheritance.enabled</name>
|
||||||
|
<value>false</value>
|
||||||
|
<description>
|
||||||
|
Set to true to enable POSIX style ACL inheritance. When it is enabled
|
||||||
|
and the create request comes from a compatible client, the NameNode
|
||||||
|
will apply default ACLs from the parent directory to the create mode
|
||||||
|
and ignore the client umask. If no default ACL found, it will apply the
|
||||||
|
client umask.
|
||||||
|
</description>
|
||||||
|
</property>
|
||||||
|
|
||||||
|
<property>
|
||||||
<name>dfs.namenode.lazypersist.file.scrub.interval.sec</name>
|
<name>dfs.namenode.lazypersist.file.scrub.interval.sec</name>
|
||||||
<value>300</value>
|
<value>300</value>
|
||||||
<description>
|
<description>
|
||||||
|
|
|
@ -333,4 +333,10 @@ Configuration Parameters
|
||||||
default, ACLs are disabled. When ACLs are disabled, the NameNode rejects
|
default, ACLs are disabled. When ACLs are disabled, the NameNode rejects
|
||||||
all attempts to set an ACL.
|
all attempts to set an ACL.
|
||||||
|
|
||||||
|
* `dfs.namenode.posix.acl.inheritance.enabled`
|
||||||
|
|
||||||
|
Set to true to enable POSIX style ACL inheritance. Disabled by default.
|
||||||
|
When it is enabled and the create request comes from a compatible client,
|
||||||
|
the NameNode will apply default ACLs from the parent directory to
|
||||||
|
the create mode and ignore the client umask. If no default ACL is found,
|
||||||
|
it will apply the client umask.
|
||||||
|
|
|
@ -32,11 +32,15 @@ public class TestAclCLI extends CLITestHelperDFS {
|
||||||
private String namenode = null;
|
private String namenode = null;
|
||||||
private String username = null;
|
private String username = null;
|
||||||
|
|
||||||
|
protected void initConf() {
|
||||||
|
conf.setBoolean(DFSConfigKeys.DFS_NAMENODE_ACLS_ENABLED_KEY, true);
|
||||||
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@Override
|
@Override
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
conf.setBoolean(DFSConfigKeys.DFS_NAMENODE_ACLS_ENABLED_KEY, true);
|
initConf();
|
||||||
cluster = new MiniDFSCluster.Builder(conf).numDataNodes(1).build();
|
cluster = new MiniDFSCluster.Builder(conf).numDataNodes(1).build();
|
||||||
fs = cluster.getFileSystem();
|
fs = cluster.getFileSystem();
|
||||||
namenode = conf.get(DFSConfigKeys.FS_DEFAULT_NAME_KEY, "file:///");
|
namenode = conf.get(DFSConfigKeys.FS_DEFAULT_NAME_KEY, "file:///");
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/**
|
||||||
|
* 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.cli;
|
||||||
|
|
||||||
|
import static org.apache.hadoop.hdfs.DFSConfigKeys.DFS_NAMENODE_POSIX_ACL_INHERITANCE_ENABLED_KEY;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test ACL CLI with POSIX ACL inheritance enabled.
|
||||||
|
*/
|
||||||
|
public class TestAclCLIWithPosixAclInheritance extends TestAclCLI {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void initConf() {
|
||||||
|
super.initConf();
|
||||||
|
conf.setBoolean(DFS_NAMENODE_POSIX_ACL_INHERITANCE_ENABLED_KEY, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getTestFile() {
|
||||||
|
return "testAclCLIWithPosixAclInheritance.xml";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Override
|
||||||
|
public void testAll() {
|
||||||
|
super.testAll();
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.hadoop.hdfs.server.namenode;
|
package org.apache.hadoop.hdfs.server.namenode;
|
||||||
|
|
||||||
|
import static org.apache.hadoop.fs.CommonConfigurationKeys.FS_PERMISSIONS_UMASK_KEY;
|
||||||
import static org.apache.hadoop.hdfs.server.namenode.AclTestHelpers.*;
|
import static org.apache.hadoop.hdfs.server.namenode.AclTestHelpers.*;
|
||||||
import static org.apache.hadoop.fs.permission.AclEntryScope.*;
|
import static org.apache.hadoop.fs.permission.AclEntryScope.*;
|
||||||
import static org.apache.hadoop.fs.permission.AclEntryType.*;
|
import static org.apache.hadoop.fs.permission.AclEntryType.*;
|
||||||
|
@ -888,6 +889,46 @@ public abstract class FSAclBaseTest {
|
||||||
assertAclFeature(filePath, true);
|
assertAclFeature(filePath, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUMaskDefaultAclNewFile() throws Exception {
|
||||||
|
FileSystem.mkdirs(fs, path, FsPermission.createImmutable((short)0750));
|
||||||
|
List<AclEntry> aclSpec = Lists.newArrayList(
|
||||||
|
aclEntry(DEFAULT, GROUP, READ_WRITE),
|
||||||
|
aclEntry(DEFAULT, USER, "foo", ALL));
|
||||||
|
fs.setAcl(path, aclSpec);
|
||||||
|
|
||||||
|
String oldUMask = fs.getConf().get(FS_PERMISSIONS_UMASK_KEY);
|
||||||
|
fs.getConf().set(FS_PERMISSIONS_UMASK_KEY, "027");
|
||||||
|
|
||||||
|
FSDirectory fsDirectory = cluster.getNamesystem().getFSDirectory();
|
||||||
|
boolean oldEnabled = fsDirectory.isPosixAclInheritanceEnabled();
|
||||||
|
|
||||||
|
try {
|
||||||
|
fsDirectory.setPosixAclInheritanceEnabled(false);
|
||||||
|
Path filePath = new Path(path, "file1");
|
||||||
|
fs.create(filePath).close();
|
||||||
|
AclStatus s = fs.getAclStatus(filePath);
|
||||||
|
AclEntry[] returned = s.getEntries().toArray(new AclEntry[0]);
|
||||||
|
assertArrayEquals(new AclEntry[]{
|
||||||
|
aclEntry(ACCESS, USER, "foo", ALL),
|
||||||
|
aclEntry(ACCESS, GROUP, READ_WRITE)}, returned);
|
||||||
|
assertPermission(filePath, (short) 010640);
|
||||||
|
|
||||||
|
fsDirectory.setPosixAclInheritanceEnabled(true);
|
||||||
|
Path file2Path = new Path(path, "file2");
|
||||||
|
fs.create(file2Path).close();
|
||||||
|
AclStatus s2 = fs.getAclStatus(file2Path);
|
||||||
|
AclEntry[] returned2 = s2.getEntries().toArray(new AclEntry[0]);
|
||||||
|
assertArrayEquals(new AclEntry[]{
|
||||||
|
aclEntry(ACCESS, USER, "foo", ALL),
|
||||||
|
aclEntry(ACCESS, GROUP, READ_WRITE)}, returned2);
|
||||||
|
assertPermission(file2Path, (short) 010660);
|
||||||
|
} finally {
|
||||||
|
fsDirectory.setPosixAclInheritanceEnabled(oldEnabled);
|
||||||
|
fs.getConf().set(FS_PERMISSIONS_UMASK_KEY, oldUMask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnlyAccessAclNewFile() throws Exception {
|
public void testOnlyAccessAclNewFile() throws Exception {
|
||||||
FileSystem.mkdirs(fs, path, FsPermission.createImmutable((short)0750));
|
FileSystem.mkdirs(fs, path, FsPermission.createImmutable((short)0750));
|
||||||
|
@ -942,6 +983,56 @@ public abstract class FSAclBaseTest {
|
||||||
assertAclFeature(dirPath, true);
|
assertAclFeature(dirPath, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUMaskDefaultAclNewDir() throws Exception {
|
||||||
|
FileSystem.mkdirs(fs, path, FsPermission.createImmutable((short)0750));
|
||||||
|
List<AclEntry> aclSpec = Lists.newArrayList(
|
||||||
|
aclEntry(DEFAULT, GROUP, ALL),
|
||||||
|
aclEntry(DEFAULT, USER, "foo", ALL));
|
||||||
|
fs.setAcl(path, aclSpec);
|
||||||
|
|
||||||
|
String oldUMask = fs.getConf().get(FS_PERMISSIONS_UMASK_KEY);
|
||||||
|
fs.getConf().set(FS_PERMISSIONS_UMASK_KEY, "027");
|
||||||
|
|
||||||
|
FSDirectory fsDirectory = cluster.getNamesystem().getFSDirectory();
|
||||||
|
boolean oldEnabled = fsDirectory.isPosixAclInheritanceEnabled();
|
||||||
|
|
||||||
|
try {
|
||||||
|
fsDirectory.setPosixAclInheritanceEnabled(false);
|
||||||
|
Path dirPath = new Path(path, "dir1");
|
||||||
|
fs.mkdirs(dirPath);
|
||||||
|
AclStatus s = fs.getAclStatus(dirPath);
|
||||||
|
AclEntry[] returned = s.getEntries().toArray(new AclEntry[0]);
|
||||||
|
assertArrayEquals(new AclEntry[]{
|
||||||
|
aclEntry(ACCESS, USER, "foo", ALL),
|
||||||
|
aclEntry(ACCESS, GROUP, ALL),
|
||||||
|
aclEntry(DEFAULT, USER, ALL),
|
||||||
|
aclEntry(DEFAULT, USER, "foo", ALL),
|
||||||
|
aclEntry(DEFAULT, GROUP, ALL),
|
||||||
|
aclEntry(DEFAULT, MASK, ALL),
|
||||||
|
aclEntry(DEFAULT, OTHER, NONE)}, returned);
|
||||||
|
assertPermission(dirPath, (short) 010750);
|
||||||
|
|
||||||
|
fsDirectory.setPosixAclInheritanceEnabled(true);
|
||||||
|
Path dir2Path = new Path(path, "dir2");
|
||||||
|
fs.mkdirs(dir2Path);
|
||||||
|
AclStatus s2 = fs.getAclStatus(dir2Path);
|
||||||
|
AclEntry[] returned2 = s2.getEntries().toArray(new AclEntry[0]);
|
||||||
|
assertArrayEquals(new AclEntry[]{
|
||||||
|
aclEntry(ACCESS, USER, "foo", ALL),
|
||||||
|
aclEntry(ACCESS, GROUP, ALL),
|
||||||
|
aclEntry(DEFAULT, USER, ALL),
|
||||||
|
aclEntry(DEFAULT, USER, "foo", ALL),
|
||||||
|
aclEntry(DEFAULT, GROUP, ALL),
|
||||||
|
aclEntry(DEFAULT, MASK, ALL),
|
||||||
|
aclEntry(DEFAULT, OTHER, NONE)}, returned2);
|
||||||
|
assertPermission(dir2Path, (short) 010770);
|
||||||
|
} finally {
|
||||||
|
fsDirectory.setPosixAclInheritanceEnabled(oldEnabled);
|
||||||
|
fs.getConf().set(FS_PERMISSIONS_UMASK_KEY, oldUMask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnlyAccessAclNewDir() throws Exception {
|
public void testOnlyAccessAclNewDir() throws Exception {
|
||||||
FileSystem.mkdirs(fs, path, FsPermission.createImmutable((short)0750));
|
FileSystem.mkdirs(fs, path, FsPermission.createImmutable((short)0750));
|
||||||
|
|
|
@ -127,7 +127,7 @@ public class TestGetBlockLocations {
|
||||||
MOCK_INODE_ID, FILE_NAME.getBytes(StandardCharsets.UTF_8),
|
MOCK_INODE_ID, FILE_NAME.getBytes(StandardCharsets.UTF_8),
|
||||||
perm, 1, 1, new BlockInfo[] {}, (short) 1,
|
perm, 1, 1, new BlockInfo[] {}, (short) 1,
|
||||||
DFS_BLOCK_SIZE_DEFAULT);
|
DFS_BLOCK_SIZE_DEFAULT);
|
||||||
fsn.getFSDirectory().addINode(iip, file);
|
fsn.getFSDirectory().addINode(iip, file, null);
|
||||||
return fsn;
|
return fsn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1570,7 +1570,9 @@ public class TestRenameWithSnapshots {
|
||||||
FSDirectory fsdir2 = Mockito.spy(fsdir);
|
FSDirectory fsdir2 = Mockito.spy(fsdir);
|
||||||
Mockito.doThrow(new NSQuotaExceededException("fake exception")).when(fsdir2)
|
Mockito.doThrow(new NSQuotaExceededException("fake exception")).when(fsdir2)
|
||||||
.addLastINode((INodesInPath) Mockito.anyObject(),
|
.addLastINode((INodesInPath) Mockito.anyObject(),
|
||||||
(INode) Mockito.anyObject(), Mockito.anyBoolean());
|
(INode) Mockito.anyObject(),
|
||||||
|
(FsPermission) Mockito.anyObject(),
|
||||||
|
Mockito.anyBoolean());
|
||||||
Whitebox.setInternalState(fsn, "dir", fsdir2);
|
Whitebox.setInternalState(fsn, "dir", fsdir2);
|
||||||
// rename /test/dir1/foo to /test/dir2/subdir2/foo.
|
// rename /test/dir1/foo to /test/dir2/subdir2/foo.
|
||||||
// FSDirectory#verifyQuota4Rename will pass since the remaining quota is 2.
|
// FSDirectory#verifyQuota4Rename will pass since the remaining quota is 2.
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue