
S16's type stopped STORY.TXT in the middle of line 335, because it read only the file's first directory entry, and one entry holds at most 16K. STORY.TXT is 20,000 bytes. This section reads the rest - and with it, every file an Einstein disc can hold.
A directory entry has room for eight block numbers: 8 x 2K = 16K. A bigger file gets more than one entry, each describing the next 16K, and all carrying the same name. Each one is an extent, and byte 12 numbers them: 0 for the first 16K, 1 for the next, 2 for the next.
Every extent but the last is full: 128 records, eight blocks. The last holds whatever is left. STORY.TXT has two:

To read the whole file, read each extent's blocks and keep its own records, in extent order, and join them. The order comes from byte 12, not from where the entries happen to sit in the directory, so the tool looks for extent 0, then extent 1, and so on - as many as there are entries with that name. If one of them is not there, the file is damaged, and the tool says so rather than handing back a file with a hole in it.
The search needs a way to say "not found yet". Python's None is a value meaning "nothing": set entry = None before looking, and if it is still None afterwards - tested with is None - nothing matched.
This section replaces S16's read_file. Delete the old one and put this in its place, after find_file:
def read_file(disc, name):
entries = find_file(disc, name)
data = b""
for extent in range(len(entries)):
entry = None
for e in entries:
if e[12] == extent:
entry = e
if entry is None:
sys.exit(f"{name} is damaged: its extent {extent} is missing")
part = b""
for block in entry_blocks(entry):
part = part + read_block(disc, block)
data = data + part[:entry[15] * 128]
return data
Nothing else changes: type calls read_file, so it now reads big files too. That is one of the rewards of putting each job in its own function.
(The whole program: s17-edisc.py.)
Run it
python3 edisc.py type FILES.DSK STORY.TXT
What you should see - 409 lines this time. Where S16 stopped, the story now runs straight on:
Line 334 of STORY.TXT, which needs two extents.
Line 335 of STORY.TXT, which needs two extents.
Line 336 of STORY.TXT, which needs two extents.
Line 337 of STORY.TXT, which needs two extents.
and it ends:
Line 408 of STORY.TXT, which needs two extents.
Line 409
The file was made 20,000 bytes long, which happens to fall in the middle of line 409.
read_file, change range(len(entries)) to range(1). Which section's behaviour do you get back?part[:entry[15] * 128] to just part. Type STORY.TXT again: the ending is the same. Why? (Think about where the 1A is, and where the extra bytes come.) What would go wrong for a file that is not text, such as NUMBERS.BIN, which has no 1A to stop at?E5, using what you learned in S5. What does type say now? And list?| Symptom | Cause |
|---|---|
STORY.TXT is damaged: its extent 0 is missing | One of the file's entries is not in use - here slot 1 was set to E5. The rest of the file is still there, but not all of it |
A file over 16K has one directory entry per 16K, all with its name, numbered 0, 1, 2 ... in byte 12: its extents. read_file now finds each extent by number, reads its blocks, keeps its records, and joins them in order, refusing a file with an extent missing. edisc.py can read any file on an Einstein disc.
S18, extract - copying a file off the disc onto your computer, byte for byte.
This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.