smbclientng.core.utils
1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# File name : utils.py 4# Author : Podalirius (@podalirius_) 5# Date created : 23 may 2024 6 7 8import datetime 9import os 10import ntpath 11import re 12import stat 13 14 15def parse_lm_nt_hashes(lm_nt_hashes_string): 16 """ 17 Parse the input string containing LM and NT hash values and return them separately. 18 19 This function takes a string containing LM and NT hash values, typically separated by a colon (:). 20 It returns the LM and NT hash values as separate strings. If only one hash value is provided, it is 21 assumed to be the NT hash and the LM hash is set to its default value. If no valid hash values are 22 found, both return values are empty strings. 23 24 Args: 25 lm_nt_hashes_string (str): A string containing LM and NT hash values separated by a colon. 26 27 Returns: 28 tuple: A tuple containing two strings (lm_hash_value, nt_hash_value). 29 - lm_hash_value: The LM hash value or its default if not provided. 30 - nt_hash_value: The NT hash value or its default if not provided. 31 32 Extracted from p0dalirius/sectools library 33 Src: https://github.com/p0dalirius/sectools/blob/7bb3f5cb7815ad4d4845713c8739e2e2b0ea4e75/sectools/windows/crypto.py#L11-L24 34 """ 35 36 lm_hash_value, nt_hash_value = "", "" 37 if lm_nt_hashes_string is not None: 38 matched = re.match("([0-9a-f]{32})?(:)?([0-9a-f]{32})?", lm_nt_hashes_string.strip().lower()) 39 m_lm_hash, m_sep, m_nt_hash = matched.groups() 40 if m_lm_hash is None and m_sep is None and m_nt_hash is None: 41 lm_hash_value, nt_hash_value = "", "" 42 elif m_lm_hash is None and m_nt_hash is not None: 43 lm_hash_value = "aad3b435b51404eeaad3b435b51404ee" 44 nt_hash_value = m_nt_hash 45 elif m_lm_hash is not None and m_nt_hash is None: 46 lm_hash_value = m_lm_hash 47 nt_hash_value = "31d6cfe0d16ae931b73c59d7e0c089c0" 48 return lm_hash_value, nt_hash_value 49 50 51def b_filesize(l): 52 """ 53 Convert a file size from bytes to a more readable format using the largest appropriate unit. 54 55 This function takes an integer representing a file size in bytes and converts it to a human-readable 56 string using the largest appropriate unit from bytes (B) to petabytes (PB). The result is rounded to 57 two decimal places. 58 59 Args: 60 l (int): The file size in bytes. 61 62 Returns: 63 str: A string representing the file size in a more readable format, including the appropriate unit. 64 """ 65 66 units = ['B','kB','MB','GB','TB','PB'] 67 for k in range(len(units)): 68 if l < (1024**(k+1)): 69 break 70 return "%4.2f %s" % (round(l/(1024**(k)),2), units[k]) 71 72 73def unix_permissions(entryname): 74 """ 75 Generate a string representing the Unix-style permissions for a given file or directory. 76 77 This function uses the os.lstat() method to retrieve the status of the specified file or directory, 78 then constructs a string that represents the Unix-style permissions based on the mode of the file. 79 80 Args: 81 entryname (str): The path to the file or directory for which permissions are being determined. 82 83 Returns: 84 str: A string of length 10 representing the Unix-style permissions (e.g., '-rwxr-xr--'). 85 The first character is either 'd' (directory), '-' (not a directory), followed by 86 three groups of 'r', 'w', 'x' (read, write, execute permissions) for owner, group, 87 and others respectively. 88 """ 89 90 mode = os.lstat(entryname).st_mode 91 permissions = [] 92 93 permissions.append('d' if stat.S_ISDIR(mode) else '-') 94 95 permissions.append('r' if mode & stat.S_IRUSR else '-') 96 permissions.append('w' if mode & stat.S_IWUSR else '-') 97 permissions.append('x' if mode & stat.S_IXUSR else '-') 98 99 permissions.append('r' if mode & stat.S_IRGRP else '-') 100 permissions.append('w' if mode & stat.S_IWGRP else '-') 101 permissions.append('x' if mode & stat.S_IXGRP else '-') 102 103 permissions.append('r' if mode & stat.S_IROTH else '-') 104 permissions.append('w' if mode & stat.S_IWOTH else '-') 105 permissions.append('x' if mode & stat.S_IXOTH else '-') 106 107 return ''.join(permissions) 108 109 110def STYPE_MASK(stype_value): 111 """ 112 Extracts the share type flags from a given share type value. 113 114 This function uses bitwise operations to determine which share type flags are set in the provided `stype_value`. 115 It checks against known share type flags and returns a list of the flags that are set. 116 117 Parameters: 118 stype_value (int): The share type value to analyze, typically obtained from SMB share properties. 119 120 Returns: 121 list: A list of strings, where each string represents a share type flag that is set in the input value. 122 """ 123 124 known_flags = { 125 ## One of the following values may be specified. You can isolate these values by using the STYPE_MASK value. 126 # Disk drive. 127 "STYPE_DISKTREE": 0x0, 128 129 # Print queue. 130 "STYPE_PRINTQ": 0x1, 131 132 # Communication device. 133 "STYPE_DEVICE": 0x2, 134 135 # Interprocess communication (IPC). 136 "STYPE_IPC": 0x3, 137 138 ## In addition, one or both of the following values may be specified. 139 # Special share reserved for interprocess communication (IPC$) or remote administration of the server (ADMIN$). 140 # Can also refer to administrative shares such as C$, D$, E$, and so forth. For more information, see Network Share Functions. 141 "STYPE_SPECIAL": 0x80000000, 142 143 # A temporary share. 144 "STYPE_TEMPORARY": 0x40000000 145 } 146 flags = [] 147 if (stype_value & 0b11) == known_flags["STYPE_DISKTREE"]: 148 flags.append("STYPE_DISKTREE") 149 elif (stype_value & 0b11) == known_flags["STYPE_PRINTQ"]: 150 flags.append("STYPE_PRINTQ") 151 elif (stype_value & 0b11) == known_flags["STYPE_DEVICE"]: 152 flags.append("STYPE_DEVICE") 153 elif (stype_value & 0b11) == known_flags["STYPE_IPC"]: 154 flags.append("STYPE_IPC") 155 if (stype_value & known_flags["STYPE_SPECIAL"]) == known_flags["STYPE_SPECIAL"]: 156 flags.append("STYPE_SPECIAL") 157 if (stype_value & known_flags["STYPE_TEMPORARY"]) == known_flags["STYPE_TEMPORARY"]: 158 flags.append("STYPE_TEMPORARY") 159 return flags 160 161 162def windows_ls_entry(entry, config, pathToPrint=None): 163 """ 164 This function generates a metadata string based on the attributes of the provided entry object. 165 166 Parameters: 167 entry (object): An object representing a file or directory entry. 168 169 Returns: 170 str: A string representing the metadata of the entry, including attributes like directory, archive, compressed, hidden, normal, readonly, system, and temporary. 171 """ 172 173 if pathToPrint is not None: 174 pathToPrint = pathToPrint + ntpath.sep + entry.get_longname() 175 else: 176 pathToPrint = entry.get_longname() 177 178 meta_string = "" 179 meta_string += ("d" if entry.is_directory() else "-") 180 meta_string += ("a" if entry.is_archive() else "-") 181 meta_string += ("c" if entry.is_compressed() else "-") 182 meta_string += ("h" if entry.is_hidden() else "-") 183 meta_string += ("n" if entry.is_normal() else "-") 184 meta_string += ("r" if entry.is_readonly() else "-") 185 meta_string += ("s" if entry.is_system() else "-") 186 meta_string += ("t" if entry.is_temporary() else "-") 187 188 size_str = b_filesize(entry.get_filesize()) 189 190 date_str = datetime.datetime.fromtimestamp(entry.get_atime_epoch()).strftime("%Y-%m-%d %H:%M") 191 192 if entry.is_directory(): 193 if config.no_colors: 194 print("%s %10s %s %s\\" % (meta_string, size_str, date_str, pathToPrint)) 195 else: 196 print("%s %10s %s \x1b[1;96m%s\x1b[0m\\" % (meta_string, size_str, date_str, pathToPrint)) 197 else: 198 if config.no_colors: 199 print("%s %10s %s %s" % (meta_string, size_str, date_str, pathToPrint)) 200 else: 201 print("%s %10s %s \x1b[1m%s\x1b[0m" % (meta_string, size_str, date_str, pathToPrint)) 202 203 204def local_tree(path, config): 205 """ 206 This function recursively lists the contents of a directory in a tree-like format. 207 208 Parameters: 209 path (str): The path to the directory to list. 210 config (object): Configuration settings which may affect the output, such as whether to use colors. 211 212 Returns: 213 None: This function does not return anything but prints the directory tree to the console. 214 """ 215 216 def recurse_action(base_dir="", path=[], prompt=[]): 217 bars = ["│ ", "├── ", "└── "] 218 219 local_path = os.path.normpath(base_dir + os.path.sep + os.path.sep.join(path) + os.path.sep) 220 221 entries = [] 222 try: 223 entries = os.listdir(local_path) 224 except Exception as err: 225 if config.no_colors: 226 print("%s%s" % (''.join(prompt+[bars[2]]), err)) 227 else: 228 print("%s\x1b[1;91m%s\x1b[0m" % (''.join(prompt+[bars[2]]), err)) 229 return 230 231 entries = sorted(entries) 232 233 # 234 if len(entries) > 1: 235 index = 0 236 for entry in entries: 237 index += 1 238 # This is the first entry 239 if index == 0: 240 if os.path.isdir(local_path + os.path.sep + entry): 241 if config.no_colors: 242 print("%s%s%s" % (''.join(prompt+[bars[1]]), entry, os.path.sep)) 243 else: 244 print("%s\x1b[1;96m%s\x1b[0m%s" % (''.join(prompt+[bars[1]]), entry, os.path.sep)) 245 recurse_action( 246 base_dir=base_dir, 247 path=path+[entry], 248 prompt=prompt+["│ "] 249 ) 250 else: 251 if config.no_colors: 252 print("%s%s" % (''.join(prompt+[bars[1]]), entry)) 253 else: 254 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry)) 255 256 # This is the last entry 257 elif index == len(entries): 258 if os.path.isdir(local_path + os.path.sep + entry): 259 if config.no_colors: 260 print("%s%s%s" % (''.join(prompt+[bars[2]]), entry, os.path.sep)) 261 else: 262 print("%s\x1b[1;96m%s\x1b[0m%s" % (''.join(prompt+[bars[2]]), entry, os.path.sep)) 263 recurse_action( 264 base_dir=base_dir, 265 path=path+[entry], 266 prompt=prompt+[" "] 267 ) 268 else: 269 if config.no_colors: 270 print("%s%s" % (''.join(prompt+[bars[2]]), entry)) 271 else: 272 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry)) 273 274 # These are entries in the middle 275 else: 276 if os.path.isdir(local_path + os.path.sep + entry): 277 if config.no_colors: 278 print("%s%s%s" % (''.join(prompt+[bars[1]]), entry, os.path.sep)) 279 else: 280 print("%s\x1b[1;96m%s\x1b[0m%s" % (''.join(prompt+[bars[1]]), entry, os.path.sep)) 281 recurse_action( 282 base_dir=base_dir, 283 path=path+[entry], 284 prompt=prompt+["│ "] 285 ) 286 else: 287 if config.no_colors: 288 print("%s%s" % (''.join(prompt+[bars[1]]), entry)) 289 else: 290 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry)) 291 292 # 293 elif len(entries) == 1: 294 entry = entries[0] 295 if os.path.isdir(local_path + os.path.sep + entry): 296 if config.no_colors: 297 print("%s%s%s" % (''.join(prompt+[bars[2]]), entry, os.path.sep)) 298 else: 299 print("%s\x1b[1;96m%s\x1b[0m%s" % (''.join(prompt+[bars[2]]), entry, os.path.sep)) 300 recurse_action( 301 base_dir=base_dir, 302 path=path+[entry], 303 prompt=prompt+[" "] 304 ) 305 else: 306 if config.no_colors: 307 print("%s%s" % (''.join(prompt+[bars[2]]), entry)) 308 else: 309 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry)) 310 311 # Entrypoint 312 try: 313 if config.no_colors: 314 print("%s%s" % (path, os.path.sep)) 315 else: 316 print("\x1b[1;96m%s\x1b[0m%s" % (path, os.path.sep)) 317 recurse_action( 318 base_dir=os.getcwd(), 319 path=[path], 320 prompt=[""] 321 ) 322 except (BrokenPipeError, KeyboardInterrupt) as e: 323 print("[!] Interrupted.")
16def parse_lm_nt_hashes(lm_nt_hashes_string): 17 """ 18 Parse the input string containing LM and NT hash values and return them separately. 19 20 This function takes a string containing LM and NT hash values, typically separated by a colon (:). 21 It returns the LM and NT hash values as separate strings. If only one hash value is provided, it is 22 assumed to be the NT hash and the LM hash is set to its default value. If no valid hash values are 23 found, both return values are empty strings. 24 25 Args: 26 lm_nt_hashes_string (str): A string containing LM and NT hash values separated by a colon. 27 28 Returns: 29 tuple: A tuple containing two strings (lm_hash_value, nt_hash_value). 30 - lm_hash_value: The LM hash value or its default if not provided. 31 - nt_hash_value: The NT hash value or its default if not provided. 32 33 Extracted from p0dalirius/sectools library 34 Src: https://github.com/p0dalirius/sectools/blob/7bb3f5cb7815ad4d4845713c8739e2e2b0ea4e75/sectools/windows/crypto.py#L11-L24 35 """ 36 37 lm_hash_value, nt_hash_value = "", "" 38 if lm_nt_hashes_string is not None: 39 matched = re.match("([0-9a-f]{32})?(:)?([0-9a-f]{32})?", lm_nt_hashes_string.strip().lower()) 40 m_lm_hash, m_sep, m_nt_hash = matched.groups() 41 if m_lm_hash is None and m_sep is None and m_nt_hash is None: 42 lm_hash_value, nt_hash_value = "", "" 43 elif m_lm_hash is None and m_nt_hash is not None: 44 lm_hash_value = "aad3b435b51404eeaad3b435b51404ee" 45 nt_hash_value = m_nt_hash 46 elif m_lm_hash is not None and m_nt_hash is None: 47 lm_hash_value = m_lm_hash 48 nt_hash_value = "31d6cfe0d16ae931b73c59d7e0c089c0" 49 return lm_hash_value, nt_hash_value
Parse the input string containing LM and NT hash values and return them separately.
This function takes a string containing LM and NT hash values, typically separated by a colon (:). It returns the LM and NT hash values as separate strings. If only one hash value is provided, it is assumed to be the NT hash and the LM hash is set to its default value. If no valid hash values are found, both return values are empty strings.
Args: lm_nt_hashes_string (str): A string containing LM and NT hash values separated by a colon.
Returns: tuple: A tuple containing two strings (lm_hash_value, nt_hash_value). - lm_hash_value: The LM hash value or its default if not provided. - nt_hash_value: The NT hash value or its default if not provided.
Extracted from p0dalirius/sectools library Src: https://github.com/p0dalirius/sectools/blob/7bb3f5cb7815ad4d4845713c8739e2e2b0ea4e75/sectools/windows/crypto.py#L11-L24
52def b_filesize(l): 53 """ 54 Convert a file size from bytes to a more readable format using the largest appropriate unit. 55 56 This function takes an integer representing a file size in bytes and converts it to a human-readable 57 string using the largest appropriate unit from bytes (B) to petabytes (PB). The result is rounded to 58 two decimal places. 59 60 Args: 61 l (int): The file size in bytes. 62 63 Returns: 64 str: A string representing the file size in a more readable format, including the appropriate unit. 65 """ 66 67 units = ['B','kB','MB','GB','TB','PB'] 68 for k in range(len(units)): 69 if l < (1024**(k+1)): 70 break 71 return "%4.2f %s" % (round(l/(1024**(k)),2), units[k])
Convert a file size from bytes to a more readable format using the largest appropriate unit.
This function takes an integer representing a file size in bytes and converts it to a human-readable string using the largest appropriate unit from bytes (B) to petabytes (PB). The result is rounded to two decimal places.
Args: l (int): The file size in bytes.
Returns: str: A string representing the file size in a more readable format, including the appropriate unit.
74def unix_permissions(entryname): 75 """ 76 Generate a string representing the Unix-style permissions for a given file or directory. 77 78 This function uses the os.lstat() method to retrieve the status of the specified file or directory, 79 then constructs a string that represents the Unix-style permissions based on the mode of the file. 80 81 Args: 82 entryname (str): The path to the file or directory for which permissions are being determined. 83 84 Returns: 85 str: A string of length 10 representing the Unix-style permissions (e.g., '-rwxr-xr--'). 86 The first character is either 'd' (directory), '-' (not a directory), followed by 87 three groups of 'r', 'w', 'x' (read, write, execute permissions) for owner, group, 88 and others respectively. 89 """ 90 91 mode = os.lstat(entryname).st_mode 92 permissions = [] 93 94 permissions.append('d' if stat.S_ISDIR(mode) else '-') 95 96 permissions.append('r' if mode & stat.S_IRUSR else '-') 97 permissions.append('w' if mode & stat.S_IWUSR else '-') 98 permissions.append('x' if mode & stat.S_IXUSR else '-') 99 100 permissions.append('r' if mode & stat.S_IRGRP else '-') 101 permissions.append('w' if mode & stat.S_IWGRP else '-') 102 permissions.append('x' if mode & stat.S_IXGRP else '-') 103 104 permissions.append('r' if mode & stat.S_IROTH else '-') 105 permissions.append('w' if mode & stat.S_IWOTH else '-') 106 permissions.append('x' if mode & stat.S_IXOTH else '-') 107 108 return ''.join(permissions)
Generate a string representing the Unix-style permissions for a given file or directory.
This function uses the os.lstat() method to retrieve the status of the specified file or directory, then constructs a string that represents the Unix-style permissions based on the mode of the file.
Args: entryname (str): The path to the file or directory for which permissions are being determined.
Returns: str: A string of length 10 representing the Unix-style permissions (e.g., '-rwxr-xr--'). The first character is either 'd' (directory), '-' (not a directory), followed by three groups of 'r', 'w', 'x' (read, write, execute permissions) for owner, group, and others respectively.
111def STYPE_MASK(stype_value): 112 """ 113 Extracts the share type flags from a given share type value. 114 115 This function uses bitwise operations to determine which share type flags are set in the provided `stype_value`. 116 It checks against known share type flags and returns a list of the flags that are set. 117 118 Parameters: 119 stype_value (int): The share type value to analyze, typically obtained from SMB share properties. 120 121 Returns: 122 list: A list of strings, where each string represents a share type flag that is set in the input value. 123 """ 124 125 known_flags = { 126 ## One of the following values may be specified. You can isolate these values by using the STYPE_MASK value. 127 # Disk drive. 128 "STYPE_DISKTREE": 0x0, 129 130 # Print queue. 131 "STYPE_PRINTQ": 0x1, 132 133 # Communication device. 134 "STYPE_DEVICE": 0x2, 135 136 # Interprocess communication (IPC). 137 "STYPE_IPC": 0x3, 138 139 ## In addition, one or both of the following values may be specified. 140 # Special share reserved for interprocess communication (IPC$) or remote administration of the server (ADMIN$). 141 # Can also refer to administrative shares such as C$, D$, E$, and so forth. For more information, see Network Share Functions. 142 "STYPE_SPECIAL": 0x80000000, 143 144 # A temporary share. 145 "STYPE_TEMPORARY": 0x40000000 146 } 147 flags = [] 148 if (stype_value & 0b11) == known_flags["STYPE_DISKTREE"]: 149 flags.append("STYPE_DISKTREE") 150 elif (stype_value & 0b11) == known_flags["STYPE_PRINTQ"]: 151 flags.append("STYPE_PRINTQ") 152 elif (stype_value & 0b11) == known_flags["STYPE_DEVICE"]: 153 flags.append("STYPE_DEVICE") 154 elif (stype_value & 0b11) == known_flags["STYPE_IPC"]: 155 flags.append("STYPE_IPC") 156 if (stype_value & known_flags["STYPE_SPECIAL"]) == known_flags["STYPE_SPECIAL"]: 157 flags.append("STYPE_SPECIAL") 158 if (stype_value & known_flags["STYPE_TEMPORARY"]) == known_flags["STYPE_TEMPORARY"]: 159 flags.append("STYPE_TEMPORARY") 160 return flags
Extracts the share type flags from a given share type value.
This function uses bitwise operations to determine which share type flags are set in the provided stype_value.
It checks against known share type flags and returns a list of the flags that are set.
Parameters: stype_value (int): The share type value to analyze, typically obtained from SMB share properties.
Returns: list: A list of strings, where each string represents a share type flag that is set in the input value.
163def windows_ls_entry(entry, config, pathToPrint=None): 164 """ 165 This function generates a metadata string based on the attributes of the provided entry object. 166 167 Parameters: 168 entry (object): An object representing a file or directory entry. 169 170 Returns: 171 str: A string representing the metadata of the entry, including attributes like directory, archive, compressed, hidden, normal, readonly, system, and temporary. 172 """ 173 174 if pathToPrint is not None: 175 pathToPrint = pathToPrint + ntpath.sep + entry.get_longname() 176 else: 177 pathToPrint = entry.get_longname() 178 179 meta_string = "" 180 meta_string += ("d" if entry.is_directory() else "-") 181 meta_string += ("a" if entry.is_archive() else "-") 182 meta_string += ("c" if entry.is_compressed() else "-") 183 meta_string += ("h" if entry.is_hidden() else "-") 184 meta_string += ("n" if entry.is_normal() else "-") 185 meta_string += ("r" if entry.is_readonly() else "-") 186 meta_string += ("s" if entry.is_system() else "-") 187 meta_string += ("t" if entry.is_temporary() else "-") 188 189 size_str = b_filesize(entry.get_filesize()) 190 191 date_str = datetime.datetime.fromtimestamp(entry.get_atime_epoch()).strftime("%Y-%m-%d %H:%M") 192 193 if entry.is_directory(): 194 if config.no_colors: 195 print("%s %10s %s %s\\" % (meta_string, size_str, date_str, pathToPrint)) 196 else: 197 print("%s %10s %s \x1b[1;96m%s\x1b[0m\\" % (meta_string, size_str, date_str, pathToPrint)) 198 else: 199 if config.no_colors: 200 print("%s %10s %s %s" % (meta_string, size_str, date_str, pathToPrint)) 201 else: 202 print("%s %10s %s \x1b[1m%s\x1b[0m" % (meta_string, size_str, date_str, pathToPrint))
This function generates a metadata string based on the attributes of the provided entry object.
Parameters: entry (object): An object representing a file or directory entry.
Returns: str: A string representing the metadata of the entry, including attributes like directory, archive, compressed, hidden, normal, readonly, system, and temporary.
205def local_tree(path, config): 206 """ 207 This function recursively lists the contents of a directory in a tree-like format. 208 209 Parameters: 210 path (str): The path to the directory to list. 211 config (object): Configuration settings which may affect the output, such as whether to use colors. 212 213 Returns: 214 None: This function does not return anything but prints the directory tree to the console. 215 """ 216 217 def recurse_action(base_dir="", path=[], prompt=[]): 218 bars = ["│ ", "├── ", "└── "] 219 220 local_path = os.path.normpath(base_dir + os.path.sep + os.path.sep.join(path) + os.path.sep) 221 222 entries = [] 223 try: 224 entries = os.listdir(local_path) 225 except Exception as err: 226 if config.no_colors: 227 print("%s%s" % (''.join(prompt+[bars[2]]), err)) 228 else: 229 print("%s\x1b[1;91m%s\x1b[0m" % (''.join(prompt+[bars[2]]), err)) 230 return 231 232 entries = sorted(entries) 233 234 # 235 if len(entries) > 1: 236 index = 0 237 for entry in entries: 238 index += 1 239 # This is the first entry 240 if index == 0: 241 if os.path.isdir(local_path + os.path.sep + entry): 242 if config.no_colors: 243 print("%s%s%s" % (''.join(prompt+[bars[1]]), entry, os.path.sep)) 244 else: 245 print("%s\x1b[1;96m%s\x1b[0m%s" % (''.join(prompt+[bars[1]]), entry, os.path.sep)) 246 recurse_action( 247 base_dir=base_dir, 248 path=path+[entry], 249 prompt=prompt+["│ "] 250 ) 251 else: 252 if config.no_colors: 253 print("%s%s" % (''.join(prompt+[bars[1]]), entry)) 254 else: 255 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry)) 256 257 # This is the last entry 258 elif index == len(entries): 259 if os.path.isdir(local_path + os.path.sep + entry): 260 if config.no_colors: 261 print("%s%s%s" % (''.join(prompt+[bars[2]]), entry, os.path.sep)) 262 else: 263 print("%s\x1b[1;96m%s\x1b[0m%s" % (''.join(prompt+[bars[2]]), entry, os.path.sep)) 264 recurse_action( 265 base_dir=base_dir, 266 path=path+[entry], 267 prompt=prompt+[" "] 268 ) 269 else: 270 if config.no_colors: 271 print("%s%s" % (''.join(prompt+[bars[2]]), entry)) 272 else: 273 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry)) 274 275 # These are entries in the middle 276 else: 277 if os.path.isdir(local_path + os.path.sep + entry): 278 if config.no_colors: 279 print("%s%s%s" % (''.join(prompt+[bars[1]]), entry, os.path.sep)) 280 else: 281 print("%s\x1b[1;96m%s\x1b[0m%s" % (''.join(prompt+[bars[1]]), entry, os.path.sep)) 282 recurse_action( 283 base_dir=base_dir, 284 path=path+[entry], 285 prompt=prompt+["│ "] 286 ) 287 else: 288 if config.no_colors: 289 print("%s%s" % (''.join(prompt+[bars[1]]), entry)) 290 else: 291 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[1]]), entry)) 292 293 # 294 elif len(entries) == 1: 295 entry = entries[0] 296 if os.path.isdir(local_path + os.path.sep + entry): 297 if config.no_colors: 298 print("%s%s%s" % (''.join(prompt+[bars[2]]), entry, os.path.sep)) 299 else: 300 print("%s\x1b[1;96m%s\x1b[0m%s" % (''.join(prompt+[bars[2]]), entry, os.path.sep)) 301 recurse_action( 302 base_dir=base_dir, 303 path=path+[entry], 304 prompt=prompt+[" "] 305 ) 306 else: 307 if config.no_colors: 308 print("%s%s" % (''.join(prompt+[bars[2]]), entry)) 309 else: 310 print("%s\x1b[1m%s\x1b[0m" % (''.join(prompt+[bars[2]]), entry)) 311 312 # Entrypoint 313 try: 314 if config.no_colors: 315 print("%s%s" % (path, os.path.sep)) 316 else: 317 print("\x1b[1;96m%s\x1b[0m%s" % (path, os.path.sep)) 318 recurse_action( 319 base_dir=os.getcwd(), 320 path=[path], 321 prompt=[""] 322 ) 323 except (BrokenPipeError, KeyboardInterrupt) as e: 324 print("[!] Interrupted.")
This function recursively lists the contents of a directory in a tree-like format.
Parameters: path (str): The path to the directory to list. config (object): Configuration settings which may affect the output, such as whether to use colors.
Returns: None: This function does not return anything but prints the directory tree to the console.