Skip to content

Commit 717a5a7

Browse files
committed
HADOOP-16082. FsShell ls: Add option -i to print inode id
Change-Id: If67575b1769dc9628d6ed57ebb7fa3317c29e291
1 parent fba222a commit 717a5a7

File tree

4 files changed

+83
-4
lines changed

4 files changed

+83
-4
lines changed

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/CommandUtils.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,42 @@
1818
package org.apache.hadoop.fs.shell;
1919

2020
final class CommandUtils {
21+
22+
private static final String FILE_STATUS_STRING_KV_SEPARATOR = "=";
23+
private static final String FILE_STATUS_STRING_DELIMITER = ";";
24+
private static final String FILE_STATUS_STRING_TERMINATOR = "}";
25+
26+
/**
27+
* Parse the FileStatus.toString() results,
28+
* and return the value of the given key.
29+
*
30+
* @param fileStatusStr String from FileStatus.toString()
31+
* @param key Key String
32+
* @return Value of the key in the String, null if not found.
33+
*/
34+
static String getValueFromFileStatusString(String fileStatusStr, String key) {
35+
String res = null;
36+
// Search backwards since this function is only used for fileId for now,
37+
// which we know we placed it at the end of the FileStatus String.
38+
int start = fileStatusStr.lastIndexOf(key);
39+
int end = -1;
40+
if (start > 0) {
41+
// fileId field found, move the start pointer to the start of the value
42+
start += key.length() + FILE_STATUS_STRING_KV_SEPARATOR.length();
43+
// Find delimiter ";" to mark value string's end
44+
end = fileStatusStr.indexOf(FILE_STATUS_STRING_DELIMITER, start);
45+
if (end < 0) {
46+
// Delimiter not found, try terminator "}"
47+
end = fileStatusStr.indexOf(FILE_STATUS_STRING_TERMINATOR, start);
48+
}
49+
}
50+
if (end > 0) {
51+
// If value end pointer is not -1
52+
res = fileStatusStr.substring(start, end);
53+
}
54+
return res;
55+
}
56+
2157
static String formatDescription(String usage, String... desciptions) {
2258
StringBuilder b = new StringBuilder(usage + ": " + desciptions[0]);
2359
for(int i = 1; i < desciptions.length; i++) {

hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/shell/Ls.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,15 @@ public static void registerCommands(CommandFactory factory) {
5757
private static final String OPTION_ATIME = "u";
5858
private static final String OPTION_SIZE = "S";
5959
private static final String OPTION_ECPOLICY = "e";
60+
private static final String OPTION_PRINTINODEID = "i";
6061

6162
public static final String NAME = "ls";
6263
public static final String USAGE = "[-" + OPTION_PATHONLY + "] [-" +
6364
OPTION_DIRECTORY + "] [-" + OPTION_HUMAN + "] [-" +
6465
OPTION_HIDENONPRINTABLE + "] [-" + OPTION_RECURSIVE + "] [-" +
6566
OPTION_MTIME + "] [-" + OPTION_SIZE + "] [-" + OPTION_REVERSE + "] [-" +
66-
OPTION_ATIME + "] [-" + OPTION_ECPOLICY +"] [<path> ...]";
67+
OPTION_ATIME + "] [-" + OPTION_ECPOLICY +"] [-" +
68+
OPTION_PRINTINODEID + "] [<path> ...]";
6769

6870
public static final String DESCRIPTION =
6971
"List the contents that match the specified file pattern. If " +
@@ -96,7 +98,9 @@ public static void registerCommands(CommandFactory factory) {
9698
" Use time of last access instead of modification for\n" +
9799
" display and sorting.\n"+
98100
" -" + OPTION_ECPOLICY +
99-
" Display the erasure coding policy of files and directories.\n";
101+
" Display the erasure coding policy of files and directories.\n" +
102+
" -" + OPTION_PRINTINODEID +
103+
" Print the inode id for files and directories.\n";
100104

101105
protected final SimpleDateFormat dateFormat =
102106
new SimpleDateFormat("yyyy-MM-dd HH:mm");
@@ -110,6 +114,7 @@ public static void registerCommands(CommandFactory factory) {
110114
private boolean orderSize;
111115
private boolean useAtime;
112116
private boolean displayECPolicy;
117+
private boolean printInodeId;
113118
private Comparator<PathData> orderComparator;
114119

115120
protected boolean humanReadable = false;
@@ -135,7 +140,8 @@ protected void processOptions(LinkedList<String> args)
135140
CommandFormat cf = new CommandFormat(0, Integer.MAX_VALUE,
136141
OPTION_PATHONLY, OPTION_DIRECTORY, OPTION_HUMAN,
137142
OPTION_HIDENONPRINTABLE, OPTION_RECURSIVE, OPTION_REVERSE,
138-
OPTION_MTIME, OPTION_SIZE, OPTION_ATIME, OPTION_ECPOLICY);
143+
OPTION_MTIME, OPTION_SIZE, OPTION_ATIME, OPTION_ECPOLICY,
144+
OPTION_PRINTINODEID);
139145
cf.parse(args);
140146
pathOnly = cf.getOpt(OPTION_PATHONLY);
141147
dirRecurse = !cf.getOpt(OPTION_DIRECTORY);
@@ -147,6 +153,7 @@ protected void processOptions(LinkedList<String> args)
147153
orderSize = !orderTime && cf.getOpt(OPTION_SIZE);
148154
useAtime = cf.getOpt(OPTION_ATIME);
149155
displayECPolicy = cf.getOpt(OPTION_ECPOLICY);
156+
printInodeId = cf.getOpt(OPTION_PRINTINODEID);
150157
if (args.isEmpty()) args.add(Path.CUR_DIR);
151158

152159
initialiseOrderComparator();
@@ -289,9 +296,21 @@ protected void processPath(PathData item) throws IOException {
289296
return;
290297
}
291298
FileStatus stat = item.stat;
299+
// Using String as fileId type since we are parsing it from a String
300+
String fileIdStr = null;
301+
if (printInodeId) {
302+
final String fileIdKey = "fileId";
303+
fileIdStr = CommandUtils.getValueFromFileStatusString(
304+
item.stat.toString(), fileIdKey);
305+
if (fileIdStr == null) {
306+
// fileId field not found, set it to "0"
307+
fileIdStr = "0";
308+
}
309+
}
292310
if (displayECPolicy) {
293311
ContentSummary contentSummary = item.fs.getContentSummary(item.path);
294312
String line = String.format(lineFormat,
313+
printInodeId ? fileIdStr + " " : "",
295314
(stat.isDirectory() ? "d" : "-"),
296315
stat.getPermission() + (stat.hasAcl() ? "+" : " "),
297316
(stat.isFile() ? stat.getReplication() : "-"),
@@ -306,6 +325,7 @@ protected void processPath(PathData item) throws IOException {
306325
out.println(line);
307326
} else {
308327
String line = String.format(lineFormat,
328+
printInodeId ? fileIdStr + " " : "",
309329
(stat.isDirectory() ? "d" : "-"),
310330
stat.getPermission() + (stat.hasAcl() ? "+" : " "),
311331
(stat.isFile() ? stat.getReplication() : "-"),
@@ -334,7 +354,7 @@ private void adjustColumnWidths(PathData items[]) throws IOException {
334354
}
335355

336356
StringBuilder fmt = new StringBuilder();
337-
fmt.append("%s%s") // permission string
357+
fmt.append("%s%s%s") // inode id and permission string
338358
.append("%" + maxRepl + "s ")
339359
.append((maxOwner > 0) ? "%-" + maxOwner + "s " : "%s")
340360
.append((maxGroup > 0) ? "%-" + maxGroup + "s " : "%s");

hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/protocol/HdfsLocatedFileStatus.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,16 @@ public int hashCode() {
188188
return super.hashCode();
189189
}
190190

191+
@Override
192+
public String toString() {
193+
String res = super.toString();
194+
// Append fileId field to the end of the String, but before the "}"
195+
StringBuilder sb = new StringBuilder();
196+
sb.append(res, 0, res.length() - "}".length());
197+
sb.append("; fileId=").append(fileId).append("}");
198+
return sb.toString();
199+
}
200+
191201
/**
192202
* Get block locations for this entity, in HDFS format.
193203
* See {@link #makeQualifiedLocated(URI, Path)}.

hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestDFSShell.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2183,6 +2183,19 @@ private static String runLsr(final FsShell shell, String root, int returnvalue
21832183
return results;
21842184
}
21852185

2186+
@Test
2187+
public void testLsInodeId() throws Exception {
2188+
dfs.mkdirs(new Path("/d1/d2"));
2189+
dfs.mkdirs(new Path("/d4/d5"));
2190+
final File f3 = createLocalFile(new File(TEST_ROOT_DIR, "f3"));
2191+
dfs.moveFromLocalFile(new Path(f3.getPath()), new Path("/d1/d2"));
2192+
2193+
FsShell shell = new FsShell(dfs.getConf());
2194+
// Check return value
2195+
assertThat(shell.run(new String[]{"-ls", "-i", "/"}), is(0));
2196+
assertThat(shell.run(new String[]{"-ls", "-i", "-R", "/"}), is(0));
2197+
}
2198+
21862199
/**
21872200
* default setting is file:// which is not a DFS
21882201
* so DFSAdmin should throw and catch InvalidArgumentException

0 commit comments

Comments
 (0)