HADOOP-10919. Copy command should preserve raw.* namespace extended attributes. (clamb)
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/fs-encryption@1616840 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
1fa2d6c4ba
commit
e6bdb33784
|
@ -46,6 +46,9 @@ fs-encryption (Unreleased)
|
||||||
HADOOP-10853. Refactor get instance of CryptoCodec and support create via
|
HADOOP-10853. Refactor get instance of CryptoCodec and support create via
|
||||||
algorithm/mode/padding. (Yi Liu)
|
algorithm/mode/padding. (Yi Liu)
|
||||||
|
|
||||||
|
HADOOP-10919. Copy command should preserve raw.* namespace
|
||||||
|
extended attributes. (clamb)
|
||||||
|
|
||||||
OPTIMIZATIONS
|
OPTIMIZATIONS
|
||||||
|
|
||||||
BUG FIXES
|
BUG FIXES
|
||||||
|
|
|
@ -57,6 +57,17 @@ abstract class CommandWithDestination extends FsCommand {
|
||||||
private boolean verifyChecksum = true;
|
private boolean verifyChecksum = true;
|
||||||
private boolean writeChecksum = true;
|
private boolean writeChecksum = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the raw xattr namespace. It would be nice to use
|
||||||
|
* XAttr.RAW.name() but we can't reference the hadoop-hdfs project.
|
||||||
|
*/
|
||||||
|
private final String RAW = "raw.";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the reserved raw directory.
|
||||||
|
*/
|
||||||
|
private final String RESERVED_RAW = "/.reserved/raw";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* This method is used to enable the force(-f) option while copying the files.
|
* This method is used to enable the force(-f) option while copying the files.
|
||||||
|
@ -231,7 +242,7 @@ abstract class CommandWithDestination extends FsCommand {
|
||||||
/**
|
/**
|
||||||
* Called with a source and target destination pair
|
* Called with a source and target destination pair
|
||||||
* @param src for the operation
|
* @param src for the operation
|
||||||
* @param target for the operation
|
* @param dst for the operation
|
||||||
* @throws IOException if anything goes wrong
|
* @throws IOException if anything goes wrong
|
||||||
*/
|
*/
|
||||||
protected void processPath(PathData src, PathData dst) throws IOException {
|
protected void processPath(PathData src, PathData dst) throws IOException {
|
||||||
|
@ -253,6 +264,8 @@ abstract class CommandWithDestination extends FsCommand {
|
||||||
// modify dst as we descend to append the basename of the
|
// modify dst as we descend to append the basename of the
|
||||||
// current directory being processed
|
// current directory being processed
|
||||||
dst = getTargetPath(src);
|
dst = getTargetPath(src);
|
||||||
|
final boolean preserveRawXattrs =
|
||||||
|
checkPathsForReservedRaw(src.path, dst.path);
|
||||||
if (dst.exists) {
|
if (dst.exists) {
|
||||||
if (!dst.stat.isDirectory()) {
|
if (!dst.stat.isDirectory()) {
|
||||||
throw new PathIsNotDirectoryException(dst.toString());
|
throw new PathIsNotDirectoryException(dst.toString());
|
||||||
|
@ -268,7 +281,7 @@ abstract class CommandWithDestination extends FsCommand {
|
||||||
}
|
}
|
||||||
super.recursePath(src);
|
super.recursePath(src);
|
||||||
if (dst.stat.isDirectory()) {
|
if (dst.stat.isDirectory()) {
|
||||||
preserveAttributes(src, dst);
|
preserveAttributes(src, dst, preserveRawXattrs);
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
dst = savedDst;
|
dst = savedDst;
|
||||||
|
@ -295,18 +308,60 @@ abstract class CommandWithDestination extends FsCommand {
|
||||||
* @param target where to copy the item
|
* @param target where to copy the item
|
||||||
* @throws IOException if copy fails
|
* @throws IOException if copy fails
|
||||||
*/
|
*/
|
||||||
protected void copyFileToTarget(PathData src, PathData target) throws IOException {
|
protected void copyFileToTarget(PathData src, PathData target)
|
||||||
|
throws IOException {
|
||||||
|
final boolean preserveRawXattrs =
|
||||||
|
checkPathsForReservedRaw(src.path, target.path);
|
||||||
src.fs.setVerifyChecksum(verifyChecksum);
|
src.fs.setVerifyChecksum(verifyChecksum);
|
||||||
InputStream in = null;
|
InputStream in = null;
|
||||||
try {
|
try {
|
||||||
in = src.fs.open(src.path);
|
in = src.fs.open(src.path);
|
||||||
copyStreamToTarget(in, target);
|
copyStreamToTarget(in, target);
|
||||||
preserveAttributes(src, target);
|
preserveAttributes(src, target, preserveRawXattrs);
|
||||||
} finally {
|
} finally {
|
||||||
IOUtils.closeStream(in);
|
IOUtils.closeStream(in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the source and target paths to ensure that they are either both in
|
||||||
|
* /.reserved/raw or neither in /.reserved/raw. If neither src nor target are
|
||||||
|
* in /.reserved/raw, then return false, indicating not to preserve raw.*
|
||||||
|
* xattrs. If both src/target are in /.reserved/raw, then return true,
|
||||||
|
* indicating raw.* xattrs should be preserved. If only one of src/target is
|
||||||
|
* in /.reserved/raw then throw an exception.
|
||||||
|
*
|
||||||
|
* @param src The source path to check. This should be a fully-qualified
|
||||||
|
* path, not relative.
|
||||||
|
* @param target The target path to check. This should be a fully-qualified
|
||||||
|
* path, not relative.
|
||||||
|
* @return true if raw.* xattrs should be preserved.
|
||||||
|
* @throws PathOperationException is only one of src/target are in
|
||||||
|
* /.reserved/raw.
|
||||||
|
*/
|
||||||
|
private boolean checkPathsForReservedRaw(Path src, Path target)
|
||||||
|
throws PathOperationException {
|
||||||
|
final boolean srcIsRR = Path.getPathWithoutSchemeAndAuthority(src).
|
||||||
|
toString().startsWith(RESERVED_RAW);
|
||||||
|
final boolean dstIsRR = Path.getPathWithoutSchemeAndAuthority(target).
|
||||||
|
toString().startsWith(RESERVED_RAW);
|
||||||
|
boolean preserveRawXattrs = false;
|
||||||
|
if (srcIsRR && !dstIsRR) {
|
||||||
|
final String s = "' copy from '" + RESERVED_RAW + "' to non '" +
|
||||||
|
RESERVED_RAW + "'. Either both source and target must be in '" +
|
||||||
|
RESERVED_RAW + "' or neither.";
|
||||||
|
throw new PathOperationException("'" + src.toString() + s);
|
||||||
|
} else if (!srcIsRR && dstIsRR) {
|
||||||
|
final String s = "' copy from non '" + RESERVED_RAW +"' to '" +
|
||||||
|
RESERVED_RAW + "'. Either both source and target must be in '" +
|
||||||
|
RESERVED_RAW + "' or neither.";
|
||||||
|
throw new PathOperationException("'" + dst.toString() + s);
|
||||||
|
} else if (srcIsRR && dstIsRR) {
|
||||||
|
preserveRawXattrs = true;
|
||||||
|
}
|
||||||
|
return preserveRawXattrs;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copies the stream contents to a temporary file. If the copy is
|
* Copies the stream contents to a temporary file. If the copy is
|
||||||
* successful, the temporary file will be renamed to the real path,
|
* successful, the temporary file will be renamed to the real path,
|
||||||
|
@ -337,9 +392,11 @@ abstract class CommandWithDestination extends FsCommand {
|
||||||
* attribute to preserve.
|
* attribute to preserve.
|
||||||
* @param src source to preserve
|
* @param src source to preserve
|
||||||
* @param target where to preserve attributes
|
* @param target where to preserve attributes
|
||||||
|
* @param preserveRawXAttrs true if raw.* xattrs should be preserved
|
||||||
* @throws IOException if fails to preserve attributes
|
* @throws IOException if fails to preserve attributes
|
||||||
*/
|
*/
|
||||||
protected void preserveAttributes(PathData src, PathData target)
|
protected void preserveAttributes(PathData src, PathData target,
|
||||||
|
boolean preserveRawXAttrs)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
if (shouldPreserve(FileAttribute.TIMESTAMPS)) {
|
if (shouldPreserve(FileAttribute.TIMESTAMPS)) {
|
||||||
target.fs.setTimes(
|
target.fs.setTimes(
|
||||||
|
@ -369,17 +426,21 @@ abstract class CommandWithDestination extends FsCommand {
|
||||||
target.fs.setAcl(target.path, srcFullEntries);
|
target.fs.setAcl(target.path, srcFullEntries);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (shouldPreserve(FileAttribute.XATTR)) {
|
final boolean preserveXAttrs = shouldPreserve(FileAttribute.XATTR);
|
||||||
|
if (preserveXAttrs || preserveRawXAttrs) {
|
||||||
Map<String, byte[]> srcXAttrs = src.fs.getXAttrs(src.path);
|
Map<String, byte[]> srcXAttrs = src.fs.getXAttrs(src.path);
|
||||||
if (srcXAttrs != null) {
|
if (srcXAttrs != null) {
|
||||||
Iterator<Entry<String, byte[]>> iter = srcXAttrs.entrySet().iterator();
|
Iterator<Entry<String, byte[]>> iter = srcXAttrs.entrySet().iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
Entry<String, byte[]> entry = iter.next();
|
Entry<String, byte[]> entry = iter.next();
|
||||||
|
final String xattrName = entry.getKey();
|
||||||
|
if (xattrName.startsWith(RAW) || preserveXAttrs) {
|
||||||
target.fs.setXAttr(target.path, entry.getKey(), entry.getValue());
|
target.fs.setXAttr(target.path, entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Helper filter filesystem that registers created files as temp files to
|
// Helper filter filesystem that registers created files as temp files to
|
||||||
// be deleted on exit unless successfully renamed
|
// be deleted on exit unless successfully renamed
|
||||||
|
|
|
@ -143,7 +143,11 @@ class CopyCommands {
|
||||||
"timestamps, ownership, permission. If -pa is specified, " +
|
"timestamps, ownership, permission. If -pa is specified, " +
|
||||||
"then preserves permission also because ACL is a super-set of " +
|
"then preserves permission also because ACL is a super-set of " +
|
||||||
"permission. Passing -f overwrites the destination if it " +
|
"permission. Passing -f overwrites the destination if it " +
|
||||||
"already exists.\n";
|
"already exists. raw namespace extended attributes are preserved " +
|
||||||
|
"if (1) they are supported (HDFS only) and, (2) all of the source and " +
|
||||||
|
"target pathnames are in the /.reserved/raw hierarchy. raw namespace " +
|
||||||
|
"xattr preservation is determined solely by the presence (or absence) " +
|
||||||
|
"of the /.reserved/raw prefix and not by the -p option.\n";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void processOptions(LinkedList<String> args) throws IOException {
|
protected void processOptions(LinkedList<String> args) throws IOException {
|
||||||
|
|
|
@ -164,6 +164,12 @@ cp
|
||||||
Copy files from source to destination. This command allows multiple sources
|
Copy files from source to destination. This command allows multiple sources
|
||||||
as well in which case the destination must be a directory.
|
as well in which case the destination must be a directory.
|
||||||
|
|
||||||
|
'raw.*' namespace extended attributes are preserved if (1) the source and
|
||||||
|
destination filesystems support them (HDFS only), and (2) all source and
|
||||||
|
destination pathnames are in the /.reserved/raw hierarchy. Determination of
|
||||||
|
whether raw.* namespace xattrs are preserved is independent of the
|
||||||
|
-p (preserve) flag.
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
|
|
||||||
* The -f option will overwrite the destination if it already exists.
|
* The -f option will overwrite the destination if it already exists.
|
||||||
|
@ -172,7 +178,8 @@ cp
|
||||||
ownership, permission, ACL, XAttr). If -p is specified with no <arg>,
|
ownership, permission, ACL, XAttr). If -p is specified with no <arg>,
|
||||||
then preserves timestamps, ownership, permission. If -pa is specified,
|
then preserves timestamps, ownership, permission. If -pa is specified,
|
||||||
then preserves permission also because ACL is a super-set of
|
then preserves permission also because ACL is a super-set of
|
||||||
permission.
|
permission. Determination of whether raw namespace extended attributes
|
||||||
|
are preserved is independent of the -p flag.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
|
|
|
@ -77,6 +77,13 @@ public class TestDFSShell {
|
||||||
|
|
||||||
static final String TEST_ROOT_DIR = PathUtils.getTestDirName(TestDFSShell.class);
|
static final String TEST_ROOT_DIR = PathUtils.getTestDirName(TestDFSShell.class);
|
||||||
|
|
||||||
|
private static final String RAW_A1 = "raw.a1";
|
||||||
|
private static final String TRUSTED_A1 = "trusted.a1";
|
||||||
|
private static final String USER_A1 = "user.a1";
|
||||||
|
private static final byte[] RAW_A1_VALUE = new byte[]{0x32, 0x32, 0x32};
|
||||||
|
private static final byte[] TRUSTED_A1_VALUE = new byte[]{0x31, 0x31, 0x31};
|
||||||
|
private static final byte[] USER_A1_VALUE = new byte[]{0x31, 0x32, 0x33};
|
||||||
|
|
||||||
static Path writeFile(FileSystem fs, Path f) throws IOException {
|
static Path writeFile(FileSystem fs, Path f) throws IOException {
|
||||||
DataOutputStream out = fs.create(f);
|
DataOutputStream out = fs.create(f);
|
||||||
out.writeBytes("dhruba: " + f);
|
out.writeBytes("dhruba: " + f);
|
||||||
|
@ -1664,8 +1671,8 @@ public class TestDFSShell {
|
||||||
final String group = status.getGroup();
|
final String group = status.getGroup();
|
||||||
final FsPermission perm = status.getPermission();
|
final FsPermission perm = status.getPermission();
|
||||||
|
|
||||||
fs.setXAttr(src, "user.a1", new byte[]{0x31, 0x32, 0x33});
|
fs.setXAttr(src, USER_A1, USER_A1_VALUE);
|
||||||
fs.setXAttr(src, "trusted.a1", new byte[]{0x31, 0x31, 0x31});
|
fs.setXAttr(src, TRUSTED_A1, TRUSTED_A1_VALUE);
|
||||||
|
|
||||||
shell = new FsShell(conf);
|
shell = new FsShell(conf);
|
||||||
|
|
||||||
|
@ -1722,8 +1729,8 @@ public class TestDFSShell {
|
||||||
assertTrue(perm.equals(targetPerm));
|
assertTrue(perm.equals(targetPerm));
|
||||||
xattrs = fs.getXAttrs(target3);
|
xattrs = fs.getXAttrs(target3);
|
||||||
assertEquals(xattrs.size(), 2);
|
assertEquals(xattrs.size(), 2);
|
||||||
assertArrayEquals(new byte[]{0x31, 0x32, 0x33}, xattrs.get("user.a1"));
|
assertArrayEquals(USER_A1_VALUE, xattrs.get(USER_A1));
|
||||||
assertArrayEquals(new byte[]{0x31, 0x31, 0x31}, xattrs.get("trusted.a1"));
|
assertArrayEquals(TRUSTED_A1_VALUE, xattrs.get(TRUSTED_A1));
|
||||||
acls = fs.getAclStatus(target3).getEntries();
|
acls = fs.getAclStatus(target3).getEntries();
|
||||||
assertTrue(acls.isEmpty());
|
assertTrue(acls.isEmpty());
|
||||||
assertFalse(targetPerm.getAclBit());
|
assertFalse(targetPerm.getAclBit());
|
||||||
|
@ -1780,6 +1787,160 @@ public class TestDFSShell {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test (timeout = 120000)
|
||||||
|
public void testCopyCommandsWithRawXAttrs() throws Exception {
|
||||||
|
final Configuration conf = new Configuration();
|
||||||
|
conf.setBoolean(DFSConfigKeys.DFS_NAMENODE_XATTRS_ENABLED_KEY, true);
|
||||||
|
final MiniDFSCluster cluster = new MiniDFSCluster.Builder(conf).
|
||||||
|
numDataNodes(1).format(true).build();
|
||||||
|
FsShell shell = null;
|
||||||
|
FileSystem fs = null;
|
||||||
|
final String testdir = "/tmp/TestDFSShell-testCopyCommandsWithRawXAttrs-"
|
||||||
|
+ counter.getAndIncrement();
|
||||||
|
final Path hdfsTestDir = new Path(testdir);
|
||||||
|
final Path rawHdfsTestDir = new Path("/.reserved/raw" + testdir);
|
||||||
|
try {
|
||||||
|
fs = cluster.getFileSystem();
|
||||||
|
fs.mkdirs(hdfsTestDir);
|
||||||
|
final Path src = new Path(hdfsTestDir, "srcfile");
|
||||||
|
final String rawSrcBase = "/.reserved/raw" + testdir;
|
||||||
|
final Path rawSrc = new Path(rawSrcBase, "srcfile");
|
||||||
|
fs.create(src).close();
|
||||||
|
|
||||||
|
final Path srcDir = new Path(hdfsTestDir, "srcdir");
|
||||||
|
final Path rawSrcDir = new Path("/.reserved/raw" + testdir, "srcdir");
|
||||||
|
fs.mkdirs(srcDir);
|
||||||
|
final Path srcDirFile = new Path(srcDir, "srcfile");
|
||||||
|
final Path rawSrcDirFile =
|
||||||
|
new Path("/.reserved/raw" + srcDirFile);
|
||||||
|
fs.create(srcDirFile).close();
|
||||||
|
|
||||||
|
final Path[] paths = { rawSrc, rawSrcDir, rawSrcDirFile };
|
||||||
|
final String[] xattrNames = { USER_A1, RAW_A1 };
|
||||||
|
final byte[][] xattrVals = { USER_A1_VALUE, RAW_A1_VALUE };
|
||||||
|
|
||||||
|
for (int i = 0; i < paths.length; i++) {
|
||||||
|
for (int j = 0; j < xattrNames.length; j++) {
|
||||||
|
fs.setXAttr(paths[i], xattrNames[j], xattrVals[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shell = new FsShell(conf);
|
||||||
|
|
||||||
|
/* Check that a file as the source path works ok. */
|
||||||
|
doTestCopyCommandsWithRawXAttrs(shell, fs, src, hdfsTestDir, false);
|
||||||
|
doTestCopyCommandsWithRawXAttrs(shell, fs, rawSrc, hdfsTestDir, false);
|
||||||
|
doTestCopyCommandsWithRawXAttrs(shell, fs, src, rawHdfsTestDir, false);
|
||||||
|
doTestCopyCommandsWithRawXAttrs(shell, fs, rawSrc, rawHdfsTestDir, true);
|
||||||
|
|
||||||
|
/* Use a relative /.reserved/raw path. */
|
||||||
|
final Path savedWd = fs.getWorkingDirectory();
|
||||||
|
try {
|
||||||
|
fs.setWorkingDirectory(new Path(rawSrcBase));
|
||||||
|
final Path relRawSrc = new Path("../srcfile");
|
||||||
|
final Path relRawHdfsTestDir = new Path("..");
|
||||||
|
doTestCopyCommandsWithRawXAttrs(shell, fs, relRawSrc, relRawHdfsTestDir,
|
||||||
|
true);
|
||||||
|
} finally {
|
||||||
|
fs.setWorkingDirectory(savedWd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that a directory as the source path works ok. */
|
||||||
|
doTestCopyCommandsWithRawXAttrs(shell, fs, srcDir, hdfsTestDir, false);
|
||||||
|
doTestCopyCommandsWithRawXAttrs(shell, fs, rawSrcDir, hdfsTestDir, false);
|
||||||
|
doTestCopyCommandsWithRawXAttrs(shell, fs, srcDir, rawHdfsTestDir, false);
|
||||||
|
doTestCopyCommandsWithRawXAttrs(shell, fs, rawSrcDir, rawHdfsTestDir,
|
||||||
|
true);
|
||||||
|
|
||||||
|
/* Use relative in an absolute path. */
|
||||||
|
final String relRawSrcDir = "./.reserved/../.reserved/raw/../raw" +
|
||||||
|
testdir + "/srcdir";
|
||||||
|
final String relRawDstDir = "./.reserved/../.reserved/raw/../raw" +
|
||||||
|
testdir;
|
||||||
|
doTestCopyCommandsWithRawXAttrs(shell, fs, new Path(relRawSrcDir),
|
||||||
|
new Path(relRawDstDir), true);
|
||||||
|
} finally {
|
||||||
|
if (null != shell) {
|
||||||
|
shell.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (null != fs) {
|
||||||
|
fs.delete(hdfsTestDir, true);
|
||||||
|
fs.close();
|
||||||
|
}
|
||||||
|
cluster.shutdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doTestCopyCommandsWithRawXAttrs(FsShell shell, FileSystem fs,
|
||||||
|
Path src, Path hdfsTestDir, boolean expectRaw) throws Exception {
|
||||||
|
Path target;
|
||||||
|
boolean srcIsRaw;
|
||||||
|
if (src.isAbsolute()) {
|
||||||
|
srcIsRaw = src.toString().contains("/.reserved/raw");
|
||||||
|
} else {
|
||||||
|
srcIsRaw = new Path(fs.getWorkingDirectory(), src).
|
||||||
|
toString().contains("/.reserved/raw");
|
||||||
|
}
|
||||||
|
final boolean destIsRaw = hdfsTestDir.toString().contains("/.reserved/raw");
|
||||||
|
final boolean srcDestMismatch = srcIsRaw ^ destIsRaw;
|
||||||
|
|
||||||
|
// -p (possibly preserve raw if src & dst are both /.r/r */
|
||||||
|
if (srcDestMismatch) {
|
||||||
|
doCopyAndTest(shell, hdfsTestDir, src, "-p", ERROR);
|
||||||
|
} else {
|
||||||
|
target = doCopyAndTest(shell, hdfsTestDir, src, "-p", SUCCESS);
|
||||||
|
checkXAttrs(fs, target, expectRaw, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// -px (possibly preserve raw, always preserve non-raw xattrs. */
|
||||||
|
if (srcDestMismatch) {
|
||||||
|
doCopyAndTest(shell, hdfsTestDir, src, "-px", ERROR);
|
||||||
|
} else {
|
||||||
|
target = doCopyAndTest(shell, hdfsTestDir, src, "-px", SUCCESS);
|
||||||
|
checkXAttrs(fs, target, expectRaw, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// no args (possibly preserve raw, never preserve non-raw xattrs. */
|
||||||
|
if (srcDestMismatch) {
|
||||||
|
doCopyAndTest(shell, hdfsTestDir, src, null, ERROR);
|
||||||
|
} else {
|
||||||
|
target = doCopyAndTest(shell, hdfsTestDir, src, null, SUCCESS);
|
||||||
|
checkXAttrs(fs, target, expectRaw, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Path doCopyAndTest(FsShell shell, Path dest, Path src,
|
||||||
|
String cpArgs, int expectedExitCode) throws Exception {
|
||||||
|
final Path target = new Path(dest, "targetfile" +
|
||||||
|
counter.getAndIncrement());
|
||||||
|
final String[] argv = cpArgs == null ?
|
||||||
|
new String[] { "-cp", src.toUri().toString(),
|
||||||
|
target.toUri().toString() } :
|
||||||
|
new String[] { "-cp", cpArgs, src.toUri().toString(),
|
||||||
|
target.toUri().toString() };
|
||||||
|
final int ret = ToolRunner.run(shell, argv);
|
||||||
|
assertEquals("cp -p is not working", expectedExitCode, ret);
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkXAttrs(FileSystem fs, Path target, boolean expectRaw,
|
||||||
|
boolean expectVanillaXAttrs) throws Exception {
|
||||||
|
final Map<String, byte[]> xattrs = fs.getXAttrs(target);
|
||||||
|
int expectedCount = 0;
|
||||||
|
if (expectRaw) {
|
||||||
|
assertArrayEquals("raw.a1 has incorrect value",
|
||||||
|
RAW_A1_VALUE, xattrs.get(RAW_A1));
|
||||||
|
expectedCount++;
|
||||||
|
}
|
||||||
|
if (expectVanillaXAttrs) {
|
||||||
|
assertArrayEquals("user.a1 has incorrect value",
|
||||||
|
USER_A1_VALUE, xattrs.get(USER_A1));
|
||||||
|
expectedCount++;
|
||||||
|
}
|
||||||
|
assertEquals("xattrs size mismatch", expectedCount, xattrs.size());
|
||||||
|
}
|
||||||
|
|
||||||
// verify cp -ptopxa option will preserve directory attributes.
|
// verify cp -ptopxa option will preserve directory attributes.
|
||||||
@Test (timeout = 120000)
|
@Test (timeout = 120000)
|
||||||
public void testCopyCommandsToDirectoryWithPreserveOption()
|
public void testCopyCommandsToDirectoryWithPreserveOption()
|
||||||
|
@ -1825,8 +1986,8 @@ public class TestDFSShell {
|
||||||
final String group = status.getGroup();
|
final String group = status.getGroup();
|
||||||
final FsPermission perm = status.getPermission();
|
final FsPermission perm = status.getPermission();
|
||||||
|
|
||||||
fs.setXAttr(srcDir, "user.a1", new byte[]{0x31, 0x32, 0x33});
|
fs.setXAttr(srcDir, USER_A1, USER_A1_VALUE);
|
||||||
fs.setXAttr(srcDir, "trusted.a1", new byte[]{0x31, 0x31, 0x31});
|
fs.setXAttr(srcDir, TRUSTED_A1, TRUSTED_A1_VALUE);
|
||||||
|
|
||||||
shell = new FsShell(conf);
|
shell = new FsShell(conf);
|
||||||
|
|
||||||
|
@ -1883,8 +2044,8 @@ public class TestDFSShell {
|
||||||
assertTrue(perm.equals(targetPerm));
|
assertTrue(perm.equals(targetPerm));
|
||||||
xattrs = fs.getXAttrs(targetDir3);
|
xattrs = fs.getXAttrs(targetDir3);
|
||||||
assertEquals(xattrs.size(), 2);
|
assertEquals(xattrs.size(), 2);
|
||||||
assertArrayEquals(new byte[]{0x31, 0x32, 0x33}, xattrs.get("user.a1"));
|
assertArrayEquals(USER_A1_VALUE, xattrs.get(USER_A1));
|
||||||
assertArrayEquals(new byte[]{0x31, 0x31, 0x31}, xattrs.get("trusted.a1"));
|
assertArrayEquals(TRUSTED_A1_VALUE, xattrs.get(TRUSTED_A1));
|
||||||
acls = fs.getAclStatus(targetDir3).getEntries();
|
acls = fs.getAclStatus(targetDir3).getEntries();
|
||||||
assertTrue(acls.isEmpty());
|
assertTrue(acls.isEmpty());
|
||||||
assertFalse(targetPerm.getAclBit());
|
assertFalse(targetPerm.getAclBit());
|
||||||
|
|
Loading…
Reference in New Issue