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.
- dissect/target/container.py +9 -1
- dissect/target/containers/asdf.py +2 -0
- dissect/target/containers/ewf.py +2 -0
- dissect/target/containers/hdd.py +2 -0
- dissect/target/containers/hds.py +2 -0
- dissect/target/containers/qcow2.py +2 -0
- dissect/target/containers/raw.py +2 -0
- dissect/target/containers/split.py +2 -0
- dissect/target/containers/vdi.py +2 -0
- dissect/target/containers/vhd.py +2 -0
- dissect/target/containers/vhdx.py +2 -0
- dissect/target/containers/vmdk.py +2 -0
- dissect/target/filesystem.py +108 -15
- dissect/target/filesystems/ad1.py +1 -1
- dissect/target/filesystems/btrfs.py +180 -0
- dissect/target/filesystems/cb.py +4 -4
- dissect/target/filesystems/config.py +161 -31
- dissect/target/filesystems/dir.py +1 -1
- dissect/target/filesystems/exfat.py +1 -1
- dissect/target/filesystems/extfs.py +5 -1
- dissect/target/filesystems/fat.py +1 -1
- dissect/target/filesystems/ffs.py +1 -1
- dissect/target/filesystems/itunes.py +1 -1
- dissect/target/filesystems/ntfs.py +1 -1
- dissect/target/filesystems/smb.py +1 -1
- dissect/target/filesystems/squashfs.py +1 -1
- dissect/target/filesystems/tar.py +1 -1
- dissect/target/filesystems/vmfs.py +1 -1
- dissect/target/filesystems/xfs.py +1 -1
- dissect/target/filesystems/zip.py +1 -1
- dissect/target/helpers/cache.py +2 -2
- dissect/target/helpers/configutil.py +283 -83
- dissect/target/helpers/fsutil.py +9 -6
- dissect/target/helpers/hashutil.py +20 -19
- dissect/target/helpers/utils.py +14 -3
- dissect/target/loaders/ad1.py +1 -1
- dissect/target/loaders/asdf.py +1 -1
- dissect/target/loaders/log.py +2 -2
- dissect/target/loaders/smb.py +23 -13
- dissect/target/loaders/targetd.py +12 -2
- dissect/target/loaders/vma.py +1 -1
- dissect/target/loaders/xva.py +1 -1
- dissect/target/plugin.py +14 -2
- dissect/target/plugins/apps/av/sophos.py +1 -2
- dissect/target/plugins/apps/av/symantec.py +3 -4
- dissect/target/plugins/apps/av/trendmicro.py +2 -3
- dissect/target/plugins/{browsers → apps/browser}/chrome.py +6 -3
- dissect/target/plugins/{browsers → apps/browser}/chromium.py +18 -13
- dissect/target/plugins/{browsers → apps/browser}/edge.py +6 -3
- dissect/target/plugins/{browsers → apps/browser}/firefox.py +3 -7
- dissect/target/plugins/{browsers → apps/browser}/iexplore.py +14 -4
- dissect/target/plugins/apps/remoteaccess/teamviewer.py +55 -27
- dissect/target/plugins/apps/ssh/opensshd.py +31 -30
- dissect/target/plugins/apps/{webservers → webserver}/apache.py +1 -1
- dissect/target/plugins/apps/{webservers → webserver}/caddy.py +1 -1
- dissect/target/plugins/apps/{webservers → webserver}/iis.py +1 -1
- dissect/target/plugins/apps/{webservers → webserver}/nginx.py +1 -1
- dissect/target/plugins/child/hyperv.py +1 -2
- dissect/target/plugins/child/vmware_workstation.py +1 -3
- dissect/target/plugins/filesystem/acquire_handles.py +2 -0
- dissect/target/plugins/filesystem/acquire_hash.py +1 -7
- dissect/target/plugins/filesystem/icat.py +5 -5
- dissect/target/plugins/filesystem/ntfs/mft.py +2 -2
- dissect/target/plugins/filesystem/ntfs/mft_timeline.py +2 -2
- dissect/target/plugins/filesystem/ntfs/usnjrnl.py +2 -3
- dissect/target/plugins/filesystem/resolver.py +1 -1
- dissect/target/plugins/filesystem/unix/capability.py +77 -66
- dissect/target/plugins/filesystem/walkfs.py +25 -19
- dissect/target/plugins/filesystem/yara.py +20 -19
- dissect/target/plugins/general/config.py +28 -11
- dissect/target/plugins/os/unix/_os.py +28 -21
- dissect/target/plugins/os/unix/bsd/osx/user.py +1 -3
- dissect/target/plugins/os/unix/cronjobs.py +4 -16
- dissect/target/plugins/os/unix/{linux/esxi → esxi}/_os.py +5 -6
- dissect/target/plugins/os/unix/generic.py +5 -1
- dissect/target/plugins/os/unix/history.py +2 -1
- dissect/target/plugins/os/unix/linux/_os.py +12 -5
- dissect/target/plugins/os/unix/linux/services.py +112 -0
- dissect/target/plugins/os/unix/linux/suse/zypper.py +4 -4
- dissect/target/plugins/os/unix/locale.py +3 -1
- dissect/target/plugins/os/unix/log/journal.py +7 -6
- dissect/target/plugins/os/unix/packagemanager.py +3 -3
- dissect/target/plugins/os/unix/shadow.py +1 -1
- dissect/target/plugins/os/windows/_os.py +2 -1
- dissect/target/plugins/os/windows/amcache.py +9 -10
- dissect/target/plugins/os/windows/catroot.py +2 -2
- dissect/target/plugins/os/windows/cim.py +5 -4
- dissect/target/plugins/os/windows/datetime.py +4 -1
- dissect/target/plugins/os/windows/defender.py +3 -3
- dissect/target/plugins/os/windows/generic.py +10 -11
- dissect/target/plugins/os/windows/lnk.py +6 -6
- dissect/target/plugins/os/windows/log/amcache.py +3 -5
- dissect/target/plugins/os/windows/log/pfro.py +1 -3
- dissect/target/plugins/os/windows/prefetch.py +5 -6
- dissect/target/plugins/os/windows/recyclebin.py +3 -4
- dissect/target/plugins/os/windows/regf/7zip.py +2 -4
- dissect/target/plugins/os/windows/regf/bam.py +1 -2
- dissect/target/plugins/os/windows/regf/cit.py +4 -5
- dissect/target/plugins/os/windows/regf/mru.py +6 -2
- dissect/target/plugins/os/windows/regf/muicache.py +1 -3
- dissect/target/plugins/os/windows/regf/recentfilecache.py +1 -2
- dissect/target/plugins/os/windows/regf/shimcache.py +1 -2
- dissect/target/plugins/os/windows/regf/trusteddocs.py +1 -1
- dissect/target/plugins/os/windows/regf/userassist.py +1 -2
- dissect/target/plugins/os/windows/services.py +2 -4
- dissect/target/plugins/os/windows/sru.py +4 -4
- dissect/target/plugins/os/windows/startupinfo.py +5 -6
- dissect/target/plugins/os/windows/syscache.py +2 -3
- dissect/target/target.py +65 -32
- dissect/target/tools/info.py +2 -1
- dissect/target/tools/mount.py +2 -12
- dissect/target/tools/shell.py +3 -2
- dissect/target/volume.py +10 -9
- dissect/target/volumes/bde.py +1 -1
- dissect/target/volumes/ddf.py +2 -0
- dissect/target/volumes/disk.py +2 -0
- dissect/target/volumes/luks.py +1 -1
- dissect/target/volumes/lvm.py +2 -0
- dissect/target/volumes/md.py +2 -0
- dissect/target/volumes/vmfs.py +2 -0
- {dissect.target-3.13.dev26.dist-info → dissect.target-3.14.dist-info}/METADATA +2 -1
- {dissect.target-3.13.dev26.dist-info → dissect.target-3.14.dist-info}/RECORD +137 -136
- {dissect.target-3.13.dev26.dist-info → dissect.target-3.14.dist-info}/WHEEL +1 -1
- dissect/target/plugins/os/unix/services.py +0 -151
- /dissect/target/plugins/apps/{containers → browser}/__init__.py +0 -0
- /dissect/target/plugins/{browsers → apps/browser}/browser.py +0 -0
- /dissect/target/plugins/apps/{vpns → container}/__init__.py +0 -0
- /dissect/target/plugins/apps/{containers → container}/docker.py +0 -0
- /dissect/target/plugins/apps/{webservers → vpn}/__init__.py +0 -0
- /dissect/target/plugins/apps/{vpns → vpn}/openvpn.py +0 -0
- /dissect/target/plugins/apps/{vpns → vpn}/wireguard.py +0 -0
- /dissect/target/plugins/{browsers → apps/webserver}/__init__.py +0 -0
- /dissect/target/plugins/apps/{webservers/webservers.py → webserver/webserver.py} +0 -0
- /dissect/target/plugins/os/unix/{linux/esxi → esxi}/__init__.py +0 -0
- {dissect.target-3.13.dev26.dist-info → dissect.target-3.14.dist-info}/COPYRIGHT +0 -0
- {dissect.target-3.13.dev26.dist-info → dissect.target-3.14.dist-info}/LICENSE +0 -0
- {dissect.target-3.13.dev26.dist-info → dissect.target-3.14.dist-info}/entry_points.txt +0 -0
- {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
|
-
|
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
|
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
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
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,
|
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
|
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
|
100
|
-
|
101
|
-
return self
|
197
|
+
if not key:
|
198
|
+
raise TypeError("key should be defined")
|
102
199
|
|
103
|
-
if
|
200
|
+
if key in self.parser_items:
|
104
201
|
return ConfigurationEntry(
|
105
202
|
self.fs,
|
106
|
-
fsutil.join(self.path,
|
203
|
+
fsutil.join(self.path, key, alt_separator=self.fs.alt_separator),
|
107
204
|
self.entry,
|
108
|
-
self.parser_items[
|
205
|
+
self.parser_items[key],
|
109
206
|
)
|
110
|
-
|
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
|
-
|
113
|
-
|
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
|
-
|
130
|
-
|
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
|
-
|
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,
|
161
|
-
|
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
|
@@ -15,7 +15,7 @@ ExfatFileTree = tuple[exfat.c_exfat.FILE, dict[str, Optional["ExfatFileTree"]]]
|
|
15
15
|
|
16
16
|
|
17
17
|
class ExfatFilesystem(Filesystem):
|
18
|
-
|
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
|
-
|
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
|
-
|
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)
|
@@ -22,7 +22,7 @@ if TYPE_CHECKING:
|
|
22
22
|
class ITunesFilesystem(Filesystem):
|
23
23
|
"""Filesystem implementation for iTunes backups."""
|
24
24
|
|
25
|
-
|
25
|
+
__type__ = "itunes"
|
26
26
|
|
27
27
|
def __init__(self, backup: ITunesBackup, *args, **kwargs):
|
28
28
|
super().__init__(None, *args, **kwargs)
|
@@ -31,7 +31,7 @@ log = logging.getLogger(__name__)
|
|
31
31
|
class SmbFilesystem(Filesystem):
|
32
32
|
"""Filesystem implementation for SMB."""
|
33
33
|
|
34
|
-
|
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)
|
dissect/target/helpers/cache.py
CHANGED
@@ -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=
|
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=
|
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)
|