RISCOS.com

www.riscos.com Technical Support:
Programmer's Reference Manual

 

Writing a filing system


Writing your own filing system

You can add filing systems to RISC OS. You must write them as relocatable modules. There are two ways of doing so:

  • by adding a module that FileSwitch communicates with directly
  • by adding a secondary module to FileCore; FileSwitch communicates with FileCore, which then communicates with your module.

In both cases, the amount of work you have to do is considerably less than if you were to write a filing system from scratch, as the FileSwitch and FileCore modules already provide a core of the functions your filing system must offer. Obviously if you use FileCore as well as FileSwitch, more is already provided for you, and so you have even less work to do. The structure of FileCore is then imposed on your filing system; to the user, it will appear very similar to ADFS, leading to a consistency of design.

Obviously there is no way that FileSwitch can know how to communicate directly with the entire range of hardware that any filing system might use. Your filing system must provide these facilities, and declare the entry points to FileSwitch. When FileSwitch receives a SWI call or * Command, it does its share of the work, and uses these entry points to get the relevant filing system to do the work that is hardware dependent.

What to read next

The relevance of the rest of this chapter depends on how you intend to write your own filing system:

  • if you are not using FileCore, then you should read this chapter, which tells you how to add a filing system to FileSwitch
  • if you are using FileCore, then you should ignore this chapter and instead read the Writing a FileCore module.

In both cases you should also see the chapter entitled Modules, for more information on how to write a module.

Filing systems

Declaring a filing system

When your module initialises, it must declare itself to be a filing system, so that FileSwitch knows of its existence. You must call OS_FSControl 12 to do this - see OS_FSControl 12 for details. R1 and R2 tell FileSwitch where to find a filing system information block. This in turn tells FileSwitch the locations of all the entry points to the filing system's low level routines that interface with the hardware.

Filing system information block

This table shows the offsets from the start of the filing system information block, and the meaning of each word in the block:

Offset Contains
&00 Offset of filing system name (null terminated)
&04 Offset of filing system startup text (null terminated)
&08 Offset of routine to open files (FSEntry_Open)
&0C Offset of routine to get bytes from media (FSEntry_GetBytes)
&10 Offset of routine to put bytes to media (FSEntry_PutBytes)
&14 Offset of routine to control open files (FSEntry_Args)
&18 Offset of routine to close open files (FSEntry_Close)
&1C Offset of routine to do whole file operations (FSEntry_File)
&20 Filing system information word
&24 Offset of routine to do various FS operations (FSEntry_Func)
&28 Offset of routine to do multi-byte operations (FSEntry_GBPB)
&2C Extra filing system information word (optional)

The offsets held in each word are from the base of the filing system module. The GBPB entry (at offset &28 from the start of the information block) is optional if the filing system supports non buffered I/O, and not required otherwise.

The block need not exist for long, as FileSwitch takes a copy of it and converts the entry points to absolute addresses. So you could set up the block as an area in a stack frame, for example.

Filing system information word

The filing system information word (at offset &20) tells FileSwitch various things about the filing system:

Bit Meaning if set
31 Special fields are supported
30 Streams are interactive (ie prompting for input is appropriate)
29 Filing system supports null length filenames
28 Filing system should be called to open a file whether or not it exists
27 Tell the filing system when flushing by calling FSEntry_Args 255
26 Filing system supports FSEntry_File 9
25 Filing system supports FSEntry_Func 20
24 Reserved - must be zero
23 Filing system supports image filing system extensions
22 Pass & and % in paths when appropriate
21 Need not store directories for this filing system
20 Use Open/GetBytes/Close entry points rather than File 255
19 Use Open/GetBytes/Close entry points rather than File 0
18 Use FSEntry_Func 9 in preference to FSEntry_File entry points
17 Extra filing system information word is present
16 Filing system is read-only
15 - 8 Maximum number of files that may be open (see below)
7 - 0 Filing system number (see below)

Bits 16 - 23 are ignored by RISC OS 2. File systems that were written for RISC OS 2 should have these bits clear, which may cause problems: for example, RISC OS 2 read-only filing systems will incorrectly have bit 16 clear.

Bits 8 - 15 tell FileSwitch the maximum number of files that can be easily opened on the filing system (per server, if appropriate). A value of 0 means that there is no definite limiting factor - DMA failure does not count as such a factor. These bits may be used by system extension modules such as the Font Manager to decide whether a file may be left open or should be opened and closed as needed, to avoid the main application running out of file handles.

Bits 0 - 7 contain the filing system identification number. Currently allocated ones are listed in the Filing system numbers. For your own allocation, contact Acorn Computers in writing: see Appendix H: Registering names.

Extra filing system information word

The extra filing system information word is present if bit 17 of the filing system information word is set. If absent, it is assumed by FileSwitch to have value zero. The meaning of the bits in the word is as follows:

Bit Meaning if set
0 Filing system supports FSEntry_Func 34
1 Filing system should be called to do Cat
2 Filing system should be called to do Ex
3 - 31 Reserved - must be zero

You should only set bits 1 and 2 if your filing system provides a non-standard format for Cat and Ex respectively.

Service Call handler

Your filing system must have a Service Call handler. It must respond to Service_FSRedeclare (see Service_FSRedeclare) by redeclaring the filing system. For some filing systems, it may be appropriate to respond to Service_CloseFile. Disc based filing systems should also support Service_IdentifyDisc, Service_EnumerateFormats, Service_IdentifyFormat, and Service_DisplayFormatHelp.

Selecting your filing system

If your filing system has associated file storage, it must provide a * Command to select itself, such as *ADFS or *Net. This must call OS_FSControl 14 to direct FileSwitch to make the named filing system current, thus:

StarFilingSystemCommand
        STMFD   r13!, {r14}              ; In a * Command so R0-R6 may be corrupted
        MOV     r0, #FSControl_SelectFS  ; 14
        ADR     r1, FilingSystemName
        SWI     XOS_FSControl
        LDMFD   r13!, {pc}

For full details of OS_FSControl 14, see OS_FSControl 14.

Other * Commands

There are no other * Commands that your filing system must provide, but it obviously should provide more than just a way to select itself. Look through the previous chapters in this part of the manual to see what other filing systems offer.

If the list of * Commands you want to provide closely matches those in the FileCore, you ought to investigate adding your filing system to FileCore rather than to FileSwitch; this will be less work for you.

Removing your filing system

The finalise entry of your module must call OS_FSControl 16 (for both soft and hard deaths), so that FileSwitch knows that your filing system is being removed:

        MOV     r0, #FSControl_RemoveFS  ; 16
        ADR     r1, FilingSystemName
        SWI     XOS_FSControl
        CMP     pc, #0                   ; Clears V (also clears N,Z, sets C)

For full details of OS_FSControl 16, see OS_FSControl 16.

Image filing systems

For a description of image filing systems, and their relationship to other filing systems, see the chapter entitled DOSFS. Image filing systems are not supported by RISC OS 2.

Declaring an image filing system

When your module initialises, it must declare itself to be an image filing system, so that FileSwitch knows of its existence. You must call OS_FSControl 35 to do this - see OS_FSControl 35 for details. R1 and R2 tell FileSwitch where to find an image filing system information block. This in turn tells FileSwitch the locations of all the entry points to the image filing system's low level routines that interface with the hardware.

Image filing system information block

This table shows the offsets from the start of the image filing system information block, and the meaning of each word in the block:

Offset Contains
&00 Image filing system information word
&04 Image filing system file type
&08 Offset of routine to open files (ImageEntry_Open)
&0C Offset of routine to get bytes from media (ImageEntry_GetBytes)
&10 Offset of routine to put bytes to media (ImageEntry_PutBytes)
&14 Offset of routine to control open files (ImageEntry_Args)
&18 Offset of routine to close open files (ImageEntry_Close)
&1C Offset of routine to do whole file operations (ImageEntry_File)
&24 Offset of routine to do various FS operations (ImageEntry_Func)

The offsets held in each word are from the base of the image filing system module.

The block need not exist for long, as FileSwitch takes a copy of it and converts the entry points to absolute addresses. So you could set up the block as an area in a stack frame, for example.

The image filing system file type gives the numerical file type of files which contain images understood by the image filing system.

Image filing system information word

The image filing system information word (at offset 0) tells FileSwitch various things about the image filing system:

Bit Meaning if set
27 Tell the image filing system when flushing by calling ImageEntry_Args 255

All other bits are reserved and should be set to zero.

Service Call handler

Your image filing system must have a Service Call handler. It must respond to the same service calls as any other filing system; see the chapter entitled Service Call handler.

* Commands

There are no * Commands that your image filing system must provide, but most should provide some. See the chapter entitled DOSFS for an example of what other image filing systems offer.

Removing your image filing system

The finalise entry of your module must call OS_FSControl 36 (for both soft and hard deaths), so that FileSwitch knows that your image filing system is being removed:

        MOV     r0, #FSControl_DeRegisterImageFS  ; 36
        ADR     r1, ImageFileType
        SWI     XOS_FSControl
        CMP     pc, #0                            ; Clears V (also clears N,Z, sets C)

For full details of OS_FSControl 36, see OS_FSControl 36.

Filing system interfaces: introduction

Calling conventions

The principal part of a filing system (or of an image filing system) is the set of low-level routines that control the filing system's hardware. There are certain conventions that apply to them.

Processor mode

Routines called by FileSwitch are always entered in SVC mode, with both IRQs and FIQs enabled. This means you do not have to change mode to access hardware devices directly, and are able to change to FIQ mode to set up FIQ registers if necessary.

Using the stack

R13 in supervisor mode is used as the system stack pointer. The filing system (or image filing system) may use this full descending stack. When the filing system (or image filing system) is entered you should take care not to push too much onto the stack, as it is only guaranteed to be 1024 bytes deep; however most of the time it is substantially greater. The stack base is on a 1Mbyte boundary. Hence, to determine how much stack space there is left for your use, use the following code:

        MOV     R0, R13, LSR #20      ; Get Mbyte value of SP
        SUB     R0, R13, R0, LSL #20  ; Sub it from actual value

You may move the stack pointer downwards by a given amount and use that amount of memory as temporary workspace. However, interrupt processes are allowed to use the supervisor stack so you must leave enough room for these to operate. Similarly, if you call any operating system routines, you must give them enough stack space.

Using file buffers

If a read or write operation occurs that requires a file buffer to be claimed for a file, and this memory claim fails, then FileSwitch will look to steal a file buffer from some other file. Victims are looked for in the order:

  1. an unmodified buffer of the same size
  2. an unmodified buffer of a larger size
  3. a modified buffer of the same size
  4. a modified buffer of a larger size.

In the last two cases, FileSwitch obviously calls the filing system (or image filing system) to write out the buffer first, before giving it to the new owner. If an error occurs in writing out the buffer under RISC OS 2, the stream that owned the data in the buffer (not the stream that needed to get the buffer) is marked as having 'data lost'; any further operations will return the 'Data lost' error. FileSwitch is always capable of having one file buffered at any time, although it won't work very well under such conditions.

Workspace

R12 on entry to the filing system (or image filing system) is set to the value of R3 it passed to FileSwitch when initialising by calling OS_FSControl 12 or 35. Conventionally, this is used as a pointer to your private word. In this case, module entries should contain the following:

LDR R12, [R12]

to load the actual private word into the register.

Returning errors

The error numbers your filing system returns should take this format:

&0001nnee

where nn is the filing system number, as passed in the information word (see the chapter entitled Filing system information word); and ee is one of the error numbers used by FileCore based filing systems (see the table on Error Token Default text), or - if none is relevant - a number that does not appear in that table.

Supporting unbuffered streams

Filing systems may support both buffered and unbuffered streams. Unbuffered streams must maintain their own sequential pointers, file extents and allocated sizes. File Switch will maintain the EOF-error-on-next-read flag for them.

Image filing system streams are always buffered; consequently they should not support unbuffered streams.

Dealing with access

Generally FileSwitch does not make calls to filing systems (or to image filing systems) unless the access on objects is correct for the requested operation.

Note that if a file is opened for buffered output and has only write access, FileSwitch may still attempt to read from it to perform its file buffering. You must not fault this.

Other conventions

Filing system (or image filing system) routines do not need to preserve any registers other than R13.

If a routine wishes to return an error, it should return to FileSwitch with V set and R0 pointing to a standard format error block.

You may assume that:

  • all names are null terminated
  • all pathnames are non-null, unless the filing system allows them (for example printer:)
  • all pathnames have correct syntax.

All pathnames should be treated as read-only If you do need to make changes to a pathname, you must copy it to your local workspace and modify that copy.

Using canonical names

All filing system interfaces, with the exception of FSEntry_Func 23, are always passed names in the canonical form. This canonical form is defined by the designer of a particular filing system and is fixed. Canonical form is used to ensure that dissimilar references to the same object reduce to identical strings, and thus the filing system can easily determine that two object references are to the same object. For example after:

*Mount 0 *Dir A.z

references to $.a.b.c and to ^.b.c will reduce to the same canonical form:

adfs::MyDisc.$.a.b.c

The use of canonical form also helps the filing system to run faster. Because all filing system interfaces only receive canonical names, the parsing can be fast and efficient. Remember that canonicalisation happens once for several calls to the filing system itself.

The chosen canonical form should be a subset of the acceptable name styles, and hence the canonical name should be acceptable to the canonicaliser as input. For example the input syntax for the NetFS canonicaliser is:

Net[#(name|number]:[:discname.]$|&

The output format is:

Net::name.$|&

It is also worthwhile optimising the canonicalisation code so that an already canonical name is processed very fast.

Canonical names are not used by RISC OS 2.

ImageEntry entry points

In the following descriptions a pathname will always be relative to the root directory of the image, and will never have any '^', '$', '@', '%', '\' or '&' characters in it. When a wildcarded pathname is specified, the operation should be applied to all matching leafnames; but earlier wildcarded elements in the path should use the first match. A null pathname indicates the root directory of the image.

Interfaces

These are the interfaces that your filing system (or image filing system) must provide. Their entry points must be declared to FileSwitch by calling OS_FSControl 12 when your filing system module is initialised, or by calling OS_FSControl 35 when your image filing system module is initialised.

FSEntry_Open and ImageEntry_Open

Open a file
On entry (FSEntry_Open)

R0 = reason code
R1 = pointer to filename
R3 = FileSwitch handle for the file
R6 = pointer to special field if present, otherwise 0

On exit (FSEntry_Open)

R0 = file information word (not the same as the filing system information word)
R1 = your filing system's handle for the file (0 if not found)
R2 = buffer size for FileSwitch to use (0 if file unbuffered, else must be a power of 2 between 64 and 1024)
R3 = file extent (buffered files only)
R4 = space currently allocated to file (buffered files only: must be a multiple of buffer size)

On entry (ImageEntry_Open)

R1 = pointer to filename
R3 = FileSwitch handle for the file
R6 = image filing system's handle for image that contains file

On exit (ImageEntry_Open)

R0 = image file information word (not the same as the image filing system information word)
R1 = your image filing system's handle for the file (0 if not found)
R2 = buffer size for FileSwitch to use (must be a power of 2 between 64 and 1024)
R3 = file extent
R4 = space allocated to file (must be a multiple of buffer size)

Use

FileSwitch calls this entry point to open a file for read or write, and to create it if necessary.

General details

On entry, R3 contains the handle that FileSwitch will use for the file if your filing system successfully opens it. This is a small integer (typically going downwards from 255), but must be treated as a 32-bit word for future compatibility. Your filing system may want to make a note of it when the file is opened, in case it needs to refer to files by their FileSwitch handles (for example, it must close all open files on a *Dismount). It is the FileSwitch handle that the user sees.

On exit, your filing system must return a 32-bit file handle that it uses internally to FileSwitch. FileSwitch will then use this file handle for any further calls to your filing system. You may use any value, apart from a handle of 0 which means that no file is open.

The value returned in R2 is the natural block size of the file; for disc oriented filing systems, this should be the same as the natural sector size. FileSwitch - when calling the filing system - will tend to use multiple of this value, aligned on a boundary which is also a multiple of this value.

If your memory allocation fails, this is not an error, and you should indicate it to FileSwitch by setting R1 to 0 on exit.

Details specific to FSEntry_Open

The reason code given in R0 has the following meaning:

Value Meaning
0 Open for read
1 Create and open for update
2 Open for update

For both reason codes 0 and 2 FileSwitch will already have checked that the object exists (unless you have overridden this by setting bit 28 of the filing system information word) and, for reason code 2 only, that it is not a directory. These reason codes must not alter a file's datestamp.

If a directory is opened for reading, then bytes will not be requested from it. The use of this is for compatibility with existing programs which use this as a method of testing the existence of an object.

For reason code 1 FileSwitch will already have checked that the leafname is not wildcarded, and that the object is not an existing directory. Your filing system should return an extent of zero. If the file already exists you should return an allocated space the same as that of the file; otherwise you should return a sensible default that allows space for the file to grow. Your filing system should also give a new file a filetype of &FFD (Data), datestamp it, and give it sensible access attributes (WR/ is recommended).

The file information word returned in R0 uses the following bits:

Bit Meaning if set
31 Write permitted to this file
30 Read permitted from this file
29 Object is a directory
28 Unbuffered OS_GBPB supported (stream-type devices only)
27 Stream is interactive

All other bits are reserved and should be set to 0.

An interactive stream is one on which prompting for input is appropriate, such as kbd:.

Details specific to ImageEntry_Open

FileSwitch will already have checked that the object exists and that it is not a directory. You must not alter a file's datestamp.

The image file information word returned in R0 uses the following bits:

Bit Meaning if set
31 Write permitted to this file
30 Read permitted from this file

All other bits are reserved and should be set to 0.

FSEntry_GetBytes (from a buffered file), and ImageEntry_GetBytes (all cases)

Get bytes from a buffered file
On entry

R1 = file handle used by your filing system/image filing system
R2 = pointer to buffer
R3 = number of bytes to read into buffer
R4 = file offset from which to get data

On exit

--

Details

This entry point is used by FileSwitch to request that you read a number of bytes from an open file, and place them in memory.

The file handle is guaranteed by FileSwitch not to be a directory, but not necessarily to have had read access granted at the time of the open - see the last case given below.

The memory address is not guaranteed to be of any particular alignment. You should if possible optimise your filing system's transfers to word-aligned locations in particular, as FileSwitch's and most clients do tend to be word-aligned. The speed of your transfer routine is vital to filing system performance. An optimised example (similar to that used in RISC OS) is given in the Example program.

The number of bytes to read, and the file offset from which to read data are guaranteed to be a multiple of the buffer size for this file. The file offset will be within the file's extent.

This call is made by FileSwitch for several purposes:

  • A client has called OS_BGet at a file offset where FileSwitch has no buffered data, and so FileSwitch needs to read the appropriate block of data into one of its buffers, from where data is returned to the client.
  • A client has called OS_GBPB to read a whole number of the buffer size at a file offset that is a multiple of the buffer size. FileSwitch requests that the filing system transfer this data directly to the client's memory. This is often the case where language libraries are being used for file access. If FileSwitch has any buffered data in the transfer range that has been modified but not yet flushed out to the filing system, then this data is copied to the client's memory after the GetBytes call to the filing system.
  • A client has called OS_GBPB to perform a more general read. FileSwitch will work out an appropriate set of data transfers. You may be called to fill FileSwitch's buffers as needed and/or to transfer data directly to the client's memory. You should make no assumptions about the exact number and sequence of such calls; as far as possible RISC OS tries to keep the calls in ascending order of file address, to increase efficiency by reducing seek times, and so on.
  • A client has called OS_GBPB to perform a more general write. FileSwitch will work out an appropriate set of data transfers. You may be called to fill FileSwitch's buffers as needed, so that the data at the start and/or end of the requested transfer can be put in the right place in FileSwitch's buffers, ready for whole buffer transfer to the filing system as necessary.

Note that FileSwitch holds no buffered data immediately after a file has been opened.

FSEntry_GetBytes (from an unbuffered file)

Get a byte from an unbuffered file
On entry

R1 = file handle used by your filing system

On exit

R0 = byte read, C clear
R0 = undefined, C set if attempting to read at end of file

Details

This entry point is called by FileSwitch to get a single byte from an unbuffered file from the position given by the file's sequential pointer. The sequential pointer must be incremented by one, unless the end of the file has been reached.

The file handle is guaranteed by FileSwitch not to be a directory and to have had read access granted at the time of the open.

Your filing system must not try to keep its own EOF-error-on-next-read flag - instead it must return with C set whenever the file's sequential pointer is equal to its extent before a byte is read. It is FileSwitch's responsibility to keep the EOF-error-on-next-read flag.

If your filing system does not support unbuffered GBPB directly, then FileSwitch will call this entry the necessary number of times to complete its client's request, stopping if you return with the C flag set (EOF).

FSEntry_PutBytes (to a buffered file), and ImageEntry_PutBytes (all cases)

Put bytes to a buffered file
On entry

R1 = file handle used by your filing system/image filing system
R2 = pointer to buffer from which to read data
R3 = number of bytes of data to read from buffer and put to file
R4 = file offset at which to put data

On exit

--

Details

This entry point is called by FileSwitch to request that you take a number of bytes, and place them in the file at the specified file offset.

The file handle is guaranteed by FileSwitch not to be a directory, and to have had write access granted at the time of the open.

The memory address is not guaranteed to be of any particular alignment. You should if possible optimise your filing system's transfers to word-aligned locations in particular, as FileSwitch's and most clients do tend to be word-aligned. The speed of your transfer routine is vital to filing system performance. An optimised example (similar to that used in FileSwitch) is given in the Example program.

The number of bytes to write, and the file offset at which to write data are guaranteed to be a multiple of the buffer size for this file. The final write will be within the file's extent, so it will not need extending.

This call is made by FileSwitch for several purposes:

  • A client has called OS_GBPB to write a whole number of the buffer size at a file offset that is a multiple of the buffer size. FileSwitch requests that the filing system transfer this data directly from the client's memory. This is often the case where language libraries are being used for file access. If FileSwitch has any buffered data in the transfer range that has been modified but not yet flushed out to the filing system, then this data is discarded (as it has obviously been invalidated by this operation).
  • A client has called OS_BGet/BPut/GBPB at a file offset where FileSwitch has no buffered data, and the current buffer held by FileSwitch has been modified and so must be written to the filing system. (The current FileSwitch implementation does not maintain multiple buffers on each file. It is likely that this will remain the case, as individual filing systems have better knowledge about how to do disc-caching, and intelligent readahead and writebehind for given devices.)
  • A client has called OS_GBPB to perform a more general write. FileSwitch will work out an appropriate set of data transfers. You may be called to empty FileSwitch's buffers as needed and/or to transfer data directly from the client's memory. You should make no assumptions about the exact number and sequence of such calls; as far as possible RISC OS tries to keep the calls in ascending order of file address, to increase efficiency by reducing seek times, and so on.

Note that FileSwitch holds no buffered data immediately after a file has been opened.

FSEntry_PutBytes (to an unbuffered file)

Put a byte to an unbuffered file
On entry

R0 = byte to put to file (top 24 bits zero)
R1 = file handle used by your filing system

On exit

--

Details

This entry point is called by FileSwitch to request that you put a single byte to an unbuffered file at the position given by the file's sequential file pointer. You must advance the sequential pointer by one. If the sequential pointer is equal to the file extent when this call is made, you must increase the allocated space of the file by at least one byte to accommodate the data - although it will be more efficient to increase the allocated space in larger chunks (256 bytes/1k is common).

The file handle is guaranteed by FileSwitch not to be a directory, and to have had write access granted at the time of the open.

If your filing system does not support unbuffered GBPB directly, then FileSwitch will call this entry the necessary number of times to complete its client's request.

FSEntry_Args and ImageEntry_Args

Various calls are made by FileSwitch through these entry points to deal with controlling open files. The actions are specified by R0 as follows:

FSEntry_Args 0

Read sequential file pointer
On entry

R0 = 0
R1 = file handle used by your filing system

On exit

R2 = sequential file pointer

Details

This entry point is called by FileSwitch to read the sequential file pointer for the given file. You should only support this call if your filing system uses unbuffered files.

If your filing system does not support a pointer as the concept is meaningless (kbd: for example) then it must return a pointer of 0, and not return an error.

FSEntry_Args 1

Write sequential file pointer
On entry

R0 = 1
R1 = file handle used by your filing system
R2 = new sequential file pointer

On exit

--

Details

This entry point is called by FileSwitch to request that you alter the sequential file pointer for a given file. You should only support this call if your filing system uses unbuffered files.

If the new pointer is greater than the current file extent then:

  • if the file was opened only for reading, or only read permission was granted, then return the error 'Outside file'
  • otherwise extend the file with zeros and set the new extent to the new sequential pointer.

If you cannot extend the file you should return an error as soon as possible, and in any case before you update the extent.

If your filing system does not support a pointer as the concept is meaningless (kbd: for example) then it must ignore the call, and not return an error.

FSEntry_Args 2

Read file extent
On entry

R0 =2
R1 = file handle used by your filing system

On exit

R2 = file extent

Details

This entry point is called by FileSwitch to read the extent of a given file. You should only support this call if your filing system uses unbuffered files.

If your filing system does not support file extents as the concept is meaningless (kbd: for example) then it must return an extent of 0, and not return an error.

FSEntry_Args 3 and ImageEntry_Args 3

Write file extent
On entry

R0 = 3
R1 = file handle used by your filing system/image filing system
R2 = new file extent

On exit

--

Details

This entry point is called by FileSwitch to request that you change the extent of a file.

The file handle is guaranteed by FileSwitch not to be a directory, and to have had write access granted at the time of the open.

If the filing system does not support file extents as the concept is meaningless (kbd: for example) then it must ignore the call, and not return an error.

Buffered files

For buffered files, FileSwitch only calls this entry point to set the real file extent just prior to closing an open file. Your filing system should store the value of R2 in the file's catalogue information as its new length.

Unbuffered files

For unbuffered files, FileSwitch calls this entry point whenever requested to by its client.

If the new extent is less than the current sequential pointer (the file is shrinking and the pointer would lie outside the file), then you must set the pointer to the new extent.

If the new extent is greater than the current one then you must extend the file with zeros. If you cannot extend the file you should return an error as soon as possible, and in any case before you update the extent.

FSEntry_Args 4 and ImageEntry_Args 4

Read size allocated to file
On entry

R0 = 4
R1 = file handle used by your filing system/image filing system

On exit

R2 = size allocated to file by filing system

Details

This entry point is called by FileSwitch to read the size allocated to a given file. All filing systems must support this call.

FSEntry_Args 5

EOF check
On entry

R0 = 5
R1 = file handle used by your filing system/image filing system

On exit

R2 = -1 if (sequential pointer is equal to current extent), otherwise R2 = 0

Details

This entry point is called by FileSwitch to determine whether the sequential pointer for a given file is at the end of the file or not. You should only support this call if your filing system uses unbuffered files.

If a filing system does not support a pointer and/or a file extent as the concept(s) are meaningless (kbd: for example) then the treatment of the C bit is dependent on that filing system. For example, kbd: gives EOF when Ctrl-D is read from the keyboard; null: always gives EOF; and vdu: never gives EOF.

FSEntry_Args 6 and ImageEntry_Args 6

Notify of a flush
On entry

R0 = 6
R1 = file handle used by your filing system/image filing system

On exit

R2 = load address of file (or 0)
R3 = execution address of file (or 0)

Details
General details

This entry point is called by FileSwitch to request that your filing system flushes any modified data that it is holding in buffers. You should only support this call if your filing system does its own buffering in addition to that done by FileSwitch. For example, ADFS does its own buffering when doing readahead/writebehind, and so needs to use this call.

Details specific to FSEntry_Args 6

The modified data should be flushed to its storage media.

This entry point is only called if your filing system is buffered, and you set bit 27 of your filing system information word when you initialised your filing system.

Details specific to ImageEntry_Args 6

The modified data should be flushed to its image. The image should subsequently be flushed to its storage media to ensure the data's integrity.

This entry point is only called if you set bit 27 of your image filing system information word when you initialised your image filing system.

FSEntry_Args 7 and ImageEntry_Args 7

Ensure file size
On entry

R0 = 7
R1 = file handle used by your filing system/image filing system
R2 = size of file to ensure

On exit

R2 = size of file actually ensured

Details

This entry point is called by FileSwitch to ensure that a file is of at least the given size. Your file system should do just this, but need not ensure that any extra space is zeroed. All filing systems must support this call.

FSEntry_Args 8 and ImageEntry_Args 8

Write zeros to file
On entry

R0 = 8
R1 = file handle used by your filing system
R2 = file offset at which to write
R3 = number of zero bytes to write

On exit

--

Details

This entry point is called by FileSwitch to request that your filing system writes a given number of zero bytes to a given offset within a file. You should only support this call if your filing system uses buffered files.

The file handle is guaranteed by FileSwitch not to be a directory, and to have had write access granted at the time of the open.

The number of bytes to write, and the file offset at which to write data are guaranteed to be a multiple of the buffer size for this file.

FSEntry_Args 9 and ImageEntry_Args 9

Read file datestamp
On entry

R0 = 9
R1 = file handle used by your filing system/image filing system

On exit

R2 = load address of file (or 0)
R3 = execution address of file (or 0)

Details

This entry point is called by FileSwitch to read the date/time stamp for a given file. The bottom four bytes of the date/time stamp are stored in the execution address of the file. The most significant byte is stored in the least significant byte of the load address. All filing systems must support this call. If your filing system cannot stamp an open file given its handle, then it should return R2 and R3 set to zero.

FSEntry_Args 10

Inform of new image stamp
On entry

R0 = 10
R1 = file handle used by your filing system/image filing system
R2 = new image stamp of image

On exit

All registers preserved

Details

This entry point is called by FileSwitch when an image filing system has changed an image's image stamp (a unique identification number). The purpose of the call is to inform your filing system of the change, and to pass it the new image stamp. If your filing system does not support the root object being an image, then it should ignore this call. Otherwise - as for example in the case of FileCore - you should update your filing system's internal note of the image stamp, as you may need to use it to identify the disc at a later time.

This call is for information only, and should not require any further action. It is not called by RISC OS 2, which does not support image filing systems.

FSEntry_Close and ImageEntry_Close

Close an open file
On entry

R1 = file handle used by your filing system/image filing system
R2 = new load address to associate with file
R3 = new execution address to associate with file

On exit

--

Details

This entry point is called by FileSwitch to request that your filing system close an open file, and put a new date/time stamp on it. For ImageEntry_Close, you should then call OS_Args 255 on the image after updating the structure for the closed file; this ensures that all data is flushed to the disc.

If your filing system returned from the FSEntry_Args 9 (or ImageEntry_Args 9) call with R2 and R3 both zero, then they will also have that value here, and you should not try to restamp the file. Restamping takes place if the file has been modified and FSEntry_Args 9 (or ImageEntry_Args 9) returned a non-zero value in R2.

Note that *Close and *Shut (ie close all open files) are performed by FileSwitch which passes the handles, one at a time, to the relevant filing system for closing. Filing systems should not try to support this themselves.

FSEntry_File and ImageEntry_File

Various calls are made by FileSwitch through these entry points to perform operations on whole files. The actions are specified by R0 as follows:

FSEntry_File 0 and ImageEntry_File 0

Save file
On entry

R0 = 0
R1 = pointer to filename
R2 = load address to associate with file
R3 = execution address to associate with file
R4 = pointer to start of buffer
R5 = pointer to byte after end of buffer
R6 = pointer to special field if present, otherwise 0 (FSEntry_File 0); or image filing system's handle for image that contains file (ImageEntry_File 0)

On exit

R6 = pointer to a leafname for printing *OPT 1 info

Details

This entry point is called by FileSwitch to request that your filing system saves data from a buffer held in memory to a file. FileSwitch has already validated the buffer, and ensured that the leafname is not wildcarded. If the file currently exists and is not locked, the old file is first discarded. The new file should have the same access attributes as the one it is replacing, or some default access if the file doesn't already exist. You should return an error such as File locked if you could not save the specified file.

FileSwitch immediately copies the leafname returned in R6, so it need not have a long lifetime. You could hold it in a small static buffer, for example.

FSEntry_File 1 and ImageEntry_File 1

Write catalogue information
On entry

R0 = 1
R1 = pointer to wildcarded filename
R2 = new load address to associate with file
R3 = new execution address to associate with file
R5 = new attributes for file
R6 = pointer to special field if present, otherwise 0 (FSEntry_File 1); or image filing system's handle for image that contains file (ImageEntry_File 1)

On exit

--

Details

This entry point is called by FileSwitch to request that your filing system updates the catalogue information for an object. If the object is a directory you must either write the information (FileCore-based filing systems do) or return an error. You must not return an error if the object does not exist.

FSEntry_File 2

Write load address
On entry

R0 = 2
R1 = pointer to wildcarded filename
R2 = new load address to associate with file
R6 = pointer to special field if present, otherwise 0

On exit

--

Details

This entry point is called by FileSwitch to request that your filing system alters the load address for a file. If the object is a directory you must either write the information (FileCore-based filing systems do) or return an error. You must not return an error if the object does not exist.

FSEntry_File 3

Write execution address
On entry

R0 = 3
R1 = pointer to wildcarded filename
R3 = execution address to associate with file
R6 = pointer to special field if present, otherwise 0

On exit

--

Details

This entry point is called by FileSwitch to request that your filing system alters the execution address for a file. If the object is a directory you must either write the information (FileCore-based filing systems do) or return an error. You must not return an error if the object does not exist.

FSEntry_File 4

Write attributes
On entry

R0 = 4
R1 = pointer to wildcarded pathname
R5 = new attributes to associate with file
R6 = pointer to special field if present, otherwise 0

On exit

--

Details

This entry point is called by FileSwitch to request that your filing system alters the attributes of an object. You must not return an error if the object does not exist.

FSEntry_File 5 and ImageEntry_File 5

Read catalogue information
On entry

R0 = 5
R1 = pointer to pathname
R6 = pointer to special field if present, otherwise 0 (FSEntry_File 5); or image filing system's handle for image that contains file (ImageEntry_File 5)

On exit

R0 = object type:

0 - not found
1 - file
2 - directory

R2 = load address
R3 = execution address
R4 = file length
R5 = file attributes
R6 preserved (ImageEntry_File 5)

Details

This entry point is called by FileSwitch to request that your filing system returns the catalogue information for an object. You should return an error if:

  • the pathname specifies a drive that is unknown
  • the pathname specifies a media name that is unknown and not made available after any UpCall
  • the special field specifies an unknown server or subsystem.

You should return type 0 if:

  • the place specified by the pathname exists, but the leafname does not match any object there
  • the place specified by the pathname does not exist.

FSEntry_File 6 and ImageEntry_File 6

Delete object
On entry

R0 = 6
R1 = pointer to filename
R6 = pointer to special field if present, otherwise 0 (FSEntry_File 6); or image filing system's handle for image that contains file (ImageEntry_File 6)

On exit

R0 = object type
R2 = load address
R3 = execution address
R4 = file length
R5 = file attributes

Details

This entry point is called by FileSwitch to request that your filing system deletes an object. FileSwitch will already have ensured that the leafname is not wildcarded. No data need be transferred to the file. You should return an error if the object is locked against deletion, but not if the object does not exist. The results refer to the object that was deleted.

FSEntry_File 7 and ImageEntry_File 7

Create file
On entry

R0 = 7
R1 = pointer to filename
R2 = load address to associate with file
R3 = execution address to associate with file
R4 = start address in memory of data
R5 = end address in memory plus one
R6 = pointer to special field if present, otherwise 0 (FSEntry_File 7); or image filing system's handle for image that contains file (ImageEntry_File 7)

On exit

R6 = pointer to a filename for printing *Opt 1 info (FSEntry_File 7 only)

Details

This entry point is called by FileSwitch to request that your filing system creates a file with a given name. R4 and R5 are used only to calculate the length of the file to be created. If the file currently exists and is not locked, the old file is first discarded. The new file should have the same access attributes as the one it is replacing, or some default access if the file doesn't already exist. You should return an error if you couldn't create the file.

FSEntry_File 8 and ImageEntry_File 8

Create directory
On entry

R0 = 8
R1 = pointer to directory name
R2 = load address (ignored by RISC OS 2)
R3 = execute address (ignored by RISC OS 2)
R4 = number of entries (0 for default)
R6 = pointer to special field if present, otherwise 0 (FSEntry_File 8); or image filing system's handle for image that contains file (ImageEntry_File 8)

On exit

--

Details

This entry point is called by FileSwitch to request that your filing system creates a directory. If the directory already exists then your filing system can do one of these:

  • return without any modification to the existing directory
  • attempt to rename the directory - you must not return an error if this fails.

If directories don't support load and execute addresses (which will only be of the directory type/datestamp form) then no error should be returned. Note that RISC OS 2 will ignore the load and execute addresses in R2 and R3.

FileSwitch will already have ensured that the leafname is not wildcarded. You should return an error if you couldn't create the directory.

FSEntry_File 9

Read catalogue information (no length)
On entry

R0 = 9
R1 = pointer to filename
R6 = pointer to special field if present, otherwise 0

On exit

R0 = object type
R2 = load address
R3 = execution address
R5 = file attributes

Details

This entry point is called by FileSwitch to read the catalogue information for an object, save for the object length. It is useful for NetFS with fileservers, as the length is not stored in a directory. You must not return an error if the object does not exist.

It is only ever called by *Copy under RISC OS 2; bit 26 of your filing system information word must have been set when the filing system was initialised. Otherwise FileSwitch calls FSEntry_File 5, and the length returned in R4 is ignored.

FSEntry_File 10 and ImageEntry_File 10

Read block size
On entry

R0 = 10
R1 = pointer to filename
R6 = pointer to special field if present, otherwise 0 (FSEntry_File 10); or image filing system's handle for image that contains file (ImageEntry_File 10)

On exit

R2 = natural block size of the file (in bytes)

Details

This entry point is called by FileSwitch to read the natural block size for a file (see FSEntry_Open and ImageEntry_Open). It is not called by RISC OS 2.

FSEntry_File 255

Load file
On entry

R0 = 255
R1 = pointer to wildcarded filename
R2 = address to load file
R6 = pointer to special file if present; otherwise 0

On exit

R0 corrupted
R2 = load address
R3 = execution address
R4 = file length
R5 = file attributes
R6 = pointer to a filename for printing *OPT 1 info

Details

This entry point is called by FileSwitch to request that your filing system loads a file.

FileSwitch will already have called FSEntry_File 5 and validated the client's load request. If FSEntry_File 5 returned with object type 0 then the user will have been returned the 'File 'xyz' not found' error; type 2 will have returned the ''xyz' is a directory' error; types 1 with corresponding load actions will have had them executed (which may recurse back down to load again), those with no read access will have returned 'Access violation', and those being partially or wholly loaded into invalid memory will have returned 'No writeable memory at this address'.

Therefore unless the filing system is accessing data stored on a multi-user server such as NetFS/FileStore, the object will still be the one whose info was read earlier.

The filename pointed to by R6 on exit should be the non-wildcarded 'leaf' name of the file. That is, if the filename given on entry was $.!b*, and the file accessed was the boot file, R6 should point to the string !Boot.

FSEntry_Func and ImageEntry_Func

Various calls are made through these entry points to deal with assorted filing system (or image filing system) control. Many of these output information. You should do this in two stages:

  • amass the information into a dynamic buffer
  • print from the buffer and dispose of it.

This avoids problems caused by the write character process being in the middle of spooling, or by an active task swapper.

If you add a header to output (cf *Info, *Cat and *Ex on ADFS) you must follow it with a blank line. You should always try to format your output to the printable width of the current window. You can read this using XOS_ReadVduVariables to read the WindowWidth variable (&100), which copes with most eventualities. Don't cache the value, but read it before each output.

The actions are specified by R0 as given below.

FSEntry_Func 0

Set current directory
On entry

R0 = 0
R1 = pointer to wildcarded directory name
R6 = pointer to special field if present, otherwise 0

On exit

--

Details

This entry point is called by FileSwitch to set the current directory to the one specified by the directory name and context given. If the directory name is null, you should assume it to be the user root directory.

You should not also make the context current, but instead provide an independent means of doing so, such as *FS on the NetFS.

This entry point is called by RISC OS 2; otherwise it is only called to perform a *Opt 1 command when bit 23 of the filing system information word is clear.

FSEntry_Func 1

Set library directory
On entry

R0 = 1
R1 = pointer to wildcarded directory name
R6 = pointer to special field if present, otherwise 0

On exit

--

Details

This entry point is called by FileSwitch to set the current library directory to the one identified by the directory name and context given. If the directory name is null, you should assume it to be the filing system default (which is dependent on your implementation).

You should not also make the context current, but instead provide an independent means of doing so, such as *FS on the NetFS.

This entry point is only called by RISC OS 2.

FSEntry_Func 2

Catalogue directory
On entry

R0 = 2
R1 = pointer to wildcarded directory name
R6 = pointer to special field if present, otherwise 0

On exit

--

Details

This entry point is called by FileSwitch to catalogue the directory identified by the directory name and context given. If the directory name is null, you should assume it to be the current directory. (This corresponds to the *Cat command.)

This entry point is called by RISC OS 2; otherwise it is only called if bit 1 of the extra filing system information word is set.

FSEntry_Func 3

Examine directory
On entry

R0 = 3
R1 = pointer to wildcarded directory name
R6 = pointer to special field if present, otherwise 0

On exit

--

Details

This entry point is called by FileSwitch to print information on all the objects in the directory identified by the directory name and context given. If the directory name is null, you should assume it to be the current directory. (This corresponds to the *Ex command.)

This entry point is called by RISC OS 2; otherwise it is only called if bit2 of the extra filing system information word is set.

FSEntry_Func 4

Catalogue library directory
On entry

R0 = 4
R1 = pointer to wildcarded directory name
R6 = pointer to special field if present, otherwise 0

On exit

--

Details

This entry point is called by FileSwitch to catalogue the specified subdirectory relative to the current library directory. If the directory name is null, you should assume it to be the current library directory. (This corresponds to the *LCat command.)

This entry point is called by RISC OS 2; otherwise it is only called if bit 1 of the extra filing system information word is set.

FSEntry_Func 5

Examine library directory
On entry

R0 = 5
R1 = pointer to wildcarded directory name
R6 = pointer to special field if present, otherwise 0

On exit

--

Details

This entry point is called by FileSwitch to print information on all the objects in the specified subdirectory relative to the current library directory. If the directory name is null, you should assume it to be the current library directory. (This corresponds to the *LEx command.)

This entry point is called by RISC OS 2; otherwise it is only called if bit 2 of the extra filing system information word is set.

FSEntry_Func 6

Examine object(s)
On entry

R0 = 6
R1 = pointer to wildcarded pathname
R6 = pointer to special field if present, otherwise 0.

On exit

--

Details

This entry point is called by FileSwitch to print information on all the objects matching the wildcarded pathname and context given, in the same format as for FSEntry_Func 3. (This corresponds to the *Info command.)

This entry point is called by RISC OS 2; otherwise it is only called if bit 2 of the extra filing system information word is set.

FSEntry_Func 7

Set filing system options
On entry

R0 = 7
R1 = new option (or 0)
R2 = new parameter
R6 = 0 (cannot specify a context)

On exit

--

Details

This entry point is called by FileSwitch to set filing system options.

An option of 0 means reset all filing system options to their default values. An option of 1 is never passed to you, as FileSwitch maintains these settings. An option of 4 is used to set the boot file action. You may use other option numbers for your own purposes; please contact Acorn for an allocation.

(This corresponds to the *Opt command.)

You should return an error for bad combinations of options and parameters.

FSEntry_Func 8 and ImageEntry_Func 8

Rename object
On entry

R0 = 8
R1 = pointer to pathname of object to be renamed
R2 = pointer to new pathname for object
R6 = pointer to first special field if present, otherwise 0 (FSEntry_Func 8); or image filing system's handle for image that contains file (ImageEntry_Func 8)
R7 = pointer to second special field if present, else 0 (FSEntry_Func 8 only)

On exit

R1 = 0 if rename performed ([NOT EQUAL]0 otherwise)

Details

This entry point is called by FileSwitch to attempt to rename an object. If the rename is not 'simple' - ie just changing the file's catalogue entry - R1 should be returned with a value other than zero. (For example, the files may be on different images.) In such cases, FileSwitch will return a 'Bad rename' error.

FSEntry_Func 9

Access object(s)
On entry

R0 = 9
R1 = pointer to wildcarded pathname
R2 = pointer to access string (null, space or control-character terminated)
R6 = pointer to special field if present, otherwise 0.

On exit

--

Details

This entry point is called by FileSwitch to give the requested access to all objects matching the wildcarded name given. (This corresponds to the *Access command.)

You should ignore inappropriate owner access bits, and try to store public access bits.

This entry point is called by RISC OS 2; otherwise it is only called if bit 18 of the filing system information word is set.

FSEntry_Func 10

Boot filing system
On entry

R0 = 10

On exit

--

Details

This entry point is called by FileSwitch to request that your filing system performs its boot action.

For example, ADFS examines the boot option - as set by *Opt 4 - of the disc in the configured drive and acts accordingly (so, if boot option 2 is set, it will *Run &.!Boot); whereas NetFS attempts to logon as the boot user to the configured file server.

This call may not return if it runs an application.

FSEntry_Func 11

Read name and boot (*OPT 4) option of disc
On entry

R0 = 11
R2 = pointer to buffer in which to put data
R6 = 0 (cannot specify a context)

On exit

--

Details

This entry point is called by FileSwitch to obtain the name of the disc that the CSD is on in the temporary filing system, and its boot option. This data should be returned in the area of memory pointed to by R2, in the following format:

<name length byte><disc name><boot option byte>

If there is no CSD, this call should return the string 'Unset' for the disc name, and the boot action should be set to zero.

The buffer pointed to by R2 will not have been validated with OS_ValidateAddress, because FileSwitch doesn't know how big the buffer has to be. It is the filing system's responsibility to validate any buffer that it uses, and to return an error if the memory required is not valid. Under RISC OS 2 it should use the error text 'No writable memory at this address'; under later versions it should instead look up the token BadWrt.

The buffer pointed to by R2 will not have been validated and so you should be prepared for faulting when you write to the memory. You must not put an interlock on when you are doing so.

FSEntry_Func 12

Read current directory name and privilege byte
On entry

R0 = 12
R2 = pointer to buffer in which to put data
R6 = 0 (cannot specify a context)

On exit

--

Details

This entry point is called by FileSwitch to obtain the name of the CSD on the temporary filing system, and privilege status in relation to that directory. This data should be returned in the area of memory pointed to by R2, in the following format:

<zero byte><name length byte><current directory name><privilege byte>

If there is no CSD, this call should return the string 'Unset' for the directory name.

The privilege byte is &00 if you have 'owner' status (ie you can create and delete objects in the directory) or &FF if you have 'public' status (ie are prevented from creating and deleting objects in the directory). On FileCore-based filing systems, you always have owner status.

The buffer pointed to by R2 will not have been validated with OS_ValidateAddress, because FileSwitch doesn't know how big the buffer has to be. It is the filing system's responsibility to validate any buffer that it uses, and to return the error 'No writable memory at this address' if the memory required is not valid.

This entry point is only called by RISC OS 2.

FSEntry_Func 13

Read library directory name and privilege byte
On entry

R0 = 13
R2 = pointer to buffer in which to put data
R6 = 0 (cannot specify a context)

On exit

--

Details

This entry point is called by FileSwitch to obtain the name of the library directory on the temporary filing system, and privilege status in relation to that directory. This data should be returned in the area of memory pointed to by R2, in the following format:

<zero byte><name length byte><library directory name><privilege byte>

If no library is selected, this call should return the string 'Unset' for the library directory name.

The buffer pointed to by R2 will not have been validated with OS_ValidateAddress, because FileSwitch doesn't know how big the buffer has to be. It is the filing system's responsibility to validate any buffer that it uses, and to return the error 'No writable memory at this address' if the memory required is not valid.

This entry point is only called by RISC OS 2.

FSEntry_Func 14 and ImageEntry_Func 14

Read directory entries
On entry

R0 = 14
R1 = pointer to wildcarded directory name
R2 = pointer to buffer in which to put data
R3 = number of object names to read
R4 = offset of first item to read in directory (0 for start of directory)
R5 = length of buffer
R6 = pointer to special field if present, otherwise 0 (FSEntry_Func 14); or image filing system's handle for image that contains file (ImageEntry_Func 14)

On exit

R3 = number of names read
R4 = offset of next item to read in directory (-1 if end)

Details

This entry point is called by FileSwitch to read the leaf names of entries in a directory into an area of memory pointed to by R2. If the directory name is null, then for filing systems the currently-selected directory should be read; for image filing systems the root directory should be read. The names are returned in the buffer as a list of null terminated strings. You must not overflow the end of the buffer, and you must only count names that you have completely inserted.

The length of buffer that FileSwitch will have validated depends on the call that was made to it:

  • if it was OS_GBPB 8, then enough space will have been validated to hold [R3] 10-character long directory entries (plus their terminators)
  • if it was OS_GBPB 9, then the entire buffer specified by R2 and R5 will have been validated.

Unfortunately there is no way you can tell which was used. RISC OS programmers are encouraged to use the latter.

You should return an error if the object being catalogued is not found or is a file. The following are, however, all valid return values:

  • R3 = 0, R4 [NOT EQUAL] -1 (the buffer overflowed)
  • R3 [NOT EQUAL] 0_ R4 [NOT EQUAL] -1 (there are more names to read)
  • R3 = 0, R4 = -1 (the previous read filled the buffer with the last name, but didn't detect the end; now there no more names to read).

FSEntry_Func 15 and ImageEntry_Func 15

Read directory entries and information
On entry

R0 = 15
R1 = pointer to wildcarded directory name
R2 = pointer to buffer in which to put data
R3 = number of object names to read
R4 = offset of first item to read in directory (0 for start of directory)
R5 = length of buffer
R6 = pointer to special field if present, otherwise 0 (FSEntry_Func 15); or image filing system's handle for image that contains file (ImageEntry_Func 15)

On exit

R3 = number of records read
R4 = offset of next item to read in directory (-1 if end)

Details

This entry point is called by FileSwitch to read the leaf names of entries (and their file information) in the given directory into a buffer pointed to by R2. If the directory name is null, then the currently-selected directory should be read. The names and information are returned in records, with the following format:

Offset Contents
&00 Load address
&04 Execution address
&08 Length
&0C Attributes
&10 Object type
&14 Object name

FileSwitch will have validated the buffer. You must not overflow the end of the buffer, and you must only count names that you have completely inserted. You should assume that the buffer is word-aligned, and your records should be so too. You may find this code fragment useful to do so:

        ADD     r2, r2, #p2-1  ; p2 is a power-of-two, in this case 4
        BIC     r2, r2, #p2-1

You should return an error if the object being catalogued is not found or is a file.

FSEntry_Func 16

Shut down
On entry

R0 = 16

On exit

--

Details

This entry point is called by FileSwitch to request that your filing system go into as dormant a state as possible. For example, it should place hard drives in their transit positions, etc. All files will have been closed by FileSwitch before this call is issued.

FSEntry_Func 17

Print start up banner
On entry

R0 = 17
R6 = 0 (cannot specify a context)

On exit

--

Details

This entry point is called by FileSwitch to print out a filing system banner that shows which filing system is selected. FileSwitch calls it if it receives a reset service call and the text offset value (in the filing system information block) is -1. This is to allow filing systems to print a message that may vary, such as Acorn Econet or Acorn Econet no clock.

You should print the string using XOS_... SWIs, and if there is an error return with V set and R0 pointing to an error block. This is not likely to happen.

FSEntry_Func 18

Set directory contexts
Details

This entry point is never called by FileSwitch.

FSEntry_Func 19

Read directory entries and information
On entry

R0 = 19
R1 = pointer to wildcarded directory name
R2 = pointer to buffer in which to put data
R3 = number of object names to read
R4 = offset of first item to read in directory
R5 = length of buffer
R6 = pointer to special field if present, otherwise 0

On exit

R3 = number of records read
R4 = offset of next item to read in directory (-1 if end)

Details

This entry point is called by FileSwitch to read the names of entries (and their file information) in the given directory into a buffer pointed to by R2. If the directory name is null, then the currently-selected directory should be read. The names and information are returned in records, with the following format:

Offset Contents
0 Load address
4 Execution address
8 Length
12 File attributes
16 Object type
20 System internal name - for internal use only
24 Time/Date (cs since 1/1/1900) - 0 if not stamped
29 Object name

Each record is word-aligned.

FSEntry_Func 20

Output full information on object(s)
On entry

R0 = 20
R1 = pointer to pathname (may be wildcarded under RISC OS 2 only)
R6 = pointer to special field if present, otherwise 0

On exit

--

Details

This entry point is called by FileSwitch to request that your filing system outputs full information on the given object (or, under RISC OS 2, on all the objects matching the wildcarded pathname). The format must be the same as for the *FileInfo command.

It is only called by FileSwitch if bit 25 of the filing system information word was set when the filing system was initialised. Otherwise FileSwitch will use calls to FSEntry_Func 6 to implement *FileInfo.

ImageEntry_Func 21

Notification of new image
On entry

R0 = 21
R1 = FileSwitch handle to the file
R2 = buffer size for file if known, otherwise 0

On exit

R1 = image filing system's handle for image

Details

This entry point is called by FileSwitch to notify your image filing system that FileSwitch would like it to handle a new image. This entry gives the image filing system a chance to set up internal structures so that data could be cached or buffered from the image. All future requests FileSwitch makes of the image filing system will quote the returned image filing system's handle for the image when appropriate.

The image should be flagged internally as 'stamp image on next update', and when it is updated its unique identification number should be updated. Whenever this number is updated the host filing system should be informed of its new value using OS_Args 8 - this is important, because otherwise the host filing system will lose track of which disc is which.

The buffer size (if given) should be treated as a hint to the sector size.

This entry point is not called by RISC OS 2.

ImageEntry_Func 22

Notification that image is about to be closed
On entry

R0 = 22
R1 = image filing system's handle for image

On exit

--

Details

This entry point is called by FileSwitch to notify your image filing system that an image is about to be closed. All files will have been closed for you before this call is made. You should save any buffered data for this image before returning, and discard any cached data.

This entry point is not called by RISC OS 2.

FSEntry_Func 23

Canonicalise special field and disc name
On entry

R0 = 23
R1 = pointer to special field if present, otherwise 0
R2 = pointer to disc name if present, otherwise 0
R3 = pointer to buffer to hold canonical special field, or 0 to return required length
R4 = pointer to buffer to hold canonical disc name, or 0 to return required length
R5 = length of buffer to hold canonical special field
R6 = length of buffer to hold canonical disc name

On exit

R1 = pointer to canonical special field if present, otherwise 0
R2 = pointer to canonical disc name if present, otherwise 0
R3 = bytes overflow from special field buffer (ie required length if R3 = 0 on entry)
R4 = bytes overflow from special field buffer (ie required length if R4 = 0 on entry)
R5, R6 preserved

Details

This entry point is called by FileSwitch to convert the given special field and disc name to canonical (unique) forms. If no buffers are passed to hold the results, this call instead returns their required lengths, which gives FileSwitch a means of finding out this information.

FileSwitch uses this call to convert user-specified special field and disc names into a canonical (unique) form. Typically this call is used in two stages: the first to find out how much space is required in the buffers, and the second to do the conversion. For example, if a user specifies a file as NetFS#Arf:&.thing.whatsit, FileSwitch uses this call as follows:

R1 = pointer to the string 'Arf'
R2 = 0
R3 = 0
R4 = 0
R5 = any value (since R3 = 0)
R6 = any value (since R4 = 0)

NetFS returns these values:

R1 = any non-zero value
R2 = any non-zero value
R3 = required length of buffer to hold canonical special field (excluding any terminating null)
R4 = required length of buffer to hold canonical disc name (excluding any terminating null)
R5, R6 preserved

FileSwitch now allocates memory for two buffers of the lengths specified by NetFS in the R3 and R4 return values, then call NetFS again as follows:

R1 = pointer to the string 'Arf'
R2 = 0
R3 = pointer to a buffer of length R5 bytes
R4 = pointer to a buffer of length R6 bytes
R5 = length of buffer pointed to by R3
R6 = length of buffer pointed to by R4

NetFS now fills in the buffers: (R3,R5) with the special field, and (R4,R6) with the disc name. It returns:

R1 = R3 on entry (and the buffer is filled with '49.254')
R2 = R4 on entry (and the buffer is filled in with 'Arf')
R3, R4 = 0 (no overflows over the end of the buffers)
R5, R6 preserved

This entry point is not called by RISC OS 2, and is only otherwise called if bit 23 of the filing system information word is set.

FSEntry_Func 24

Resolve wildcard
On entry

R1 = pointer to directory pathname
R2 = pointer to buffer to hold resolved name, or 0 if none
R3 = pointer to wildcarded object name
R5 = length of buffer
R6 = pointer to special field if present, otherwise 0

On exit

R1 preserved
R2 = -1 if not found, else preserved
R3 preserved
R4 = -1 if FileSwitch should resolve this wildcard itself, else bytes overflow from buffer
R5 preserved

Details

This entry point is called by FileSwitch to find which object in the given directory matches the name given. If the filing system can not do a more efficient job than FileSwitch would if it were to use FSEntry_Func 14 and then to find which was the first match, then the filing system should just return with R4 = -1.

This entry point is not called by RISC OS 2, and is only otherwise called if bit 23 of the filing system information word is set.

FSEntry_Func 25 and ImageEntry_Func 25

Read defect list
On entry

R0 = 25
R1 = pointer to name of image (FSEntry_Func 25 only)
R2 = pointer to buffer
R5 = length of buffer
R6 = pointer to special field if present, otherwise 0 (FSEntry_Func 25); or image filing system's handle for image (ImageEntry_Func 25)

On exit

R0 - R6 preserved

Details

This entry point is called by FileSwitch to request that your filing system fills the given buffer with the byte offsets to the start of any defects in the specified image. The list must be terminated by the value &20000000.

It is an error if the specified image is not the root object in an image (eg it is an error to map out a defect from adfs::HardDisc4.$.fred, but not an error to map it out from adfs::HardDisc4.$).

This entry point is not called by RISC OS 2.

FSEntry_Func 26 and ImageEntry_Func 26

Add a defect
On entry

R0 = 26
R1 = pointer to name of image (FSEntry_Func 26 only)
R2 = byte offset to start of defect
R6 = pointer to special field if present, otherwise 0 (FSEntry_Func 26); or image filing system's handle for image (ImageEntry_Func 26)

On exit

R0 - R2, R6 preserved

Details

This entry point is called by FileSwitch to request that your filing system maps out the given defect from the specified image.

It is an error if the specified image is not the root object in an image (eg it is an error to map out a defect from adfs::HardDisc4.$.fred, but not an error to map it out from adfs::HardDisc4.$). If the defect cannot be mapped out because it is not free, then you should return an error.

This entry point is not called by RISC OS 2.

FSEntry_Func 27 and ImageEntry_Func 27

Read boot option
On entry

R0 = 27
R1 = pointer to pathname of any object on image (FSEntry_Func 27 only)
R6 = pointer to special field if present, otherwise 0 (FSEntry_Func 27); or image filing system's handle for image (ImageEntry_Func 27)

On exit

R0, R1, R6 preserved
R2 = boot option (as in *Opt 4,n)

Details

This entry point is called by FileSwitch to read the boot option (ie the value n in *Opt 4,n) of the image that holds the object specified by R1 (FSEntry_Func 27), or that is specified by the handle in R6 (ImageEntry_Func 27).

This entry point is not called by RISC OS 2.

FSEntry_Func 28 and ImageEntry_Func 28

Write boot option
On entry

R0 = 28
R1 = pointer to pathname of any object on image (FSEntry_Func 28 only)
R2 = new boot option
R6 = pointer to special field if present, otherwise 0 (FSEntry_Func 28); or image filing system's handle for image (ImageEntry_Func 28)

On exit

R0 - R2, R6 preserved

Details

This entry point is called by FileSwitch to request that your filing system writes the boot option (ie the value n in *Opt 4,n) of the image that holds the object specified by R1 (FSEntry_Func 28), or that is specified by the handle in R6 (ImageEntry_Func 28).

This entry point is not called by RISC OS 2.

FSEntry_Func 29 and ImageEntry_Func 29

Read used space map
On entry

R0 = 29
R1 = pointer to pathname of any object on image (FSEntry_Func 29 only)
R2 = pointer to buffer for map (pre-filled with 0s)
R5 = size of buffer
R6 = pointer to special field if present, otherwise 0 (FSEntry_Func 29); or image filing system's handle for image (ImageEntry_Func 29)

On exit

R0 - R2, R5, R6 preserved

Details

This entry point is called by FileSwitch to read the used space map for the image that holds the object specified by R1 (FSEntry_Func 29), or that is specified by the handle in R6 (ImageEntry_Func 29). It is used by the *Backup command to decide which sectors to copy.

Your filing system should fill the given buffer with 0 bits for unused blocks, and 1 bits for used blocks. The buffer must be filled to its limit, or to the image's limit, whichever is less. The 'perfect' size of the buffer can be calculated from the image's size and its block size (as returned from FSEntry_Open or ImageEntry_Open: see FSEntry_Open and ImageEntry_Open). The correspondence of the buffer to the file is 1 bit to 1 block. The least significant bit (bit 0) in a byte comes before the most significant bit.

This entry point is not called by RISC OS 2.

FSEntry_Func 30 and ImageEntry_Func 30

Read free space
On entry

R0 = 30
R1 = pointer to pathname of any object on image (FSEntry_Func 30 only)
R6 = pointer to special field if present, otherwise 0 (FSEntry_Func 30); or image filing system's handle for image (ImageEntry_Func 30)

On exit

R0 = free space
R1 = biggest object creatable
R2 = disc size

Details

This entry point is called by FileSwitch to read the free space for the image that holds the object specified by R1 (FSEntry_Func 30), or that is specified by the handle in R6 (ImageEntry_Func 30).

This entry point is not called by RISC OS 2.

FSEntry_Func 31 and ImageEntry_Func 31

Name image
On entry

R0 = 31
R1 = pointer to pathname of any object on image (FSEntry_Func 31 only)
R2 = pointer to new name of image
R6 = pointer to special field if present, otherwise 0 (FSEntry_Func 31); or image filing system's handle for image (ImageEntry_Func 31)

On exit

Registers preserved

Details

This entry point is called by FileSwitch to request that your filing system name the image that holds the object specified by R1 (FSEntry_Func 31), or that is specified by the handle in R6 (ImageEntry_Func 31).

This refers to the image's name (eg a disc name), rather than the name of the file containing that image.

This entry point is not called by RISC OS 2.

FSEntry_Func 32 and ImageEntry_Func 32

Stamp image
On entry

R0 = 32
R1 = pointer to pathname of any object on image (FSEntry_Func 32 only)
R2 = reason code
R6 = pointer to special field if present, otherwise 0 (FSEntry_Func 32); or image filing system's handle for image (ImageEntry_Func 32)

On exit

Registers preserved

Details

This entry point is called by FileSwitch to request that your filing system stamp the image that holds the object specified by R1 (FSEntry_Func 32), or that is specified by the handle in R6 (ImageEntry_Func 32). It is used for FileCore to communicate with an image filing system for the control and management of the disc Id of a given image. Valid values for R2 on entry are:

Value Meaning
0 stamp image on next update
1 stamp image now

To stamp an image the image's unique identification number should be updated to a different value. This value is used to distinguish between different images with the same name, and to determine when a given image has been updated. It should be filled in the disc record disc id field when the disc is originally identified. The kind of uses expected for these calls are:

  • When a Backup program wishes to cause a backup of the original to be distinguishable from the original it may use the 'stamp image now' form.

and, for ImageEntry_Func 32 only, the following two uses:

  • When FileCore notices that a given disc may have been removed from the drive it will call the image filing system (via FileSwitch) with the 'stamp image on next update' call. This informs the image filing system that when it next changes something in that image that it should also explicitly change the unique Id number (if possible). This so that if another machine saw the disc whilst it was removed, then the changed that other machine will be given a clue that the disc has since been changed by the Id number changing - the other machine will probably discard any cached data it has as none of it could be trusted to still be accurate. Once the Id has been updated once there is no further need to update it on an update unless, of course, a further 'stamp image on next update' occurs.
  • When FileCore is explicitly requested to stamp a disc it will use the 'stamp image now' call to get the message through to the relevant image filing system.

This entry point is not called by RISC OS 2.

FSEntry_Func 33 and ImageEntry_Func 33

Get usage of offset
On entry

R0 = 33
R1 = pointer to pathname of any object on image (FSEntry_Func 33 only)
R2 = byte offset into image
R3 = pointer to buffer to receive object name (if object found)
R4 = length of buffer
R6 = pointer to special field if present, otherwise 0 (FSEntry_Func 33); or image filing system's handle for image (ImageEntry_Func 33)

On exit

R2 = kind of object found at offset:

0 - no object found; offset is free/a defect/beyond end of image
1 - no object found; offset is allocated, but not free/a defect/beyond end of image
2 - object found; cannot share the offset with other objects
3 - object found; can share the offset with other objects
Details

This entry point is called by FileSwitch to find the usage of the given offset within the image that holds the object specified by R1 (FSEntry_Func 33), or that is specified by the handle in R6 (ImageEntry_Func 33). If the offset is free, a defect or outside the image then you should return with R2 = 0. If the offset is used, but has no object name which corresponds to it (for example the free space map, FAT tables, boot block and the such), then return with R2 = 1. If the given offset is associated with only one object (such that deleting that object would definitely free the given offset), then you should return with R2 = 2. If the offset is associated with several objects (files/directories), but cannot be said to be associated with one only (for example, the disc may have one large section allocated which is used by several files within one directory), then return with R2 = 3.

You may corrupt the buffer during the search and, if you find an object (ie R2 = 2 or 3), you should return its pathname in the buffer. The pathname should not have a '$' prefix, but the first path element should have a '.' prefix, eg:

.a.b.c.d

rather than:

a.b.c.d

This entry point is not called by RISC OS 2.

FSEntry_Func 34

Notification of changed directory
On entry

R1 = pointer to null-terminated directory name
R2 = changed directory (0 => CSD_ 1 => PSD_ 2 => URD_ 3 => Lib)
R6 = pointer to special field if present, otherwise 0

On exit

R1, R2, R6 preserved

Details

This entry point is provided so that filing systems can optimise their handling of directory caches. It is called when FileSwitch has successfully changed a directory, as indicated by R2.There is no reason for a filing system to have these directories stored, but even if it does it should not change its record of the directory; instead it should use this information to help it decide which directories to cache, and which not to.

FSEntry_GBPB

Get/put bytes from/to an unbuffered file

This entry point is used to implement multiple get byte and put byte operations on unbuffered files. It is only ever called if you set bit 28 of the file information word on return from FSEntry_Open, and you need not otherwise provide it. FileSwitch will instead use multiple calls to FSEntry_PutBytes and FSEntry_GetBytes to implement these operations.

FSEntry_GBPB 1 and 2

Put multiple bytes to an unbuffered file
On entry

R0 = 1 or 2
R1 = file handle used by your filing system
R2 = pointer to buffer
R3 = number of bytes to put to file
If R0 = 1

R4 = sequential file pointer to use for start of block

On exit

R0, R1 preserved
R2 = address of byte after the last one transferred from buffer
R3 = number of bytes not transferred
R4 = initial file pointer + number of bytes transferred

Details

This entry point is called by FileSwitch to request that your filing system transfer data from memory to the file at either the specified file pointer (R0 = 1), or the current one (R0 = 2). If the specified pointer is beyond the end of the file, then you must fill the file with zeros between the current file extent and the specified pointer before the bytes are transferred.

The file handle is guaranteed by FileSwitch not to be a directory, and to have had write access granted at the time of the open.

FSEntry_GBPB 3 and 4

Read bytes from an open file
On entry

R0 = 3 or 4
R1 = file handle used by your filing system
R2 = pointer to buffer
R3 = number of bytes to get from file
If R0 = 3

R4 = sequential file pointer to use for start of block

On exit

R0, R1 preserved
R2 = address of byte after the last one transferred to buffer
R3 = number of bytes not transferred
R4 = initial file pointer + number of bytes transferred

Details

This entry point is called by FileSwitch to request that your filing system transfer data from a file to memory, either from the specified file pointer (R0 = 3), or from the current one (R0 = 4).

If the specified pointer is greater than or equal to the current file extent then you must not update the sequential file pointer, nor must you return an error.

The file handle is guaranteed by FileSwitch not to be a directory and to have had read access granted at the time of the open.

Your filing system must not try to keep its own EOF-error-on-next-read flag - instead it is FileSwitch's responsibility to keep the EOF-error-on-next-read flag. Unlike FSEntry_GetBytes, FileSwitch will set the C bit before it returns to its caller if your filing system returns a non-zero value in R3 - so your filing system need not handle this either.

Example program

This code fragment is an optimised routine for moving blocks of memory. It could be further enhanced to take advantage of the higher speed of memory access given by the MEMC chip if LDM and STM instructions are quad-word aligned. You should find this useful when writing your own filing systems, as efficient transfer code is crucial to the performance of a filing system.

; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; MoveBytes(source, dest, size in bytes) - fast data copier from RCM
; =========
; SKS Reordered registers and order of copying to suit FileSwitch
; **Not yet optimised to do transfers to make most of 1N,3S feature of MEMC**
; extern void MoveBytes(void *source, void *destination, size_t count);
; In:   r1 = src^ (byte address)
;       r2 = dst^ (byte address)
;       r3 = count (byte count - never zero!)
; Out:  r0-r3, lr corrupt. Flags preserved
mbsrc1          RN 0
mbsrcptr        RN 1
mbdstptr        RN 2
mbcnt           RN 3
mbsrc2          RN 14                           ; Note deviancy, so care in LDM/STM
mbsrc3          RN 4
mbsrc4          RN 5
mbsrc5          RN 6
mbsrc6          RN 7
mbsrc7          RN 8
mbsrc8          RN 9
mbsrc9          RN 10
mbshftL         RN 11                           ; These two go at end to save a word
mbshftR         RN 12                           ; and an extra Pull lr!
sp              RN 13
lr              RN 14
pc              RN 15
MoveBytes ROUT
        STMDB   sp!, {lr}
        TST     mbdstptr, #3
        BNE     MovByt100                       ; [dst^ not word aligned]
MovByt20                                        ; dst^ now word aligned.
                                                ; branched back to from below
        TST     mbsrcptr, #3
        BNE     MovByt200                       ; [src^ not word aligned]
; src^ & dst^ are now both word aligned
; count is a byte value (may not be a whole number of words)
; Quick sort out of what we've got left to do
        SUBS    mbcnt, mbcnt, #4*4              ; Four whole words to do (or more) ?
        BLT     MovByt40                        ; [no]
        SUBS    mbcnt, mbcnt, #8*4-4*4          ; Eight whole words to do (or more) ?
        BLT     MovByt30                        ; [no]
        STMDB   sp!, {mbsrc3-mbsrc8}            ; Push some more registers
MovByt25
        LDMIA   mbsrcptr!, {mbsrc1, mbsrc3-mbsrc8, mbsrc2} ; NB. Order!
        STMIA   mbdstptr!, {mbsrc1, mbsrc3-mbsrc8, mbsrc2}
        SUBS    mbcnt, mbcnt, #8*4
        BGE     MovByt25                        ; [do another 8 words]
        CMP     mbcnt, #-8*4                    ; Quick test rather than chaining down
        LDMEQDB sp!, {mbsrc3-mbsrc8, pc}^       ; [finished]
        LDMDB   sp!, {mbsrc3-mbsrc8}
MovByt30
        ADDS    mbcnt, mbcnt, #8*4-4*4          ; Four whole words to do ?
        BLT     MovByt40
        STMDB   sp!, {mbsrc3-mbsrc4}            ; Push some more registers
        LDMIA   mbsrcptr!, {mbsrc1, mbsrc3-mbsrc4, mbsrc2} ; NB. Order!
        STMIA   mbdstptr!, {mbsrc1, mbsrc3-mbsrc4, mbsrc2}
        LDMEQDB sp!, {mbsrc3-mbsrc4, pc}^       ; [finished]
        LDMDB   sp!, {mbsrc3-mbsrc4}
        SUB     mbcnt, mbcnt, #4*4
MovByt40
        ADDS    mbcnt, mbcnt, #4*4-2*4          ; Two whole words to do ?
        BLT     MovByt50
        LDMIA   mbsrcptr!, {mbsrc1, mbsrc2}
        STMIA   mbdstptr!, {mbsrc1, mbsrc2}
        LDMEQDB sp!, {pc}^                      ; [finished]
        SUB     mbcnt, mbcnt, #2*4
MovByt50
        ADDS    mbcnt, mbcnt, #2*4-1*4         ; One whole word to do ?
        BLT     MovByt60
        LDR     mbsrc1, [mbsrcptr], #4
        STR     mbsrc1, [mbdstptr], #4
        LDMEQDB sp!, {pc}^                      ; [finished]
        SUB     mbcnt, mbcnt, #1*4
MovByt60
        ADDS    mbcnt, mbcnt, #1*4-0*4          ; No more to do ?
        LDMEQDB sp!, {pc}^                      ; [finished]
        LDR     mbsrc1, [mbsrcptr]              ; Store remaining 1, 2 or 3 bytes
MovByt70
        STRB    mbsrc1, [mbdstptr], #1
        MOV     mbsrc1, mbsrc1, LSR #8
        SUBS    mbcnt, mbcnt, #1
        BGT     MovByt70
        LDMDB   sp!, {pc}^                      ; [finished]
; Initial dest^ not word aligned. Loop doing bytes (1,2 or 3) until it is
MovByt100
        LDRB    mbsrc1, [mbsrcptr], #1
        STRB    mbsrc1, [mbdstptr], #1
        SUBS    mbcnt, mbcnt, #1
        LDMEQDB sp!, {pc}^                      ; [finished after 1..3 bytes]
        TST     mbdstptr, #3
        BNE     MovByt100
        B       MovByt20                        ; Back to mainline code
MovByt200 ; dst^ now word aligned, but src^ isn't. just lr stacked here
        STMDB    sp!, {mbshftL, mbshftR}        ; Need more registers this section
        AND     mbshftR, mbsrcptr, #3           ; Offset
        BIC     mbsrcptr, mbsrcptr, #3          ; Align src^
        MOV     mbshftR, mbshftR, LSL #3        ; rshft = 0, 8, 16 or 24 only
        RSB     mbshftL, mbshftR, #32           ; lshft = 32, 24, 16 or 8  only
        LDR     mbsrc1, [mbsrcptr], #4
        MOV     mbsrc1, mbsrc1, LSR mbshftR     ; Always have mbsrc1 prepared
; Quick sort out of what we've got left to do
        SUBS    mbcnt, mbcnt, #4*4              ; Four whole words to do (or more) ?
        BLT     MovByt240                       ; [no]
        SUBS    mbcnt, mbcnt, #8*4-4*4          ; Eight whole words to do (or more) ?
        BLT     MovByt230                       ; [no]
        STMDB   sp!, {mbsrc3-mbsrc9}            ; Push some more registers
MovByt225
        LDMIA   mbsrcptr!, {mbsrc3-mbsrc9, mbsrc2} ; NB. Order!
        ORR     mbsrc1, mbsrc1, mbsrc3, LSL mbshftL
        MOV     mbsrc3, mbsrc3, LSR mbshftR
        ORR     mbsrc3, mbsrc3, mbsrc4, LSL mbshftL
        MOV     mbsrc4, mbsrc4, LSR mbshftR
        ORR     mbsrc4, mbsrc4, mbsrc5, LSL mbshftL
        MOV     mbsrc5, mbsrc5, LSR mbshftR
        ORR     mbsrc5, mbsrc5, mbsrc6, LSL mbshftL
        MOV     mbsrc6, mbsrc6, LSR mbshftR
        ORR     mbsrc6, mbsrc6, mbsrc7, LSL mbshftL
        MOV     mbsrc7, mbsrc7, LSR mbshftR
        ORR     mbsrc7, mbsrc7, mbsrc8, LSL mbshftL
        MOV     mbsrc8, mbsrc8, LSR mbshftR
        ORR     mbsrc8, mbsrc8, mbsrc9, LSL mbshftL
        MOV     mbsrc9, mbsrc9, LSR mbshftR
        ORR     mbsrc9, mbsrc9, mbsrc2, LSL mbshftL
        STMIA   mbdstptr!, {mbsrc1, mbsrc3-mbsrc9}
        MOV     mbsrc1, mbsrc2, LSR mbshftR     ; Keep mbsrc1 prepared
        SUBS    mbcnt, mbcnt, #8*4
        BGE     MovByt225                       ; [do another 8 words]
        CMP     mbcnt, #-8*4                    ; Quick test rather than chaining down
        LDMEQDB sp!, {mbsrc3-mbsrc9, mbshftL, mbshftR, pc}^ ; [finished]
        LDMDB   sp!, {mbsrc3-mbsrc9}
MovByt230
        ADDS    mbcnt, mbcnt, #8*4-4*4          ; Four whole words to do ?
        BLT     MovByt240
        STMDB   sp!, {mbsrc3-mbsrc5}            ; Push some more registers
        LDMIA   mbsrcptr!, {mbsrc3-mbsrc5, mbsrc2} ; NB. Order!
        ORR     mbsrc1, mbsrc1, mbsrc3, LSL mbshftL
        MOV     mbsrc3, mbsrc3, LSR mbshftR
        ORR     mbsrc3, mbsrc3, mbsrc4, LSL mbshftL
        MOV     mbsrc4, mbsrc4, LSR mbshftR
        ORR     mbsrc4, mbsrc4, mbsrc5, LSL mbshftL
        MOV     mbsrc5, mbsrc5, LSR mbshftR
        ORR     mbsrc5, mbsrc5, mbsrc2, LSL mbshftL
        STMIA   mbdstptr!, {mbsrc1, mbsrc3-mbsrc5}
        LDMEQDB sp!, {mbsrc3-mbsrc5, mbshftL, mbshftR, pc}^ ; [finished]
        LDMDB   sp!, {mbsrc3-mbsrc5}
        SUB     mbcnt, mbcnt, #4*4
        MOV     mbsrc1, mbsrc2, LSR mbshftR     ; Keep mbsrc1 prepared
MovByt240
        ADDS    mbcnt, mbcnt, #2*4              ; Two whole words to do ?
        BLT     MovByt250
        STMDB   sp!, {mbsrc3}                   ; Push another register
        LDMIA   mbsrcptr!, {mbsrc3, mbsrc2}     ; NB. Order!
        ORR     mbsrc1, mbsrc1, mbsrc3, LSL mbshftL
        MOV     mbsrc3, mbsrc3, LSR mbshftR
        ORR     mbsrc3, mbsrc3, mbsrc2, LSL mbshftL
        STMIA   mbdstptr!, {mbsrc1, mbsrc3}
        LDMEQDB sp!, {mbsrc3, mbshftL, mbshftR, pc}^ ; [finished]
        LDMDB   sp!, {mbsrc3}
        SUB     mbcnt, mbcnt, #2*4
        MOV     mbsrc1, mbsrc2, LSR mbshftR     ; Keep mbsrc1 prepared
MovByt250
        ADDS    mbcnt, mbcnt, #2*4-1*4          ; One whole word to do ?
        BLT     MovByt260
        LDR     mbsrc2, [mbsrcptr], #4
        ORR     mbsrc1, mbsrc1, mbsrc2, LSL mbshftL
        STR     mbsrc1, [mbdstptr], #4
        LDMEQDB sp!, {mbshftL, mbshftR, pc}^    ; [finished]
        SUB     mbcnt, mbcnt, #1*4
        MOV     mbsrc1, mbsrc2, LSR mbshftR     ; Keep mbsrc1 prepared
MovByt260
        ADDS    mbcnt, mbcnt, #1*4-0*4
        LDMEQDB sp!, {mbshftL, mbshftR, pc}^    ; [finished]
        LDR     mbsrc2, [mbsrcptr]              ; Store remaining 1, 2 or 3 bytes
        ORR     mbsrc1, mbsrc1, mbsrc2, LSL mbshftL
MovByt270
        STRB    mbsrc1, [mbdstptr], #1
        MOV     mbsrc1, mbsrc1, LSR #8
        SUBS    mbcnt, mbcnt, #1
        BGT     MovByt270
        LDMDB   sp!, {mbshftL, mbshftR, pc}^
; ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        END

This edition Copyright © 3QD Developments Ltd 2015
Last Edit: Tue,03 Nov 2015