mirror of
https://github.com/elliotnunn/machfs.git
synced 2024-11-25 23:49:16 +00:00
outputting
This commit is contained in:
parent
d4dfe6dc19
commit
b681e95d5a
230
thing.py
230
thing.py
@ -25,6 +25,7 @@ def _dump_btree_recs(buf, start):
|
|||||||
# Ask about the header record in the header node
|
# Ask about the header record in the header node
|
||||||
bthDepth, bthRoot, bthNRecs, bthFNode, bthLNode, bthNodeSize, bthKeyLen, bthNNodes, bthFree = \
|
bthDepth, bthRoot, bthNRecs, bthFNode, bthLNode, bthNodeSize, bthKeyLen, bthNNodes, bthFree = \
|
||||||
struct.unpack_from('>HLLLLHHLL', header_rec)
|
struct.unpack_from('>HLLLLHHLL', header_rec)
|
||||||
|
# print('btree', bthDepth, bthRoot, bthNRecs, bthFNode, bthLNode, bthNodeSize, bthKeyLen, bthNNodes, bthFree)
|
||||||
|
|
||||||
# And iterate through the linked list of leaf nodes
|
# And iterate through the linked list of leaf nodes
|
||||||
this_leaf = bthFNode
|
this_leaf = bthFNode
|
||||||
@ -62,6 +63,17 @@ def _will_fit_in_leaf_node(keyvals):
|
|||||||
def _will_fit_in_index_node(keyvals):
|
def _will_fit_in_index_node(keyvals):
|
||||||
return len(keyvals) <= 8
|
return len(keyvals) <= 8
|
||||||
|
|
||||||
|
def _bits(ntotal, nset):
|
||||||
|
nset = max(nset, 0)
|
||||||
|
nset = min(nset, ntotal)
|
||||||
|
a = b'\xFF' * (nset // 8)
|
||||||
|
c = b'\x00' * ((ntotal-nset) // 8)
|
||||||
|
if (len(a) + len(c)) * 8 < ntotal:
|
||||||
|
b = [b'\x00', b'\x80', b'\xC0', b'\xE0', b'\xF0', b'\xF8', b'\xFC', b'\xFE', b'\xFF'][nset % 8]
|
||||||
|
return b''.join([a,b,c])
|
||||||
|
else:
|
||||||
|
return b''.join([a,c])
|
||||||
|
|
||||||
class _Node:
|
class _Node:
|
||||||
def __bytes__(self):
|
def __bytes__(self):
|
||||||
buf = bytearray(512)
|
buf = bytearray(512)
|
||||||
@ -88,8 +100,10 @@ class _Node:
|
|||||||
|
|
||||||
def _mkbtree(records):
|
def _mkbtree(records):
|
||||||
biglist = [[[]]] # [level][node][record]
|
biglist = [[[]]] # [level][node][record]
|
||||||
|
bthNRecs = 0
|
||||||
|
|
||||||
for keyval in records:
|
for keyval in records:
|
||||||
|
bthNRecs += 1
|
||||||
curnode = biglist[-1][-1]
|
curnode = biglist[-1][-1]
|
||||||
curnode.append(keyval)
|
curnode.append(keyval)
|
||||||
if not _will_fit_in_leaf_node(curnode):
|
if not _will_fit_in_leaf_node(curnode):
|
||||||
@ -112,11 +126,11 @@ def _mkbtree(records):
|
|||||||
biglist.reverse() # index nodes then leaf nodes
|
biglist.reverse() # index nodes then leaf nodes
|
||||||
|
|
||||||
# cool, now biglist is of course brilliant
|
# cool, now biglist is of course brilliant
|
||||||
for i, level in enumerate(biglist, 1):
|
# for i, level in enumerate(biglist, 1):
|
||||||
print('LEVEL', i)
|
# print('LEVEL', i)
|
||||||
for node in level:
|
# for node in level:
|
||||||
print('(%d)' % len(node), *(rec[0] for rec in node))
|
# print('(%d)' % len(node), *(rec[0] for rec in node))
|
||||||
print()
|
# print()
|
||||||
|
|
||||||
# Make space for a header node at element 0
|
# Make space for a header node at element 0
|
||||||
hnode = _Node()
|
hnode = _Node()
|
||||||
@ -142,11 +156,11 @@ def _mkbtree(records):
|
|||||||
else:
|
else:
|
||||||
newnode.ndType = 0 # index node
|
newnode.ndType = 0 # index node
|
||||||
|
|
||||||
for n in nodelist:
|
# for n in nodelist:
|
||||||
print(n.ndNHeight, n.records)
|
# print(n.ndNHeight, n.records)
|
||||||
print()
|
# print()
|
||||||
|
|
||||||
print(spiderdict)
|
# print(spiderdict)
|
||||||
|
|
||||||
# pack the records in the index and leaf nodes
|
# pack the records in the index and leaf nodes
|
||||||
for node in nodelist:
|
for node in nodelist:
|
||||||
@ -156,28 +170,56 @@ def _mkbtree(records):
|
|||||||
node.records = [_pack_index_record(k, spiderdict[node.ndNHeight+1, k]) for (k, v) in node.records]
|
node.records = [_pack_index_record(k, spiderdict[node.ndNHeight+1, k]) for (k, v) in node.records]
|
||||||
|
|
||||||
# make the map nodes so that the bitmap covers what we use
|
# make the map nodes so that the bitmap covers what we use
|
||||||
|
# (this does not yet populate the bitmap)
|
||||||
bits_covered = 2048
|
bits_covered = 2048
|
||||||
|
mapnodes = []
|
||||||
while bits_covered < len(nodelist):
|
while bits_covered < len(nodelist):
|
||||||
bits_covered += 3952 # bits in a max-sized record
|
bits_covered += 3952 # bits in a max-sized record
|
||||||
mapnode = _Node()
|
mapnode = _Node()
|
||||||
nodelist.append(mapnode)
|
nodelist.append(mapnode)
|
||||||
|
mapnodes.append(mapnode)
|
||||||
mapnode.ndType = 2
|
mapnode.ndType = 2
|
||||||
ndNHeight = 1 # fix, not sure about this
|
ndNHeight = 1 # fix, not sure about this
|
||||||
mapnode.records = [] # fix this
|
mapnode.records = [] # fix this
|
||||||
|
|
||||||
# now we run back and forth to join up!
|
# now we run back and forth to join up nodes of similar type
|
||||||
most_recent = {}
|
most_recent = {}
|
||||||
for i, node in enumerate(nodelist):
|
for i, node in enumerate(nodelist):
|
||||||
node.ndBLink = most_recent.get(node.ndType, 0)
|
node.ndBLink = most_recent.get(node.ndType, 0)
|
||||||
most_recent[node.ndType] = i
|
most_recent[node.ndType] = i
|
||||||
|
bthLNode = most_recent[0xFF]
|
||||||
most_recent = {}
|
most_recent = {}
|
||||||
for i, node in reversed(list(enumerate(nodelist))):
|
for i, node in reversed(list(enumerate(nodelist))):
|
||||||
node.ndFLink = most_recent.get(node.ndType, 0)
|
node.ndFLink = most_recent.get(node.ndType, 0)
|
||||||
most_recent[node.ndType] = i
|
most_recent[node.ndType] = i
|
||||||
|
bthFNode = most_recent[0xFF]
|
||||||
|
|
||||||
for n in nodelist:
|
# for n in nodelist:
|
||||||
print(n.__dict__)
|
# print(n.__dict__)
|
||||||
|
|
||||||
|
bthFree = len(nodelist) // 4 # maybe limber this up in the future
|
||||||
|
|
||||||
|
# populate the bitmap (1 = used)
|
||||||
|
hnode.records[2] = _bits(2048, len(nodelist))
|
||||||
|
for i, mnode in mapnodes:
|
||||||
|
nset = len(nodelist) - 2048 - i*3952
|
||||||
|
mnode.records = [_bits(3952, nset)]
|
||||||
|
|
||||||
|
# populate the header node:
|
||||||
|
bthDepth = len(biglist)
|
||||||
|
bthRoot = 1 # root node is first-but-one
|
||||||
|
# bthNRecs set above
|
||||||
|
# bthFNode/bthLNode also set above
|
||||||
|
bthNodeSize = 512
|
||||||
|
bthKeyLen = 37
|
||||||
|
bthNNodes = len(nodelist) + bthFree # how do we calculate this?
|
||||||
|
# bthFree set above
|
||||||
|
hnode.records[0] = struct.pack('>HLLLLHHLL76x',
|
||||||
|
bthDepth, bthRoot, bthNRecs, bthFNode, bthLNode,
|
||||||
|
bthNodeSize, bthKeyLen, bthNNodes, bthFree)
|
||||||
|
|
||||||
|
# last little hack: append free nodes to nodelist
|
||||||
|
nodelist.append(512 * bthFree) # these will become zeroes
|
||||||
return b''.join(bytes(node) for node in nodelist)
|
return b''.join(bytes(node) for node in nodelist)
|
||||||
|
|
||||||
def _catrec_sorter(b):
|
def _catrec_sorter(b):
|
||||||
@ -273,6 +315,18 @@ class Folder(_AbstractFolder):
|
|||||||
self.crdat = self.mddat = self.bkdat = 0
|
self.crdat = self.mddat = self.bkdat = 0
|
||||||
|
|
||||||
|
|
||||||
|
def _chunkify(b, blksize):
|
||||||
|
for i in range(0, len(b), blksize):
|
||||||
|
ab = b[i:i+blksize]
|
||||||
|
if len(ab) < blksize: ab += bytes(blksize-len(ab))
|
||||||
|
yield ab
|
||||||
|
|
||||||
|
|
||||||
|
class _TempWrapper:
|
||||||
|
def __init__(self, of):
|
||||||
|
self.of = of
|
||||||
|
|
||||||
|
|
||||||
class Volume(_AbstractFolder):
|
class Volume(_AbstractFolder):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
@ -363,34 +417,83 @@ class Volume(_AbstractFolder):
|
|||||||
|
|
||||||
setattr(f, fork, accum)
|
setattr(f, fork, accum)
|
||||||
|
|
||||||
|
# elif datatype == 3:
|
||||||
|
# print('dir thread:', rec)
|
||||||
|
# elif datatype == 4:
|
||||||
|
# print('fil thread:', rec)
|
||||||
|
|
||||||
for parent, children in childrenof.items():
|
for parent, children in childrenof.items():
|
||||||
if parent != 1: # not the mythical parent of root!
|
if parent != 1: # not the mythical parent of root!
|
||||||
cnids[parent].update(children)
|
cnids[parent].update(children)
|
||||||
|
|
||||||
self.update(cnids[2])
|
self.update(cnids[2])
|
||||||
|
|
||||||
def write(self, size=None):
|
def write(self, size):
|
||||||
pass
|
size -= size % 512
|
||||||
|
|
||||||
drAlBlkSiz = 4096
|
# choose an alloc block size
|
||||||
|
drAlBlkSiz = 512
|
||||||
|
while drAlBlkSiz * 65536 < size:
|
||||||
|
drAlBlkSiz += 512
|
||||||
|
|
||||||
catalog = []
|
# decide how many bitmap blocks we need
|
||||||
|
nbitblks = 0
|
||||||
|
while (size - (3 + nbitblks) * 512) // drAlBlkSiz < nbitblks * 512 * 8:
|
||||||
|
nbitblks += 1
|
||||||
|
|
||||||
cnids = {} # keys are path-component-tuples
|
# decide how many alloc blocks there will be
|
||||||
objects = {}
|
drNmAlBlks = (size - (3 + nbitblks) * 512) // drAlBlkSiz
|
||||||
next_cnid = 16
|
blkaccum = []
|
||||||
|
|
||||||
|
# <<< put the empty extents overflow file in here >>>
|
||||||
|
|
||||||
|
# write all the files in the volume
|
||||||
|
topwrap = _TempWrapper(self)
|
||||||
|
topwrap.path = (self.drVN,)
|
||||||
|
topwrap.cnid = 2
|
||||||
|
|
||||||
|
godwrap = _TempWrapper(None)
|
||||||
|
godwrap.cnid = 1
|
||||||
|
|
||||||
|
path2wrap = {(): godwrap, (self.drVN,): topwrap}
|
||||||
|
drNxtCNID = 16
|
||||||
for path, obj in self.paths():
|
for path, obj in self.paths():
|
||||||
# what needs to happen here? we create a file/folder entry, a thread entry, what else?
|
path = (self.drVN,) + path
|
||||||
|
wrap = _TempWrapper(obj)
|
||||||
cnids[path] = next_cnid; this_cnid = next_cnid; next_cnid += 1
|
path2wrap[path] = wrap
|
||||||
objects[path] = obj
|
wrap.path = path
|
||||||
|
wrap.cnid = drNxtCNID; drNxtCNID += 1
|
||||||
|
|
||||||
if isinstance(obj, File):
|
if isinstance(obj, File):
|
||||||
|
wrap.dfrk, wrap.rfrk = None, None
|
||||||
|
if obj.data:
|
||||||
|
pre = len(blkaccum)
|
||||||
|
blkaccum.extend(_chunkify(obj.data, drAlBlkSiz))
|
||||||
|
wrap.dfrk = (pre, len(obj.data))
|
||||||
|
if obj.rsrc:
|
||||||
|
pre = len(blkaccum)
|
||||||
|
blkaccum.extend(_chunkify(obj.rsrc, drAlBlkSiz))
|
||||||
|
wrap.rfrk = (pre, len(obj.rsrc))
|
||||||
|
|
||||||
|
catalog = [] # (key, value) tuples
|
||||||
|
|
||||||
|
drFilCnt = drDirCnt = 0
|
||||||
|
|
||||||
|
for path, wrap in path2wrap.items():
|
||||||
|
if wrap.cnid == 1: continue
|
||||||
|
|
||||||
|
obj = wrap.of
|
||||||
|
|
||||||
|
mainrec_key = struct.pack('>LB', path2wrap[path[:-1]].cnid, len(path[-1])) + path[-1]
|
||||||
|
|
||||||
|
if isinstance(wrap.of, File):
|
||||||
|
drFilCnt += 1
|
||||||
|
|
||||||
|
cdrType = 2
|
||||||
filFlags = 0 # todo must fix
|
filFlags = 0 # todo must fix
|
||||||
filTyp = 0
|
filTyp = 0
|
||||||
filUsrWds = struct.pack('>4s4sHHHxxxxxx', obj.type, obj.creator, obj.flags, obj.x, obj.y)
|
filUsrWds = struct.pack('>4s4sHHHxxxxxx', obj.type, obj.creator, obj.flags, obj.x, obj.y)
|
||||||
filFlNum = next_cnid
|
filFlNum = wrap.cnid
|
||||||
filStBlk, filLgLen, filPyLen = 0, len(obj.data), _pad_up(len(obj.data), drAlBlkSiz) # todo must fix
|
filStBlk, filLgLen, filPyLen = 0, len(obj.data), _pad_up(len(obj.data), drAlBlkSiz) # todo must fix
|
||||||
filRStBlk, filRLgLen, filRPyLen = 0, len(obj.rsrc), _pad_up(len(obj.rsrc), drAlBlkSiz) # todo must fix
|
filRStBlk, filRLgLen, filRPyLen = 0, len(obj.rsrc), _pad_up(len(obj.rsrc), drAlBlkSiz) # todo must fix
|
||||||
filCrDat, filMdDat, filBkDat = obj.crdat, obj.mddat, obj.bkdat
|
filCrDat, filMdDat, filBkDat = obj.crdat, obj.mddat, obj.bkdat
|
||||||
@ -399,26 +502,82 @@ class Volume(_AbstractFolder):
|
|||||||
filExtRec = struct.pack('>HHHHHH', 0, _pad_up(len(obj.data), drAlBlkSiz) // drAlBlkSiz, 0, 0, 0, 0)
|
filExtRec = struct.pack('>HHHHHH', 0, _pad_up(len(obj.data), drAlBlkSiz) // drAlBlkSiz, 0, 0, 0, 0)
|
||||||
filRExtRec = struct.pack('>HHHHHH', 0, _pad_up(len(obj.rsrc), drAlBlkSiz) // drAlBlkSiz, 0, 0, 0, 0)
|
filRExtRec = struct.pack('>HHHHHH', 0, _pad_up(len(obj.rsrc), drAlBlkSiz) // drAlBlkSiz, 0, 0, 0, 0)
|
||||||
|
|
||||||
rec = bytearray(struct.pack('>BB16sLHLLHLLLLL16sH12s12sxxxx',
|
mainrec_val = struct.pack('>BxBB16sLHLLHLLLLL16sH12s12sxxxx',
|
||||||
|
cdrType, \
|
||||||
filFlags, filTyp, filUsrWds, filFlNum, \
|
filFlags, filTyp, filUsrWds, filFlNum, \
|
||||||
filStBlk, filLgLen, filPyLen, \
|
filStBlk, filLgLen, filPyLen, \
|
||||||
filRStBlk, filRLgLen, filRPyLen, \
|
filRStBlk, filRLgLen, filRPyLen, \
|
||||||
filCrDat, filMdDat, filBkDat, \
|
filCrDat, filMdDat, filBkDat, \
|
||||||
filFndrInfo, filClpSize, \
|
filFndrInfo, filClpSize, \
|
||||||
filExtRec, filRExtRec, \
|
filExtRec, filRExtRec, \
|
||||||
))
|
)
|
||||||
|
|
||||||
catalog.append((path[-1], rec))
|
|
||||||
|
|
||||||
catalog.sort(key=_catrec_sorter)
|
|
||||||
_mkbtree(catalog)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
else: # assume directory
|
||||||
|
drDirCnt += 1
|
||||||
|
|
||||||
|
cdrType = 1
|
||||||
|
dirFlags = 0 # must fix
|
||||||
|
dirVal = len(wrap.of)
|
||||||
|
dirDirID = wrap.cnid
|
||||||
|
dirCrDat, dirMdDat, dirBkDat = (0,0,0) if obj is self else (obj.crdat, obj.mddat, obj.bkdat)
|
||||||
|
dirUsrInfo = bytes(16)
|
||||||
|
dirFndrInfo = bytes(16)
|
||||||
|
mainrec_val = struct.pack('>BxHHLLLL16s16sxxxxxxxx',
|
||||||
|
cdrType, dirFlags, dirVal, dirDirID,
|
||||||
|
dirCrDat, dirMdDat, dirBkDat,
|
||||||
|
dirUsrInfo, dirFndrInfo,
|
||||||
|
)
|
||||||
|
|
||||||
|
catalog.append((mainrec_key, mainrec_val))
|
||||||
|
|
||||||
|
thdrec_key = struct.pack('>L', wrap.cnid)
|
||||||
|
thdrec_val_type = 4 if isinstance(wrap.of, File) else 3
|
||||||
|
thdrec_val = struct.pack('>BxxxxxxxxxLB', thdrec_val_type, path2wrap[path[:-1]].cnid, len(path[-1])) + path[-1]
|
||||||
|
|
||||||
|
catalog.append((thdrec_key, thdrec_val))
|
||||||
|
|
||||||
|
# now it is time to sort these records! fuck that shit...
|
||||||
|
# catalog.sort...
|
||||||
|
catalogfile = _mkbtree(catalog)
|
||||||
|
# also need to do some cleverness to ensure that this gets picked up...
|
||||||
|
drCTFlSize = len(catalogfile)
|
||||||
|
drCTExtRec_Start = len(blkaccum)
|
||||||
|
blkaccum.extend(_chunkify(catalogfile, drAlBlkSiz))
|
||||||
|
drCTExtRec_Cnt = len(blkaccum) - drCTExtRec_Start
|
||||||
|
|
||||||
|
# Create the bitmap of free volume allocation blocks
|
||||||
|
bitmap = _bits(nbitblks * 512 * 8, len(blkaccum))
|
||||||
|
|
||||||
|
# Create the Volume Information Block
|
||||||
|
drSigWord = b'BD'
|
||||||
|
drNmFls = sum(isinstance(x, File) for x in self.values())
|
||||||
|
drNmRtDirs = sum(not isinstance(x, File) for x in self.values())
|
||||||
|
drVBMSt = 3 # first block of volume bitmap
|
||||||
|
drAllocPtr = len(blkaccum)
|
||||||
|
drClpSiz = drXTClpSiz = drCTClpSiz = drAlBlkSiz
|
||||||
|
drAlBlSt = 3 + nbitblks
|
||||||
|
drFreeBks = drNmAlBlks - len(blkaccum)
|
||||||
|
drWrCnt = 0 # ????volume write count
|
||||||
|
drVCSize = drVBMCSize = drCtlCSize = 99
|
||||||
|
drXTFlSize = 0 # currently faking out the extents overflow file
|
||||||
|
drXTExtRec_Start = 0
|
||||||
|
drXTExtRec_Cnt = 0
|
||||||
|
|
||||||
|
headernode = struct.pack('2sLLHHHHHLLHLH28pLHLLLHLL32sHHHLHHxxxxxxxxLHHxxxxxxxx',
|
||||||
|
drSigWord, self.drCrDate, self.drLsMod, self.drAtrb, drNmFls,
|
||||||
|
drVBMSt, drAllocPtr, drNmAlBlks, drAlBlkSiz, drClpSiz, drAlBlSt,
|
||||||
|
drNxtCNID, drFreeBks, self.drVN, self.drVolBkUp, self.drVSeqNum,
|
||||||
|
drWrCnt, drXTClpSiz, drCTClpSiz, drNmRtDirs, drFilCnt, drDirCnt,
|
||||||
|
self.drFndrInfo, drVCSize, drVBMCSize, drCtlCSize,
|
||||||
|
drXTFlSize, drXTExtRec_Start, drXTExtRec_Cnt,
|
||||||
|
drCTFlSize, drCTExtRec_Start, drCTExtRec_Cnt,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
assert all(len(x) == drAlBlkSiz for x in blkaccum)
|
||||||
|
finalchunks = [self.bootblocks, headernode, bitmap, *blkaccum]
|
||||||
|
finalchunks.append(bytes(size - sum(len(x) for x in finalchunks)))
|
||||||
|
return b''.join(finalchunks)
|
||||||
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
@ -433,7 +592,7 @@ h.read(open(infile,'rb').read())
|
|||||||
# pprint.pprint(h)
|
# pprint.pprint(h)
|
||||||
# for path, obj in h.paths():
|
# for path, obj in h.paths():
|
||||||
# print(path, obj)
|
# print(path, obj)
|
||||||
h.write()
|
open('/tmp/thing','wb').write(h.write(128*1024*1024))
|
||||||
# h.walk_catalog()
|
# h.walk_catalog()
|
||||||
|
|
||||||
|
|
||||||
@ -481,5 +640,6 @@ h.write()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user