dissect.target 3.13.dev26__py3-none-any.whl → 3.14__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (138) hide show
  1. dissect/target/container.py +9 -1
  2. dissect/target/containers/asdf.py +2 -0
  3. dissect/target/containers/ewf.py +2 -0
  4. dissect/target/containers/hdd.py +2 -0
  5. dissect/target/containers/hds.py +2 -0
  6. dissect/target/containers/qcow2.py +2 -0
  7. dissect/target/containers/raw.py +2 -0
  8. dissect/target/containers/split.py +2 -0
  9. dissect/target/containers/vdi.py +2 -0
  10. dissect/target/containers/vhd.py +2 -0
  11. dissect/target/containers/vhdx.py +2 -0
  12. dissect/target/containers/vmdk.py +2 -0
  13. dissect/target/filesystem.py +108 -15
  14. dissect/target/filesystems/ad1.py +1 -1
  15. dissect/target/filesystems/btrfs.py +180 -0
  16. dissect/target/filesystems/cb.py +4 -4
  17. dissect/target/filesystems/config.py +161 -31
  18. dissect/target/filesystems/dir.py +1 -1
  19. dissect/target/filesystems/exfat.py +1 -1
  20. dissect/target/filesystems/extfs.py +5 -1
  21. dissect/target/filesystems/fat.py +1 -1
  22. dissect/target/filesystems/ffs.py +1 -1
  23. dissect/target/filesystems/itunes.py +1 -1
  24. dissect/target/filesystems/ntfs.py +1 -1
  25. dissect/target/filesystems/smb.py +1 -1
  26. dissect/target/filesystems/squashfs.py +1 -1
  27. dissect/target/filesystems/tar.py +1 -1
  28. dissect/target/filesystems/vmfs.py +1 -1
  29. dissect/target/filesystems/xfs.py +1 -1
  30. dissect/target/filesystems/zip.py +1 -1
  31. dissect/target/helpers/cache.py +2 -2
  32. dissect/target/helpers/configutil.py +283 -83
  33. dissect/target/helpers/fsutil.py +9 -6
  34. dissect/target/helpers/hashutil.py +20 -19
  35. dissect/target/helpers/utils.py +14 -3
  36. dissect/target/loaders/ad1.py +1 -1
  37. dissect/target/loaders/asdf.py +1 -1
  38. dissect/target/loaders/log.py +2 -2
  39. dissect/target/loaders/smb.py +23 -13
  40. dissect/target/loaders/targetd.py +12 -2
  41. dissect/target/loaders/vma.py +1 -1
  42. dissect/target/loaders/xva.py +1 -1
  43. dissect/target/plugin.py +14 -2
  44. dissect/target/plugins/apps/av/sophos.py +1 -2
  45. dissect/target/plugins/apps/av/symantec.py +3 -4
  46. dissect/target/plugins/apps/av/trendmicro.py +2 -3
  47. dissect/target/plugins/{browsers → apps/browser}/chrome.py +6 -3
  48. dissect/target/plugins/{browsers → apps/browser}/chromium.py +18 -13
  49. dissect/target/plugins/{browsers → apps/browser}/edge.py +6 -3
  50. dissect/target/plugins/{browsers → apps/browser}/firefox.py +3 -7
  51. dissect/target/plugins/{browsers → apps/browser}/iexplore.py +14 -4
  52. dissect/target/plugins/apps/remoteaccess/teamviewer.py +55 -27
  53. dissect/target/plugins/apps/ssh/opensshd.py +31 -30
  54. dissect/target/plugins/apps/{webservers → webserver}/apache.py +1 -1
  55. dissect/target/plugins/apps/{webservers → webserver}/caddy.py +1 -1
  56. dissect/target/plugins/apps/{webservers → webserver}/iis.py +1 -1
  57. dissect/target/plugins/apps/{webservers → webserver}/nginx.py +1 -1
  58. dissect/target/plugins/child/hyperv.py +1 -2
  59. dissect/target/plugins/child/vmware_workstation.py +1 -3
  60. dissect/target/plugins/filesystem/acquire_handles.py +2 -0
  61. dissect/target/plugins/filesystem/acquire_hash.py +1 -7
  62. dissect/target/plugins/filesystem/icat.py +5 -5
  63. dissect/target/plugins/filesystem/ntfs/mft.py +2 -2
  64. dissect/target/plugins/filesystem/ntfs/mft_timeline.py +2 -2
  65. dissect/target/plugins/filesystem/ntfs/usnjrnl.py +2 -3
  66. dissect/target/plugins/filesystem/resolver.py +1 -1
  67. dissect/target/plugins/filesystem/unix/capability.py +77 -66
  68. dissect/target/plugins/filesystem/walkfs.py +25 -19
  69. dissect/target/plugins/filesystem/yara.py +20 -19
  70. dissect/target/plugins/general/config.py +28 -11
  71. dissect/target/plugins/os/unix/_os.py +28 -21
  72. dissect/target/plugins/os/unix/bsd/osx/user.py +1 -3
  73. dissect/target/plugins/os/unix/cronjobs.py +4 -16
  74. dissect/target/plugins/os/unix/{linux/esxi → esxi}/_os.py +5 -6
  75. dissect/target/plugins/os/unix/generic.py +5 -1
  76. dissect/target/plugins/os/unix/history.py +2 -1
  77. dissect/target/plugins/os/unix/linux/_os.py +12 -5
  78. dissect/target/plugins/os/unix/linux/services.py +112 -0
  79. dissect/target/plugins/os/unix/linux/suse/zypper.py +4 -4
  80. dissect/target/plugins/os/unix/locale.py +3 -1
  81. dissect/target/plugins/os/unix/log/journal.py +7 -6
  82. dissect/target/plugins/os/unix/packagemanager.py +3 -3
  83. dissect/target/plugins/os/unix/shadow.py +1 -1
  84. dissect/target/plugins/os/windows/_os.py +2 -1
  85. dissect/target/plugins/os/windows/amcache.py +9 -10
  86. dissect/target/plugins/os/windows/catroot.py +2 -2
  87. dissect/target/plugins/os/windows/cim.py +5 -4
  88. dissect/target/plugins/os/windows/datetime.py +4 -1
  89. dissect/target/plugins/os/windows/defender.py +3 -3
  90. dissect/target/plugins/os/windows/generic.py +10 -11
  91. dissect/target/plugins/os/windows/lnk.py +6 -6
  92. dissect/target/plugins/os/windows/log/amcache.py +3 -5
  93. dissect/target/plugins/os/windows/log/pfro.py +1 -3
  94. dissect/target/plugins/os/windows/prefetch.py +5 -6
  95. dissect/target/plugins/os/windows/recyclebin.py +3 -4
  96. dissect/target/plugins/os/windows/regf/7zip.py +2 -4
  97. dissect/target/plugins/os/windows/regf/bam.py +1 -2
  98. dissect/target/plugins/os/windows/regf/cit.py +4 -5
  99. dissect/target/plugins/os/windows/regf/mru.py +6 -2
  100. dissect/target/plugins/os/windows/regf/muicache.py +1 -3
  101. dissect/target/plugins/os/windows/regf/recentfilecache.py +1 -2
  102. dissect/target/plugins/os/windows/regf/shimcache.py +1 -2
  103. dissect/target/plugins/os/windows/regf/trusteddocs.py +1 -1
  104. dissect/target/plugins/os/windows/regf/userassist.py +1 -2
  105. dissect/target/plugins/os/windows/services.py +2 -4
  106. dissect/target/plugins/os/windows/sru.py +4 -4
  107. dissect/target/plugins/os/windows/startupinfo.py +5 -6
  108. dissect/target/plugins/os/windows/syscache.py +2 -3
  109. dissect/target/target.py +65 -32
  110. dissect/target/tools/info.py +2 -1
  111. dissect/target/tools/mount.py +2 -12
  112. dissect/target/tools/shell.py +3 -2
  113. dissect/target/volume.py +10 -9
  114. dissect/target/volumes/bde.py +1 -1
  115. dissect/target/volumes/ddf.py +2 -0
  116. dissect/target/volumes/disk.py +2 -0
  117. dissect/target/volumes/luks.py +1 -1
  118. dissect/target/volumes/lvm.py +2 -0
  119. dissect/target/volumes/md.py +2 -0
  120. dissect/target/volumes/vmfs.py +2 -0
  121. {dissect.target-3.13.dev26.dist-info → dissect.target-3.14.dist-info}/METADATA +2 -1
  122. {dissect.target-3.13.dev26.dist-info → dissect.target-3.14.dist-info}/RECORD +137 -136
  123. {dissect.target-3.13.dev26.dist-info → dissect.target-3.14.dist-info}/WHEEL +1 -1
  124. dissect/target/plugins/os/unix/services.py +0 -151
  125. /dissect/target/plugins/apps/{containers → browser}/__init__.py +0 -0
  126. /dissect/target/plugins/{browsers → apps/browser}/browser.py +0 -0
  127. /dissect/target/plugins/apps/{vpns → container}/__init__.py +0 -0
  128. /dissect/target/plugins/apps/{containers → container}/docker.py +0 -0
  129. /dissect/target/plugins/apps/{webservers → vpn}/__init__.py +0 -0
  130. /dissect/target/plugins/apps/{vpns → vpn}/openvpn.py +0 -0
  131. /dissect/target/plugins/apps/{vpns → vpn}/wireguard.py +0 -0
  132. /dissect/target/plugins/{browsers → apps/webserver}/__init__.py +0 -0
  133. /dissect/target/plugins/apps/{webservers/webservers.py → webserver/webserver.py} +0 -0
  134. /dissect/target/plugins/os/unix/{linux/esxi → esxi}/__init__.py +0 -0
  135. {dissect.target-3.13.dev26.dist-info → dissect.target-3.14.dist-info}/COPYRIGHT +0 -0
  136. {dissect.target-3.13.dev26.dist-info → dissect.target-3.14.dist-info}/LICENSE +0 -0
  137. {dissect.target-3.13.dev26.dist-info → dissect.target-3.14.dist-info}/entry_points.txt +0 -0
  138. {dissect.target-3.13.dev26.dist-info → dissect.target-3.14.dist-info}/top_level.txt +0 -0
dissect/target/target.py CHANGED
@@ -155,7 +155,9 @@ class Target:
155
155
  """Resolve all disks, volumes and filesystems and load an operating system on the current ``Target``."""
156
156
  self.disks.apply()
157
157
  self.volumes.apply()
158
+ self.filesystems.apply()
158
159
  self._init_os()
160
+ self._mount_others()
159
161
  self._applied = True
160
162
 
161
163
  @property
@@ -424,7 +426,8 @@ class Target:
424
426
  if isinstance(os_plugin, plugin.OSPlugin):
425
427
  self._os_plugin = os_plugin.__class__
426
428
  elif issubclass(os_plugin, plugin.OSPlugin):
427
- os_plugin = os_plugin.create(self, os_plugin.detect(self))
429
+ if fs := os_plugin.detect(self):
430
+ os_plugin = os_plugin.create(self, fs)
428
431
 
429
432
  self._os = self.add_plugin(os_plugin)
430
433
  return
@@ -481,6 +484,20 @@ class Target:
481
484
  self._os_plugin = os_plugin
482
485
  self._os = self.add_plugin(os_plugin.create(self, fs))
483
486
 
487
+ def _mount_others(self) -> None:
488
+ root_fs = self.fs
489
+ counter = 0
490
+ path = "/$fs$/fs0"
491
+
492
+ for fs in self.filesystems:
493
+ if fs not in root_fs.mounts.values():
494
+ # determine mount point
495
+ while root_fs.path(path).exists():
496
+ counter += 1
497
+ path = f"/$fs$/fs{counter}"
498
+
499
+ root_fs.mount(path, fs)
500
+
484
501
  def add_plugin(
485
502
  self,
486
503
  plugin_cls: Union[plugin.Plugin, type[plugin.Plugin]],
@@ -712,18 +729,12 @@ class DiskCollection(Collection[container.Container]):
712
729
 
713
730
 
714
731
  class VolumeCollection(Collection[volume.Volume]):
715
- def open(self, vol: volume.Volume) -> None:
716
- try:
717
- if not hasattr(vol, "fs") or vol.fs is None:
718
- vol.fs = filesystem.open(vol)
719
- self.target.log.debug("Opened filesystem: %s on %s", vol.fs, vol)
720
- self.target.filesystems.add(vol.fs)
721
- except FilesystemError as e:
722
- self.target.log.warning("Can't identify filesystem: %s", vol)
723
- self.target.log.debug("", exc_info=e)
724
-
725
732
  def apply(self) -> None:
726
- todo = self.entries
733
+ # We don't want later additions to modify the todo, so make a copy
734
+ todo = self.entries[:]
735
+ fs_volumes = []
736
+ lvm_volumes = []
737
+ encrypted_volumes = []
727
738
 
728
739
  while todo:
729
740
  new_volumes = []
@@ -738,23 +749,35 @@ class VolumeCollection(Collection[volume.Volume]):
738
749
  else:
739
750
  # We could be getting "regular" volume systems out of LVM or encrypted volumes
740
751
  # Try to open each volume as a regular volume system, or add as a filesystem if it fails
752
+ # There are a few scenarios were we want to discard the opened volume, though
753
+ #
754
+ # If the current volume offset is 0 and originates from a "regular" volume system, we're likely
755
+ # opening a volume system on the same disk again
756
+ # Sometimes BSD systems are configured this way and an FFS volume "starts" at offset 0
757
+ #
758
+ # If we opened an empty volume system, it might also be the case that a filesystem actually
759
+ # "starts" at offset 0
760
+
761
+ # Regardless of what happens, we want to try to open it as a filesystem later on
762
+ fs_volumes.append(vol)
763
+
764
+ if vol.offset == 0 and vol.vs and vol.vs.__type__ == "disk":
765
+ # We are going to re-open a volume system on itself, bail out
766
+ self.target.log.info("Found volume with offset 0, opening as raw volume instead")
767
+ continue
768
+
741
769
  try:
742
770
  vs = volume.open(vol)
743
771
  except Exception:
744
772
  # If opening a volume system fails, there's likely none, so open as a filesystem instead
745
- self.open(vol)
746
773
  continue
747
774
 
748
775
  if not len(vs.volumes):
749
- self.open(vol)
776
+ # We opened an empty volume system, discard
750
777
  continue
751
778
 
752
- for new_vol in vs.volumes:
753
- if new_vol.offset == 0:
754
- self.target.log.info("Found volume with offset 0, opening as raw volume instead")
755
- self.open(new_vol)
756
- continue
757
- new_volumes.append(new_vol)
779
+ self.entries.extend(vs.volumes)
780
+ new_volumes.extend(vs.volumes)
758
781
 
759
782
  self.target.log.debug("LVM volumes found: %s", lvm_volumes)
760
783
  self.target.log.debug("Encrypted volumes found: %s", encrypted_volumes)
@@ -773,20 +796,30 @@ class VolumeCollection(Collection[volume.Volume]):
773
796
 
774
797
  todo = new_volumes
775
798
 
776
- # ASDF - getting the correct starting system volume
777
- start_fs = None
778
- start_vol = None
779
- for idx, vol in enumerate(self.entries):
780
- if start_fs is None and (vol.name is None):
781
- start_fs = idx
799
+ mv_fs_volumes = []
800
+ for vol in fs_volumes:
801
+ try:
802
+ if getattr(vol, "fs", None) is None:
803
+ if filesystem.is_multi_volume_filesystem(vol):
804
+ mv_fs_volumes.append(vol)
805
+ else:
806
+ vol.fs = filesystem.open(vol)
807
+ self.target.log.debug("Opened filesystem: %s on %s", vol.fs, vol)
782
808
 
783
- if start_vol is None and start_fs is not None and (vol.name is not None and vol.fs is None):
784
- start_vol = idx
809
+ if getattr(vol, "fs", None) is not None:
810
+ self.target.filesystems.add(vol.fs)
811
+ except FilesystemError as e:
812
+ self.target.log.warning("Can't identify filesystem: %s", vol)
813
+ self.target.log.debug("", exc_info=e)
785
814
 
786
- if start_fs is not None and start_vol is not None and (vol.name is not None and vol.fs is None):
787
- rel_vol = idx - start_vol
788
- vol.fs = self.entries[start_fs + rel_vol].fs
815
+ for fs in filesystem.open_multi_volume(mv_fs_volumes):
816
+ self.target.filesystems.add(fs)
817
+ for vol in fs.volume:
818
+ vol.fs = fs
789
819
 
790
820
 
791
821
  class FilesystemCollection(Collection[filesystem.Filesystem]):
792
- pass
822
+ def apply(self) -> None:
823
+ for fs in self.entries:
824
+ for subfs in fs.iter_subfs():
825
+ self.add(subfs)
@@ -86,7 +86,8 @@ def main():
86
86
  print("-" * 70)
87
87
  print_target_info(target)
88
88
  except Exception as e:
89
- target.log.error("Exception in retrieving information for target: `%s`", target, exc_info=e)
89
+ target.log.error("Exception in retrieving information for target: `%s`. Use `-vv` for details.", target)
90
+ target.log.debug("", exc_info=e)
90
91
 
91
92
 
92
93
  def get_target_info(target: Target) -> dict[str, Union[str, list[str]]]:
@@ -3,6 +3,7 @@ import logging
3
3
  from typing import Union
4
4
 
5
5
  from dissect.target import Target, filesystem
6
+ from dissect.target.helpers.utils import parse_options_string
6
7
  from dissect.target.tools.utils import (
7
8
  catch_sigpipe,
8
9
  configure_generic_arguments,
@@ -70,7 +71,7 @@ def main():
70
71
  vfs.mount(fname, fs)
71
72
 
72
73
  # This is kinda silly because fusepy will convert this back into string arguments
73
- options = _parse_options(args.options) if args.options else {}
74
+ options = parse_options_string(args.options) if args.options else {}
74
75
 
75
76
  options["nothreads"] = True
76
77
  options["allow_other"] = True
@@ -83,17 +84,6 @@ def main():
83
84
  parser.exit("FUSE error")
84
85
 
85
86
 
86
- def _parse_options(options: str) -> dict[str, Union[str, bool]]:
87
- result = {}
88
- for opt in options.split(","):
89
- if "=" in opt:
90
- key, _, value = opt.partition("=")
91
- result[key] = value
92
- else:
93
- result[opt] = True
94
- return result
95
-
96
-
97
87
  def _format_options(options: dict[str, Union[str, bool]]) -> str:
98
88
  return ",".join([key if value is True else f"{key}={value}" for key, value in options.items()])
99
89
 
@@ -171,6 +171,7 @@ class TargetCmd(cmd.Cmd):
171
171
  if command_args_str is not None:
172
172
  lexer = shlex.shlex(command_args_str, posix=True, punctuation_chars=True)
173
173
  lexer.wordchars += "$"
174
+ lexer.whitespace_split = True
174
175
  argparts = list(lexer)
175
176
 
176
177
  try:
@@ -448,7 +449,7 @@ class TargetCli(TargetCmd):
448
449
  # entries has an alternative data stream and also list them.
449
450
  entry = file_.get()
450
451
  if isinstance(entry, RootFilesystemEntry):
451
- if entry.entries.fs.__fstype__ == "ntfs":
452
+ if entry.entries.fs.__type__ == "ntfs":
452
453
  attrs = entry.lattr()
453
454
  for data_stream in attrs.DATA:
454
455
  if data_stream.name != "":
@@ -888,7 +889,7 @@ class UnixConfigTreeCli(TargetCli):
888
889
  if isinstance(path, fsutil.TargetPath):
889
890
  return path
890
891
 
891
- # It uses the alt seperator of the underlying fs
892
+ # It uses the alt separator of the underlying fs
892
893
  path = fsutil.abspath(path, cwd=str(self.cwd), alt_separator=self.target.fs.alt_separator)
893
894
  return self.config_tree.path(path)
894
895
 
dissect/target/volume.py CHANGED
@@ -57,6 +57,11 @@ class VolumeSystem:
57
57
  serial: Serial number of the volume system, if any.
58
58
  """
59
59
 
60
+ # Due to lazy importing we generally can't use isinstance(), so we add a short identifying string to each class
61
+ # This has the added benefit of having a readily available "pretty name" for each implementation
62
+ __type__: str = None
63
+ """A short string identifying the type of volume system."""
64
+
60
65
  def __init__(
61
66
  self, fh: Union[BinaryIO, list[BinaryIO]], dsk: Optional[Container] = None, serial: Optional[str] = None
62
67
  ):
@@ -65,6 +70,9 @@ class VolumeSystem:
65
70
  self.serial = serial
66
71
  self._volumes_list: list[Volume] = None
67
72
 
73
+ if self.__type__ is None:
74
+ raise NotImplementedError(f"{self.__class__.__name__} must define __type__")
75
+
68
76
  def __repr__(self) -> str:
69
77
  return f"<{self.__class__.__name__} serial={self.serial}>"
70
78
 
@@ -124,20 +132,13 @@ class EncryptedVolumeSystem(VolumeSystem):
124
132
  It adds helper functions for interacting with the :attr:`~dissect.target.helpers.keychain.KEYCHAIN`,
125
133
  so that subclasses don't have to manually interact with it.
126
134
 
127
- Subclasses must set the ``PROVIDER`` class attribute to a unique string, e.g. ``bitlocker``.
128
-
129
135
  Args:
130
136
  fh: The file-like object on which to open the encrypted volume system.
131
137
  """
132
138
 
133
- PROVIDER: str = None
134
-
135
139
  def __init__(self, fh: BinaryIO, *args, **kwargs):
136
140
  super().__init__(fh, *args, **kwargs)
137
-
138
- if not self.PROVIDER:
139
- raise ValueError("Provider identifier is not set")
140
- self.keys = keychain.get_keys_for_provider(self.PROVIDER) + keychain.get_keys_without_provider()
141
+ self.keys = keychain.get_keys_for_provider(self.__type__) + keychain.get_keys_without_provider()
141
142
 
142
143
  def get_keys_for_identifier(self, identifier: str) -> list[keychain.Key]:
143
144
  """Retrieves a list of keys that match a single ``identifier``.
@@ -399,7 +400,7 @@ def open_encrypted(volume: BinaryIO) -> Iterator[Volume]:
399
400
  log.debug("", exc_info=e)
400
401
  except Exception as e:
401
402
  log.error(
402
- "Failed to open an encrypted volume %s with volume manager %s: %s", volume, manager_cls.PROVIDER, e
403
+ "Failed to open an encrypted volume %s with volume manager %s: %s", volume, manager_cls.__type__, e
403
404
  )
404
405
  log.debug("", exc_info=e)
405
406
  return None
@@ -17,7 +17,7 @@ class BitlockerVolumeSystemError(VolumeSystemError):
17
17
 
18
18
 
19
19
  class BitlockerVolumeSystem(EncryptedVolumeSystem):
20
- PROVIDER = "bitlocker"
20
+ __type__ = "bitlocker"
21
21
 
22
22
  def __init__(self, fh: Union[BinaryIO, list[BinaryIO]], *args, **kwargs):
23
23
  super().__init__(fh, *args, **kwargs)
@@ -8,6 +8,8 @@ from dissect.target.volume import LogicalVolumeSystem, Volume
8
8
 
9
9
 
10
10
  class DdfVolumeSystem(LogicalVolumeSystem):
11
+ __type__ = "ddf"
12
+
11
13
  def __init__(self, fh: Union[BinaryIO, list[BinaryIO]], *args, **kwargs):
12
14
  self.ddf = DDF(fh)
13
15
  super().__init__(fh, *args, **kwargs)
@@ -6,6 +6,8 @@ from dissect.target.volume import Volume, VolumeSystem
6
6
 
7
7
 
8
8
  class DissectVolumeSystem(VolumeSystem):
9
+ __type__ = "disk"
10
+
9
11
  def __init__(self, fh: Union[BinaryIO, list[BinaryIO]], *args, **kwargs):
10
12
  self._disk = disk.Disk(fh)
11
13
  super().__init__(fh, serial=self._disk.serial, *args, **kwargs)
@@ -17,7 +17,7 @@ class LUKSVolumeSystemError(VolumeSystemError):
17
17
 
18
18
 
19
19
  class LUKSVolumeSystem(EncryptedVolumeSystem):
20
- PROVIDER = "luks"
20
+ __type__ = "luks"
21
21
 
22
22
  def __init__(self, fh: Union[BinaryIO, list[BinaryIO]], *args, **kwargs):
23
23
  super().__init__(fh, *args, **kwargs)
@@ -22,6 +22,8 @@ KNOWN_SKIP_TYPES = (
22
22
 
23
23
 
24
24
  class LvmVolumeSystem(LogicalVolumeSystem):
25
+ __type__ = "lvm"
26
+
25
27
  def __init__(self, fh: Union[BinaryIO, list[BinaryIO]], *args, **kwargs):
26
28
  self.lvm = lvm.LVM2(fh)
27
29
  super().__init__(fh, *args, **kwargs)
@@ -7,6 +7,8 @@ from dissect.target.volume import LogicalVolumeSystem, Volume
7
7
 
8
8
 
9
9
  class MdVolumeSystem(LogicalVolumeSystem):
10
+ __type__ = "md"
11
+
10
12
  def __init__(self, fh: Union[BinaryIO, list[BinaryIO]], *args, **kwargs):
11
13
  self.md = MD(fh)
12
14
  super().__init__(fh, *args, **kwargs)
@@ -11,6 +11,8 @@ log = logging.getLogger(__name__)
11
11
 
12
12
 
13
13
  class VmfsVolumeSystem(LogicalVolumeSystem):
14
+ __type__ = "vmfs"
15
+
14
16
  def __init__(self, fh: Union[BinaryIO, list[BinaryIO]], *args, **kwargs):
15
17
  self.lvm = lvm.LVM(fh)
16
18
  super().__init__(fh, *args, **kwargs)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: dissect.target
3
- Version: 3.13.dev26
3
+ Version: 3.14
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
@@ -38,6 +38,7 @@ Requires-Dist: dissect.target[full] ; extra == 'cb'
38
38
  Requires-Dist: carbon-black-cloud-sdk-python ~=1.4.3 ; extra == 'cb'
39
39
  Provides-Extra: full
40
40
  Requires-Dist: asn1crypto ; extra == 'full'
41
+ Requires-Dist: dissect.btrfs <2.0.dev,>=1.0.dev ; extra == 'full'
41
42
  Requires-Dist: dissect.cim <4.0.dev,>=3.0.dev ; extra == 'full'
42
43
  Requires-Dist: dissect.clfs <2.0.dev,>=1.0.dev ; extra == 'full'
43
44
  Requires-Dist: dissect.esedb <4.0.dev,>=3.0.dev ; extra == 'full'