This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
"""Offline parser for the bounded Phase-1.0DM snapshot stream."""
|
||||
from __future__ import annotations
|
||||
from dataclasses import dataclass
|
||||
import hashlib,struct
|
||||
|
||||
MAGIC=b"CHS10DM1";FRAME=struct.Struct("<8sIIiiQQQQq");MAX_BYTES=64*1024*1024
|
||||
BEGIN=1;END=2;ERROR=3
|
||||
class ProtocolError(ValueError):pass
|
||||
@dataclass(frozen=True)
|
||||
class SnapshotResult:
|
||||
data:bytes
|
||||
sha256:str
|
||||
size:int
|
||||
device:int
|
||||
inode:int
|
||||
mtime:int
|
||||
|
||||
def _frame(data:bytes):
|
||||
if len(data)!=64:raise ProtocolError("frame size")
|
||||
values=FRAME.unpack(data)
|
||||
if values[0]!=MAGIC or values[1]!=1:raise ProtocolError("frame identity")
|
||||
return values
|
||||
|
||||
def parse_stream(raw:bytes)->SnapshotResult:
|
||||
if not isinstance(raw,bytes) or len(raw)<128:raise ProtocolError("stream truncated")
|
||||
begin=_frame(raw[:64]);kind,status,saved,size,sent,dev,ino,mtime=begin[2:]
|
||||
if kind==ERROR:raise ProtocolError(f"target error {status}")
|
||||
if kind!=BEGIN or status!=0 or saved!=0 or sent!=0 or not 0<size<=MAX_BYTES:raise ProtocolError("begin invalid")
|
||||
if len(raw)!=64+size+64:raise ProtocolError("stream length")
|
||||
payload=raw[64:64+size];end=_frame(raw[64+size:]);ekind,estatus,esaved,esize,esent,edev,eino,emtime=end[2:]
|
||||
if ekind!=END or estatus!=0 or esaved!=0 or esize!=size or esent!=size or (edev,eino,emtime)!=(dev,ino,mtime):raise ProtocolError("terminal invalid")
|
||||
if payload[:16]!=b"SQLite format 3\x00":raise ProtocolError("not sqlite")
|
||||
return SnapshotResult(payload,hashlib.sha256(payload).hexdigest(),size,dev,ino,mtime)
|
||||
Reference in New Issue
Block a user