Notes on FileSwitch/FileCore interface


History:

  0.01  07-Jan-94  Created from info in PRM
  0.02  10-Jan-94  Updated after discussions with JRo


When FileCore initialises (by calling OS_FSControl 12) the filing system
information word (and the extra FSIW) indicate the following:

bit val  meaning     (FSIW)

 31  0   special fields are not supported
 30  0   streams are not interactive
 29  0   null length file names are not supported
 28  0   calls to open a file should be made only if it is known to exist
 27  1   notify FileCore when flushing (FSEntry_Args 6 [not 255, I think])
 26  0   does not support FSEntry_File 9 (read catalogue info without length)
 25  0   does not support FSEntry_Func 20 (*fileinfo)
 24  0       <reserved>
*23  1   image filing system extensions are supported
 22  0   & and % should not appear in path names
 21  0   does not support CSD etc. (ie expects FileSwitch to do so)
 20  1   use open, read, close instead of load (ie no FSEntry_File 255)
 19  0   supports save (FSEntry_File 0)
 18  0   does not support FSEntry_Func 9 (setting access)
 17  1   extra FSIW is present (but is, in fact, all zeros)
 16  0   filing system is *not* read-only

 15-8 there is no explicit limit on maximum number of files that may be open

  * Note that bit 23 really means "supports the new ways of doing things",
    and includes:
       - Use Func-27, Func-28 for managing boot options instead of Func-7 and
         Func-11
       - Supports/expects canonicalisation
       - Supports/expects wild card resolution

bit val  meaning     (Extra FSIW)

  0  0   FSEntry_Func 34 (notification of updated directory) is not supported
  1  0   *cat is not supported
  2  0   *ex is not supported

There is no FSEntry_GBPB entry - since these calls are not required when all
I/O is buffered.


FileSwitch holds at most one buffer per open file; the size of this buffer is
specified by FileCore when the file is opened.


The entry points - and sub-entry points where appropriate - are located as
follows:

  FSEntry_Open        OpenFileEntry  in  FileCore70
  FSEntry_Close       CloseFileEntry in  FileCore70

  FSEntry_GetBytes    GetBytesEntry  in  FileCore70
  FSEntry_PutBytes    PutBytesEntry  in  FileCore70

  FSEntry_Args        OsArgsEntry    in  FileCore70

       3  DoOsArgs-SetEXT
       6          -Flush
       7          -EnsureSize
       8          -WriteZeroes
       9          -ReadLoadExec
      10          -ImageStampIs
           [ FSEntry_Args 4 - read size allocated to file - does not need to
              be supported since FSEntry_Open returns this value (although
              the PRM erroneously says that "all filing systems must support
              this call" - p.2-541). ]

  FSEntry_File        OsFileEntry    in  FileCore45

       0  DoOsFile-Save
       1          -WriteInfo
       2          -WriteLoad
       3          -WriteExec
       4          -WriteAttr
       5          -ReadInfo
       6          -Delete
       7          -Create
       8          -CreateDir
       9          -ReadInfoNoLen
      10          -ReadBlockSize
     255          -Load
           [ Why are FSEntry_File 9 - ReadInfoNoLen - and FSEntry_File 255 -
              Load - supplied, when the filing system information word
              indicates that these are never to be called? - probably for
              historical reasons ...]

  FSEntry_Func        OsFunEntry     in  FileCore60

       7  DoOsFun-Opt
       8         -Rename
      10         -Bootup
      14         -ReadDirEntries
      15         -ReadDirEntriesInfo
      16         -ShutDown
      19         -CatalogObjects
      23         -CanonicaliseSpecialAndDisc
      24         -ResolveWildcard
      25         -DefectList
      26         -AddDefect
      27         -ReadBootOption
      28         -WriteBootOption
      29         -UsedSpaceMap
      30         -ReadFreeSpace
      31         -NameDisc
      32         -StampImage
      33         -ObjectAtOffset
           [ FSEntry_Func 17 - print start up banner - does not need to be
              supported because FileSwitch does it instead; not clear how
              FileSwitch determines to do this (is it bit 23 again?). ]

FileCore does not need to check access rights - FileSwitch will only make
calls that are legal (but remember that FileSwitch may need to read from a
write-only file in order to (re)fill one of its internal file buffers).


FileSwitch always ensures that:

  - file names are full path names in canonical form (as defined by Func-23)
  - names are zero-terminated
  - path names are never null, and always have correct syntax
  - path names do *not* contain wild cards (except for calls to Func-24)


Terminology (mine):

  extent     -  number of bytes in a file
  allocation -  number of bytes allocated to the file; this is always a
                multiple of the buffer size
  handle     -  FileCore's identification for an open file
  timestamp  -  the date/time value held in the load and exec address fields


Note that the following descriptions are intended to be sufficient to cover
only the interface between FileSwitch and FileCore on RISC OS 3; other
options are omitted.



Open  - open a file

             In                      Out

    R0    code                    file information word
    R1    ->name                  handle (0 if not found)
    R2                            buffer size  (2^n st 6<=n<=10)
    R3    FileSwitch's handle     extent
    R4                            allocation

  code = 0    -  open for input
  code = 2    -  open for update

  file information word:

     bit  meaning
      31  write permitted
      30  read permitted
      29  object is a directory
    28-0  0

  The object is known to exist - and is guaranteed to be a file if code = 2.

  If a call is made with code = 0 for a directory, then no attempt will be
  made to read from the object after opening it (this is for backwards
  compatibility with applications which test for the existence of a directory
  by opening it).



Close  - close an open file

             In                      Out

    R0
    R1    handle
    R2    load
    R3    exec

  Close the file, and, if either load or exec is non-zero, store these new
  values.

  Note that FileSwitch will ensure that R2=R3=0 whenever a read-only or
  unmodified file is closed.

  An open directory can also be closed (see Open above).



GetBytes  - get bytes from a buffered file

             In                      Out

    R0    
    R1    handle
    R2    ->buffer
    R3    number of bytes
    R4    file offset

  The file offset and number of bytes to read are guaranteed to be a multiple
  of the file's buffer size.

  The file offset is guaranteed to be less than the file's extent, but the
  (file offset + number of bytes) may be greater - but will still lie within
  the file's allocation.

  There is no guarantee as to the alignment of the buffer.



PutBytes  - put bytes to a buffered file

             In                      Out

    R0    
    R1    handle
    R2    ->buffer
    R3    number of bytes
    R4    file offset

  The file offset and number of bytes to read are guaranteed to be a multiple
  of the file's buffer size.

  The (file offset + number of bytes) is guaranteed to be less than the
  file's extent [or do I mean allocation?] - the true extent is written
  explicitly before closing.

  There is no guarantee as to the alignment of the buffer.



Args  - controlling open files

Args  3  - write file extent

             In                      Out

    R0    3
    R1    handle
    R2    extent

  This call is only made just before closing an open file after it has been
  modified; the corresponding directory entry should be updated.



Args  6  - notification of a flush

             In                      Out

    R0    6
    R1    handle
    R2                            load
    R3                            exec

  Ensure that all data written to this file is secure on disc.

  Return the file's timestamp information.



Args  7  - ensure file size

             In                      Out

    R0    7
    R1    handle
    R2    allocation              allocation

  Ensure that the space allocated to the file is at least as great as R2;
  the space actually allocated is returned as the new value of R2.



Args  8  - write zeros to file

             In                      Out

    R0    8
    R1    handle
    R2    file offset
    R3    number of bytes

  The file offset and number of zero bytes to write are guaranteed to be
  multiples of the file's buffer size.



Args  9  - read file datestamp

             In                      Out

    R0    9
    R1    handle
    R2                            load
    R3                            exec



Args 10  - inform of new image stamp

             In                      Out

    R0    code
    R1    handle
    R2    new image stamp

  This call is to inform FileCore that the open file - which is an image file
  for an image filing system - has been assigned a new image stamp value.
  This value - like the "cycle" number for floppy discs - can be considered
  as part of the image's identification. FileCore must use it to identify
  reloaded removeable media containing image files.



File  - whole file operations

File   0  - save file

             In                      Out

    R0    0
    R1    ->file name
    R2    load
    R3    exec
    R4    ->buff
    R5    ->(byte following buff)
    R6                            ->(*OPT 1 string)

  On entry, FileSwitch guarantees:
    - leaf name contains no wild cards
    - the buffer exists (valid addresses)

  If the file already exists (and is not locked) it should be discarded.

  The new file should inherit access rights from its predecessor, if any -
  otherwise use suitable defaults.

  The "*OPT 1 string" is described on p.2-176; this facility can almost
  certainly be dropped from future versions of FileCore.



File   1  - write catalogue information

             In                      Out

    R0    1
    R1    ->name
    R2    load
    R3    exec
    R4
    R5    attributes

  The object may be a file or a directory.

  Do not return an error if the object does not exist.



File   2  - write load address

             In                      Out

    R0    2
    R1    ->name
    R2    load

  The object may be a file or directory.

  Do not return an error if the object does not exist.



File   3  - write execution address

             In                      Out

    R0    3
    R1    ->name
    R2
    R3    exec

  The object may be a file or directory.

  Do not return an error if the object does not exist.



File   4  - write attributes

             In                      Out

    R0    4
    R1    ->name
    R2
    R3
    R4
    R5    attributes

  The object may be a file or directory.

  Do not return an error if the object does not exist.



File   5  - read catalogue information

             In                      Out

    R0    5                       object type
    R1    ->name
    R2                            load
    R3                            exec
    R4                            extent
    R5                            attributes

  object type    meaning

     0           not found
     1           file
     2           directory

  Return an error if pathname specifies media or drive that cannot be found,
  but set object type = 0 if the object does not exist on the specified
  media/drive.



File   6  - delete object

             In                      Out

    R0    6                       object type
    R1    ->name
    R2                            load
    R3                            exec
    R4                            extent
    R5                            attributes

  FileSwitch guarantees that the leaf name is not wildcarded.

  Return an error if the object is locked, but not if it does not exist.



File   7  - create file

             In                      Out

    R0    7
    R1    ->file name
    R2    load
    R3    exec
    R4    addr1
    R5    addr2
    R6                            ->(*OPT 1 string)

  On entry, FileSwitch guarantees that the leaf name contains no wild cards.

  The new file's extent is given by (addr2 - addr1); the contents of the file
  are not initialised.

  If the file already exists (and is not locked) it should be discarded.

  The new file should inherit access rights from its predecessor, if any -
  otherwise use suitable defaults.

  The "*OPT 1 string" is described on p.2-176; this facility can almost
  certainly be dropped from future versions of FileCore.

  Return an error if the file was not created.



File   8  - create directory

             In                      Out

    R0    8
    R1    ->dir name
    R2    load
    R3    exec
    R4    number of entries

  The number of entries is a hint - 0 means use some suitable default.

  Do not return an error if the directory already exists - but you may try
  to rename it (to reset the case of the name as the user wants, and, maybe,
  to reset load/exec/timestamp data?).

  Return an error if the directory was not created.



File   9  - read catalogue information (no length)   [*** not needed ***]

             In                      Out

    R0    9                       object type
    R1    ->file name
    R2                            load
    R3                            exec
    R4
    R5                            attributes

  Used by *Copy under RISC OS 2 - if bit 26 of the Filing System Information
  Word is set. Useful for NetFS with fileservers, where the length is not
  stored in the directory.



File  10  - read block size

             In                      Out

    R0    10
    R1    ->name
    R2                            natural block size

  The natural block size for a file is the same as the buffer size returned
  when the file is opened by FSEntry_Open.



File 255  - load file                                [*** not needed ***]

             In                      Out

    R0    255                     (corrupted)
    R1    ->file name
    R2    load address            load
    R3                            exec
    R4                            extent
    R5                            attributes
    R6                            ->(*OPT 1 string)

  FileSwitch will have already validated the Load request - so the object is
  known to exist and to be a file, the buffer is in writable memory, the
  buffer is large enough, and the file's access bits allow loading.



Func  - miscellaneous filing system operations

Func  7  - set filing system options                 [*** not needed ***]

             In                      Out

    R0    7
    R1    option
    R2    parameter

  This implements *OPT <option> <parameter>.

  If option = 0, all filing system options should be reset to their default
  values.

  Otherwise, only option = 4, parameter = 0-3 will be passed (FileSwitch
  handles *OPT 1, 0-3 internally).



Func  8  - rename object

             In                      Out

    R0    8
    R1    ->name                  0 iff rename achieved
    R2    ->new name

  Peform the rename only if it's possible by changing the object's catalogue
  entry; otherwise return 0 in R1.



Func 10  - boot filing system

             In                      Out

    R0    10

  Execute the filing system's boot action; this call may not return!

  Note that the location of the boot file - and the relevant action as
  determined by *OPT 4,n - are filing system dependent; for FileCore, the
  configured drive is examined, and the boot file is !Boot on that drive.



Func 14  - read directory entries

             In                      Out

    R0    14
    R1    ->dir name
    R2    ->buff
    R3    number to read          number read
    R4    first item to read      next item to read
    R5    buffer length

  "first item to read" is 0 to start at the beginning of the directory, and
  "next item to read" is -1 if there are no more left.

  The names of the objects in the directory are returned in the buffer as a
  list of null-terminated strings.

  Return an error if the object is a file, or does not exist.

  FileSwitch validates the buffer in different ways according to how it has
  been called - see PRM for details!



Func 15  - read directory entries and information

             In                      Out

    R0    15
    R1    ->dir name
    R2    ->buff
    R3    number to read          number read
    R4    first item to read      next item to read
    R5    buffer length

  "first item to read" is 0 to start at the beginning of the directory, and
  "next item to read" is -1 if there are no more left.

  The directory information is returned in word-aligned records with the
  following format:

      0   load
      4   exec
      8   extent
     12   attributes
     16   object type  (1 or 2)
     20   name  (zero-terminated string)

  Return an error if the object is a file, or does not exist.

  FileSwitch validates the buffer prior to the call.



Func 16  - shut down

             In                      Out

    R0    16

  Note that all files will have been closed before this call is made.



Func 19  - read directory entries and information

             In                      Out

    R0    19
    R1    ->dir name
    R2    ->buff
    R3    number to read          number read
    R4    first item to read      next item to read
    R5    buffer length

  "first item to read" is 0 to start at the beginning of the directory, and
  "next item to read" is -1 if there are no more left.

  The directory information is returned in word-aligned records with the
  following format:

      0   load
      4   exec
      8   extent
     12   attributes
     16   object type  (1 or 2)
     20   system internal name
     24   timestamp
     29   name  (zero-terminated string)

  The timestamp is given in centiseconds since 01-Jan-1900.

  Return an error if the object is a file, or does not exist.

  FileSwitch validates the buffer prior to the call.



Func 23  - canonicalise special field and disc name

             In                      Out

    R0    23
    R1
    R2    ->disc name             ->canonical disc name or 0
    R3
    R4    ->buff or 0             bytes overflow
    R5
    R6    length (if R4 != 0)

  If called with R4 = 0, then R4 will be set on exit to the size of the
  canonical disc name.

  Otherwise, [as much as possible of?] the canonical disc name is copied to
  the buffer, and the number of bytes remaining is recorded in R4; finally,
  R2 is set to R4.

  (Note that this call in general handles special fields as well - but since
   FileCore does not support these, such calls will never be made.)



Func 24  - resolve wildcard

             In                      Out

    R0    24
    R1    ->dir name
    R2    ->buff or 0             -1 if not found
    R3    ->object name
    R4                            bytes overflow
    R5    length (if R2 != 0)

  Possible "wild cards" are:

    * - matches zero or more characters
    # - matches a single character

  This is called to determine the first match - if any - for the wild-carded
  object name in the specified directory.

  If called with R2 = 0, then R4 will be set to the size of buffer needed.

  Note that FileCore always resolves wildcards, and so R4 is never set to -1
  on exit (which would tell FileSwitch to do its own wildcard resolution).

  Otherwise, [as much as possible of?] the "first" matching object name is
  copied to the buffer, and R4 is set to the number of bytes left over.



Func 25  - read defect list

             In                      Out

    R0    25
    R1    ->name
    R2    ->buff
    R3
    R4
    R5    length

  "name" must identify the root object in an image.

  The buffer is filled with the byte offsets of any defects in the image,
  terminated by &20000000.

  These byte offsets are the addresses of defective sectors on the disc.

  Maybe this function canc be called with R5 = 0 to find out how many defects
  there are?

  This call should return an error if FileCore does not support defect
  mapping.



Func 26  - add a defect

             In                      Out

    R0    26
    R1    ->name
    R2    offset

  "name" must identify the root object in an image, and "offset" is a byte
  offset within this image.

  The sector identified by the offset (containing the offset? starting at the
  offset?) should be marked as unusable - in other words "mapped out" -
  unless it is already in use, in which case an error should be returned.

  This call should return an error if FileCore does not support defect
  mapping.



Func 27  - read boot option

             In                      Out

    R0    27
    R1    ->name
    R2                            boot option

  Reads the boot option (ie the "n" in *OPT 4,n) for the image in which the
  specified object is located.



Func 28  - write boot option

             In                      Out

    R0    28
    R1    ->name
    R2    boot option

  Sets the boot option for the image in which the specified object exists.



Func 29  - read used space map

             In                      Out

    R0    29
    R1    ->name
    R2    ->buff
    R3
    R4
    R5    length

  The image whose map is to be read is that which contains the specified
  object.

  The buffer must be prefilled with zeros.

  The used space map - one bit per block - is copied to the buffer.

  Note that the size of buffer required can be calculated from the image's
  size, and its block size - this latter being returned by FSEntry_Open.



Func 30  - read free space

             In                      Out

    R0    30                      free space
    R1    ->name                  max object size
    R2                            image size

  Information about free space and its availability on the image containing
  the specified object is returned.



Func 31  - name image

             In                      Out

    R0    31
    R1    ->name
    R2    ->image name

  The image containing the specified object (ie the object whose name is
  given by R1) is given the "disc name" specified in R2.



Func 32  - stamp image

             In                      Out

    R0    32
    R1    ->name
    R2    code

  "name" identifies the image containing the object of that name.

  code = 0  => stamp image on next update
  code = 1  => stamp image now

  Update the image's "cycle number" - here described as a "disc id".

  This is used to determine when removeable media is updated, or when two
  discs with the same name are the same.



Func 33  - get usage of offset

             In                      Out

    R0    33
    R1    ->name
    R2    offset                   return code
    R3    ->buff
    R4    length

  "name" identifies the image containing the object of that name.

  return code   meaning

      0         no object found (offset is free/a defect/outside image)
      1         no object found (offset is allocated - eg free space map)
      2         object found - cannot share offset with other objects
      3         object found - can share offset with other objects

  It's not clear what happens if the buffer is not long enough.
