forked from admin/terminal_worse
72 lines
1.9 KiB
Python
72 lines
1.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Minimal ar archive packer/extractor for .deb files on a-Shell.
|
|
|
|
Usage:
|
|
ardeb pack <out.ar> <file> [file ...]
|
|
ardeb extract <in.ar> <dest-dir>
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
|
|
|
|
def pack(out_path, files):
|
|
with open(out_path, "wb") as out:
|
|
out.write(b"!<arch>\n")
|
|
for path in files:
|
|
data = open(path, "rb").read()
|
|
name = os.path.basename(path)
|
|
if len(name) > 15:
|
|
raise SystemExit("ardeb: member name too long: " + name)
|
|
header = (
|
|
name.ljust(16)
|
|
+ "0".ljust(12)
|
|
+ "0".ljust(6)
|
|
+ "0".ljust(6)
|
|
+ "100644".ljust(8)
|
|
+ str(len(data)).ljust(10)
|
|
+ "`\n"
|
|
).encode("ascii")
|
|
out.write(header)
|
|
out.write(data)
|
|
if len(data) & 1:
|
|
out.write(b"\n")
|
|
|
|
|
|
def extract(archive, dest):
|
|
data = open(archive, "rb").read()
|
|
if not data.startswith(b"!<arch>\n"):
|
|
raise SystemExit("ardeb: not an ar archive")
|
|
os.makedirs(dest, exist_ok=True)
|
|
pos = 8
|
|
while pos + 60 <= len(data):
|
|
header = data[pos:pos + 60]
|
|
pos += 60
|
|
name = header[:16].decode("ascii", "ignore").strip().rstrip("/")
|
|
if not name:
|
|
continue
|
|
try:
|
|
size = int(header[48:58].decode("ascii", "ignore").strip() or "0")
|
|
except ValueError:
|
|
size = 0
|
|
body = data[pos:pos + size]
|
|
pos += size + (size & 1)
|
|
if name in (".", ".."):
|
|
continue
|
|
open(os.path.join(dest, name), "wb").write(body)
|
|
|
|
|
|
def main():
|
|
if len(sys.argv) < 4:
|
|
raise SystemExit(__doc__)
|
|
if sys.argv[1] == "pack":
|
|
pack(sys.argv[2], sys.argv[3:])
|
|
elif sys.argv[1] == "extract":
|
|
extract(sys.argv[2], sys.argv[3])
|
|
else:
|
|
raise SystemExit(__doc__)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|