File: show_block_group_data_extent_filenames.py

package info (click to toggle)
python-btrfs 15-1
  • links: PTS
  • area: main
  • in suites: sid, trixie
  • size: 620 kB
  • sloc: python: 4,772; makefile: 195
file content (79 lines) | stat: -rwxr-xr-x 3,109 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#!/usr/bin/python3

import btrfs
import errno
import sys

if len(sys.argv) < 3:
    print("Usage: {} <vaddr> <mountpoint>".format(sys.argv[0]))
    sys.exit(1)


def using_v1(fd, vaddr):
    return btrfs.ioctl.logical_ino(fd, vaddr)


def using_v2(fd, vaddr):
    inodes, bytes_missed = btrfs.ioctl.logical_ino_v2(fd, vaddr, ignore_offset=True)
    if bytes_missed > 0:
        inodes, bytes_missed = \
            btrfs.ioctl.logical_ino_v2(fd, vaddr, bufsize=65536+bytes_missed,
                                          ignore_offset=True)
    return inodes, bytes_missed


def find_out_about_v1_or_v2(fd, vaddr):
    global logical_ino_fn
    try:
        inodes, bytes_missed = using_v2(fd, vaddr)
        logical_ino_fn = using_v2
        return inodes, bytes_missed
    except IOError as e:
        if e.errno == errno.ENOTTY:
            inodes, bytes_missed = using_v1(fd, vaddr)
            logical_ino_fn = using_v1
            return inodes, bytes_missed
        raise


vaddr = int(sys.argv[1])
path_cache = {}

with btrfs.FileSystem(sys.argv[2]) as fs:
    block_group = fs.block_group(vaddr)
    print(block_group)

    logical_ino_fn = find_out_about_v1_or_v2

    for extent in fs.extents(vaddr, vaddr + block_group.length - 1):
        if isinstance(extent, btrfs.ctree.ExtentItem) \
                and extent.flags & btrfs.ctree.EXTENT_FLAG_DATA:
            print(extent)
            inodes, bytes_missed = logical_ino_fn(fs.fd, extent.vaddr)
            for inode in inodes:
                if inode.root == btrfs.ctree.FS_TREE_OBJECTID or \
                    (inode.root >= btrfs.ctree.FIRST_FREE_OBJECTID and
                     inode.root <= btrfs.ctree.LAST_FREE_OBJECTID):
                    cache_key = (inode.root, inode.inum)
                    if cache_key not in path_cache:
                        try:
                            path = btrfs.ioctl.ino_lookup(fs.fd, treeid=inode.root,
                                                          objectid=inode.inum)[1][:-1]
                            path_cache[cache_key] = btrfs.utils.embedded_text_for_str(path)
                        except IOError as e:
                            if e.errno == errno.ENOENT:
                                path_cache[cache_key] = None
                            else:
                                raise
                    print("    root {} inode {} offset {} path {}".format(
                        inode.root, inode.inum, inode.offset, path_cache[cache_key]))
                else:
                    print("    root {} inode {} offset {}".format(
                        inode.root, inode.inum, inode.offset))
            if len(inodes) == 0 and logical_ino_fn == using_v1:
                print("    [... no result and no kernel support for LOGICAL_INO_V2]")
            if bytes_missed > 0:
                if logical_ino_fn == using_v1:
                    print("    [... remainder can't be shown; no kernel support for LOGICAL_INO_V2]")  # noqa
                else:
                    print("    [... remainder can't be shown; too many items for buffer size]")