Skip to content

Commit

Permalink
Implemented 'ltree' command
Browse files Browse the repository at this point in the history
  • Loading branch information
p0dalirius committed May 31, 2024
1 parent 3acb666 commit 95dcfef
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 9 deletions.
6 changes: 5 additions & 1 deletion smbclientng/core/CommandCompleter.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ class CommandCompleter(object):
"description": ["List the contents of the current remote working directory.", "Syntax: 'ls'"],
"subcommands": []
},
"ltree": {
"description": ["Displays a tree view of the local directories.", "Syntax: ltree [directory]"],
"subcommands": []
},
"mkdir": {
"description": ["Creates a new remote directory.", "Syntax: 'mkdir <directory>'"],
"subcommands": []
Expand Down Expand Up @@ -123,7 +127,7 @@ class CommandCompleter(object):
"subcommands": []
},
"tree": {
"description": ["Displays a tree view of the nested subfolders.", "Syntax: tree [directory]"],
"description": ["Displays a tree view of the remote directories.", "Syntax: tree [directory]"],
"subcommands": []
},
}
Expand Down
26 changes: 20 additions & 6 deletions smbclientng/core/InteractiveShell.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from rich.console import Console
from rich.table import Table
from smbclientng.core.CommandCompleter import CommandCompleter
from smbclientng.core.utils import b_filesize, unix_permissions, windows_ls_entry
from smbclientng.core.utils import b_filesize, unix_permissions, windows_ls_entry, local_tree


## Decorators
Expand Down Expand Up @@ -172,6 +172,10 @@ def process_command(self, command, arguments=[]):
elif command == "lmkdir":
self.command_lmkdir(arguments, command)

# Shows the current local directory
elif command == "lpwd":
self.command_lpwd(arguments, command)

# Removes a local file
elif command == "lrm":
self.command_lrm(arguments, command)
Expand All @@ -181,10 +185,10 @@ def process_command(self, command, arguments=[]):
self.command_lrmdir(arguments, command)

# Shows the current local directory
elif command == "lpwd":
self.command_lpwd(arguments, command)
elif command == "ltree":
self.command_ltree(arguments, command)

#
# Modules
elif command == "module":
self.command_module(arguments, command)

Expand Down Expand Up @@ -373,6 +377,13 @@ def command_lmkdir(self, arguments, command):
if not os.path.exists(tmp_path):
os.mkdir(path=tmp_path)

def command_lpwd(self, arguments, command):
# Command arguments required : No
# Active SMB connection needed : No
# SMB share needed : No

print(os.getcwd())

@command_arguments_required
def command_lrm(self, arguments, command):
# Command arguments required : Yes
Expand Down Expand Up @@ -409,12 +420,15 @@ def command_lrmdir(self, arguments, command):
else:
print("[!] Path '%s' does not exist." % path)

def command_lpwd(self, arguments, command):
def command_ltree(self, arguments, command):
# Command arguments required : No
# Active SMB connection needed : No
# SMB share needed : No

print(os.getcwd())
if len(arguments) == 0:
local_tree(path='.', config=self.config)
else:
local_tree(path=' '.join(arguments), config=self.config)

@active_smb_connection_needed
@smb_share_is_set
Expand Down
116 changes: 114 additions & 2 deletions smbclientng/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def windows_ls_entry(entry, config, pathToPrint=None):
"""

if pathToPrint is None:
pathToPrint = entry.get_longname()
pathToPrint = entry

meta_string = ""
meta_string += ("d" if entry.is_directory() else "-")
Expand All @@ -174,4 +174,116 @@ def windows_ls_entry(entry, config, pathToPrint=None):
if config.no_colors:
print("%s %10s %s %s" % (meta_string, size_str, date_str, pathToPrint))
else:
print("%s %10s %s \x1b[1m%s\x1b[0m" % (meta_string, size_str, date_str, pathToPrint))
print("%s %10s %s \x1b[1m%s\x1b[0m" % (meta_string, size_str, date_str, pathToPrint))


def local_tree(path, config):
def recurse_action(base_dir="", path=[], prompt=[]):
bars = ["│ ", "├── ", "└── "]

local_path = os.path.normpath(base_dir + os.path.sep + os.path.sep.join(path) + os.path.sep)

entries = []
try:
entries = os.listdir(local_path)
except Exception as err:
if config.no_colors:
print("%s%s" % (''.join(prompt+[bars[2]]), err))
else:
print("%s\x1b[1;91m%s\x1b[0m" % (''.join(prompt+[bars[2]]), err))
return

entries = sorted(entries)

#
if len(entries) > 1:
index = 0
for entry in entries:
index += 1
# This is the first entry
if index == 0:
if os.path.isdir(local_path + os.path.sep + entry):
if config.no_colors:
print("%s%s%s" % (''.join(prompt+[bars[1]]), entry, os.path.sep))
else:
print("%s\x1b[1;96m%s\x1b[0m%s" % (''.join(prompt+[bars[1]]), entry, os.path.sep))
recurse_action(
base_dir=base_dir,
path=path+[entry],
prompt=prompt+["│ "]
)
else:
if config.no_colors:
print("%s%s" % (''.join(prompt+[bars[1]]), entry))
else:
print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry))

# This is the last entry
elif index == len(entries):
if os.path.isdir(local_path + os.path.sep + entry):
if config.no_colors:
print("%s%s%s" % (''.join(prompt+[bars[2]]), entry, os.path.sep))
else:
print("%s\x1b[1;96m%s\x1b[0m%s" % (''.join(prompt+[bars[2]]), entry, os.path.sep))
recurse_action(
base_dir=base_dir,
path=path+[entry],
prompt=prompt+[" "]
)
else:
if config.no_colors:
print("%s%s" % (''.join(prompt+[bars[2]]), entry))
else:
print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry))

# These are entries in the middle
else:
if os.path.isdir(local_path + os.path.sep + entry):
if config.no_colors:
print("%s%s%s" % (''.join(prompt+[bars[1]]), entry, os.path.sep))
else:
print("%s\x1b[1;96m%s\x1b[0m%s" % (''.join(prompt+[bars[1]]), entry, os.path.sep))
recurse_action(
base_dir=base_dir,
path=path+[entry],
prompt=prompt+["│ "]
)
else:
if config.no_colors:
print("%s%s" % (''.join(prompt+[bars[1]]), entry))
else:
print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry))

#
elif len(entries) == 1:
entry = entries[0]
if os.path.isdir(local_path + os.path.sep + entry):
if config.no_colors:
print("%s%s%s" % (''.join(prompt+[bars[2]]), entry, os.path.sep))
else:
print("%s\x1b[1;96m%s\x1b[0m%s" % (''.join(prompt+[bars[2]]), entry, os.path.sep))
recurse_action(
base_dir=base_dir,
path=path+[entry],
prompt=prompt+[" "]
)
else:
if config.no_colors:
print("%s%s" % (''.join(prompt+[bars[2]]), entry))
else:
print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry))

# Entrypoint
try:
if config.no_colors:
print("%s%s" % (path, os.path.sep))
else:
print("\x1b[1;96m%s\x1b[0m%s" % (path, os.path.sep))
recurse_action(
base_dir=os.getcwd(),
path=[path],
prompt=[""]
)
except (BrokenPipeError, KeyboardInterrupt) as e:
print("[!] Interrupted.")

0 comments on commit 95dcfef

Please sign in to comment.