Initial remote commit
This commit is contained in:
88
test/inspect.py
Normal file
88
test/inspect.py
Normal file
@@ -0,0 +1,88 @@
|
||||
import struct
|
||||
|
||||
CHUNK = 128 * 512
|
||||
LV_START = 5120000 * 512
|
||||
BSIZE = 4096
|
||||
IPG = 8192
|
||||
INODE_SIZE = 256
|
||||
|
||||
def read_virt(virt_offset, length):
|
||||
result = bytearray(length)
|
||||
pos = virt_offset
|
||||
remaining = length
|
||||
with open('/dev/nbd0', 'rb') as f:
|
||||
while remaining > 0:
|
||||
f.seek(pos)
|
||||
chunk = f.read(min(remaining, 65536))
|
||||
if not chunk: break
|
||||
dst = pos - virt_offset
|
||||
result[dst:dst+len(chunk)] = chunk
|
||||
pos += len(chunk)
|
||||
remaining -= len(chunk)
|
||||
return bytes(result)
|
||||
|
||||
def get_inode_table_block(group):
|
||||
# Use backup GDT at group 1
|
||||
gdt_start = (1 * 32768 + 1) * BSIZE
|
||||
entry = read_virt(gdt_start + group * 64, 64)
|
||||
it_lo = struct.unpack_from('<I', entry, 8)[0]
|
||||
it_hi = struct.unpack_from('<I', entry, 40)[0]
|
||||
return (it_hi << 32) | it_lo
|
||||
|
||||
def read_inode(inode_num):
|
||||
group = (inode_num - 1) // IPG
|
||||
index = (inode_num - 1) % IPG
|
||||
it_block = get_inode_table_block(group)
|
||||
inode_off = it_block * BSIZE + index * INODE_SIZE
|
||||
return read_virt(inode_off, INODE_SIZE)
|
||||
|
||||
def read_extents(inode_data):
|
||||
blocks = []
|
||||
eh_magic = struct.unpack_from('<H', inode_data, 40)[0]
|
||||
if eh_magic != 0xf30a:
|
||||
return blocks
|
||||
eh_entries = struct.unpack_from('<H', inode_data, 42)[0]
|
||||
eh_depth = struct.unpack_from('<H', inode_data, 46)[0]
|
||||
if eh_depth == 0:
|
||||
for i in range(min(eh_entries, 4)):
|
||||
off = 52 + i * 12
|
||||
ee_len = struct.unpack_from('<H', inode_data, off+4)[0]
|
||||
ee_start_hi = struct.unpack_from('<H', inode_data, off+6)[0]
|
||||
ee_start_lo = struct.unpack_from('<I', inode_data, off+8)[0]
|
||||
ee_start = (ee_start_hi << 32) | ee_start_lo
|
||||
for b in range(ee_len):
|
||||
blocks.append(ee_start + b)
|
||||
return blocks
|
||||
|
||||
def list_dir(inode_num):
|
||||
inode_data = read_inode(inode_num)
|
||||
mode = struct.unpack_from('<H', inode_data, 0)[0]
|
||||
size = struct.unpack_from('<I', inode_data, 4)[0]
|
||||
links = struct.unpack_from('<H', inode_data, 26)[0]
|
||||
print(f'Inode {inode_num}: mode=0x{mode:04x} size={size} links={links}')
|
||||
|
||||
entries = []
|
||||
for block_num in read_extents(inode_data):
|
||||
data = read_virt(block_num * BSIZE, BSIZE)
|
||||
off = 0
|
||||
while off < BSIZE - 8:
|
||||
ino = struct.unpack_from('<I', data, off)[0]
|
||||
rec_len = struct.unpack_from('<H', data, off+4)[0]
|
||||
name_len = data[off+6]
|
||||
ftype = data[off+7]
|
||||
if rec_len < 8: break
|
||||
if ino > 0 and name_len > 0:
|
||||
name = data[off+8:off+8+name_len].decode('utf-8',errors='replace')
|
||||
grp = (ino-1)//IPG
|
||||
entries.append((name, ino, ftype, grp))
|
||||
off += rec_len
|
||||
|
||||
type_names = {1:'file',2:'dir',7:'symlink'}
|
||||
print(f'Directory entries ({len(entries)}):')
|
||||
for name, ino, ftype, grp in sorted(entries):
|
||||
status = 'INTACT' if grp >= 13 else 'LOST'
|
||||
tname = type_names.get(ftype, str(ftype))
|
||||
print(f' [{status}] {tname:6s} inode={ino:10d} group={grp:6d} {name!r}')
|
||||
|
||||
# Read the volumes directory
|
||||
list_dir(1585918)
|
||||
Reference in New Issue
Block a user