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
@@ -15,7 +15,32 @@ log = getLogger(__name__)
15
15
 
16
16
 
17
17
  class ConfigurationFilesystem(VirtualFilesystem):
18
- __fstype__: str = "META:configuration"
18
+ """A special :class:`.Filesystem` class that allows you to browse and interact with configuration files
19
+ as ``directories`` and ``files`` by parsing the file into key/value pairs.
20
+
21
+ Depending on the ``value`` of a configuration file's ``key``, it will act like a ``directory`` or ``file``:
22
+ * When the ``key`` contains sub-values (dictionary), it will act like a ``directory``.
23
+ * Otherwise it will act like a ``file``.
24
+
25
+ Examples:
26
+ >>> fs = ConfigurationFilesystem(target, "/etc")
27
+ >>> entry = fs.get("xattr.conf")
28
+ <ConfigurationEntry path=/etc/xattr.conf value=<dissect.target.helpers.configutil.Default object at 0x115683280>
29
+ >>> entry.listdir() # listed entries are the keys in the configuration file
30
+ [...
31
+ 'system.posix_acl_access',
32
+ 'system.posix_acl_default',
33
+ 'trusted.SGI_ACL_DEFAULT',
34
+ 'trusted.SGI_ACL_FILE',
35
+ ...]
36
+ >>> entry.get("system.posix_acl_access") # returns the value of the key
37
+ <ConfigurationEntry path=/etc/xattr.conf/system.posix_acl_access value=permissions>
38
+ >>> entry.get("system.posix_acl_access").open().read() # returns the raw value of the key
39
+ b'permissions\\n'
40
+
41
+ """
42
+
43
+ __type__: str = "META:configuration"
19
44
 
20
45
  def __init__(self, target: Target, path: str, **kwargs):
21
46
  super().__init__(**kwargs)
@@ -28,8 +53,8 @@ class ConfigurationFilesystem(VirtualFilesystem):
28
53
  the start of the path.
29
54
 
30
55
  Returns:
31
- A list of ``parts``: [filename, keys, into, the, file].
32
- And the resolved entry.
56
+ A list of ``parts`` containing keys: [keys, into, the, file].
57
+ And the resolved entry: Entry(filename)
33
58
  """
34
59
  entry = relentry or self.root
35
60
 
@@ -40,7 +65,7 @@ class ConfigurationFilesystem(VirtualFilesystem):
40
65
 
41
66
  parts = path.split("/")
42
67
 
43
- for idx, part in enumerate(parts):
68
+ for idx, part in enumerate(parts, start=1):
44
69
  # Resolve link
45
70
  if entry.is_symlink():
46
71
  entry = entry.readlink_ext()
@@ -63,30 +88,85 @@ class ConfigurationFilesystem(VirtualFilesystem):
63
88
  def get(
64
89
  self, path: str, relentry: Optional[FilesystemEntry] = None, *args, **kwargs
65
90
  ) -> Union[FilesystemEntry, ConfigurationEntry]:
91
+ """Retrieve a :class:`ConfigurationEntry` or :class:`.FilesystemEntry` relative to the root or ``relentry``.
92
+
93
+ Raises:
94
+ FileNotFoundError: if it could not find the entry.
95
+ """
66
96
  parts, entry = self._get_till_file(path, relentry)
67
97
 
98
+ if entry.is_dir():
99
+ return entry
100
+
101
+ entry = self._convert_entry(entry, *args, **kwargs)
102
+
68
103
  for part in parts:
69
- if isinstance(entry, ConfigurationEntry):
70
- entry = entry.get(part)
71
- else:
72
- try:
73
- # The parts in _get_till_file also includes the filename, so we do not join
74
- # the part with entry.path here.
75
- config_parser = parse(entry, *args, **kwargs)
76
- entry = ConfigurationEntry(self, entry.path, entry, config_parser)
77
- except (FileNotFoundError, ConfigurationParsingError):
78
- # If a parsing error gets created, it should return the `entry`
79
- log.debug(f"Error when parsing {entry.path}/{part}")
104
+ _prev_entry = entry
105
+ entry = entry.get(part)
106
+ if entry is None:
107
+ raise FileNotFoundError(f"{part!r} not found in {_prev_entry}.")
108
+
109
+ return entry
110
+
111
+ def _convert_entry(
112
+ self, file_entry: FilesystemEntry, *args, **kwargs
113
+ ) -> Union[ConfigurationEntry, FilesystemEntry]:
114
+ """Creates a :class:`ConfigurationEntry` from a ``file_entry``.
115
+
116
+ If an error occurs during the parsing of the file contents,
117
+ the original ``file_entry`` is returned.
118
+ """
119
+ entry = file_entry
120
+ try:
121
+ config_parser = parse(entry, *args, **kwargs)
122
+ entry = ConfigurationEntry(self, entry.path, entry, config_parser)
123
+ except ConfigurationParsingError:
124
+ # If a parsing error gets created, it should return the `entry`
125
+ log.debug("Error when parsing %s", entry.path)
126
+
80
127
  return entry
81
128
 
82
129
 
83
130
  class ConfigurationEntry(FilesystemEntry):
131
+ """A Special filesystem entry.
132
+
133
+ Behaves like a ``directory`` when :attr:`parser_items` is a :class:`.ConfigurationParser` or a ``dict``.
134
+ Behaves like a ``file`` otherwise.
135
+
136
+ Attributes:
137
+ parser_items: A dict-like object containing all configuration entries and values.
138
+ In most cases this is either a :class:`.ConfigurationParser` or ``dict``.
139
+ Otherwise, its the entry's value
140
+
141
+ Examples:
142
+ >>> fs = ConfigurationFilesystem(target, "/etc")
143
+ >>> entry = fs.get("xattr.conf")
144
+ <ConfigurationEntry path=/etc/xattr.conf value=<dissect.target.helpers.configutil.Default object at 0x115683280>
145
+ >>> entry.listdir() # listed entries are the keys in the configuration file
146
+ [...
147
+ 'system.posix_acl_access',
148
+ 'system.posix_acl_default',
149
+ 'trusted.SGI_ACL_DEFAULT',
150
+ 'trusted.SGI_ACL_FILE',
151
+ ...]
152
+ >>> entry.as_dict()
153
+ {
154
+ ...
155
+ "system.posix_acl_access" : "...",
156
+ ...
157
+ }
158
+ >>> entry.get("system.posix_acl_access") # returns the value of the key
159
+ <ConfigurationEntry path=/etc/xattr.conf/system.posix_acl_access value=permissions>
160
+ >>> entry.get("system.posix_acl_access").open().read() # returns the raw value of the key
161
+ b'permissions\\n'
162
+ """
163
+
84
164
  def __init__(
85
165
  self,
86
166
  fs: Filesystem,
87
167
  path: str,
88
168
  entry: FilesystemEntry,
89
- parser_items: Optional[Union[dict, Any]] = None,
169
+ parser_items: Optional[Union[dict, ConfigurationParser, str, list]] = None,
90
170
  ) -> None:
91
171
  super().__init__(fs, path, entry)
92
172
  self.parser_items = parser_items
@@ -94,23 +174,48 @@ class ConfigurationEntry(FilesystemEntry):
94
174
  def __getitem__(self, item: str) -> ConfigurationEntry:
95
175
  return self.parser_items[item]
96
176
 
97
- def get(self, path: Optional[str] = None) -> ConfigurationEntry:
177
+ def __repr__(self) -> str:
178
+ output = f"path={self.path}"
179
+
180
+ if not isinstance(self.parser_items, dict):
181
+ output += f" value={self.parser_items}"
182
+
183
+ return f"<{self.__class__.__name__} {output}"
184
+
185
+ def get(self, key, default: Optional[Any] = None) -> Union[ConfigurationEntry, Any, None]:
186
+ """Gets the dictionary key that belongs to this entry using ``key``.
187
+ Behaves like ``dictionary.get()``.
188
+
189
+ Args:
190
+ ``key``: A dictionary key that is inside :attr:`parser_items`.
191
+ ``default``: The default value to return if ``key`` is not inside this entry.
192
+
193
+ Returns:
194
+ a :class:`ConfigurationEntry` when ``key`` is present, otherwise its ``default``.
195
+ """
98
196
  # Check for path in config entry
99
- if not path:
100
- # Return self if configuration was found.
101
- return self
197
+ if not key:
198
+ raise TypeError("key should be defined")
102
199
 
103
- if path in self.parser_items:
200
+ if key in self.parser_items:
104
201
  return ConfigurationEntry(
105
202
  self.fs,
106
- fsutil.join(self.path, path, alt_separator=self.fs.alt_separator),
203
+ fsutil.join(self.path, key, alt_separator=self.fs.alt_separator),
107
204
  self.entry,
108
- self.parser_items[path],
205
+ self.parser_items[key],
109
206
  )
110
- raise NotADirectoryError(f"Cannot open a {path!r} on a value")
207
+ return default
208
+
209
+ def _write_value_mapping(self, values: dict[str, Any], indentation_nr: int = 0) -> str:
210
+ """Internal function to transform the ``values`` dictionary to a string representation.
111
211
 
112
- def _write_value_mapping(self, values: dict[str, Any], indentation_nr=0) -> str:
113
- """Writes a dictionary to the output, c style."""
212
+ Args:
213
+ values: A dictionary or its contents.
214
+ indentation_nr: How much indentation this entry should receive.
215
+
216
+ Returns:
217
+ An indented string containing all the information inside ``values``.
218
+ """
114
219
  prefix = " " * indentation_nr
115
220
  output_buffer = io.StringIO()
116
221
 
@@ -126,9 +231,14 @@ class ConfigurationEntry(FilesystemEntry):
126
231
  return output_buffer.getvalue()
127
232
 
128
233
  def open(self) -> BinaryIO:
129
- # Return fh for path if entry is a file
130
- # Return bytes of value if entry is ConfigurationEntry
234
+ """Open this :class:`ConfigurationEntry`.
235
+
236
+ If :attr:`parser_items` is a :class:`.ConfigurationParser`,
237
+ it will ``open`` the underlying entry.
131
238
 
239
+ Returns:
240
+ A file-like object holding a byte representation of :attr:`parser_items`.
241
+ """
132
242
  if isinstance(self.parser_items, ConfigurationParser):
133
243
  # Currently trying to open the underlying entry
134
244
  return self.entry.open()
@@ -141,7 +251,7 @@ class ConfigurationEntry(FilesystemEntry):
141
251
  yield entry.name
142
252
 
143
253
  def scandir(self) -> Iterator[ConfigurationEntry]:
144
- # Return dict keys
254
+ """Return the items inside :attr:`parser_items` as ``ConfigurationEntries``."""
145
255
  if self.is_file():
146
256
  raise NotADirectoryError()
147
257
 
@@ -152,19 +262,39 @@ class ConfigurationEntry(FilesystemEntry):
152
262
  return not self.is_dir(follow_symlinks)
153
263
 
154
264
  def is_dir(self, follow_symlinks: bool = True) -> bool:
265
+ """Returns whether this :class:`ConfigurationEntry` can be considered a directory."""
266
+ # if self.parser_items has keys (thus sub-values), we can consider it a directory.
155
267
  return hasattr(self.parser_items, "keys")
156
268
 
157
269
  def is_symlink(self) -> bool:
270
+ """Return whether this :class:`ConfigurationEntry` is a symlink or not.
271
+
272
+ Returns:
273
+ False, as ``ConfigurationEntries`` are never symlinks.
274
+ """
275
+ # ConfigurationEntries are already resolved, so are never symlinks.
158
276
  return False
159
277
 
160
- def exists(self, path: str) -> bool:
161
- return self.entry.exists() and path in self.parser_items
278
+ def exists(self, key: str) -> bool:
279
+ """Return whether the underlying :class:`.FilesystemEntry` :attr:`entry` and
280
+ supplied ``key`` exists inside this :class:`ConfigurationEntry`.
281
+
282
+ Returns:
283
+ Whether the ``entry`` and ``key`` exists
284
+ """
285
+ return self.entry.exists() and key in self.parser_items
162
286
 
163
287
  def stat(self, follow_symlinks: bool = True) -> fsutil.stat_result:
288
+ """Returns the stat from the underlying :class:`.FilesystemEntry` :attr:`entry`."""
164
289
  return self.entry.stat(follow_symlinks)
165
290
 
166
291
  def lstat(self) -> fsutil.stat_result:
292
+ """Returns the lstat from the underlying :class:`.FilesystemEntry` :attr:`entry`."""
293
+
167
294
  return self.entry.lstat()
168
295
 
169
296
  def as_dict(self) -> dict:
297
+ """Returns :attr:`parser_items` as a dictionary."""
298
+ if isinstance(self.parser_items, ConfigurationParser):
299
+ return self.parser_items.parsed_data
170
300
  return self.parser_items
@@ -13,7 +13,7 @@ from dissect.target.helpers import fsutil
13
13
 
14
14
 
15
15
  class DirectoryFilesystem(Filesystem):
16
- __fstype__ = "dir"
16
+ __type__ = "dir"
17
17
 
18
18
  def __init__(self, path: Path, *args, **kwargs):
19
19
  super().__init__(None, *args, **kwargs)
@@ -15,7 +15,7 @@ ExfatFileTree = tuple[exfat.c_exfat.FILE, dict[str, Optional["ExfatFileTree"]]]
15
15
 
16
16
 
17
17
  class ExfatFilesystem(Filesystem):
18
- __fstype__ = "exfat"
18
+ __type__ = "exfat"
19
19
 
20
20
  def __init__(self, fh: BinaryIO, *args, **kwargs):
21
21
  super().__init__(fh, case_sensitive=False, alt_separator="\\", *args, **kwargs)
@@ -15,7 +15,7 @@ from dissect.target.helpers import fsutil
15
15
 
16
16
 
17
17
  class ExtFilesystem(Filesystem):
18
- __fstype__ = "ext"
18
+ __type__ = "ext"
19
19
 
20
20
  def __init__(self, fh: BinaryIO, *args, **kwargs):
21
21
  super().__init__(fh, *args, **kwargs)
@@ -125,6 +125,10 @@ class ExtFilesystemEntry(FilesystemEntry):
125
125
  ]
126
126
  )
127
127
 
128
+ # Set birthtime if available
129
+ if self.entry.crtime:
130
+ st_info.st_birthtime = self.entry.crtime.timestamp()
131
+
128
132
  # Set the nanosecond resolution separately
129
133
  st_info.st_atime_ns = self.entry.atime_ns
130
134
  st_info.st_mtime_ns = self.entry.mtime_ns
@@ -11,7 +11,7 @@ from dissect.target.helpers import fsutil
11
11
 
12
12
 
13
13
  class FatFilesystem(Filesystem):
14
- __fstype__ = "fat"
14
+ __type__ = "fat"
15
15
 
16
16
  def __init__(self, fh: BinaryIO, *args, **kwargs):
17
17
  super().__init__(fh, case_sensitive=False, alt_separator="\\", *args, **kwargs)
@@ -14,7 +14,7 @@ from dissect.target.helpers import fsutil
14
14
 
15
15
 
16
16
  class FfsFilesystem(Filesystem):
17
- __fstype__ = "ffs"
17
+ __type__ = "ffs"
18
18
 
19
19
  def __init__(self, fh: BinaryIO, *args, **kwargs):
20
20
  super().__init__(fh, *args, **kwargs)
@@ -22,7 +22,7 @@ if TYPE_CHECKING:
22
22
  class ITunesFilesystem(Filesystem):
23
23
  """Filesystem implementation for iTunes backups."""
24
24
 
25
- __fstype__ = "itunes"
25
+ __type__ = "itunes"
26
26
 
27
27
  def __init__(self, backup: ITunesBackup, *args, **kwargs):
28
28
  super().__init__(None, *args, **kwargs)
@@ -20,7 +20,7 @@ from dissect.target.helpers import fsutil
20
20
 
21
21
 
22
22
  class NtfsFilesystem(Filesystem):
23
- __fstype__ = "ntfs"
23
+ __type__ = "ntfs"
24
24
 
25
25
  def __init__(
26
26
  self,
@@ -31,7 +31,7 @@ log = logging.getLogger(__name__)
31
31
  class SmbFilesystem(Filesystem):
32
32
  """Filesystem implementation for SMB."""
33
33
 
34
- __fstype__ = "smb"
34
+ __type__ = "smb"
35
35
 
36
36
  def __init__(self, conn: SMBConnection, share_name: str, *args, **kwargs):
37
37
  super().__init__(None, *args, **kwargs, alt_separator="\\", case_sensitive=False)
@@ -15,7 +15,7 @@ from dissect.target.helpers import fsutil
15
15
 
16
16
 
17
17
  class SquashFSFilesystem(Filesystem):
18
- __fstype__ = "squashfs"
18
+ __type__ = "squashfs"
19
19
 
20
20
  def __init__(self, fh: BinaryIO, *args, **kwargs):
21
21
  super().__init__(fh, *args, **kwargs)
@@ -28,7 +28,7 @@ log = logging.getLogger(__name__)
28
28
  class TarFilesystem(Filesystem):
29
29
  """Filesystem implementation for tar files."""
30
30
 
31
- __fstype__ = "tar"
31
+ __type__ = "tar"
32
32
 
33
33
  def __init__(
34
34
  self,
@@ -16,7 +16,7 @@ from dissect.target.helpers import fsutil
16
16
 
17
17
 
18
18
  class VmfsFilesystem(Filesystem):
19
- __fstype__ = "vmfs"
19
+ __type__ = "vmfs"
20
20
 
21
21
  def __init__(self, fh: BinaryIO, *args, **kwargs):
22
22
  super().__init__(fh, *args, **kwargs)
@@ -18,7 +18,7 @@ log = logging.getLogger(__name__)
18
18
 
19
19
 
20
20
  class XfsFilesystem(Filesystem):
21
- __fstype__ = "xfs"
21
+ __type__ = "xfs"
22
22
 
23
23
  def __init__(self, fh: BinaryIO, *args, **kwargs):
24
24
  super().__init__(fh, *args, **kwargs)
@@ -28,7 +28,7 @@ class ZipFilesystem(Filesystem):
28
28
  See https://github.com/python/cpython/issues/82102 for more information.
29
29
  """
30
30
 
31
- __fstype__ = "zip"
31
+ __type__ = "zip"
32
32
 
33
33
  def __init__(
34
34
  self,
@@ -144,7 +144,7 @@ class Cache:
144
144
 
145
145
  if read_file_cache:
146
146
  target.log.debug("Reading from cache file: %s", cache_file)
147
- if os.access(cache_file, os.R_OK, effective_ids=True):
147
+ if os.access(cache_file, os.R_OK, effective_ids=bool(os.supports_effective_ids)):
148
148
  if os.stat(cache_file).st_size != 0:
149
149
  try:
150
150
  return self.open_reader(cache_file, output)
@@ -173,7 +173,7 @@ class Cache:
173
173
  err,
174
174
  )
175
175
 
176
- if os.access(temp_dir, os.W_OK | os.R_OK | os.X_OK, effective_ids=True):
176
+ if os.access(temp_dir, os.W_OK | os.R_OK | os.X_OK, effective_ids=bool(os.supports_effective_ids)):
177
177
  if os.path.exists(temp_path):
178
178
  try:
179
179
  os.remove(temp_path)