71 lines
2.6 KiB
Python
71 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
|
import json
|
|
import os
|
|
import sys
|
|
from fuse import FUSE, FuseOSError, Operations
|
|
|
|
class LonghornBackupFS(Operations):
|
|
def __init__(self, backup_dir):
|
|
self.backup_dir = backup_dir
|
|
self.blocks_dir = f"{backup_dir}/blocks"
|
|
|
|
backup_cfg = f"{backup_dir}/backups/backup_backup-eac0221d1cab4a9c.cfg"
|
|
with open(backup_cfg) as f:
|
|
data = json.load(f)
|
|
|
|
self.size = int(data['Size'])
|
|
self.block_map = {b['Offset']: b['BlockChecksum'] for b in data['Blocks']}
|
|
self.block_size = 2097152 # 2MB
|
|
|
|
print(f"Volume size: {self.size}")
|
|
print(f"Blocks: {len(self.block_map)}")
|
|
|
|
def getattr(self, path, fh=None):
|
|
return {'st_size': self.size, 'st_mode': 0o100644, 'st_nlink': 1}
|
|
|
|
def read(self, path, size, offset, fh):
|
|
result = bytearray()
|
|
remaining = size
|
|
current_offset = offset
|
|
|
|
while remaining > 0:
|
|
block_start = (current_offset // self.block_size) * self.block_size
|
|
block_offset = current_offset - block_start
|
|
read_size = min(remaining, self.block_size - block_offset)
|
|
|
|
if block_start in self.block_map:
|
|
checksum = self.block_map[block_start]
|
|
block_path = f"{self.blocks_dir}/{checksum[:2]}/{checksum[2:4]}/{checksum}.blk"
|
|
|
|
if os.path.exists(block_path):
|
|
with open(block_path, 'rb') as f:
|
|
f.seek(block_offset)
|
|
result.extend(f.read(read_size))
|
|
else:
|
|
result.extend(b'\x00' * read_size)
|
|
else:
|
|
result.extend(b'\x00' * read_size)
|
|
|
|
current_offset += read_size
|
|
remaining -= read_size
|
|
|
|
return bytes(result)
|
|
|
|
if __name__ == '__main__':
|
|
if len(sys.argv) < 3:
|
|
print(f"Usage: {sys.argv[0]} <backup_dir> <mount_point>")
|
|
print(f"Example: {sys.argv[0]} /mnt2/backed-up-drive/backupstore/volumes/2c/df/pvc-5c1f48e3-346f-4c35-8e6a-8fc0c4c3a842 /tmp/longhorn-fuse")
|
|
sys.exit(1)
|
|
|
|
backup_dir = sys.argv[1]
|
|
mount_point = sys.argv[2]
|
|
|
|
os.makedirs(mount_point, exist_ok=True)
|
|
|
|
print(f"Mounting {backup_dir} at {mount_point}")
|
|
print("This creates a virtual block device file at the mount point")
|
|
print("Then run: sudo losetup -fP {mount_point}/volume.img && sudo mount /dev/loopX /mnt/point")
|
|
|
|
fs = LonghornBackupFS(backup_dir)
|
|
fuse = FUSE(fs, mount_point, nothreads=True, foreground=True, allow_other=True)
|