Files
homey/scripts/longhorn-fuse.py
T
2026-04-15 16:49:18 +03:00

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)