dissect.target 3.19.dev32__py3-none-any.whl → 3.19.dev34__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,27 +1,35 @@
1
+ from __future__ import annotations
2
+
1
3
  import ast
2
4
  import importlib.machinery
3
5
  import importlib.util
4
6
  import logging
5
7
  from pathlib import Path
6
8
  from types import ModuleType
7
- from typing import Optional, Union
8
9
 
9
10
  log = logging.getLogger(__name__)
10
11
 
11
12
  CONFIG_NAME = ".targetcfg.py"
12
13
 
13
14
 
14
- def load(path: Optional[Union[Path, str]]) -> ModuleType:
15
+ def load(paths: list[Path | str] | Path | str | None) -> ModuleType:
16
+ """Attempt to load one configuration from the provided path(s)."""
17
+
18
+ if isinstance(paths, Path) or isinstance(paths, str):
19
+ paths = [paths]
20
+
15
21
  config_spec = importlib.machinery.ModuleSpec("config", None)
16
22
  config = importlib.util.module_from_spec(config_spec)
17
- config_file = _find_config_file(path)
23
+ config_file = _find_config_file(paths)
24
+
18
25
  if config_file:
19
26
  config_values = _parse_ast(config_file.read_bytes())
20
27
  config.__dict__.update(config_values)
28
+
21
29
  return config
22
30
 
23
31
 
24
- def _parse_ast(code: str) -> dict[str, Union[str, int]]:
32
+ def _parse_ast(code: str) -> dict[str, str | int]:
25
33
  # Only allow basic value assignments for backwards compatibility
26
34
  obj = {}
27
35
 
@@ -49,15 +57,19 @@ def _parse_ast(code: str) -> dict[str, Union[str, int]]:
49
57
  return obj
50
58
 
51
59
 
52
- def _find_config_file(path: Optional[Union[Path, str]]) -> Optional[Path]:
53
- """Find a config file anywhere in the given path and return it.
60
+ def _find_config_file(paths: list[Path | str] | None) -> Path | None:
61
+ """Find a config file anywhere in the given path(s) and return it.
54
62
 
55
63
  This algorithm allows parts of the path to not exist or the last part to be a filename.
56
64
  It also does not look in the root directory ('/') for config files.
57
65
  """
58
66
 
67
+ if not paths:
68
+ return
69
+
59
70
  config_file = None
60
- if path:
71
+
72
+ for path in paths:
61
73
  path = Path(path)
62
74
  cur_path = path.absolute()
63
75
 
@@ -69,4 +81,7 @@ def _find_config_file(path: Optional[Union[Path, str]]) -> Optional[Path]:
69
81
  config_file = cur_config
70
82
  cur_path = cur_path.parent
71
83
 
84
+ if config_file:
85
+ break
86
+
72
87
  return config_file
@@ -5,7 +5,7 @@ import re
5
5
  import urllib
6
6
  from os import PathLike
7
7
  from pathlib import Path
8
- from typing import TYPE_CHECKING, BinaryIO, Optional, Union
8
+ from typing import TYPE_CHECKING, BinaryIO
9
9
 
10
10
  from dissect.target.exceptions import FileNotFoundError
11
11
  from dissect.target.filesystem import Filesystem
@@ -42,12 +42,31 @@ def add_virtual_ntfs_filesystem(
42
42
  fh_sds = _try_open(fs, sds_path)
43
43
 
44
44
  if any([fh_boot, fh_mft]):
45
- ntfs = NtfsFilesystem(boot=fh_boot, mft=fh_mft, usnjrnl=fh_usnjrnl, sds=fh_sds)
46
- target.filesystems.add(ntfs)
47
- fs.ntfs = ntfs.ntfs
45
+ ntfs = None
48
46
 
49
-
50
- def _try_open(fs: Filesystem, path: str) -> BinaryIO:
47
+ try:
48
+ ntfs = NtfsFilesystem(boot=fh_boot, mft=fh_mft, usnjrnl=fh_usnjrnl, sds=fh_sds)
49
+ except Exception as e:
50
+ if fh_boot:
51
+ log.warning("Failed to load NTFS filesystem from %s, retrying without $Boot file", fs)
52
+ log.debug("", exc_info=e)
53
+
54
+ try:
55
+ # Try once more without the $Boot file
56
+ ntfs = NtfsFilesystem(mft=fh_mft, usnjrnl=fh_usnjrnl, sds=fh_sds)
57
+ except Exception:
58
+ log.warning("Failed to load NTFS filesystem from %s without $Boot file, skipping", fs)
59
+ return
60
+
61
+ # Only add it if we have a valid NTFS with an MFT
62
+ if ntfs and ntfs.ntfs.mft:
63
+ target.filesystems.add(ntfs)
64
+ fs.ntfs = ntfs.ntfs
65
+ else:
66
+ log.warning("Opened NTFS filesystem from %s but could not find $MFT, skipping", fs)
67
+
68
+
69
+ def _try_open(fs: Filesystem, path: str) -> BinaryIO | None:
51
70
  paths = [path] if not isinstance(path, list) else path
52
71
 
53
72
  for path in paths:
@@ -61,7 +80,7 @@ def _try_open(fs: Filesystem, path: str) -> BinaryIO:
61
80
  pass
62
81
 
63
82
 
64
- def extract_path_info(path: Union[str, Path]) -> tuple[Path, Optional[urllib.parse.ParseResult]]:
83
+ def extract_path_info(path: str | Path) -> tuple[Path, urllib.parse.ParseResult | None]:
65
84
  """
66
85
  Extracts a ParseResult from a path if it has
67
86
  a scheme and adjusts the path if necessary.
dissect/target/target.py CHANGED
@@ -87,9 +87,10 @@ class Target:
87
87
  self._applied = False
88
88
 
89
89
  try:
90
- self._config = config.load(self.path)
90
+ self._config = config.load([self.path, os.getcwd()])
91
91
  except Exception as e:
92
- self.log.debug("Error loading config file", exc_info=e)
92
+ self.log.warning("Error loading config file: %s", self.path)
93
+ self.log.debug("", exc_info=e)
93
94
  self._config = config.load(None) # This loads an empty config.
94
95
 
95
96
  # Fill the disks and/or volumes and/or filesystems and apply() will
@@ -58,6 +58,7 @@ try:
58
58
  except ImportError:
59
59
  # Readline is not available on Windows
60
60
  log.warning("Readline module is not available")
61
+ readline = None
61
62
 
62
63
  # ['mode', 'addr', 'dev', 'nlink', 'uid', 'gid', 'size', 'atime', 'mtime', 'ctime']
63
64
  STAT_TEMPLATE = """ File: {path} {symlink}
@@ -111,12 +112,43 @@ class TargetCmd(cmd.Cmd):
111
112
 
112
113
  CMD_PREFIX = "cmd_"
113
114
 
115
+ DEFAULT_HISTFILE = "~/.dissect_history"
116
+ DEFAULT_HISTFILESIZE = 10_000
117
+ DEFAULT_HISTDIR = None
118
+ DEFAULT_HISTDIRFMT = ".dissect_history_{uid}_{target}"
119
+
114
120
  def __init__(self, target: Target):
115
121
  cmd.Cmd.__init__(self)
116
122
  self.target = target
117
123
  self.debug = False
118
124
  self.identchars += "."
119
125
 
126
+ self.histfilesize = getattr(target._config, "HISTFILESIZE", self.DEFAULT_HISTFILESIZE)
127
+ self.histdir = getattr(target._config, "HISTDIR", self.DEFAULT_HISTDIR)
128
+
129
+ if self.histdir:
130
+ self.histdirfmt = getattr(target._config, "HISTDIRFMT", self.DEFAULT_HISTDIRFMT)
131
+ self.histfile = pathlib.Path(self.histdir).resolve() / pathlib.Path(
132
+ self.histdirfmt.format(uid=os.getuid(), target=target.name)
133
+ )
134
+ else:
135
+ self.histfile = pathlib.Path(getattr(target._config, "HISTFILE", self.DEFAULT_HISTFILE)).expanduser()
136
+
137
+ def preloop(self) -> None:
138
+ if readline and self.histfile.exists():
139
+ try:
140
+ readline.read_history_file(self.histfile)
141
+ except Exception as e:
142
+ log.debug("Error reading history file: %s", e)
143
+
144
+ def postloop(self) -> None:
145
+ if readline:
146
+ readline.set_history_length(self.histfilesize)
147
+ try:
148
+ readline.write_history_file(self.histfile)
149
+ except Exception as e:
150
+ log.debug("Error writing history file: %s", e)
151
+
120
152
  def __getattr__(self, attr: str) -> Any:
121
153
  if attr.startswith("help_"):
122
154
  _, _, command = attr.partition("_")
@@ -1241,10 +1273,11 @@ def run_cli(cli: cmd.Cmd) -> None:
1241
1273
  # Print an empty newline on exit
1242
1274
  print()
1243
1275
  return
1276
+
1244
1277
  except KeyboardInterrupt:
1245
1278
  # Add a line when pressing ctrl+c, so the next one starts at a new line
1246
1279
  print()
1247
- pass
1280
+
1248
1281
  except Exception as e:
1249
1282
  if cli.debug:
1250
1283
  log.exception(e)
@@ -1252,7 +1285,6 @@ def run_cli(cli: cmd.Cmd) -> None:
1252
1285
  log.info(e)
1253
1286
  print(f"*** Unhandled error: {e}")
1254
1287
  print("If you wish to see the full debug trace, enable debug mode.")
1255
- pass
1256
1288
 
1257
1289
 
1258
1290
  @catch_sigpipe
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dissect.target
3
- Version: 3.19.dev32
3
+ Version: 3.19.dev34
4
4
  Summary: This module ties all other Dissect modules together, it provides a programming API and command line tools which allow easy access to various data sources inside disk images or file collections (a.k.a. targets)
5
5
  Author-email: Dissect Team <dissect@fox-it.com>
6
6
  License: Affero General Public License v3
@@ -5,7 +5,7 @@ dissect/target/filesystem.py,sha256=G1gbOUpnQZyovubYGEUKgaDV0eHH5vE83-0gTc5PZAM,
5
5
  dissect/target/loader.py,sha256=I8WNzDA0SMy42F7zfyBcSKj_VKNv64213WUvtGZ77qE,7374
6
6
  dissect/target/plugin.py,sha256=HAN8maaDt-Rlqt8Rr1IW7gXQpzNQZjCVz-i4aSPphSw,48677
7
7
  dissect/target/report.py,sha256=06uiP4MbNI8cWMVrC1SasNS-Yg6ptjVjckwj8Yhe0Js,7958
8
- dissect/target/target.py,sha256=KZ3vDsMjrXxEP6sQE1kOlxMNjqFFsxnivYhoX26GBEY,32363
8
+ dissect/target/target.py,sha256=nqd5OuVTwYR7XSzlMp7SHQoRCgZD_Z7QshnEEKcX-tw,32426
9
9
  dissect/target/volume.py,sha256=aQZAJiny8jjwkc9UtwIRwy7nINXjCxwpO-_UDfh6-BA,15801
10
10
  dissect/target/containers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  dissect/target/containers/asdf.py,sha256=DJp0QEFwUjy2MFwKYcYqIR_BS1fQT1Yi9Kcmqt0aChM,1366
@@ -45,7 +45,7 @@ dissect/target/filesystems/xfs.py,sha256=kIyFGKYlyFYC7H3jaEv-lNKtBW4ZkD92H0WpfGc
45
45
  dissect/target/filesystems/zip.py,sha256=WT1bQhzX_1MXXVZTKrJniae4xqRqMZ8FsfbvhgGQRTQ,4462
46
46
  dissect/target/helpers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
47
  dissect/target/helpers/cache.py,sha256=TXlJBdFRz6V9zKs903am4Yawr0maYw5kZY0RqklDQJM,8568
48
- dissect/target/helpers/config.py,sha256=6917CZ6eDHaK_tOoiVEIndyhRXO6r6eCBIleq6f47PQ,2346
48
+ dissect/target/helpers/config.py,sha256=RMHnIuKJHINHiLrvKN3EyA0jFA1o6-pbeaycG8Pgrp8,2596
49
49
  dissect/target/helpers/configutil.py,sha256=AEnkMQ0e6PncvCqGa-ACzBQWQBhMGBCzO5qzGJtRu60,27644
50
50
  dissect/target/helpers/cyber.py,sha256=WnJlk-HqAETmDAgLq92JPxyDLxvzSoFV_WrO-odVKBI,16805
51
51
  dissect/target/helpers/descriptor_extensions.py,sha256=uT8GwznfDAiIgMM7JKKOY0PXKMv2c0GCqJTCkWFgops,2605
@@ -54,7 +54,7 @@ dissect/target/helpers/fsutil.py,sha256=tPyH4RBDqM9QXjamIQaDRLUy3b4dKmfrT6k3ZP01
54
54
  dissect/target/helpers/hashutil.py,sha256=bYAGEjyYyxuCTziO4kCx6srzY1Cm-PXmayRRcxt5ca4,1061
55
55
  dissect/target/helpers/keychain.py,sha256=wYH0sf7eaxP0bZTo80RF_BQMWulCWmIQ8Tzt9K5TSNQ,3611
56
56
  dissect/target/helpers/lazy.py,sha256=823VtmdWsbJyVZvNWopDhQdqq2i1xtj6b8IKfveboKw,1771
57
- dissect/target/helpers/loaderutil.py,sha256=kiyMWra_gVxfNSGwLlgxLcuuqAYuCMDc5NiCDprVNnc,2649
57
+ dissect/target/helpers/loaderutil.py,sha256=4cS0RKGgsljQYYc5uGzmnWJ_NXt7QfWJ1jvtEINZmdE,3415
58
58
  dissect/target/helpers/localeutil.py,sha256=Y4Fh4jDSGfm5356xSLMriUCN8SZP_FAHg_iodkAxNq4,1504
59
59
  dissect/target/helpers/mount.py,sha256=JxhUYyEbDnHfzPpfuWy4nV9OwCJPoDSGdHHNiyvd_l0,3949
60
60
  dissect/target/helpers/mui.py,sha256=i-7XoHbu4WO2fYapK9yGAMW04rFlgRispknc1KQIS5Q,22258
@@ -331,7 +331,7 @@ dissect/target/tools/logging.py,sha256=5ZnumtMWLyslxfrUGZ4ntRyf3obOOhmn8SBjKfdLc
331
331
  dissect/target/tools/mount.py,sha256=L_0tSmiBdW4aSaF0vXjB0bAkTC0kmT2N1hrbW6s5Jow,3254
332
332
  dissect/target/tools/query.py,sha256=ONHu2FVomLccikb84qBrlhNmEfRoHYFQMcahk_y2c9A,15580
333
333
  dissect/target/tools/reg.py,sha256=FDsiBBDxjWVUBTRj8xn82vZe-J_d9piM-TKS3PHZCcM,3193
334
- dissect/target/tools/shell.py,sha256=_widEuIRqZhYzcFR52NYI8O2aPFm6tG5Uiv-AIrC32U,45155
334
+ dissect/target/tools/shell.py,sha256=sjoc4nI9fsU5ZG7nDPNZvE-RtIPTwREbVdbg8WA3XTo,46442
335
335
  dissect/target/tools/utils.py,sha256=sQizexY3ui5vmWw4KOBLg5ecK3TPFjD-uxDqRn56ZTY,11304
336
336
  dissect/target/tools/yara.py,sha256=70k-2VMulf1EdkX03nCACzejaOEcsFHOyX-4E40MdQU,2044
337
337
  dissect/target/tools/dump/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -346,10 +346,10 @@ dissect/target/volumes/luks.py,sha256=OmCMsw6rCUXG1_plnLVLTpsvE1n_6WtoRUGQbpmu1z
346
346
  dissect/target/volumes/lvm.py,sha256=wwQVR9I3G9YzmY6UxFsH2Y4MXGBcKL9aayWGCDTiWMU,2269
347
347
  dissect/target/volumes/md.py,sha256=7ShPtusuLGaIv27SvEETtgsuoQyAa4iAAeOR1NEaajI,1689
348
348
  dissect/target/volumes/vmfs.py,sha256=-LoUbn9WNwTtLi_4K34uV_-wDw2W5hgaqxZNj4UmqAQ,1730
349
- dissect.target-3.19.dev32.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
350
- dissect.target-3.19.dev32.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
351
- dissect.target-3.19.dev32.dist-info/METADATA,sha256=aYH5ExmLUxmscik9N5OAaWx16j-W7AHvqsONGGGOZoE,12719
352
- dissect.target-3.19.dev32.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
353
- dissect.target-3.19.dev32.dist-info/entry_points.txt,sha256=BWuxAb_6AvUAQpIQOQU0IMTlaF6TDht2AIZK8bHd-zE,492
354
- dissect.target-3.19.dev32.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
355
- dissect.target-3.19.dev32.dist-info/RECORD,,
349
+ dissect.target-3.19.dev34.dist-info/COPYRIGHT,sha256=m-9ih2RVhMiXHI2bf_oNSSgHgkeIvaYRVfKTwFbnJPA,301
350
+ dissect.target-3.19.dev34.dist-info/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
351
+ dissect.target-3.19.dev34.dist-info/METADATA,sha256=fiUYaR4jBceVkr1ddarm8Xyn0sU8feK-AvW5l7JAbXU,12719
352
+ dissect.target-3.19.dev34.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
353
+ dissect.target-3.19.dev34.dist-info/entry_points.txt,sha256=BWuxAb_6AvUAQpIQOQU0IMTlaF6TDht2AIZK8bHd-zE,492
354
+ dissect.target-3.19.dev34.dist-info/top_level.txt,sha256=Mn-CQzEYsAbkxrUI0TnplHuXnGVKzxpDw_po_sXpvv4,8
355
+ dissect.target-3.19.dev34.dist-info/RECORD,,