boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

extract-blk.sh (3240B)


      1 #!/usr/bin/env python3
      2 """extract-blk — extract files from a SEEDFS image written to blk1 by the
      3 seed kernel.
      4 
      5 Layout (sector-aligned, little-endian):
      6   sector 0:        char magic[8] = "SEEDFS\0\0"; u32 nfiles; u32 reserved;
      7   sector 1..T:     nfiles * { char path[96]; u32 data_offset_sectors;
      8                               u32 _pad;     u64 size_bytes; }
      9                    (entry size 112 B, 4 entries/sector → T=ceil(nfiles/4))
     10   sector T+1..:    file data, each padded up to a 512-byte boundary.
     11 
     12 The kernel dumps every tmpfs entry, including in/-prefixed inputs. We
     13 filter to out/-prefixed entries here, strip the prefix, and write to
     14 <outdir>/<rel> — so callers can point <outdir> at $STAGE/out/ directly.
     15 
     16 Usage: extract-blk.sh <outdir> <out.img>
     17 """
     18 
     19 import os
     20 import struct
     21 import sys
     22 
     23 ENT_SIZE = 112
     24 HDR_FMT = "<8sII"     # magic[8], nfiles u32, reserved u32
     25 ENT_FMT = "<96sIIQ"   # path[96], data_offset u32, _pad u32, size u64
     26 
     27 
     28 def fail(msg: str) -> None:
     29     print(f"extract-blk: {msg}", file=sys.stderr)
     30     sys.exit(3)
     31 
     32 
     33 def main() -> int:
     34     if len(sys.argv) != 3:
     35         print("usage: extract-blk.sh <outdir> <out.img>", file=sys.stderr)
     36         return 2
     37 
     38     outdir, img_path = sys.argv[1], sys.argv[2]
     39     if not os.path.isfile(img_path):
     40         fail(f"missing {img_path}")
     41     os.makedirs(outdir, exist_ok=True)
     42 
     43     with open(img_path, "rb") as f:
     44         hdr = f.read(16)
     45         if len(hdr) < 16:
     46             fail("image too small for header")
     47         magic, nfiles, _reserved = struct.unpack(HDR_FMT, hdr)
     48         if magic != b"SEEDFS\0\0":
     49             fail(f"bad magic at sector 0 (got {magic!r}) — kernel didn't reach exit")
     50         if nfiles < 0:
     51             fail(f"bad nfiles={nfiles}")
     52 
     53         table_sectors = (nfiles + 3) // 4
     54         f.seek(512)
     55         table = f.read(table_sectors * 512)
     56         if len(table) < nfiles * ENT_SIZE:
     57             fail("image truncated mid-table")
     58 
     59         written = 0
     60         for i in range(nfiles):
     61             path_bytes, off_sectors, _pad, size_bytes = struct.unpack_from(
     62                 ENT_FMT, table, i * ENT_SIZE
     63             )
     64             path = path_bytes.split(b"\0", 1)[0].decode("utf-8", "replace")
     65             if not path:
     66                 fail(f"empty path at entry {i}")
     67 
     68             if not path.startswith("out/"):
     69                 continue
     70             rel = path[len("out/"):]
     71             if not rel:
     72                 continue
     73 
     74             out = os.path.join(outdir, rel)
     75             os.makedirs(os.path.dirname(out) or ".", exist_ok=True)
     76 
     77             if size_bytes == 0:
     78                 open(out, "wb").close()
     79                 written += 1
     80                 continue
     81 
     82             f.seek(off_sectors * 512)
     83             remaining = size_bytes
     84             with open(out, "wb") as g:
     85                 while remaining > 0:
     86                     chunk = f.read(min(remaining, 1 << 20))
     87                     if not chunk:
     88                         fail(f"image truncated reading {path}")
     89                     g.write(chunk)
     90                     remaining -= len(chunk)
     91             written += 1
     92 
     93     print(f"extract-blk: wrote {written} file(s) to {outdir} (filtered from {nfiles})", file=sys.stderr)
     94     return 0
     95 
     96 
     97 if __name__ == "__main__":
     98     sys.exit(main())