Skip to content

Commit

Permalink
Add command sizeof (#20)
Browse files Browse the repository at this point in the history
* Created get_entry() function

* Created 'sizeof' command
  • Loading branch information
p0dalirius authored Jun 5, 2024
1 parent acbc0dd commit 0f5dd34
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 4 deletions.
16 changes: 15 additions & 1 deletion smbclientng/core/CommandCompleter.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ class CommandCompleter(object):
],
"subcommands": []
},
"debug": {
"description": [
"Command for dev debugging.",
"Syntax: 'debug'"
],
"subcommands": []
},
"dir": {
"description": [
"List the contents of the current working directory.",
Expand Down Expand Up @@ -208,6 +215,13 @@ class CommandCompleter(object):
],
"subcommands": []
},
"sizeof": {
"description": [
"Recursively compute the size of a folder.",
"Syntax: 'sizeof [directory|file]'"
],
"subcommands": []
},
"shares": {
"description": [
"Lists the SMB shares served by the remote machine.",
Expand Down Expand Up @@ -299,7 +313,7 @@ def complete(self, text, state):
if s.lower().startswith(remainder.lower())
]

elif command in ["bat", "cat", "get", "rm"]:
elif command in ["bat", "cat", "debug", "get", "rm"]:
# Choose local files and directories
path = ""
if '\\' in remainder.strip() or '/' in remainder.strip():
Expand Down
79 changes: 79 additions & 0 deletions smbclientng/core/InteractiveShell.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ def process_command(self, command, arguments=[]):
# Change directory in the current share
elif command == "cd":
self.command_cd(arguments, command)

# debug
elif command == "debug":
self.command_debug(arguments, command)

# Get a file
elif command == "get":
Expand Down Expand Up @@ -222,6 +226,10 @@ def process_command(self, command, arguments=[]):
elif command == "rmdir":
self.command_rmdir(arguments, command)

# List shares
elif command == "sizeof":
self.command_sizeof(arguments, command)

# List shares
elif command == "shares":
self.command_shares(arguments, command)
Expand All @@ -236,6 +244,12 @@ def process_command(self, command, arguments=[]):

# Commands ================================================================

def command_debug(self, arguments, command):
try:
pass
except Exception as e:
traceback.print_exc()

@command_arguments_required
@active_smb_connection_needed
@smb_share_is_set
Expand Down Expand Up @@ -626,6 +640,71 @@ def command_rmdir(self, arguments, command):
else:
print("[!] Remote directory '%s' does not exist." % path)

@active_smb_connection_needed
@smb_share_is_set
def command_sizeof(self, arguments, command):
# Command arguments required : Yes
# Active SMB connection needed : Yes
# SMB share needed : Yes

class RecursiveSizeOfPrint(object):
def __init__(self, entry, smbSession, config):
self.entry = entry
self.config = config
self.smbSession = smbSession
self.size = 0

def update(self, entry, fullpath, depth):
self.size += entry.get_filesize()
self.print(end='\r')

def print(self, end='\n'):
#
if self.entry.is_directory():
if self.config.no_colors:
path = "%s\\" % self.entry.get_longname()
else:
path = "\x1b[1;96m%s\x1b[0m\\" % self.entry.get_longname()
#
else:
if self.config.no_colors:
path = "%s" % self.entry.get_longname()
else:
path = "\x1b[1m%s\x1b[0m" % self.entry.get_longname()
print("%10s %s" % (b_filesize(self.size), path), end=end)

entries = []
if len(arguments) == 0:
entries = self.smbSession.list_contents()
entries = [entry for name, entry in entries.items() if name not in ['.', '..']]
else:
entry = self.smbSession.get_entry(path=' '.join(arguments))
entries = []
if entry is not None:
entries = [entry]
else:
print("[!] Path '%s' does not exist." % ' '.join(arguments))

total = 0
for entry in entries:
rsop = RecursiveSizeOfPrint(entry=entry, smbSession=self.smbSession, config=self.config)
# Directory
if entry.is_directory():
self.smbSession.find(
paths=[entry.get_longname()],
callback=rsop.update
)
# File
else:
rsop.update(entry=entry, fullpath=entry.get_longname(), depth=0)
# Close the print
rsop.print()
total += rsop.size

if len(entries) > 1:
print("──────────────────────")
print(" total %s" % b_filesize(total))

@active_smb_connection_needed
def command_shares(self, arguments, command):
# Command arguments required : No
Expand Down
32 changes: 29 additions & 3 deletions smbclientng/core/SMBSession.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,9 @@ def find(self, paths=[], callback=None):
def recurse_action(paths=[], depth=0, callback=None):
if callback is None:
return []

next_directories_to_explore = []

for path in paths:
remote_smb_path = ntpath.normpath(self.smb_cwd + ntpath.sep + path)
entries = []
Expand All @@ -210,14 +212,14 @@ def recurse_action(paths=[], depth=0, callback=None):

for entry in entries:
if entry.is_directory():
callback(entry, path + entry.get_longname() + ntpath.sep, depth)
callback(entry, path + ntpath.sep + entry.get_longname() + ntpath.sep, depth)
else:
callback(entry, path + entry.get_longname(), depth)
callback(entry, path + ntpath.sep + entry.get_longname(), depth)

# Next directories to explore
for entry in entries:
if entry.is_directory():
next_directories_to_explore.append(path + entry.get_longname() + ntpath.sep)
next_directories_to_explore.append(path + ntpath.sep + entry.get_longname() + ntpath.sep)

return next_directories_to_explore
#
Expand Down Expand Up @@ -352,6 +354,30 @@ def recurse_action(base_dir="", path=[]):
self.close_smb_session()
self.init_smb_session()

def get_entry(self, path=None):
"""
Retrieves information about a specific entry located at the provided path on the SMB share.
This method checks if the specified path exists on the SMB share. If the path exists, it retrieves the details of the entry at that path, including the directory name and file name. If the entry is found, it returns the entry object; otherwise, it returns None.
Args:
path (str): The path of the entry to retrieve information about.
Returns:
Entry: An object representing the entry at the specified path, or None if the entry is not found.
"""

if self.path_exists(path=path):
matches = self.smbClient.listPath(shareName=self.smb_share, path=path)

if len(matches) == 1:
return matches[0]
else:
return None

else:
return None

def info(self, share=True, server=True):
"""
Displays information about the server and optionally the shares.
Expand Down

0 comments on commit 0f5dd34

Please sign in to comment.