mirror of
https://github.com/elliotnunn/machfs.git
synced 2024-11-21 13:30:59 +00:00
Refactor Make/DumpHFS into Python library
This commit is contained in:
parent
34eecddc28
commit
350f11b0c0
48
bin/DumpHFS
48
bin/DumpHFS
@ -1,16 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import os.path as path
|
||||
from machfs import Volume, Folder, File
|
||||
import macresources
|
||||
|
||||
def any_exists(at_path):
|
||||
if path.exists(at_path): return True
|
||||
if path.exists(at_path + '.rdump'): return True
|
||||
if path.exists(at_path + '.idump'): return True
|
||||
return False
|
||||
from machfs import Volume
|
||||
|
||||
args = argparse.ArgumentParser()
|
||||
|
||||
@ -23,39 +14,4 @@ with open(args.src[0], 'rb') as f:
|
||||
v = Volume()
|
||||
v.read(f.read())
|
||||
|
||||
written = []
|
||||
for p, obj in v.iter_paths():
|
||||
nativepath = path.join(args.dir[0], *(comp.replace(path.sep, ':') for comp in p))
|
||||
|
||||
if isinstance(obj, Folder):
|
||||
os.makedirs(nativepath, exist_ok=True)
|
||||
|
||||
elif obj.mddate != obj.bkdate or not any_exists(nativepath):
|
||||
data = obj.data
|
||||
if obj.type == b'TEXT':
|
||||
data = data.decode('mac_roman').replace('\r', os.linesep).encode('utf8')
|
||||
|
||||
rsrc = obj.rsrc
|
||||
if rsrc:
|
||||
rsrc = macresources.parse_file(rsrc)
|
||||
rsrc = macresources.make_rez_code(rsrc, ascii_clean=True)
|
||||
|
||||
info = obj.type + obj.creator
|
||||
if info == b'????????': info = b''
|
||||
|
||||
for thing, suffix in ((data, ''), (rsrc, '.rdump'), (info, '.idump')):
|
||||
wholepath = nativepath + suffix
|
||||
if thing or (suffix == '' and not rsrc):
|
||||
written.append(wholepath)
|
||||
with open(written[-1], 'wb') as f:
|
||||
f.write(thing)
|
||||
else:
|
||||
try:
|
||||
os.remove(wholepath)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
if written:
|
||||
t = path.getmtime(written[-1])
|
||||
for f in written:
|
||||
os.utime(f, (t, t))
|
||||
v.write_folder(args.dir[0])
|
||||
|
99
bin/MakeHFS
99
bin/MakeHFS
@ -1,12 +1,8 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import os.path as path
|
||||
import re
|
||||
from datetime import datetime
|
||||
from machfs import Volume, Folder, File
|
||||
import macresources
|
||||
from machfs import Volume
|
||||
|
||||
########################################################################
|
||||
|
||||
@ -76,99 +72,8 @@ args = args.parse_args()
|
||||
|
||||
vol = Volume()
|
||||
vol.name = args.name
|
||||
vol.crdate = vol.mddate = vol.bkdate = args.date
|
||||
|
||||
########################################################################
|
||||
|
||||
def includefilter(n):
|
||||
if n.startswith('.'): return False
|
||||
if n.endswith('.rdump'): return True
|
||||
if n.endswith('.idump'): return True
|
||||
return True
|
||||
|
||||
def swapsep(n):
|
||||
return n.replace(':', path.sep)
|
||||
|
||||
def mkbasename(n):
|
||||
base, ext = path.splitext(n)
|
||||
if ext in ('.rdump', '.idump'):
|
||||
return base
|
||||
else:
|
||||
return n
|
||||
|
||||
if args.dir is not None:
|
||||
tmptree = {args.dir: vol}
|
||||
|
||||
for dirpath, dirnames, filenames in os.walk(args.dir):
|
||||
dirnames[:] = [swapsep(x) for x in dirnames if includefilter(x)]
|
||||
filenames[:] = [swapsep(x) for x in filenames if includefilter(x)]
|
||||
|
||||
for dn in dirnames:
|
||||
newdir = Folder()
|
||||
newdir.crdate = newdir.mddate = newdir.bkdate = args.date
|
||||
tmptree[dirpath][dn] = newdir
|
||||
tmptree[path.join(dirpath, dn)] = newdir
|
||||
|
||||
for fn in filenames:
|
||||
basename = mkbasename(fn)
|
||||
fullbase = path.join(dirpath, basename)
|
||||
fullpath = path.join(dirpath, fn)
|
||||
|
||||
try:
|
||||
thefile = tmptree[fullbase]
|
||||
except KeyError:
|
||||
thefile = File()
|
||||
thefile.real_t = 0 # for the MPW hack
|
||||
thefile.crdate = thefile.mddate = thefile.bkdate = args.date
|
||||
thefile.contributors = []
|
||||
tmptree[fullbase] = thefile
|
||||
|
||||
if fn.endswith('.idump'):
|
||||
with open(fullpath, 'rb') as f:
|
||||
thefile.type = f.read(4)
|
||||
thefile.creator = f.read(4)
|
||||
elif fn.endswith('rdump'):
|
||||
rez = open(fullpath, 'rb').read()
|
||||
resources = macresources.parse_rez_code(rez)
|
||||
resfork = macresources.make_file(resources, align=4)
|
||||
thefile.rsrc = resfork
|
||||
else:
|
||||
thefile.data = open(fullpath, 'rb').read()
|
||||
|
||||
thefile.contributors.append(fullpath)
|
||||
if args.mpw_dates:
|
||||
thefile.real_t = max(thefile.real_t, path.getmtime(fullpath))
|
||||
|
||||
tmptree[dirpath][basename] = thefile
|
||||
|
||||
for pathtpl, obj in vol.iter_paths():
|
||||
try:
|
||||
if obj.type == b'TEXT':
|
||||
obj.data = obj.data.decode('utf8').replace('\r\n', '\r').replace('\n', '\r').encode('mac_roman')
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
########################################################################
|
||||
|
||||
if args.mpw_dates:
|
||||
all_real_times = set()
|
||||
for pathtpl, obj in vol.iter_paths():
|
||||
try:
|
||||
all_real_times.add(obj.real_t)
|
||||
except AttributeError:
|
||||
pass
|
||||
ts2idx = {ts: idx for (idx, ts) in enumerate(sorted(set(all_real_times)))}
|
||||
|
||||
for pathtpl, obj in vol.iter_paths():
|
||||
try:
|
||||
real_t = obj.real_t
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
fake_t = obj.crdate + 60 * ts2idx[real_t]
|
||||
obj.crdate = obj.mddate = obj.bkdate = fake_t
|
||||
|
||||
########################################################################
|
||||
if args.dir: vol.read_folder(args.dir, date=args.date, mpw_dates=args.mpw_dates)
|
||||
|
||||
image = vol.write(args.size, startapp=args.app)
|
||||
with open(args.dest[0], 'wb') as f:
|
||||
|
136
machfs/main.py
136
machfs/main.py
@ -1,5 +1,7 @@
|
||||
import struct
|
||||
from macresources import Resource, make_file, parse_file
|
||||
import os
|
||||
from os import path
|
||||
from macresources import Resource, make_file, parse_file, make_rez_code, parse_rez_code
|
||||
from . import btree, bitmanip, directory
|
||||
|
||||
|
||||
@ -494,3 +496,135 @@ class Volume(directory.AbstractFolder):
|
||||
finalchunks.append(vib)
|
||||
finalchunks.append(bytes(512))
|
||||
return b''.join(finalchunks)
|
||||
|
||||
def read_folder(self, folder_path, date=0, mpw_dates=False):
|
||||
def includefilter(n):
|
||||
if n.startswith('.'): return False
|
||||
if n.endswith('.rdump'): return True
|
||||
if n.endswith('.idump'): return True
|
||||
return True
|
||||
|
||||
def swapsep(n):
|
||||
return n.replace(':', path.sep)
|
||||
|
||||
def mkbasename(n):
|
||||
base, ext = path.splitext(n)
|
||||
if ext in ('.rdump', '.idump'):
|
||||
return base
|
||||
else:
|
||||
return n
|
||||
|
||||
self.crdate = self.mddate = self.bkdate = date
|
||||
|
||||
tmptree = {folder_path: self}
|
||||
|
||||
for dirpath, dirnames, filenames in os.walk(folder_path):
|
||||
dirnames[:] = [swapsep(x) for x in dirnames if includefilter(x)]
|
||||
filenames[:] = [swapsep(x) for x in filenames if includefilter(x)]
|
||||
|
||||
for dn in dirnames:
|
||||
newdir = Folder()
|
||||
newdir.crdate = newdir.mddate = newdir.bkdate = date
|
||||
tmptree[dirpath][dn] = newdir
|
||||
tmptree[path.join(dirpath, dn)] = newdir
|
||||
|
||||
for fn in filenames:
|
||||
basename = mkbasename(fn)
|
||||
fullbase = path.join(dirpath, basename)
|
||||
fullpath = path.join(dirpath, fn)
|
||||
|
||||
try:
|
||||
thefile = tmptree[fullbase]
|
||||
except KeyError:
|
||||
thefile = File()
|
||||
thefile.real_t = 0 # for the MPW hack
|
||||
thefile.crdate = thefile.mddate = thefile.bkdate = date
|
||||
thefile.contributors = []
|
||||
tmptree[fullbase] = thefile
|
||||
|
||||
if fn.endswith('.idump'):
|
||||
with open(fullpath, 'rb') as f:
|
||||
thefile.type = f.read(4)
|
||||
thefile.creator = f.read(4)
|
||||
elif fn.endswith('rdump'):
|
||||
rez = open(fullpath, 'rb').read()
|
||||
resources = parse_rez_code(rez)
|
||||
resfork = make_file(resources, align=4)
|
||||
thefile.rsrc = resfork
|
||||
else:
|
||||
thefile.data = open(fullpath, 'rb').read()
|
||||
|
||||
thefile.contributors.append(fullpath)
|
||||
if mpw_dates:
|
||||
thefile.real_t = max(thefile.real_t, path.getmtime(fullpath))
|
||||
|
||||
tmptree[dirpath][basename] = thefile
|
||||
|
||||
for pathtpl, obj in self.iter_paths():
|
||||
try:
|
||||
if obj.type == b'TEXT':
|
||||
obj.data = obj.data.decode('utf8').replace('\r\n', '\r').replace('\n', '\r').encode('mac_roman')
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
if mpw_dates:
|
||||
all_real_times = set()
|
||||
for pathtpl, obj in self.iter_paths():
|
||||
try:
|
||||
all_real_times.add(obj.real_t)
|
||||
except AttributeError:
|
||||
pass
|
||||
ts2idx = {ts: idx for (idx, ts) in enumerate(sorted(set(all_real_times)))}
|
||||
|
||||
for pathtpl, obj in self.iter_paths():
|
||||
try:
|
||||
real_t = obj.real_t
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
fake_t = obj.crdate + 60 * ts2idx[real_t]
|
||||
obj.crdate = obj.mddate = obj.bkdate = fake_t
|
||||
|
||||
def write_folder(self, folder_path):
|
||||
def any_exists(at_path):
|
||||
if path.exists(at_path): return True
|
||||
if path.exists(at_path + '.rdump'): return True
|
||||
if path.exists(at_path + '.idump'): return True
|
||||
return False
|
||||
|
||||
written = []
|
||||
for p, obj in self.iter_paths():
|
||||
nativepath = path.join(folder_path, *(comp.replace(path.sep, ':') for comp in p))
|
||||
|
||||
if isinstance(obj, Folder):
|
||||
os.makedirs(nativepath, exist_ok=True)
|
||||
|
||||
elif obj.mddate != obj.bkdate or not any_exists(nativepath):
|
||||
data = obj.data
|
||||
if obj.type == b'TEXT':
|
||||
data = data.decode('mac_roman').replace('\r', os.linesep).encode('utf8')
|
||||
|
||||
rsrc = obj.rsrc
|
||||
if rsrc:
|
||||
rsrc = parse_file(rsrc)
|
||||
rsrc = make_rez_code(rsrc, ascii_clean=True)
|
||||
|
||||
info = obj.type + obj.creator
|
||||
if info == b'????????': info = b''
|
||||
|
||||
for thing, suffix in ((data, ''), (rsrc, '.rdump'), (info, '.idump')):
|
||||
wholepath = nativepath + suffix
|
||||
if thing or (suffix == '' and not rsrc):
|
||||
written.append(wholepath)
|
||||
with open(written[-1], 'wb') as f:
|
||||
f.write(thing)
|
||||
else:
|
||||
try:
|
||||
os.remove(wholepath)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
if written:
|
||||
t = path.getmtime(written[-1])
|
||||
for w in written:
|
||||
os.utime(w, (t, t))
|
||||
|
Loading…
Reference in New Issue
Block a user