#!/usr/bin/env python3 """Verify downloaded volumes, then extract without concatenating a large archive.""" import hashlib,json,subprocess,sys from pathlib import Path root=Path(__file__).resolve().parent m=json.loads((root/'backup-manifest.json').read_text()) if not m['complete']: raise SystemExit('This backup is still uploading.') for part in m['parts']: p=root/part['path']; h=hashlib.sha256() with p.open('rb') as f: for block in iter(lambda:f.read(4*1024*1024),b''):h.update(block) if p.stat().st_size!=part['size'] or h.hexdigest()!=part['sha256']: raise SystemExit('Missing/corrupt volume or unmaterialized LFS pointer: '+str(p)) print('All volume checksums verified.',flush=True) out=Path(sys.argv[1]).resolve() if len(sys.argv)>1 else root out.mkdir(parents=True,exist_ok=True) z=subprocess.Popen(['zstd','-d','-c'],stdin=subprocess.PIPE,stdout=subprocess.PIPE) t=subprocess.Popen(['tar','-xf','-','-C',str(out)],stdin=z.stdout) z.stdout.close() try: for part in m['parts']: with (root/part['path']).open('rb') as f: for block in iter(lambda:f.read(4*1024*1024),b''):z.stdin.write(block) z.stdin.close() if z.wait()!=0 or t.wait()!=0:raise SystemExit('Extraction failed.') finally: for proc in [z,t]: if proc.poll() is None:proc.terminate() print('Restored the archived directories to',out)