You've already forked ultrasm64-2
mirror of
https://github.com/HackerN64/ultrasm64-2.git
synced 2026-01-21 10:38:08 -08:00
91 lines
2.9 KiB
Python
91 lines
2.9 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
#
|
||
|
|
# Patch metadata in .ar files
|
||
|
|
#
|
||
|
|
|
||
|
|
import argparse
|
||
|
|
|
||
|
|
def ar_patch(ar, original, new_uid, new_gid, new_filemode):
|
||
|
|
"""
|
||
|
|
AR file headers
|
||
|
|
|
||
|
|
Offset Length Name Format
|
||
|
|
0 16 File identifier ASCII
|
||
|
|
16 12 File modification timestamp (in seconds) Decimal
|
||
|
|
28 6 Owner ID Decimal
|
||
|
|
34 6 Group ID Decimal
|
||
|
|
40 8 File mode (type and permission) Octal
|
||
|
|
48 10 File size in bytes Decimal
|
||
|
|
58 2 Ending characters 0x60 0x0A
|
||
|
|
"""
|
||
|
|
assert len(ar) > 0x24 , "Got empty archive?"
|
||
|
|
|
||
|
|
armap_time1 = None
|
||
|
|
armap_time2 = None
|
||
|
|
|
||
|
|
i = 8
|
||
|
|
while i < len(original):
|
||
|
|
file_name = original[i:][0:][:16].decode("ASCII")
|
||
|
|
file_size = int(original[i:][48:][:10].decode("ASCII").strip())
|
||
|
|
end = original[i:][58:][:2].decode("ASCII")
|
||
|
|
|
||
|
|
assert end == "`\n"
|
||
|
|
|
||
|
|
if file_name.strip() == "/":
|
||
|
|
armap_time1 = original[i+16:i+16+12]
|
||
|
|
elif file_name.strip() == "//":
|
||
|
|
armap_time2 = original[i+16:i+16+12]
|
||
|
|
|
||
|
|
if file_size % 2 != 0:
|
||
|
|
file_size += 1
|
||
|
|
i += file_size + 60
|
||
|
|
|
||
|
|
assert armap_time1 is not None
|
||
|
|
assert armap_time2 is not None
|
||
|
|
|
||
|
|
i = 8
|
||
|
|
while i < len(ar):
|
||
|
|
file_name = ar[i:][0:][:16].decode("ASCII")
|
||
|
|
file_size = int(ar[i:][48:][:10].decode("ASCII").strip())
|
||
|
|
end = ar[i:][58:][:2].decode("ASCII")
|
||
|
|
|
||
|
|
assert end == "`\n"
|
||
|
|
|
||
|
|
if file_name.strip() == "/":
|
||
|
|
ar[i+16:i+16+12] = armap_time1
|
||
|
|
elif file_name.strip() == "//":
|
||
|
|
ar[i+16:i+16+12] = armap_time2
|
||
|
|
else:
|
||
|
|
ar[i+28:i+28+6] = f"{new_uid:<6}".encode("ASCII")[:6]
|
||
|
|
ar[i+34:i+34+6] = f"{new_gid:<6}".encode("ASCII")[:6]
|
||
|
|
ar[i+40:i+40+8] = f"{new_filemode:<8}".encode("ASCII")[:8]
|
||
|
|
|
||
|
|
if file_size % 2 != 0:
|
||
|
|
file_size += 1
|
||
|
|
i += file_size + 60
|
||
|
|
|
||
|
|
def main():
|
||
|
|
parser = argparse.ArgumentParser(description="Patch metadata in .a files.")
|
||
|
|
parser.add_argument("target", help="path to the ar file to patch")
|
||
|
|
parser.add_argument("original", help="path to the original ar file")
|
||
|
|
parser.add_argument("uid", help="new uid")
|
||
|
|
parser.add_argument("gid", help="new gid")
|
||
|
|
parser.add_argument("filemode", help="new filemode")
|
||
|
|
args = parser.parse_args()
|
||
|
|
|
||
|
|
ar = None
|
||
|
|
with open(args.target, "rb") as ar_file:
|
||
|
|
ar = bytearray(ar_file.read())
|
||
|
|
|
||
|
|
original = None
|
||
|
|
with open(args.original, "rb") as original_ar_file:
|
||
|
|
original = bytearray(original_ar_file.read())
|
||
|
|
|
||
|
|
ar_patch(ar, original, args.uid, args.gid, args.filemode)
|
||
|
|
|
||
|
|
with open(args.target, "wb") as ar_file:
|
||
|
|
ar_file.write(ar)
|
||
|
|
|
||
|
|
if __name__ == '__main__':
|
||
|
|
main()
|