> LowFSDoc THE LOW LEVEL FILING SYSTEM INTERFACE ===================================== Quick note : -> that the supplied pathname must be a directory; it should be an error if a file is found. Filing System Initialisation ============================ At some point in the initialisation code of a Relocatable Module, you may wish to inform the Operating System that your module contains a Filing System To do this, you should call XOS_FSControl with reason code FSControl_AddFS, pointing R1 at your module base, and load R2 with the offset of your FS information block (see below) within the module. R3 should contain to the value you wish to have in R12 (your private word pointer) on entry to any of your Filing System entry points or Filing System star command code entries In all code examples below, Module_BaseAddr is a symbol which is assumed to be the origin of your module MOV R0, #FSControl_AddFS ADR R1, Module_BaseAddr MOV R2, FSInfoBlock-Module_BaseAddr MOV R3, R12 SWI XOS_FSControl BVS FailedToAdd ; R0 -> error If XOS_FSControl returns with V clear, your Filing System will have been added to the list of known Filing Systems maintained by FileSwitch, otherwise you have an error on your hands The format of a Filing System information block is as follows : +----------+ | NamePtr | Offset to Filing System name +----------+ | BannerPtr| Offset to Filing System banner text +----------+ | Open | Offset of routine to open files +----------+ | GetBytes | Offset of routine to fill a file buffer from media +----------+ | PutBytes | Offset of routine to put a file buffer to media +----------+ | Args | Offset of routine to do things to open files, eg. extend +----------+ | Close | Offset of routine to close open files +----------+ | File | Offset of routine to do whole file operations +----------+ | Info | Word of Filing System type information +----------+ | Func | Offset of routine to do assorted Filing System operations +----------+ All fields are 32 bits long, so DCD (AAsm) or EQUD (BASIC) should be used to declare them An example Filing System information block is shown below : ALIGN FSInfoBlock DCD FilingSystemName -Module_BaseAddr DCD FilingSystemBanner -Module_BaseAddr DCD FSEntry_Open -Module_BaseAddr DCD FSEntry_GetBytes -Module_BaseAddr DCD FSEntry_PutBytes -Module_BaseAddr DCD FSEntry_Args -Module_BaseAddr DCD FSEntry_Close -Module_BaseAddr DCD FSEntry_File -Module_BaseAddr DCD FSInfoWord DCD FSEntry_Func -Module_BaseAddr FilingSystemName DCB "TestFS", 0 FilingSystemBanner DCB "A Test Filing System", 0 ALIGN The information word tells FileSwitch various things about the Filing System bit 31 1 if special fields (eg. net#48.:, printer#serial:) are supported by this Filing System 0 otherwise bit 30 1 if streams on this Filing System are interactive, eg. kbd: 0 otherwise bit 29 1 if this Filing System supports null length filenames, eg. vdu: 0 otherwise bits 7-0 Filing System identification number (eg. 8 for ADFS, 5 for NET) Filing System Selection ======================= To be able to select a Filing System as the current Filing System, one of your module star command handlers must execute code as below in response to a suitable utility star command, eg. *ADFS, *NET StarFilingSystemCommand Push R14 MOV R0, #FSControl_SelectFS ADR R1, FilingSystemName SWI XOS_FSControl Pull PC ; Returns either VClear (ok) or VSet (error^ in r0) Filing System Removal ===================== At some point (eg. in the Die entry of a Relocatable Module) you may wish to remove your Filing System from the list held by FileSwitch. The following code shows how to do this : MOV R0, #FSControl_RemoveFS ADR R1, FilingSystemName SWI XOS_FSControl CLRV Modules should NOT complain about errors in Filing System removal otherwise it will not be possible to restart the module after reinitialising FileSwitch Calls to the Filing System interface ==================================== Routines called by FileSwitch are always entered in supervisor mode, so that access to associated hardware is ok r13_svc is a FD stack which may be used by the Filing System; appropriate care should be taken to ensure that you do not push too much onto this stack as it is only guaranteed to be 256 bytes deep when you are entered. You may wish to determine how much stack is left for your use by knowing that the stack base is on a 1M boundary; the following code shows how to do this: BIC rtemp, r13, #&00FFFFFF ; Clear down to 1M boundary SUB rtemp, r13, rtemp ; rtemp := amount of stack left You may move the stack pointer downwards by an amount and use that amount of memory as temporary workspace. However, as interrupt processes are allowed to use the supervisor stack, you must leave enough room for these to operate; similarly, if you call any OS routines, you must give them enough stack space R12 on entry to the Filing System is set to the value of R3 passed to FileSwitch in the FSControl_AddFS call. Conventionally, this will be your pointer to your private word, such that LDR r12, [r12] would be entered on all your module entries The link register (R14) with which routines are entered has the V bit position clear, so it may be used for a non-error return to FileSwitch. The V bit in the PSR is also clear on entry Routines need not preserve ANY registers other than r13_svc Routines that wish to return errors should return to FileSwitch with V set and R0 pointing to a standard format error block. This applies to all Filing System routines called by FileSwitch; the descriptions of the routines below only describe parameters that are expected back with V clear. Any errors that are given with an open file in use will eventually have the message 'on FileSwitch handle nnn' appended. FSEntry_File : Whole file operations ==================================== R0 on entry determines the operation : R0 = &FF : Load File ==================== In R1 = pointer to wildcarded filename (0 terminated) R2 = address to load file (validated for whole file) R3 = 0 -> load file at address given by R2 <> 0 -> load file at it's own address (may not be needed; see me) R6 = pointer to special field if present and allowed (0 terminated) = 0 otherwise Out R0 = object type R2 = load address R3 = exec address R4 = file length R5 = file attributes R6 = pointer to a filename suitable for printing as OPT 1 info It shall be an error if the specified file does not exist, or is a directory. R0 = 0 : Save File ================== In R1 = pointer to filename (0 terminated) R2 = load address to put on file R3 = exec address to put on file R4 = start address in memory of data (validated for whole file) R5 = end address in memory (ie. address of byte after last one to xfer) R6 = pointer to special field if present and allowed (0 terminated) = 0 otherwise Out R6 = pointer to a filename suitable for printing as OPT 1 info It shall be an error if the specified file could not be saved. R0 = 1 : Write catalogue info ============================= In R1 = pointer to wildcarded filename (0 terminated) R2 = new load address to put on file R3 = new exec address to put on file R5 = new attributes to put on file R6 = pointer to special field if present and allowed (0 terminated) = 0 otherwise NB. The file length may not be written back using this call; R4 is ignored. It shall be an error if the object is a directory. It is not an error if the object does not exist. R0 = 2 : Write load address =========================== In R1 = pointer to wildcarded filename (0 terminated) R2 = new load address to put on file R6 = pointer to special field if present and allowed (0 terminated) = 0 otherwise It shall be an error if the object is a directory. It is not an error if the object does not exist. R0 = 3 : Write exec address =========================== In R1 = pointer to wildcarded filename (0 terminated) R3 = new exec address to put on file R6 = pointer to special field if present and allowed (0 terminated) = 0 otherwise It shall be an error if the object is a directory. It is not an error if the object does not exist. R0 = 4 : Write object attributes ================================ In R1 = pointer to wildcarded filename (0 terminated) R5 = new attributes to put on object R6 = pointer to special field if present and allowed (0 terminated) = 0 otherwise It shall be an error if the object is a directory. It is not an error if the object does not exist. R0 = 5 : Read catalogue info ============================ In R1 = pointer to wildcarded filename (0 terminated) R6 = pointer to special field if present and allowed (0 terminated) = 0 otherwise Out R0 = object type R2 = load address R3 = exec address R4 = file length R5 = file attributes It is not an error if the object does not exist. R0 = 6 : Delete object ====================== In R1 = pointer to filename (0 terminated) R6 = pointer to special field if present and allowed (0 terminated) = 0 otherwise Out R0 = old object type R2 = old load address R3 = old exec address R4 = old file length R5 = old file attributes It shall be an error if the object is locked against deletion. It is not an error if the object did not exist. R0 = 7 : Create file ==================== In R1 = pointer to filename (0 terminated) R2 = load address to put on file R3 = exec address to put on file R4 = start address in memory of data R5 = end address in memory (ie. address of byte after last one to xfer) R6 = pointer to special field if present and allowed (0 terminated) = 0 otherwise Out R6 = pointer to a filename suitable for printing as OPT 1 info It shall be an error if the file could not be created. It is not an error if the file already exists (old file is discarded) R0 = 8 : Create directory ========================= In R1 = pointer to dirname (0 terminated) R4 = number of entries = 0 -> use sensible default, Filing System dependent R4 may be ignored if it does not apply R6 = pointer to special field if present and allowed (0 terminated) = 0 otherwise All Filing Systems should support this operation, even if mapping it to nothing, so that eg. *Copy $.fred.* netprint#falcon: -recurse is possible. It shall be an error if the directory could not be created. It is not an error if the directory already exists (old one is kept intact). FSEntry_Open : Opening files ============================ Filing Systems are asked to open files for FileSwitch as follows : In R0 = 0 open for read 1 create and open for update 2 open for update R1 = pointer to filename (0 terminated) (wildcarded allowed if read) R3 = handle that will be allocated by FileSwitch to this stream if the open operation succeeds (so Filing Systems can call FileSwitch; eg. *BYE wishes to close open files on a disc) R6 = pointer to special field if present and allowed (0 terminated) = 0 otherwise Out R0 : bit 31 set -> object has write permission bit 30 set -> object has read permission bit 29 set -> object is a directory bit 28 set -> unbuffered GBPB is available for stream R1 = Filing System handle, or 0 if object not found R2 = 0 stream is unbuffered, eg. streams on vdu: Filing System <> 0 buffer size to use with this file, eg. 256 byte sectors This value must be a power of two between 32 and 1024 inclusive R3 = file extent (only buffered streams) R4 = space currently allocated to file (only buffered streams) if unsure or impossible to get, return the same as for file extent FileSwitch treats any 32 bit handle except 0 returned by the Filing System to be valid, and will use this full handle for any further calls to the Filing System regarding that file. The user is passed a handle which is derived by FileSwitch; thus the user doesn't get hold of a 'real' Filing System handle as such If the object is a directory, then it may only be opened for reading; bytes are never requested from it, so that the only use of this is compatibility with old programs that use openin to test existence of an object, and mainly to use with the set directory context call FSEntry_GetBytes : Getting bytes from an open file ================================================== There are two rather distinct cases to consider : 1) Filing Systems that do not buffer streams, eg. vdu: 2) Filing Systems that buffer streams, eg. adfs: Different code is used in FileSwitch to deal with these two cases, and this entry is either used to read a single byte into a register or many bytes into memory directly, similar to OSBGET/OSGBPB on a BBC Getting a byte from an unbuffered stream ======================================== In R1 = Filing System handle Out R0 = byte read from stream if C clear = undefined if C set (EOF) Getting bytes from a buffered stream ==================================== In R1 = Filing System handle R2 = memory address to put data R3 = number of bytes to read (guaranteed to be a multiple of the buffer size for this stream) R4 = file address to get data from (always starts at a multiple of the buffer size for this stream) FSEntry_PutBytes : Putting bytes to an open file ================================================ Again, two different mechanisms are used by FileSwitch to put bytes to the Filing System, similar to the BBC OSBPUT/OSGBPB routines 1) Putting a byte to an unbuffered stream ========================================= In R0 = byte to put to stream (top 24 bits are zero) R1 = Filing System handle 2) Putting bytes to a buffered stream ===================================== In R1 = Filing System handle R2 = memory address to take data from R3 = number of bytes to put to file (guaranteed to be a multiple of buffer size for this stream) R4 = file address to put data to (always starts at a multiple of the buffer size for this stream) FSEntry_Args : Open file control ================================ Various calls are made through this entry point to deal with controlling open files; actions being specified by R0 : R0 = 0 : Read sequential file pointer ===================================== In R1 = Filing System handle Out R2 = sequential file pointer Only Filing Systems that use unbuffered streams should support this call R0 = 1 : Write sequential file pointer ====================================== In R1 = Filing System handle R2 = new sequential file pointer The file must be extended with if the new pointer is greater than the current file extent. Only Filing Systems that use unbuffered streams should support this call R0 = 2 : Read file extent ========================= In R1 = Filing System handle Out R2 = file extent Only Filing Systems that use unbuffered streams should support this call R0 = 3 : Write file extent ========================== In R1 = Filing System handle R2 = new file extent Buffered streams : WriteExtent is only issued internally by FileSwitch in order to set the real file extent just prior to closing an open file Unbuffered streams : WriteExtent is passed directly through from the user. The file must be extended with zeroes if the new extent is greater than the current file extent R0 = 4 : Read size allocated to file ==================================== In R1 = Filing System handle Out R2 = size allocated to file by Filing System All Filing Systems must support this call R0 = 5 : EOF check ================== In R1 = Filing System handle Out R1 = 0 if PTR <> EXT <> 0 if PTR = EXT Only Filing Systems that use unbuffered streams should support this call R0 = 6 : Flush file buffer ========================== In R1 = Filing System handle Flush any buffered data for file Only Filing Systems that use unbuffered streams should support this call R0 = 7 : Ensure file size ========================= In R1 = Filing System handle R2 = size of file to ensure Out R2 = size of file actually ensured No data need be written into the file as the file extent has not changed All Filing Systems must support this call R0 = 8 : Write zeroes ===================== In R1 = Filing System handle R2 = file address to write zeroes at R3 = number of zero bytes to write (guaranteed to be a multiple of buffer size for this stream) This call is only issued internally by FileSwitch AFTER an EnsureSize call; eg. on file extension, so Filing Systems like ANFS (limited by FileServer support) may choose to ignore this call if they make EnsureSize into a WriteExtent call which writes zeroes off the end of a file Only Filing Systems that use buffered streams should support this call R0 = 9 : Read file datestamp ============================ In R1 = Filing System handle Out R2 = load address of file R3 = exec address of file All Filing Systems must support this call; if a Filing System cannot stamp an open file given its handle (see FSEntry_Close) then it should return R2 = R3 = 0 FSEntry_Close : Closing open files ================================== When closing a file, FileSwitch passes the appropriate Filing System handle to the Filing System close routine : In R1 = Filing System handle R2 = new load address to put on file R3 = new exec address to put on file R2 = R3 = 0 means don't restamp file NB. CLOSE#0 is done by FileSwitch, which passes file handles one at a time to the Filing System for closing, so Filing Systems should NOT try to support this themselves FSEntry_Func : Various Filing System functions ============================================== Various calls are made through this entry point to deal with assorted Filing System control; actions being specified by R0 : R0 = 0 : Set directory ====================== In R1 = pointer to wildcarded dirname (0 terminated) R6 = pointer to special field if present and allowed (0 terminated) = 0 otherwise A null name implies set directory to a Filing System dependent default R0 = 1 : Set library ==================== In R1 = pointer to wildcarded dirname (0 terminated) R6 = pointer to special field if present and allowed (0 terminated) = 0 otherwise A null name implies set library to a Filing System dependent default R0 = 2 : Catalogue directory ============================ In R1 = pointer to wildcarded dirname (0 terminated) R6 = pointer to special field if present and allowed (0 terminated) = 0 otherwise A null name implies that the currently selected directory is to be catalogued R0 = 3 : Examine directory ========================== In R1 = pointer to wildcarded dirname (0 terminated) R6 = pointer to special field if present and allowed (0 terminated) = 0 otherwise A null name implies that the currently selected directory is to be examined R0 = 4 : Catalogue library ========================== In R1 = pointer to wildcarded dirname (0 terminated) R6 = pointer to special field if present and allowed (0 terminated) = 0 otherwise A null name implies that the currently selected library is to be catalogued R0 = 5 : Examine library ======================== In R1 = pointer to wildcarded dirname (0 terminated) R6 = pointer to special field if present and allowed (0 terminated) = 0 otherwise A null name implies that the currently selected library is to be examined R0 = 6 : Examine file ===================== In R1 = pointer to wildcarded pathname (0 terminated) R6 = pointer to special field if present and allowed (0 terminated) = 0 otherwise R0 = 7 : Set Filing System options ================================== In R1 = option R2 = parameter An option of 0 means reset all Filing System options to their default R0 = 8 : Rename object ====================== In R1 = pointer to first pathname (0 terminated) R2 = pointer to second pathname (0 terminated) R6 = pointer to first special field if present and allowed (0 term) = 0 otherwise R7 = pointer to second special field if present and allowed (0 term) = 0 otherwise Out R1 = 0 Rename performed R1 <> 0 Rename not simple; must be done by Copy/Delete in FileSwitch R0 = 9 : Access objects ======================= In R1 = pointer to wildcarded pathname (0 terminated) R2 = pointer to access string (0 terminated) All objects matching the wilcarded names are given the requested access R0 = 10 : Boot Filing System ============================ The Filing System should perform its (FS dependent) boot action on this call; eg. NetFS will do *%Logon Boot ADFS will examine the opt 4 of the disc in the configured drive and act accordingly, eg. *%run &.!Boot R0 = 11 : Read disc name ======================== In R1 = memory address to put data R2 = buffer length The disc name is returned as a 0 terminated string R0 = 12 : Read directory name ============================= In R1 = memory R2 = buffer length The directory name is returned as a 0 terminated string R0 = 13 : Read library name ============================= In R1 = memory R2 = buffer length The library name is returned as a 0 terminated string R0 = 14 : Read directory entries ================================ In R1 = pointer to wildcarded dirname (0 terminated) R2 = memory address to put data R3 = number of object names to read R4 = offset of first item to read in directory R5 = buffer length R6 = pointer to special field if present and allowed (0 terminated) = 0 otherwise Out R3 = number of names read R4 = offset of next item to read in directory, or -1 if finished A null name implies that the currently selected directory is to be read Names are returned in the buffer as a list of 0 terminated strings Any unused buffer may be trashed by the Filing System on this call R0 = 15 : Read directory entries and info ========================================= In R1 = pointer to wildcarded dirname (0 terminated) R2 = memory address to put data (word aligned) R3 = number of items to read R4 = offset of first item to read in directory R5 = buffer length R6 = pointer to special field if present and allowed (0 terminated) = 0 otherwise Out R3 = number of items read R4 = offset of next item to read in directory, or -1 if finished A null name implies that the currently selected directory is to be read Object names and info are returned as records with the below format : Offset Contents 00 Word : Load address 04 Word : Exec address 08 Word : Length 0C Word : Attributes (as per OSFile_ReadInfo) 10 Word : Object type (as per OSFile_ReadInfo) 14 Bytes : Object name (0 terminated) ALIGN 4 Any unused buffer may be trashed by the Filing System on this call R0 = 16 : Shut down =================== The Filing System should attempt to go into as dormant a state as possible; eg. parking winchesters, logging off FileServers as appropriate R0 = 17 : Set directory contexts ================================ In R1 = new CSD handle (0 -> no change) R2 = new URD handle (0 -> no change) R3 = new LIB handle (0 -> no change) Out R1 = old CSD handle (-1 -> 'Unset' : adfs only) R2 = old URD handle (-1 -> 'Unset' : adfs only) R3 = old LIB handle (-1 -> 'Unset' : adfs only)