59 lines
1.9 KiB
Python
59 lines
1.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Copy a GPU addon (NGPUADD2, see UniXNU scripts/make-gpu-addon.py) and add the files of DIR below PREFIX.
|
|
usage: addon-add-dir.py IN.bin OUT.bin PREFIX DIR [PREFIX DIR ...] (executables keep 0755, the rest 0644)"""
|
|
import os
|
|
import struct
|
|
import sys
|
|
import zlib
|
|
from pathlib import Path
|
|
|
|
|
|
def pad(b):
|
|
return b + bytes(-len(b) % 8)
|
|
|
|
|
|
def read(path):
|
|
data = Path(path).read_bytes()
|
|
assert data[:8] == b'NGPUADD2', 'not an addon'
|
|
count = struct.unpack_from('<I', data, 8)[0]
|
|
at, files = 24, []
|
|
for _ in range(count):
|
|
plen, mode, size, packed = struct.unpack_from('<IIQQ', data, at)
|
|
at += 24
|
|
name = data[at:at + plen - 1].decode()
|
|
at += (plen + 7) & ~7
|
|
body = zlib.decompress(data[at:at + packed])
|
|
assert len(body) == size
|
|
at += (packed + 7) & ~7
|
|
files.append((name, mode, body))
|
|
return files
|
|
|
|
|
|
def write(path, files):
|
|
out = b''
|
|
for name, mode, body in files:
|
|
raw = name.encode() + b'\0'
|
|
assert len(raw) <= 160, name
|
|
packed = zlib.compress(body, 9)
|
|
out += struct.pack('<IIQQ', len(raw), mode, len(body), len(packed)) + pad(raw) + pad(packed)
|
|
blob = b'NGPUADD2' + struct.pack('<IIQ', len(files), 0, 24 + len(out)) + out
|
|
Path(path).write_bytes(blob)
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) < 5 or len(sys.argv) % 2 == 0:
|
|
sys.exit(__doc__)
|
|
files = read(sys.argv[1])
|
|
for prefix, directory in zip(sys.argv[3::2], sys.argv[4::2]):
|
|
base = Path(directory)
|
|
for p in sorted(x for x in base.rglob('*') if x.is_file()):
|
|
name = prefix.rstrip('/') + '/' + p.relative_to(base).as_posix()
|
|
mode = 0o755 if os.access(p, os.X_OK) else 0o644
|
|
files = [f for f in files if f[0] != name] + [(name, mode, p.read_bytes())]
|
|
write(sys.argv[2], files)
|
|
assert [f[0] for f in read(sys.argv[2])] == [f[0] for f in files]
|
|
print(f'{sys.argv[2]}: {len(files)} files')
|
|
|
|
|
|
main()
|