From e50989c41ee937fc8ce4dcada2446165da29a3da Mon Sep 17 00:00:00 2001 From: Srivathsa Dara Date: Mon, 7 Oct 2024 16:26:35 +0000 Subject: [PATCH] ls: Add support to recursively print dentries of subdirectories Currently, ls module prints the dentries of a given directory. Add support to print the dentries of its subdirectories recursively up to a specified depth. Signed-off-by: Srivathsa Dara --- drgn_tools/dentry.py | 45 +++++++++++++++++++++++++++++++++++++++----- tests/test_dentry.py | 2 +- 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/drgn_tools/dentry.py b/drgn_tools/dentry.py index 1a79d977..90852b65 100644 --- a/drgn_tools/dentry.py +++ b/drgn_tools/dentry.py @@ -381,24 +381,44 @@ def __file_type(mode: Object) -> str: return "UNKN" -def ls(prog: Program, directory: str, count: bool = False) -> None: +def ls( + prog: Program, + directory: str, + parent_dentry: Object, + depth: int, + count: bool = False, +) -> None: """ Print dentry children, like the ls command :param directory: directory to print children of :param count: when true, only print counts (not the full contents) """ - dentries = dentry_for_each_child(path_lookup(prog, directory).dentry) + if depth < 0: + return + + subdirs = [] + dentries = dentry_for_each_child( + parent_dentry if parent_dentry else path_lookup(prog, directory).dentry + ) + print(f"{directory}:") pos = neg = 0 for i, dentry in enumerate(dentries): + dentry_type = "positive" path = dentry_path_any_mount(dentry).decode() if dentry_is_negative(dentry): neg += 1 + dentry_type = "negative" else: + if stat.S_ISDIR(int(dentry.d_inode.i_mode)): + subdirs.append([path, dentry]) pos += 1 if not count: - print(f"{i:05d} {path}") - print(f"{pos} positive, {neg} negative dentries") + print(f"\t{i:05d} {path} ({dentry_type})") + print(f"\t{pos} positive, {neg} negative dentries") + + for dir in subdirs: + ls(prog, dir[0], dir[1], depth - 1, count) class Ls(CorelensModule): @@ -411,6 +431,14 @@ class Ls(CorelensModule): run_when = "never" def add_args(self, parser: argparse.ArgumentParser) -> None: + def non_negative_int(value): + ivalue = int(value) + if ivalue < 0: + raise argparse.ArgumentTypeError( + f"Invalid depth value: {value}. Depth must be a non-negative integer." + ) + return ivalue + parser.add_argument( "directory", type=str, @@ -422,9 +450,16 @@ def add_args(self, parser: argparse.ArgumentParser) -> None: action="store_true", help="only print counts, rather than every element", ) + parser.add_argument( + "--depth", + "-d", + type=non_negative_int, + default=0, + help="Print the dentries of subdirectories recursively up to the specified depth.", + ) def run(self, prog: Program, args: argparse.Namespace) -> None: - ls(prog, args.directory, count=args.count) + ls(prog, args.directory, None, depth=args.depth, count=args.count) class DentryCache(CorelensModule): diff --git a/tests/test_dentry.py b/tests/test_dentry.py index 90fa413a..9f68701e 100644 --- a/tests/test_dentry.py +++ b/tests/test_dentry.py @@ -17,4 +17,4 @@ def test_list_dentries_in_hashtable(prog): def test_ls(prog): - dentry.ls(prog, "/") + dentry.ls(prog, "/", None, 0)