Rip 'em up and Start Again
I've currently arrived at the stage of considering ripping things up and starting again... er, I mean, refactoring to reconsider some basic assumptions. There will likely be an amount of moving fast and breaking things...
Where I am at the moment:
- I can create a named file
- I can delete a named file
- I can list a given directory
- I can cat a named file (ideally a text file, but anything works)
which means basically I can manipulate the FAT sectors with speed and despatch. It does take rather more 32-bit arithmetic than I would like, but it all seems to work.
But...
This is fine as long as I only ever want to open one file at a time. Unfortunately I can see at least a handful of use cases where that's not enough:
- Copying from one file into another
- Operating e.g. a text editor with a working file larger than available memory
- Anything where it might be handy to have a .bak or .tmp file
- Something like an assembler, which might require multiple .asm files as input, with .hex and .lst as outputs
There are no doubt others. So there seems merit in C's
FILE * system; before a named file is used, it must be opened for reading or writing and a file structure populated defining all sorts of information about the file in question. That suggests that multiple buffers be used into or from which data is transferred during file reads and writes.
I _could_ simply move from
transient to a named buffer each time a sector is read (and the reverse, obviously), but that has two serious implications: firstly, a simple read of a buffer takes twice as long since, and secondly, every access to a file requires reloading at least the current sector, since we don't know what else has been done in the meantime.
So
cf_read changes so that instead of using a fixed address of
transient as a target, a pointer is set before each call. (I also ask
cf_read to do the
cf_set_lba before each read, since it's required every time and I previously had it called before the
cf_read call anyway (when I remembered)).
cf_write changes similarly. Indeed, those two routines are so similar I may combine them and simply set a flag to decide whether a read or write is desired. I'm not yet sure whether it's worth it.
At the moment,
f_create,
f_del,
f_cat and
f_dir don't require
FILE structures and can work entirely within
transient, and all the FAT record tracing works within
transient, and I don't see a reason to change that.
FILE structure
This structure is still very tentative. It's also likely to be quite large, so it will have to live in main memory, not zero page. However, first thoughts indicate that it should contain the following pointers/flags:
- Read/write flag
- Dirty flag (set if the sector has been written to and so requires a rewrite to disc) (note that both these flags are contained in the directory entry's attribute byte)
- Buffer address (uint16, though if I insist on a page boundary alignment it could be just one byte)
- File Pointer (the position we're currently reading/writing from/to)
- Current cluster (uint32)
- Current sector (uint32) which also provides a useful indicator if we need a new cluster
- Copy of the directory entry - 32 bytes, but has lots of useful stuff in it, at least some of which I'll need like the filename and starting cluster
f_open
So
f_open has to perform a number of tasks.
- Check whether a file is already open, and fail if it is (or maybe not; I can see where it might be handy to open the same file for both read _and_ write operations, but I'm not sure I want to get into that yet.)
- Check whether the file exists, and fail if it doesn't (or call f_create?)
- Copy the file's directory entry into the FILE structure
- Zero the file pointer entry and current cluster
- Allocate a memory buffer, and note its address
- Finally, load the sector into memory
I'm sure more will occur to me later, but the first step is to test that everything works with modified cf_read and cf_write routines.
Neil