dissect.btrfs 1.6.dev1__tar.gz → 1.7.dev2__tar.gz
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.
- dissect_btrfs-1.7.dev2/.git-blame-ignore-revs +6 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/PKG-INFO +2 -2
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/dissect/btrfs/btrfs.py +21 -23
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/dissect/btrfs/tree.py +36 -35
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/dissect.btrfs.egg-info/PKG-INFO +2 -2
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/dissect.btrfs.egg-info/SOURCES.txt +1 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/pyproject.toml +48 -5
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/conftest.py +10 -5
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/test_btrfs.py +2 -5
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/test_exceptions.py +3 -1
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tox.ini +4 -10
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/.gitattributes +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/COPYRIGHT +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/LICENSE +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/MANIFEST.in +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/README.md +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/dissect/btrfs/__init__.py +2 -2
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/dissect/btrfs/c_btrfs.py +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/dissect/btrfs/exceptions.py +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/dissect/btrfs/stream.py +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/dissect.btrfs.egg-info/dependency_links.txt +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/dissect.btrfs.egg-info/requires.txt +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/dissect.btrfs.egg-info/top_level.txt +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/setup.cfg +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/__init__.py +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-compression.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-default.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-dup-1.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-dup-2.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid0-1.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid0-2.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid1-1.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid1-2.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid10-1.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid10-2.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid1c3-1.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid1c3-2.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid1c3-3.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid1c4-1.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid1c4-2.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid1c4-3.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid1c4-4.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid5-1.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid5-2.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid6-1.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid6-2.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-raid6-3.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-sparse.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-subvolume-custom-default.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-subvolume-nested.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-subvolume-snapshot.bin.gz +0 -0
- {dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-subvolume.bin.gz +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: dissect.btrfs
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.7.dev2
|
|
4
4
|
Summary: A Dissect module implementing a parser for the Btrfs file system, a commonly used Linux filesystem.
|
|
5
5
|
Author-email: Dissect Team <dissect@fox-it.com>
|
|
6
6
|
License: Affero General Public License v3
|
|
@@ -7,9 +7,8 @@ from __future__ import annotations
|
|
|
7
7
|
|
|
8
8
|
import io
|
|
9
9
|
import stat
|
|
10
|
-
from datetime import datetime
|
|
11
10
|
from functools import cache, cached_property, lru_cache
|
|
12
|
-
from typing import
|
|
11
|
+
from typing import TYPE_CHECKING, BinaryIO
|
|
13
12
|
from uuid import UUID
|
|
14
13
|
|
|
15
14
|
from dissect.util import ts
|
|
@@ -35,6 +34,10 @@ from dissect.btrfs.exceptions import (
|
|
|
35
34
|
from dissect.btrfs.stream import ChunkStream, Extent, ExtentStream, decode_extent
|
|
36
35
|
from dissect.btrfs.tree import BTree
|
|
37
36
|
|
|
37
|
+
if TYPE_CHECKING:
|
|
38
|
+
from collections.abc import Iterator
|
|
39
|
+
from datetime import datetime
|
|
40
|
+
|
|
38
41
|
|
|
39
42
|
class Btrfs:
|
|
40
43
|
"""Btrfs filesystem implementation.
|
|
@@ -46,7 +49,7 @@ class Btrfs:
|
|
|
46
49
|
fh: A file-like object for the volume to use for parsing Btrfs.
|
|
47
50
|
"""
|
|
48
51
|
|
|
49
|
-
def __init__(self, fh:
|
|
52
|
+
def __init__(self, fh: BinaryIO | list[BinaryIO]):
|
|
50
53
|
self.fhs = fh if isinstance(fh, list) else [fh]
|
|
51
54
|
|
|
52
55
|
if not self.fhs:
|
|
@@ -89,7 +92,7 @@ class Btrfs:
|
|
|
89
92
|
self.default_subvolume = self._open_default_subvolume()
|
|
90
93
|
self.root = self.default_subvolume.root
|
|
91
94
|
|
|
92
|
-
def get(self, path:
|
|
95
|
+
def get(self, path: str | int, node: INode | None = None) -> INode:
|
|
93
96
|
"""Retrieve a Btrfs inode by path or inode number.
|
|
94
97
|
|
|
95
98
|
Args:
|
|
@@ -113,7 +116,7 @@ class Btrfs:
|
|
|
113
116
|
yield self.open_subvolume(item.key.offset)
|
|
114
117
|
cursor.reset()
|
|
115
118
|
|
|
116
|
-
def find_subvolume(self, path:
|
|
119
|
+
def find_subvolume(self, path: str | None = None) -> Subvolume | None:
|
|
117
120
|
"""Find a subvolume by path.
|
|
118
121
|
|
|
119
122
|
Args:
|
|
@@ -123,7 +126,9 @@ class Btrfs:
|
|
|
123
126
|
if subvolume.path == path:
|
|
124
127
|
return subvolume
|
|
125
128
|
|
|
126
|
-
|
|
129
|
+
return None
|
|
130
|
+
|
|
131
|
+
def open_subvolume(self, objectid: int, parent: INode | None = None) -> Subvolume:
|
|
127
132
|
"""Open a subvolume.
|
|
128
133
|
|
|
129
134
|
Args:
|
|
@@ -194,7 +199,7 @@ class Subvolume:
|
|
|
194
199
|
parent: Optional parent node to attach to the root of the subvolume.
|
|
195
200
|
"""
|
|
196
201
|
|
|
197
|
-
def __init__(self, btrfs: Btrfs, objectid: int, parent:
|
|
202
|
+
def __init__(self, btrfs: Btrfs, objectid: int, parent: INode | None = None):
|
|
198
203
|
self.btrfs = btrfs
|
|
199
204
|
self.objectid = objectid
|
|
200
205
|
self.parent = parent
|
|
@@ -234,7 +239,7 @@ class Subvolume:
|
|
|
234
239
|
|
|
235
240
|
return "/".join(parts[::-1])
|
|
236
241
|
|
|
237
|
-
def get(self, path:
|
|
242
|
+
def get(self, path: str | int, node: INode | None = None) -> INode:
|
|
238
243
|
"""Retrieve a Btrfs inode by path or inode number.
|
|
239
244
|
|
|
240
245
|
Args:
|
|
@@ -286,7 +291,7 @@ class Subvolume:
|
|
|
286
291
|
|
|
287
292
|
return node
|
|
288
293
|
|
|
289
|
-
def inode(self, inum: int, type:
|
|
294
|
+
def inode(self, inum: int, type: int | None = None, parent: INode | None = None) -> INode:
|
|
290
295
|
"""Return an :class:`INode` by number, optionally attaching a type and parent."""
|
|
291
296
|
return INode(self, inum, type, parent)
|
|
292
297
|
|
|
@@ -312,13 +317,7 @@ class INode:
|
|
|
312
317
|
parent: Optional parent of this inode, if this inode is parsed from a directory listing.
|
|
313
318
|
"""
|
|
314
319
|
|
|
315
|
-
def __init__(
|
|
316
|
-
self,
|
|
317
|
-
subvolume: Subvolume,
|
|
318
|
-
inum: int,
|
|
319
|
-
type: Optional[int] = None,
|
|
320
|
-
parent: Optional[INode] = None,
|
|
321
|
-
):
|
|
320
|
+
def __init__(self, subvolume: Subvolume, inum: int, type: int | None = None, parent: INode | None = None):
|
|
322
321
|
self.subvolume = subvolume
|
|
323
322
|
self.btrfs = subvolume.btrfs
|
|
324
323
|
self.inum = inum
|
|
@@ -450,14 +449,11 @@ class INode:
|
|
|
450
449
|
def link_inode(self) -> INode:
|
|
451
450
|
"""Resolve the symlink target to an inode."""
|
|
452
451
|
link = self.link
|
|
453
|
-
if link.startswith("/")
|
|
454
|
-
relnode = None
|
|
455
|
-
else:
|
|
456
|
-
relnode = self.parent
|
|
452
|
+
relnode = None if link.startswith("/") else self.parent
|
|
457
453
|
return self.subvolume.get(self.link, relnode)
|
|
458
454
|
|
|
459
455
|
@property
|
|
460
|
-
def parents(self) ->
|
|
456
|
+
def parents(self) -> Iterator[INode]:
|
|
461
457
|
for item, data in self.subvolume.tree.cursor().iter(
|
|
462
458
|
self.inum, c_btrfs.BTRFS_INODE_REF_KEY, 0, ignore_offset=True
|
|
463
459
|
):
|
|
@@ -517,7 +513,7 @@ class INode:
|
|
|
517
513
|
|
|
518
514
|
def listdir(self) -> dict[str, INode]:
|
|
519
515
|
"""Return a directory listing."""
|
|
520
|
-
return
|
|
516
|
+
return dict(self.iterdir())
|
|
521
517
|
|
|
522
518
|
def iterdir(self) -> Iterator[tuple[str, INode]]:
|
|
523
519
|
"""Iterate directory contents."""
|
|
@@ -543,11 +539,13 @@ class INode:
|
|
|
543
539
|
else:
|
|
544
540
|
raise NotImplementedError(f"Unknown dir_item type: {dir_item}")
|
|
545
541
|
|
|
546
|
-
def extents(self) ->
|
|
542
|
+
def extents(self) -> list[Extent] | None:
|
|
547
543
|
with self.open() as fh:
|
|
548
544
|
if isinstance(fh, ExtentStream):
|
|
549
545
|
return fh.extents
|
|
550
546
|
|
|
547
|
+
return None
|
|
548
|
+
|
|
551
549
|
def open(self) -> BinaryIO:
|
|
552
550
|
"""Return the data stream for the inode.
|
|
553
551
|
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from functools import lru_cache
|
|
4
|
-
from typing import TYPE_CHECKING,
|
|
4
|
+
from typing import TYPE_CHECKING, Literal
|
|
5
5
|
|
|
6
6
|
from dissect.btrfs.c_btrfs import c_btrfs
|
|
7
7
|
|
|
8
8
|
if TYPE_CHECKING:
|
|
9
|
+
from collections.abc import Iterator
|
|
10
|
+
|
|
9
11
|
from dissect.btrfs.btrfs import Btrfs
|
|
10
12
|
|
|
11
13
|
|
|
@@ -20,9 +22,7 @@ class BTree:
|
|
|
20
22
|
root_offset: Optional offset to open the B-tree from.
|
|
21
23
|
"""
|
|
22
24
|
|
|
23
|
-
def __init__(
|
|
24
|
-
self, btrfs: Btrfs, root_item: Optional[c_btrfs.btrfs_root_item] = None, root_offset: Optional[int] = None
|
|
25
|
-
):
|
|
25
|
+
def __init__(self, btrfs: Btrfs, root_item: c_btrfs.btrfs_root_item | None = None, root_offset: int | None = None):
|
|
26
26
|
self.btrfs = btrfs
|
|
27
27
|
|
|
28
28
|
if not root_item and not root_offset:
|
|
@@ -38,7 +38,7 @@ class BTree:
|
|
|
38
38
|
return Cursor(self)
|
|
39
39
|
|
|
40
40
|
def find(
|
|
41
|
-
self, objectid:
|
|
41
|
+
self, objectid: int | None = None, type: int | None = None, offset: int | None = None
|
|
42
42
|
) -> tuple[c_btrfs.btrfs_item, memoryview]:
|
|
43
43
|
"""Search for a single item in the B-tree.
|
|
44
44
|
|
|
@@ -127,7 +127,7 @@ class Cursor:
|
|
|
127
127
|
|
|
128
128
|
return key
|
|
129
129
|
|
|
130
|
-
def _read_item(self, index: int) ->
|
|
130
|
+
def _read_item(self, index: int) -> c_btrfs.btrfs_key_ptr | c_btrfs.btrfs_item:
|
|
131
131
|
"""Read an item at the specified index.
|
|
132
132
|
|
|
133
133
|
Args:
|
|
@@ -214,7 +214,7 @@ class Cursor:
|
|
|
214
214
|
"""
|
|
215
215
|
return self.item(), self.data()
|
|
216
216
|
|
|
217
|
-
def item(self) ->
|
|
217
|
+
def item(self) -> c_btrfs.btrfs_key_ptr | c_btrfs.btrfs_item:
|
|
218
218
|
"""Retrieve a leaf or branch item.
|
|
219
219
|
|
|
220
220
|
Cursor can be positioned at a branch or leaf item.
|
|
@@ -224,9 +224,9 @@ class Cursor:
|
|
|
224
224
|
|
|
225
225
|
return self._read_item(self._index)
|
|
226
226
|
|
|
227
|
-
def items(self) -> Iterator[
|
|
227
|
+
def items(self) -> Iterator[c_btrfs.btrfs_key_ptr | c_btrfs.btrfs_item]:
|
|
228
228
|
"""Iterate over all items in the current node."""
|
|
229
|
-
for i in range(
|
|
229
|
+
for i in range(self._header.nritems):
|
|
230
230
|
yield self._read_item(i)
|
|
231
231
|
|
|
232
232
|
def data(self) -> memoryview:
|
|
@@ -245,9 +245,9 @@ class Cursor:
|
|
|
245
245
|
|
|
246
246
|
def iter(
|
|
247
247
|
self,
|
|
248
|
-
objectid:
|
|
249
|
-
type:
|
|
250
|
-
offset:
|
|
248
|
+
objectid: int | None = None,
|
|
249
|
+
type: int | None = None,
|
|
250
|
+
offset: int | None = None,
|
|
251
251
|
ignore_offset: bool = False,
|
|
252
252
|
) -> Iterator[tuple[c_btrfs.btrfs_item, memoryview]]:
|
|
253
253
|
"""Search and iterate the B-tree for the specified key.
|
|
@@ -274,9 +274,9 @@ class Cursor:
|
|
|
274
274
|
|
|
275
275
|
def walk(
|
|
276
276
|
self,
|
|
277
|
-
objectid:
|
|
278
|
-
type:
|
|
279
|
-
offset:
|
|
277
|
+
objectid: int | None = None,
|
|
278
|
+
type: int | None = None,
|
|
279
|
+
offset: int | None = None,
|
|
280
280
|
) -> Iterator[tuple[c_btrfs.btrfs_item, memoryview]]:
|
|
281
281
|
"""Walk all leaf items of the B-tree and yield all matching leafs.
|
|
282
282
|
|
|
@@ -296,7 +296,7 @@ class Cursor:
|
|
|
296
296
|
except ValueError:
|
|
297
297
|
return
|
|
298
298
|
|
|
299
|
-
def search(self, objectid:
|
|
299
|
+
def search(self, objectid: int | None = None, type: int | None = None, offset: int | None = None) -> bool:
|
|
300
300
|
"""Perform a binary search on the current node for the key with the given parameters.
|
|
301
301
|
|
|
302
302
|
Puts the cursor at the index of the matching item, or just before a "greater" item if no exact match is found.
|
|
@@ -330,22 +330,23 @@ class Cursor:
|
|
|
330
330
|
self._index = min_idx
|
|
331
331
|
self.push(self._read_item(min_idx).blockptr)
|
|
332
332
|
continue
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
333
|
+
|
|
334
|
+
if result >= 0:
|
|
335
|
+
# Count a matching or larger key as a win
|
|
336
|
+
self._index = min_idx
|
|
337
|
+
return True
|
|
338
|
+
|
|
339
|
+
if min_idx == self._header.nritems - 1:
|
|
340
|
+
# Special case where we have exhausted all leaf nodes but all keys are still smaller
|
|
341
|
+
# In this case, try to travel to the next node (up one level, next item, down one level)
|
|
342
|
+
# Worst case we end up at a key that's larger than our search parameters.
|
|
343
|
+
self._index = min_idx
|
|
344
|
+
try:
|
|
345
|
+
self.next_node()
|
|
346
|
+
continue
|
|
347
|
+
except ValueError:
|
|
348
|
+
self._index = None
|
|
349
|
+
return False
|
|
349
350
|
|
|
350
351
|
break
|
|
351
352
|
|
|
@@ -355,9 +356,9 @@ class Cursor:
|
|
|
355
356
|
|
|
356
357
|
def _cmp_key(
|
|
357
358
|
key: c_btrfs.btrfs_disk_key,
|
|
358
|
-
objectid:
|
|
359
|
-
type:
|
|
360
|
-
offset:
|
|
359
|
+
objectid: int | None = None,
|
|
360
|
+
type: int | None = None,
|
|
361
|
+
offset: int | None = None,
|
|
361
362
|
) -> Literal[1, -1, 0]:
|
|
362
363
|
"""Compare a B-tree key on disk to a given object ID, type and offset.
|
|
363
364
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: dissect.btrfs
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.7.dev2
|
|
4
4
|
Summary: A Dissect module implementing a parser for the Btrfs file system, a commonly used Linux filesystem.
|
|
5
5
|
Author-email: Dissect Team <dissect@fox-it.com>
|
|
6
6
|
License: Affero General Public License v3
|
|
@@ -53,13 +53,56 @@ dev = [
|
|
|
53
53
|
"dissect.util>=3.0.dev,<4.0.dev",
|
|
54
54
|
]
|
|
55
55
|
|
|
56
|
-
[tool.
|
|
56
|
+
[tool.ruff]
|
|
57
57
|
line-length = 120
|
|
58
|
+
required-version = ">=0.9.0"
|
|
58
59
|
|
|
59
|
-
[tool.
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
[tool.ruff.format]
|
|
61
|
+
docstring-code-format = true
|
|
62
|
+
|
|
63
|
+
[tool.ruff.lint]
|
|
64
|
+
select = [
|
|
65
|
+
"F",
|
|
66
|
+
"E",
|
|
67
|
+
"W",
|
|
68
|
+
"I",
|
|
69
|
+
"UP",
|
|
70
|
+
"YTT",
|
|
71
|
+
"ANN",
|
|
72
|
+
"B",
|
|
73
|
+
"C4",
|
|
74
|
+
"DTZ",
|
|
75
|
+
"T10",
|
|
76
|
+
"FA",
|
|
77
|
+
"ISC",
|
|
78
|
+
"G",
|
|
79
|
+
"INP",
|
|
80
|
+
"PIE",
|
|
81
|
+
"PYI",
|
|
82
|
+
"PT",
|
|
83
|
+
"Q",
|
|
84
|
+
"RSE",
|
|
85
|
+
"RET",
|
|
86
|
+
"SLOT",
|
|
87
|
+
"SIM",
|
|
88
|
+
"TID",
|
|
89
|
+
"TCH",
|
|
90
|
+
"PTH",
|
|
91
|
+
"PLC",
|
|
92
|
+
"TRY",
|
|
93
|
+
"FLY",
|
|
94
|
+
"PERF",
|
|
95
|
+
"FURB",
|
|
96
|
+
"RUF",
|
|
97
|
+
]
|
|
98
|
+
ignore = ["E203", "B904", "UP024", "ANN002", "ANN003", "ANN204", "ANN401", "SIM105", "TRY003"]
|
|
99
|
+
|
|
100
|
+
[tool.ruff.lint.per-file-ignores]
|
|
101
|
+
"tests/docs/**" = ["INP001"]
|
|
102
|
+
|
|
103
|
+
[tool.ruff.lint.isort]
|
|
104
|
+
known-first-party = ["dissect.btrfs"]
|
|
105
|
+
known-third-party = ["dissect"]
|
|
63
106
|
|
|
64
107
|
[tool.setuptools]
|
|
65
108
|
license-files = ["LICENSE", "COPYRIGHT"]
|
|
@@ -1,17 +1,22 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import contextlib
|
|
2
4
|
import gzip
|
|
3
|
-
import
|
|
4
|
-
from typing import IO,
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import IO, TYPE_CHECKING, BinaryIO
|
|
5
7
|
|
|
6
8
|
import pytest
|
|
7
9
|
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from collections.abc import Iterator
|
|
12
|
+
|
|
8
13
|
|
|
9
|
-
def absolute_path(filename: str) ->
|
|
10
|
-
return
|
|
14
|
+
def absolute_path(filename: str) -> Path:
|
|
15
|
+
return Path(__file__).parent / filename
|
|
11
16
|
|
|
12
17
|
|
|
13
18
|
def open_file(name: str, mode: str = "rb") -> Iterator[IO]:
|
|
14
|
-
with
|
|
19
|
+
with absolute_path(name).open(mode) as f:
|
|
15
20
|
yield f
|
|
16
21
|
|
|
17
22
|
|
|
@@ -200,11 +200,8 @@ def test_btrfs_profiles(fixture: str, request: pytest.FixtureRequest) -> None:
|
|
|
200
200
|
)
|
|
201
201
|
def test_btrfs_profiles_partial(fixture: str, request: pytest.FixtureRequest) -> None:
|
|
202
202
|
fhs = request.getfixturevalue(fixture)
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
fhs = fhs[:-1]
|
|
206
|
-
else:
|
|
207
|
-
fhs = fhs[1:]
|
|
203
|
+
# The btrfs_profile_dup test data just so happens to have all chunks on the second device
|
|
204
|
+
fhs = fhs[:-1] if fixture == "btrfs_profile_dup" else fhs[1:]
|
|
208
205
|
|
|
209
206
|
if fixture in ("btrfs_profile_dup", "btrfs_profile_raid0"):
|
|
210
207
|
with pytest.raises(Error, match="Missing stripe disk for chunk offset .+"):
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
import pytest
|
|
2
4
|
|
|
3
5
|
from dissect.btrfs import exceptions
|
|
4
6
|
|
|
5
7
|
|
|
6
8
|
@pytest.mark.parametrize(
|
|
7
|
-
"exc, std",
|
|
9
|
+
("exc", "std"),
|
|
8
10
|
[
|
|
9
11
|
(exceptions.FileNotFoundError, FileNotFoundError),
|
|
10
12
|
(exceptions.IsADirectoryError, IsADirectoryError),
|
|
@@ -32,23 +32,17 @@ commands =
|
|
|
32
32
|
[testenv:fix]
|
|
33
33
|
package = skip
|
|
34
34
|
deps =
|
|
35
|
-
|
|
36
|
-
isort==5.11.4
|
|
35
|
+
ruff==0.9.2
|
|
37
36
|
commands =
|
|
38
|
-
|
|
39
|
-
isort dissect tests
|
|
37
|
+
ruff format dissect tests
|
|
40
38
|
|
|
41
39
|
[testenv:lint]
|
|
42
40
|
package = skip
|
|
43
41
|
deps =
|
|
44
|
-
|
|
45
|
-
flake8
|
|
46
|
-
flake8-black
|
|
47
|
-
flake8-isort
|
|
48
|
-
isort==5.11.4
|
|
42
|
+
ruff==0.9.2
|
|
49
43
|
vermin
|
|
50
44
|
commands =
|
|
51
|
-
|
|
45
|
+
ruff check dissect tests
|
|
52
46
|
vermin -t=3.9- --no-tips --lint dissect tests
|
|
53
47
|
|
|
54
48
|
[flake8]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/dissect.btrfs.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-subvolume-custom-default.bin.gz
RENAMED
|
File without changes
|
|
File without changes
|
{dissect_btrfs-1.6.dev1 → dissect_btrfs-1.7.dev2}/tests/data/btrfs-subvolume-snapshot.bin.gz
RENAMED
|
File without changes
|
|
File without changes
|