From cd433459d07da32654decb94330c195eb4cda56b Mon Sep 17 00:00:00 2001 From: Elliot Nunn Date: Tue, 23 Oct 2018 17:51:37 +0800 Subject: [PATCH] Throw clear out-of-space and bad-name exceptions --- machfs/bitmanip.py | 3 +-- machfs/directory.py | 3 --- machfs/main.py | 45 ++++++++++++++++++++++++++++++++++++--------- 3 files changed, 37 insertions(+), 14 deletions(-) diff --git a/machfs/bitmanip.py b/machfs/bitmanip.py index 279cd42..0d1b90b 100644 --- a/machfs/bitmanip.py +++ b/machfs/bitmanip.py @@ -35,5 +35,4 @@ def chunkify(b, blksize): def pstring(orig): - macroman = orig.encode('mac_roman') - return bytes([len(macroman)]) + macroman + return bytes([len(orig)]) + orig diff --git a/machfs/directory.py b/machfs/directory.py index 739757b..1bdb6b1 100644 --- a/machfs/directory.py +++ b/machfs/directory.py @@ -15,9 +15,6 @@ class AbstractFolder(collections.MutableMapping): key.encode('mac_roman') - if not (1 <= len(key) <= 31): - raise ValueError('%r: Filename range 1-31 chars' % key) - lower = key.lower() self._prefdict[lower] = key self._maindict[lower] = value diff --git a/machfs/main.py b/machfs/main.py index f4cdec4..64f7475 100644 --- a/machfs/main.py +++ b/machfs/main.py @@ -78,12 +78,36 @@ def _get_every_extent(nblocks, firstrecord, cnid, xoflow, fork): return extlist +def _encode_name(name, is_vol_name=False): + longest = 27 if is_vol_name else 31 + + try: + encoded = name.encode('mac_roman') + except UnicodeEncodeError: + raise BadNameError(name) + except AttributeError: + pass + + if not 1 <= len(encoded) <= longest or b':' in encoded: + raise BadNameError(name) + + return encoded + + class _TempWrapper: """Volume uses this to store metadata while serialising""" def __init__(self, of): self.of = of +class OutOfSpaceError(Exception): + pass + + +class BadNameError(Exception): + pass + + class Folder(directory.AbstractFolder): def __init__(self): super().__init__() @@ -226,6 +250,8 @@ class Volume(directory.AbstractFolder): if size < 400 * 1024 or size % 512: raise ValueError('size must be a multiple of 512b and >= 800K') + drVN = _encode_name(self.name, is_vol_name=True) + # overall layout: # 1. two boot blocks (offset=0) # 2. one volume control block (offset=2) @@ -252,12 +278,17 @@ class Volume(directory.AbstractFolder): drNmAlBlks = (size - (5+bitmap_blk_cnt)*512) // drAlBlkSiz blkaccum = [] + def accumulate(x): + blkaccum.extend(x) + if len(blkaccum) > drNmAlBlks: + raise OutOfSpaceError + # <<< put the empty extents overflow file in here >>> extoflowfile = btree.make_btree([], bthKeyLen=7, blksize=drAlBlkSiz) # also need to do some cleverness to ensure that this gets picked up... drXTFlSize = len(extoflowfile) drXTExtRec_Start = len(blkaccum) - blkaccum.extend(bitmanip.chunkify(extoflowfile, drAlBlkSiz)) + accumulate(bitmanip.chunkify(extoflowfile, drAlBlkSiz)) drXTExtRec_Cnt = len(blkaccum) - drXTExtRec_Start # write all the files in the volume @@ -300,11 +331,11 @@ class Volume(directory.AbstractFolder): wrap.dfrk = wrap.rfrk = (0, 0) if obj.data: pre = len(blkaccum) - blkaccum.extend(bitmanip.chunkify(obj.data, drAlBlkSiz)) + accumulate(bitmanip.chunkify(obj.data, drAlBlkSiz)) wrap.dfrk = (pre, len(blkaccum)-pre) if obj.rsrc: pre = len(blkaccum) - blkaccum.extend(bitmanip.chunkify(obj.rsrc, drAlBlkSiz)) + accumulate(bitmanip.chunkify(obj.rsrc, drAlBlkSiz)) wrap.rfrk = (pre, len(blkaccum)-pre) self._prefdict = root_dict_backup @@ -318,7 +349,7 @@ class Volume(directory.AbstractFolder): if wrap.cnid == 1: continue obj = wrap.of - pstrname = bitmanip.pstring(path[-1]) + pstrname = bitmanip.pstring(_encode_name(path[-1])) mainrec_key = struct.pack('>L', path2wrap[path[:-1]].cnid) + pstrname @@ -379,7 +410,7 @@ class Volume(directory.AbstractFolder): # also need to do some cleverness to ensure that this gets picked up... drCTFlSize = len(catalogfile) drCTExtRec_Start = len(blkaccum) - blkaccum.extend(bitmanip.chunkify(catalogfile, drAlBlkSiz)) + accumulate(bitmanip.chunkify(catalogfile, drAlBlkSiz)) drCTExtRec_Cnt = len(blkaccum) - drCTExtRec_Start if len(blkaccum) > drNmAlBlks: @@ -400,15 +431,11 @@ class Volume(directory.AbstractFolder): drWrCnt = 0 # ????volume write count drVCSize = drVBMCSize = drCtlCSize = 0 drAtrb = 1<<8 # volume attributes (hwlock, swlock, CLEANUNMOUNT, badblocks) - drVN = self.name.encode('mac_roman') drVolBkUp = 0 # date and time of last backup drVSeqNum = 0 # volume backup sequence number drFndrInfo = bytes(32) # information used by the Finder drCrDate, drLsMod, drVolBkUp = self.crdate, self.mddate, self.bkdate - if not (1 <= len(drVN) <= 27): - raise ValueError('Volume name range 1-27 chars') - vib = struct.pack('>2sLLHHHHHLLHLH28pLHLLLHLL32sHHHLHHxxxxxxxxLHHxxxxxxxx', drSigWord, drCrDate, drLsMod, drAtrb, drNmFls, drVBMSt, drAllocPtr, drNmAlBlks, drAlBlkSiz, drClpSiz, drAlBlSt,