HADOOP-13522. Add %A and %a formats for fs -stat command to print permissions. Contributed by Alex Garbarini.

(cherry picked from commit bedfec0c10)
This commit is contained in:
Akira Ajisaka 2016-10-18 14:37:32 +09:00
parent 278eeb1056
commit b2618685fb
5 changed files with 46 additions and 7 deletions

View File

@ -169,6 +169,18 @@ public class FsPermission implements Writable {
return toShort();
}
/**
* Returns the FsPermission in an octal format.
*
* @return short Unlike {@link #toShort()} which provides a binary
* representation, this method returns the standard octal style permission.
*/
public short toOctal() {
int n = this.toShort();
int octal = (n>>>9&1)*1000 + (n>>>6&7)*100 + (n>>>3&7)*10 + (n&7);
return (short)octal;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof FsPermission) {

View File

@ -31,6 +31,8 @@ import org.apache.hadoop.fs.FileStatus;
/**
* Print statistics about path in specified format.
* Format sequences:<br>
* %a: Permissions in octal<br>
* %A: Permissions in symbolic style<br>
* %b: Size of file in blocks<br>
* %F: Type<br>
* %g: Group name of owner<br>
@ -56,7 +58,8 @@ class Stat extends FsCommand {
public static final String USAGE = "[format] <path> ...";
public static final String DESCRIPTION =
"Print statistics about the file/directory at <path>" + NEWLINE +
"in the specified format. Format accepts filesize in" + NEWLINE +
"in the specified format. Format accepts permissions in" + NEWLINE +
"octal (%a) and symbolic (%A), filesize in" + NEWLINE +
"blocks (%b), type (%F), group name of owner (%g)," + NEWLINE +
"name (%n), block size (%o), replication (%r), user name" + NEWLINE +
"of owner (%u), modification date (%y, %Y)." + NEWLINE +
@ -95,6 +98,12 @@ class Stat extends FsCommand {
// this silently drops a trailing %?
if (i + 1 == fmt.length) break;
switch (fmt[++i]) {
case 'a':
buf.append(stat.getPermission().toOctal());
break;
case 'A':
buf.append(stat.getPermission());
break;
case 'b':
buf.append(stat.getLen());
break;

View File

@ -639,11 +639,11 @@ stat
Usage: `hadoop fs -stat [format] <path> ...`
Print statistics about the file/directory at \<path\> in the specified format. Format accepts filesize in blocks (%b), type (%F), group name of owner (%g), name (%n), block size (%o), replication (%r), user name of owner(%u), and modification date (%y, %Y). %y shows UTC date as "yyyy-MM-dd HH:mm:ss" and %Y shows milliseconds since January 1, 1970 UTC. If the format is not specified, %y is used by default.
Print statistics about the file/directory at \<path\> in the specified format. Format accepts permissions in octal (%a) and symbolic (%A), filesize in blocks (%b), type (%F), group name of owner (%g), name (%n), block size (%o), replication (%r), user name of owner(%u), and modification date (%y, %Y). %y shows UTC date as "yyyy-MM-dd HH:mm:ss" and %Y shows milliseconds since January 1, 1970 UTC. If the format is not specified, %y is used by default.
Example:
* `hadoop fs -stat "%F %u:%g %b %y %n" /file`
* `hadoop fs -stat "%F %a %u:%g %b %y %n" /file`
Exit Code: Returns 0 on success and -1 on error.

View File

@ -859,7 +859,11 @@
</comparator>
<comparator>
<type>RegexpComparator</type>
<expected-output>^( |\t)*in the specified format. Format accepts filesize in( )*</expected-output>
<expected-output>^( |\t)*in the specified format. Format accepts permissions in( )*</expected-output>
</comparator>
<comparator>
<type>RegexpComparator</type>
<expected-output>^( |\t)*octal \(%a\) and symbolic \(%A\), filesize in( )*</expected-output>
</comparator>
<comparator>
<type>RegexpComparator</type>

View File

@ -1954,17 +1954,31 @@ public class TestDFSShell {
out.toString(), String.format("%s%n%s%n", mtime1, mtime2));
doFsStat(dfs.getConf(), "%F %u:%g %b %y %n");
out.reset();
doFsStat(dfs.getConf(), "%F %u:%g %b %y %n", testDir1);
doFsStat(dfs.getConf(), "%F %a %A %u:%g %b %y %n", testDir1);
assertTrue(out.toString(), out.toString().contains(mtime1));
assertTrue(out.toString(), out.toString().contains("directory"));
assertTrue(out.toString(), out.toString().contains(status1.getGroup()));
assertTrue(out.toString(),
out.toString().contains(status1.getPermission().toString()));
int n = status1.getPermission().toShort();
int octal = (n>>>9&1)*1000 + (n>>>6&7)*100 + (n>>>3&7)*10 + (n&7);
assertTrue(out.toString(),
out.toString().contains(String.valueOf(octal)));
out.reset();
doFsStat(dfs.getConf(), "%F %u:%g %b %y %n", testDir1, testFile2);
doFsStat(dfs.getConf(), "%F %a %A %u:%g %b %y %n", testDir1, testFile2);
n = status2.getPermission().toShort();
octal = (n>>>9&1)*1000 + (n>>>6&7)*100 + (n>>>3&7)*10 + (n&7);
assertTrue(out.toString(), out.toString().contains(mtime1));
assertTrue(out.toString(), out.toString().contains("regular file"));
assertTrue(out.toString(),
out.toString().contains(status2.getPermission().toString()));
assertTrue(out.toString(),
out.toString().contains(String.valueOf(octal)));
assertTrue(out.toString(), out.toString().contains(mtime2));
}