hjalfi
Experienced Member
It's Friday, I'm bored, so...
Not long ago I wrote a 6502 port of CP/M. I ended up getting so heavily invested with the details that I had cpmfs dirents oozing out of every pore. A question bugged me: how difficult would it be to add proper directories to CP/M 2.2 with as few changes as possible?
The way this would work is:
- directories are represented as simple zero-length directory entries. One of the status bits identifies them. (You could probably get away with just using the S bit for this.)
- the user code field on the on-disk dirent. Instead of being a 0..15 value representing the user code, it's now identifies that entry's enclosing directory.
- a directory's code would be its directory entry index (with some mapping, see below).
- directory code 0xe5 is still special and still marks a deleted file.
- the get/set user code BDOS call becomes a get/set current directory code call.
- there would be entries in the root directory for directories 1..15.
There would be very few BDOS changes required, mostly limited to the code which turns an FCB into a dirent and back again.
Pros:
- non-directory-aware programs on a directory-aware BDOS would work fine. Anything which didn't use user codes would use the current directory; anything which did would get access to the root directory and special directories USER1...USER15.
- using directory-aware disks in non-directory-aware BDOSes would _mostly_ work. You'd be able to see files in directories 0..15. Other directories would be inaccessible.
Cons:
- thoroughly incompatible with disk labels, timestamps, CP/M 3 passwords, etc.
- resolving a path into a current-directory/FCB pair would be a reasonably chunky amount of user code. It'd make sense to try and embed this into the BDOS because nearly every program which uses filenames will require it, but I doubt there's room.
- you'd need to add a CD command to the CCP.
- it'd be trivially possible to put files into non-existent directories, at which point they get lost.
- there's a single current directory for all drives. This is pretty problematic. You might need to repurpose one of the DPH bytes to hold a drive's current directory, but that would need the BDOS to use a different algorithm for block-to-CHS conversion to free up space.
- you're limited to ~255 directories. That's probably enough for any reasonable CP/M filesystem, but on systems with a directory bigger than 255 entries, it would be possible to run out of candidate dirents to place a directory in. You'd probably want to map the directory code to the dirent index by spreading them through the directory, e.g. dircode = directoryindex/4 + 1. (The +1 is so that the root directory, with code 0, doesn't occupy a directory slot.)
This all seems quite feasible; fiddly if you want to maintain backwards compatibility, but pretty simple otherwise. The directory parsing code would be the single biggest job. Architecturally there's nothing really to it --- Apple's MFS, which was used on early Macs, used essentially the same scheme.
...which all kinda begs the question; why hasn't anyone tried this before?
Not long ago I wrote a 6502 port of CP/M. I ended up getting so heavily invested with the details that I had cpmfs dirents oozing out of every pore. A question bugged me: how difficult would it be to add proper directories to CP/M 2.2 with as few changes as possible?
The way this would work is:
- directories are represented as simple zero-length directory entries. One of the status bits identifies them. (You could probably get away with just using the S bit for this.)
- the user code field on the on-disk dirent. Instead of being a 0..15 value representing the user code, it's now identifies that entry's enclosing directory.
- a directory's code would be its directory entry index (with some mapping, see below).
- directory code 0xe5 is still special and still marks a deleted file.
- the get/set user code BDOS call becomes a get/set current directory code call.
- there would be entries in the root directory for directories 1..15.
There would be very few BDOS changes required, mostly limited to the code which turns an FCB into a dirent and back again.
Pros:
- non-directory-aware programs on a directory-aware BDOS would work fine. Anything which didn't use user codes would use the current directory; anything which did would get access to the root directory and special directories USER1...USER15.
- using directory-aware disks in non-directory-aware BDOSes would _mostly_ work. You'd be able to see files in directories 0..15. Other directories would be inaccessible.
Cons:
- thoroughly incompatible with disk labels, timestamps, CP/M 3 passwords, etc.
- resolving a path into a current-directory/FCB pair would be a reasonably chunky amount of user code. It'd make sense to try and embed this into the BDOS because nearly every program which uses filenames will require it, but I doubt there's room.
- you'd need to add a CD command to the CCP.
- it'd be trivially possible to put files into non-existent directories, at which point they get lost.
- there's a single current directory for all drives. This is pretty problematic. You might need to repurpose one of the DPH bytes to hold a drive's current directory, but that would need the BDOS to use a different algorithm for block-to-CHS conversion to free up space.
- you're limited to ~255 directories. That's probably enough for any reasonable CP/M filesystem, but on systems with a directory bigger than 255 entries, it would be possible to run out of candidate dirents to place a directory in. You'd probably want to map the directory code to the dirent index by spreading them through the directory, e.g. dircode = directoryindex/4 + 1. (The +1 is so that the root directory, with code 0, doesn't occupy a directory slot.)
This all seems quite feasible; fiddly if you want to maintain backwards compatibility, but pretty simple otherwise. The directory parsing code would be the single biggest job. Architecturally there's nothing really to it --- Apple's MFS, which was used on early Macs, used essentially the same scheme.
...which all kinda begs the question; why hasn't anyone tried this before?