Bug fixes. Incomplete extract command.

This commit is contained in:
Eric Smith 2018-07-10 00:25:04 -06:00
parent e647c9f7bb
commit c27ca404b8
2 changed files with 93 additions and 19 deletions

View File

@ -14,8 +14,39 @@ def cmd_mkfs(args, disk):
print('XXX mkfs')
def cmd_extract(args, disk):
for sf in disk.files(path = '', recursive = True):
name = sf.get_name()
#print(name)
#print(len(name))
eof = sf.get_eof()
data = sf.read(0, eof)
#print(len(data))
with open(name, 'wb') as f:
f.write(data)
break # XXX for debug, only extract first file
parser = argparse.ArgumentParser()
fmt_group = parser.add_mutually_exclusive_group()
fmt_group.add_argument('--do',
dest = 'format',
action = 'store_const',
const = 'do',
help = "image in DOS sector order")
fmt_group.add_argument('--po',
dest = 'format',
action = 'store_const',
const = 'po',
help = "image in SOS/ProDOS sector order")
parser.add_argument('image',
type = str,
help = "SOS/ProDOS disk image")
subparsers = parser.add_subparsers(title = 'commands',
dest = 'cmd')
@ -40,23 +71,19 @@ mkfs_parser.add_argument('--size',
default = 280,
help = 'filesystem size in blocks')
parser.add_argument('image',
type = str,
help = "SOS/ProDOS disk image")
extract_parser = subparsers.add_parser('x',
help = 'extract file(s)')
extract_parser.set_defaults(cmd_fn = cmd_extract)
fmt_group = parser.add_mutually_exclusive_group()
extract_parser.add_argument('-r', '--recursive',
action = 'store_true',
help = 'recursively extract subdirectory content')
fmt_group.add_argument('--do',
dest = 'format',
action = 'store_const',
const = 'do',
help = "image in DOS sector order")
fmt_group.add_argument('--po',
dest = 'format',
action = 'store_const',
const = 'po',
help = "image in SOS/ProDOS sector order")
extract_parser.add_argument('filename',
type = str,
nargs = '+',
help = 'filename(s) to extract',
)
args = parser.parse_args()
#print(args)
@ -72,7 +99,8 @@ else:
sys.exit(2)
file_mode = { 'mkfs': 'w',
'ls': 'r' } [args.cmd] + 'b'
'ls': 'r',
'x': 'r' } [args.cmd] + 'b'
image = open(args.image, file_mode)

View File

@ -124,7 +124,7 @@ sos_valid_fn_chars = set(string.ascii_uppercase + string.digits + '.')
def bytes_to_sos_filename(l, b):
assert len(b) == 15
assert 1 <= l <= 15
s = str(b, 'ascii')
s = str(b[:l], 'ascii')
assert all(c in sos_valid_fn_chars for c in s[:l])
assert all(c == 0 for c in b[l:])
return s.lower()
@ -213,6 +213,21 @@ class SOSStorage:
def is_sparse(self):
return self.data_blocks != (self.last_block_index + 1)
def read(self,
offset = 0,
length = 0):
data = bytearray(length)
while length > 0:
block_index = offset // self.disk.block_size
block_offset = offset % self.disk.block_size
chunk_length = min(length, self.disk.block_size - block_offset)
if block_index in self.index:
block_number = self.index[block_index]
data[offset:offset+chunk_length] = self.disk.get_blocks(block_number)[block_offset:block_offset+chunk_length]
offset += chunk_length
length -= chunk_length
return data
class SOSSeedling(SOSStorage):
def __init__(self, disk, key_pointer):
@ -271,7 +286,12 @@ class SOSDirectoryEntry:
pass
class SOSVolumeDirectoryHeader(SOSDirectoryEntry):
class SOSDirectoryHeader(SOSDirectoryEntry):
def __init__(self, disk):
super().__init__(disk)
class SOSVolumeDirectoryHeader(SOSDirectoryHeader):
def __init__(self, disk, entry_data):
super().__init__(disk)
(storage_nl, name_b, self.reserved, creation_b, self.version, self.min_version, self.access, self.entry_length, self.entries_per_block, self.file_count, self.bitmap_pointer, self.total_blocks) = struct.unpack('<B15s8sLBBBBBHHH', entry_data)
@ -286,7 +306,7 @@ class SOSVolumeDirectoryHeader(SOSDirectoryEntry):
assert self.total_blocks == disk.block_count
self.creation = u32_to_sos_timestamp(creation_b)
class SOSSubdirectoryHeader(SOSDirectoryEntry):
class SOSSubdirectoryHeader(SOSDirectoryHeader):
def __init__(self, disk, entry_data):
super().__init__(disk)
(storage_nl, name_b, self.reserved, creation_b, self.version, self.min_version, self.access, self.entry_length, self.entries_per_block, self.file_count, self.bitmap_pointer, self.total_blocks) = struct.unpack('<B15s8sLBBBBBHHH', entry_data)
@ -320,6 +340,20 @@ class SOSFileEntry(SOSDirectoryEntry):
self.storage = SOSStorage.create(self.disk, self.storage_type, self.key_pointer)
def get_name(self):
return self.name
def get_eof(self):
return self.eof
def read(self,
offset = 0,
length = None):
return self.storage.read(offset, length)
def print(self,
prefix,
recursive = False,
@ -424,6 +458,13 @@ class SOSDirectory:
else:
block_num = first_block + i
def files(self,
path,
recursive = False):
for db in self.directory_blocks:
for entry in db.entries:
if isinstance(entry, SOSFileEntry) and (entry.storage_type != StorageType.unused_entry) and hasattr(entry, 'storage'):
yield entry
def print(self, prefix,
recursive = False,
@ -492,6 +533,11 @@ class SOSDisk:
length = count * 512
return memoryview(self.data)[offset:offset+length]
def files(self,
path,
recursive = True):
return self.volume_directory.files(path, recursive)
def print_directory(self,
recursive = False,
long = False,