# unpack_logs.py # Author: David Niedbala Giraudin, ORCID 0009-0009-1526-1178 # Technical assistance: Claude (Anthropic) # # The solver logs and search trees of both programs are shipped as one file, logs_bundle.log # (the archive may contain at most 99 files). run() recreates the folder logs/ from it, byte for # byte, and checks the size and the SHA-256 of every file against the bundle header. It is called # by verify_logs.py and drat_spot_check.py; it can also be run alone (no arguments, < 1 s). # Bundle format: for each file, a line "##### FILE ", then exactly # bytes of content, then one newline. import os, hashlib HERE = os.path.dirname(os.path.abspath(__file__)) def run(verbose=False): data = open(os.path.join(HERE, 'logs_bundle.log'), 'rb').read() out = os.path.join(HERE, 'logs'); os.makedirs(out, exist_ok=True) pos, n = 0, 0 while pos < len(data): end = data.index(b'\n', pos) head = data[pos:end].decode().split() assert len(head) == 5 and head[0] == '#####' and head[1] == 'FILE', 'bad bundle header' name, size, digest = head[2], int(head[3]), head[4] assert '/' not in name and '\\' not in name and not name.startswith('.'), 'bad file name' body = data[end + 1:end + 1 + size] assert len(body) == size and hashlib.sha256(body).hexdigest() == digest, 'checksum mismatch: ' + name assert data[end + 1 + size:end + 2 + size] == b'\n', 'bad bundle separator' with open(os.path.join(out, name), 'wb') as f: f.write(body) pos = end + 2 + size; n += 1 if verbose: print('logs/: %d files recreated, all SHA-256 checked' % n, flush=True) return n if __name__ == '__main__': run(True)