lock it in
As noted, I’ve started hacking on DOS. The first thing on my list is to make it use
struct FileLock correctly.
AmigaOS has two types for referring to some kind of on-disk object -
struct FileLock, which can reference any type of object (file or directory) and
struct FileHandle, which is only used for files, but contains extra information such as a buffer and current position, allowing I/O. Internally it contains a lock to the underlying file as well. For the most part, a filesystem handler only operates on locks, leaving handles to
dos.library. (There’s a couple of minor exceptions where handles are manipulated by the handler, but its not really of any consequence and so I’m not going any more detail).
When AROS was given its own filesystem API, it also did away with locks as well, using handles for everything. The main functions of the lock - providing a pointer to the handler, a pointer to the underlying file context, and the current access mode - were all added to
struct FileHandle, reusing undefined DOS-private fields (
fh_Func3). Since the pointers accepted and returned by DOS functions are opaque
BPTRs, its not actually an issue for most programs, and so life has continued happily for the past ten-odd years.
Where this system falls down is with the DOS packet functions
WaitPkt() (and indirectly,
ReplyPkt()). The problem is simple: under AmigaOS these functions don’t deal with locks or handles, but with the message port the filesystem handler uses to receive packets on. That handler is usually obtained by using
BADDR() on a BPTR returned by
Lock() to get a
struct FileLock, and then getting the port from its
This used to be completely impossible, as until my recent work with
struct FileLock didn’t even exist on AROS, so your code wouldn’t even compile. Now it does, but if you try to fish
fl_Task out of a “lock” you end up with some random stuff that patently isn’t a port, and so sending to it just won’t work. Of course, AROS filesystems don’t take packets and don’t use ports anyway, which is why
ReplyPkt() try to do packet conversion (which doesn’t really work), but some programs also like to send their own packets. If anything tries to send to the “port” obtained from the filehandle its likely the system will crash (that position in the struct is held by
fh_Buf, which is the I/O buffer.
One of the other issues here is that even if locks are used, AROS filesystems don’t use ports, so even if we did use
struct FileLock properly the
fl_Task won’t be anything useful, unless populated with a port owned by
packet.handler that can do packet->IOFS conversion.
The goal to remove IOFS has come from a few things. Its not adding any real value to have it, we have a handful of minor devices that use it directly (CDVDFS and SFS are both packet-based handlers with IOFS wrappers that coule be easily removed), and source compatibility isn’t there. Replacing it however is a big job, so we’re taking an incremental approach. The initial goal is to support both IOFS and packets natively inside DOS. The first step is to bring
struct FileLock back to life, which I started on yesterday and is nearly done.
To do that these structures have been updated such that
struct FileHandle no longer holds stuff to reference the filesystem, but instead contains a pointer to a
struct FileLock which does have this information. The lock is held in
fh_Arg1, as was always the way under AmigaOS.
With normal packet handlers, the lock contains two fields to reference the file:
fl_Task which is a message port for the handler, and
fl_Key which is some random data set by the handler that it can use to find the file on disk. IOFS handlers had a similar pair of fields held in the filehandle -
fh_Device which is a pointer to the Exec device of the handler, and
fh_Unit which is the opaque data. Pavel Fedin, in a stroke of genius that now seems completely obvious, suggested simply storing the IOFS device and unit into
fl_Key as a fast and cheap way of bringing
This is fine if you only have one type of handler, but we have two, and so need to be able to tell the difference. Pavel came to the rescue here too - give
struct FileLock and extra field,
fl_Device. Put the device pointer there, and the unit pointer in
fl_Key, and use
fl_Task as a flag to determine the type - when its NULL, its a IOFS handler
fl_Device is valid, if its
NULL then its a packet handler and
fl_Device has no meaning (and in fact shouldn’t even be accessed, as locks are then entirely allocated by the handler which may have something different here (like
struct ExtFileLock in
fat.handler) or nothing at all if the handler is using original AmigaOS sizings).
So far I’ve set up these definitions and reworked the DOS internals (and a few other bits of code around the place that were using IOFS directly) to match. Its mostly a case of renaming
FileLock, bouncing through
fh_Arg1 to get the device and unit pointers, and of course allocating and deallocating lock structures in the right place. There’s a small build issue to figure out (wiating for a reply from aros-dev) but once thats fine AROS should at least start, and then I can begin tracking down the several million edge cases that will probably arise from this.
If you want to see the code, ask me - not checking it in yet because I have no desire to break the tree.