mirror of
https://github.com/elliotnunn/machfs.git
synced 2024-06-15 12:29:30 +00:00
neater and passing tests
This commit is contained in:
parent
58bc5f6430
commit
854e8b987c
64
directory.py
64
directory.py
|
@ -1,14 +1,66 @@
|
||||||
class AbstractFolder(dict):
|
import collections
|
||||||
def paths(self):
|
|
||||||
|
|
||||||
|
_CASE = list(range(256)) # cheating, fix this!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _to_lower(orig):
|
||||||
|
return bytes(_CASE[x] for x in orig)
|
||||||
|
|
||||||
|
|
||||||
|
class AbstractFolder(collections.MutableMapping):
|
||||||
|
def __init__(self, from_dict=()):
|
||||||
|
self._prefdict = {} # lowercase to preferred
|
||||||
|
self._maindict = {} # lowercase to contents
|
||||||
|
self.update(from_dict)
|
||||||
|
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
try:
|
||||||
|
key = key.encode('mac_roman')
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if len(key) > 31:
|
||||||
|
raise ValueError('Max filename length = 31')
|
||||||
|
|
||||||
|
lower = _to_lower(key)
|
||||||
|
self._prefdict[lower] = key
|
||||||
|
self._maindict[lower] = value
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
try:
|
||||||
|
key = key.encode('mac_roman')
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
lower = _to_lower(key)
|
||||||
|
return self._maindict[lower]
|
||||||
|
|
||||||
|
def __delitem__(self, key):
|
||||||
|
try:
|
||||||
|
value = value.encode('mac_roman')
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
lower = _to_lower(key)
|
||||||
|
del self._maindict[lower]
|
||||||
|
del self._prefdict[lower]
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return iter(self._prefdict.values())
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self._maindict)
|
||||||
|
|
||||||
|
def iter_paths(self):
|
||||||
for name, child in self.items():
|
for name, child in self.items():
|
||||||
|
print(name, child)
|
||||||
yield ((name,), child)
|
yield ((name,), child)
|
||||||
try:
|
try:
|
||||||
childs_children = child.paths()
|
childs_children = child.iter_paths()
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
for each_path, each_child in childs_children:
|
for each_path, each_child in childs_children:
|
||||||
yield (name,) + each_path, each_child
|
yield (name,) + each_path, each_child
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return 'Folder valence=%d' % len(self)
|
|
||||||
|
|
41
main.py
41
main.py
|
@ -101,27 +101,27 @@ class Volume(_directory.AbstractFolder):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.bootblocks = bytes(1024) # optional; for booting HFS volumes
|
self.bootblocks = bytes(1024) # optional; for booting HFS volumes
|
||||||
self.drCrDate = 0 # date and time of volume creation
|
self.crdate = 0 # date and time of volume creation
|
||||||
self.drLsMod = 0 # date and time of last modification
|
self.lsmod = 0 # date and time of last modification
|
||||||
self.drAtrb = 1<<8 # volume attributes (hwlock, swlock, CLEANUNMOUNT, badblocks)
|
self.name = b'Untitled'
|
||||||
self.drVN = b'Untitled' # volume name Pascal string
|
|
||||||
self.drVolBkUp = 0 # date and time of last backup
|
|
||||||
self.drVSeqNum = 0 # volume backup sequence number
|
|
||||||
self.drFndrInfo = bytes(32) # information used by the Finder
|
|
||||||
|
|
||||||
def read(self, from_volume):
|
def read(self, from_volume):
|
||||||
self._dirtree = {}
|
self._dirtree = {}
|
||||||
self.bootblocks = from_volume[:1024]
|
self.bootblocks = from_volume[:1024]
|
||||||
|
|
||||||
drSigWord, self.drCrDate, self.drLsMod, self.drAtrb, drNmFls, \
|
drSigWord, drCrDate, drLsMod, drAtrb, drNmFls, \
|
||||||
drVBMSt, drAllocPtr, drNmAlBlks, drAlBlkSiz, drClpSiz, drAlBlSt, \
|
drVBMSt, drAllocPtr, drNmAlBlks, drAlBlkSiz, drClpSiz, drAlBlSt, \
|
||||||
drNxtCNID, drFreeBks, self.drVN, self.drVolBkUp, self.drVSeqNum, \
|
drNxtCNID, drFreeBks, drVN, drVolBkUp, drVSeqNum, \
|
||||||
drWrCnt, drXTClpSiz, drCTClpSiz, drNmRtDirs, drFilCnt, drDirCnt, \
|
drWrCnt, drXTClpSiz, drCTClpSiz, drNmRtDirs, drFilCnt, drDirCnt, \
|
||||||
self.drFndrInfo, drVCSize, drVBMCSize, drCtlCSize, \
|
drFndrInfo, drVCSize, drVBMCSize, drCtlCSize, \
|
||||||
drXTFlSize, drXTExtRec, \
|
drXTFlSize, drXTExtRec, \
|
||||||
drCTFlSize, drCTExtRec, \
|
drCTFlSize, drCTExtRec, \
|
||||||
= struct.unpack_from('>2sLLHHHHHLLHLH28pLHLLLHLL32sHHHL12sL12s', from_volume, 1024)
|
= struct.unpack_from('>2sLLHHHHHLLHLH28pLHLLLHLL32sHHHL12sL12s', from_volume, 1024)
|
||||||
|
|
||||||
|
self.crdate = drCrDate
|
||||||
|
self.lsmod = drLsMod
|
||||||
|
self.name = drVN
|
||||||
|
|
||||||
block2offset = lambda block: 512*drAlBlSt + drAlBlkSiz*block
|
block2offset = lambda block: 512*drAlBlSt + drAlBlkSiz*block
|
||||||
extent2bytes = lambda firstblk, blkcnt: from_volume[block2offset(firstblk):block2offset(firstblk+blkcnt)]
|
extent2bytes = lambda firstblk, blkcnt: from_volume[block2offset(firstblk):block2offset(firstblk+blkcnt)]
|
||||||
extrec2bytes = lambda extrec: b''.join(extent2bytes(a, b) for (a, b) in _btree.unpack_extent_record(extrec))
|
extrec2bytes = lambda extrec: b''.join(extent2bytes(a, b) for (a, b) in _btree.unpack_extent_record(extrec))
|
||||||
|
@ -248,16 +248,16 @@ class Volume(_directory.AbstractFolder):
|
||||||
|
|
||||||
# write all the files in the volume
|
# write all the files in the volume
|
||||||
topwrap = _TempWrapper(self)
|
topwrap = _TempWrapper(self)
|
||||||
topwrap.path = (self.drVN,)
|
topwrap.path = (self.name,)
|
||||||
topwrap.cnid = 2
|
topwrap.cnid = 2
|
||||||
|
|
||||||
godwrap = _TempWrapper(None)
|
godwrap = _TempWrapper(None)
|
||||||
godwrap.cnid = 1
|
godwrap.cnid = 1
|
||||||
|
|
||||||
path2wrap = {(): godwrap, (self.drVN,): topwrap}
|
path2wrap = {(): godwrap, (self.name,): topwrap}
|
||||||
drNxtCNID = 16
|
drNxtCNID = 16
|
||||||
for path, obj in self.paths():
|
for path, obj in self.iter_paths():
|
||||||
path = (self.drVN,) + path
|
path = (self.name,) + path
|
||||||
wrap = _TempWrapper(obj)
|
wrap = _TempWrapper(obj)
|
||||||
path2wrap[path] = wrap
|
path2wrap[path] = wrap
|
||||||
wrap.path = path
|
wrap.path = path
|
||||||
|
@ -363,13 +363,20 @@ class Volume(_directory.AbstractFolder):
|
||||||
drFreeBks = drNmAlBlks - len(blkaccum)
|
drFreeBks = drNmAlBlks - len(blkaccum)
|
||||||
drWrCnt = 0 # ????volume write count
|
drWrCnt = 0 # ????volume write count
|
||||||
drVCSize = drVBMCSize = drCtlCSize = 0
|
drVCSize = drVBMCSize = drCtlCSize = 0
|
||||||
|
drAtrb = 1<<8 # volume attributes (hwlock, swlock, CLEANUNMOUNT, badblocks)
|
||||||
|
drVN = self.name
|
||||||
|
drVolBkUp = 0 # date and time of last backup
|
||||||
|
drVSeqNum = 0 # volume backup sequence number
|
||||||
|
drFndrInfo = bytes(32) # information used by the Finder
|
||||||
|
drCrDate = self.crdate
|
||||||
|
drLsMod = self.lsmod
|
||||||
|
|
||||||
vib = struct.pack('>2sLLHHHHHLLHLH28pLHLLLHLL32sHHHLHHxxxxxxxxLHHxxxxxxxx',
|
vib = struct.pack('>2sLLHHHHHLLHLH28pLHLLLHLL32sHHHLHHxxxxxxxxLHHxxxxxxxx',
|
||||||
drSigWord, self.drCrDate, self.drLsMod, self.drAtrb, drNmFls,
|
drSigWord, drCrDate, drLsMod, drAtrb, drNmFls,
|
||||||
drVBMSt, drAllocPtr, drNmAlBlks, drAlBlkSiz, drClpSiz, drAlBlSt,
|
drVBMSt, drAllocPtr, drNmAlBlks, drAlBlkSiz, drClpSiz, drAlBlSt,
|
||||||
drNxtCNID, drFreeBks, self.drVN, self.drVolBkUp, self.drVSeqNum,
|
drNxtCNID, drFreeBks, drVN, drVolBkUp, drVSeqNum,
|
||||||
drWrCnt, drXTClpSiz, drCTClpSiz, drNmRtDirs, drFilCnt, drDirCnt,
|
drWrCnt, drXTClpSiz, drCTClpSiz, drNmRtDirs, drFilCnt, drDirCnt,
|
||||||
self.drFndrInfo, drVCSize, drVBMCSize, drCtlCSize,
|
drFndrInfo, drVCSize, drVBMCSize, drCtlCSize,
|
||||||
drXTFlSize, drXTExtRec_Start, drXTExtRec_Cnt,
|
drXTFlSize, drXTExtRec_Start, drXTExtRec_Cnt,
|
||||||
drCTFlSize, drCTExtRec_Start, drCTExtRec_Cnt,
|
drCTFlSize, drCTExtRec_Start, drCTExtRec_Cnt,
|
||||||
)
|
)
|
||||||
|
|
|
@ -19,7 +19,7 @@ def test_roundtrip():
|
||||||
|
|
||||||
def test_macos_mount():
|
def test_macos_mount():
|
||||||
h = Volume()
|
h = Volume()
|
||||||
h.drVN = b'ElmoTest'
|
h.name = b'ElmoTest'
|
||||||
hf = File()
|
hf = File()
|
||||||
hf.data = b'12345' * 10
|
hf.data = b'12345' * 10
|
||||||
for i in reversed(range(100)):
|
for i in reversed(range(100)):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user