Author: | Aaron Digulla |
---|---|
Copyright: | Copyright © 2001, The AROS Development Team |
Version: | 45860 |
Date: | 2012-10-04 |
Note
This document is currently only a draft and as such will most likely change before it is accepted as an official specification. It might also be deprecated if a better approach has been found in the mean time, and doesn't necessarily correspond precisely with the current implementations.
As an application programmer you don't have to worry about the file system interface -- you can do everything you want via simple calls to DOS. However you may need to know how to interface with a file system if you:
Of the above the most useful of these would be doing asynchronous I/O, although it is in many cases better to use one of the publicly available libraries to do this, as that will hide from you the file systems' implementation details.
The interface to the file systems under AROS differs from that under AmigaOS in many ways:
Obviously this change renders the file system incompatible to the current AmigaOS file systems and DOS implementation. However it should be possible to build a bridge between the file systems if necessary.
The major API-change of file systems is that they now use the Exec Device API. You can use the normal device functions (DoIO(), AbortIO(), etc.). The I/O Request structure is defined in dos/file systems.h:
/* IORequest from <exec/io.h> */ struct IORequest { struct Message io_Message; struct Device *io_Device; /* file system base pointer */ struct Unit *io_Unit; /* file or directory handle */ UWORD io_Command; /* the command */ UBYTE io_Flags; /* normal device flags (IOF_QUICK) */ BYTE io_Error; /* error code from device functions */ }; struct IOFileSys { struct IORequest IOFS; LONG io_DosError; /* secondary error code (IoErr()) */ union {} io_Union; /* arguments - command dependent */ };
The io_DosError field is used to return the secondary error code to the caller. This is the code that is returned by the dos.library function IoErr(). The io_Error`field of `struct IORequest should only be used to return a simple failure/success for file system commands, and should have the normal effect for the device open/close commands.
The io_Union field is an union containing different structures for each of the commands. This field has a variable length depending upon the command. The fields listed in the "Input" sections of the autodocs below refer to a specific member of this union.
OpenDevice("*.handler", 0, iofs, 0);
Mount a new file system. The IOFileSys structure passed in iofs to the handler should contain enough information for the handler to mount the file system.
If a volume is mounted in this device, it's the responsibility of the handler to add the required volume nodes to the DOS device list before returning to the caller. Note here, that the DOS device list is already locked, so you do not need to lock it yourself.
The file system must return a handle to the device in the io_Unit pointer of the struct IOFileSys. The io_Error and io_DosError fields should be set appropriately for success or failure.
The union field io_OpenDevice is being used. Fill it with these values:
CloseDevice()
Try to dismount a DOS device. If there are any mounted volumes in the device, the file system should remove them from the DOS device list. Note that the DOS device list will have already been locked by the caller, so you will not have to do this yourself.
You should not dismount the device if there are open files or outstanding locks remaining.
The DOS device shall be dismounted if possible.
FSA_OPEN
Create a handle to an existing file or directory. You can use this handle to read directories or read/write files.
The filename io_Args[0] is relative to the path of the directory associated with the handle io_Unit. If io_Unit is NULL however, the filename should be taken as relative to the root directory of the device.
This command uses the io_Union.io_OPEN member.
Mode to open with:
FSA_CLOSE - close an open file
Close a file or directory handle. You should write out any buffered data before returning. It is the responsibility of the file system to free the data pointed to by io_Unit.
FSA_READ
Try and read the requested number of bytes from the file handle. A handler will normally try and fulfil the request completely, but special handlers (such as the console) may return less than the requested number of bytes.
If you reach the end of the file, you should return the number of bytes read in the current attempt. On the next call you should return 0 for EOF. Any further attempts to read should result in a return of -1 with an error code.
This function uses the io_Union.io_READ_WRITE field.
The buffer io_Buffer should contain some data if it was possible to read any.
FSA_WRITE - Write to a file
Try to write the requested number of bytes to the file handle. A handler should try and fulfil the request completely, but special handlers may write less than the requested number of bytes.
If you cannot write any bytes return 0 in io_Length.
This command uses the io_Union.io_READ_WRITE member.
The contents of the buffer should have been written to the stream.
FSA_SEEK - Seek within a file.
This command shall change the position of the next read or write in the file. The command will also return the old position in the file.
FIXME: Error condition for seeking before the start, or after the end of file.
This command uses the io_Union.io_SEEK member.
A command with io_Offset == 0, and io_SeekMode == OFFSET_CURRENT is a NOP in terms of seeking and will simply return the current file position.
mode
FSA_SET_FILE_SIZE - Set the size of a file.
Change the size of a file.
If the old file size is less than the new size, then the file is simply truncated. If the file is made larger, then the data contained in the new section is invalid.
This command uses the io_Union.io_SEEK member.
mode
Not all handlers will support this command.
FSA_WAIT_CHAR - wait for a character to arrive
This command will wait for a character to be ready for reading. You should only wait for a maximum of io_Timeout microseconds. If io_Timeout is 0, then you should wait indefinitely.
This command can be used on both plain files and interactive files. For plain files it should return immediately, unless for some reason there is no data available (a PIPE or a network file where there is no data yet).
This command uses the io_Union.io_WAIT_CHAR member.
FSA_FILE_MODE - set the mode of a file
Apply a new mode to the file. This command uses a mask to define which of the modes should be changed. Supplying a mask of 0 will return the current set of modes.
This command uses the io_Union.io_FILE_MODE member.
The modes should be set to those described by the mask and mode flags.
FSA_IS_INTERACTIVE - is this file a terminal
Query the file system as to whether this file is a interactive terminal.
This function uses the io_Union.io_IS_INTERACTIVE member.
FSA_SAME_LOCK - are two locks the same?
This function will compare two locks, and return whether the refer to the same object in the file system.
This command uses the io_Union.io_SAME_LOCK member.
FSA_EXAMINE - examine a file or directory
This command will obtain information about the current file or directory and return it in the ExAllData structure passed in.
Passing file systems the FileInfoBlock structure is not supported, as that has limits upon the size of paths. The AROS dos.library will handle the translation between the two structures.
You need only return the information requested, which is determined by the value in io_Mode.
This command uses the io_Union.io_EXAMINE.
FSA_EXAMINE_ALL - Examine the contents of a directory
Read the directory information of the current file or directory. If the handle is for a file, then you need only fill in the information for that file. You need only fill in the information requested by the caller.
You should continue filling in information in the buffer until you run out of space. The ed_Next fields of the ExAllData structure are used to link the entries together. The last entry should have ed_Next = NULL. Entries should be aligned to the size of the system pointer datatype.
If io_DosError != 0, then the contents of the buffer is undefined. If you need space to store filenames, comments strings, etc. these should be placed at the end of the buffer.
FSA_EXAMINE_ALL_END - Finish examining a number of files.
Finish examining a number of objects in the file system. This is used to reset the file systems internal state if required.
This command does not use the io_Union field.
FSA_OPEN_FILE
Open a handle for a file, creating the file if necessary. This command only works on files, not directories.
Open a handle for a file, creating the file if necessary. Thee io_Filename field gives the name of the file, which is relative to the handle passed in io_Unit. If the io_Unit handle is NULL, then the file is relative to the root of the directory tree.
This command also allows you to change the protection bits of the file.
mode to open with:
FSA_CREATE_DIR - Create a new directory
This command tells the file system to create a new directory, lock it, and return a handle to the lock. The directory should be created with the modes given in io_Args[1].
FIXME: Is the lock read or write?
The lock should be relative to the handle in io_Unit, or to the root directory if io_Unit == NULL.
The requested directory exists, if it could be created.
FSA_CREATE_HARDLINK - Create a hard link to a file.
Create a hard link to a file. There is no difference between a hard link and its original file. If the original file is deleted, the data will still exist because of the link.
Hard links can not point across devices.
This command uses the io_Union.io_CREATE_HARDLINK member.
A hard link will have been created, if possible.
FSA_CREATE_SOFTLINK - Create a soft link to a file.
Create a soft link to a file. There is a difference between a soft link and its original file. If the original file is deleted, the soft link will no longer be valid (but it will not be deleted).
As soft links are stored as the filename of the link to file, they can be used across devices. This means that the filename stored must be an absolute filename, as the current directory will be unknown at read time.
This command uses the io_Union.io_CREATE_SOFTLINK member.
A soft link will have been created if possible.
FSA_RENAME - Rename an object in the file system
Rename an object in the file system. This function may be called on a file which doesn't exist. The filenames specified should be considered relative to io_Unit which specifies the current directory (or NULL for the root directory).
Renaming a directory is equivalent to moving the entire contents of the directory.
This command uses the io_Union.io_RENAME member.
FSA_READ_SOFTLINK - Read the name of a soft-linked file.
This command will read the name of the file referenced by file io_Unit. The filename returned is an absolute filename.
This command uses the io_Union.io_READ_SOFTLINK member.
The buffer io_Buffer will contain the absolute filename that this link refers to.
FSA_DELETE_OBJECT - Delete an object from the file system
Delete a given file or directory. It is illegal to try and delete a directory which contains files - you should return ERROR_DIRECTORY_NOT_EMPTY if an attempt is made.
Files with outstanding handles cannot be deleted.
If the io_Unit handle is NULL, the file to delete is relative to the root of the file system.
FSA_SET_COMMENT - Set the comment of an object
Set a new comment for a file or directory. The maximum length for a comment has historically been 80 characters (including NULL termination).
FSA_SET_PROTECT - Set protection bits for a file
Set the protection bits on a file or directory. Note that there are four groups of protection bits:
You should note that the owner bits are handled a bit strangely as they are active low (i.e. 0 means enabled/set).
Note that if io_Unit is valid (i.e. non-NULL) and io_Args[0] is NULL, then you should change the mode of the object described by the io_Unit handle.
FSA_SET_OWNER - Set the owner of a file
This command allows a user to set the ownership of files. The file should be changed to reflect the new owner of the directory.
The owner and group fields in the arguments are interpreted as 32-bit values, however in general, they will only be 16-bit values. If the values are outside the 16-bit range, and you are unable to handle the values then you can return an error. The ERROR_BAD_NUMBER appears to be the most appropriate error number.
Special User ID's:
0 | root/Supervisor |
-1 | No owner (0x0000FFFF or 0xFFFFFFFF) |
Special Group ID's:
0 | wheel/Supergroup |
-1 | No group (0x0000FFFF or 0xFFFFFFFF) |
Typically AmigaOS file systems have had little multi-user support, and it should be expected that few file systems will actually support this command. For security reasons, only the superuser or the owner of a file should be allowed to change the ownership.
FSA_SET_DATE - Set the date of a file/directory
Set the modification date of a file or directory. If the file system does not support the date, for example if it's too old, then you should return ERROR_BAD_NUMBER. It should not be possible to set the creation date of an object (except by creating it).
FSA_IS_FILESYSTEM - Ask the file system handler whether it's a file system
Query the file system as to whether it is a proper file system. An example of something that is not a file system is a device handler, like PAR:.
This command uses the io_Union.io_IS_FILESYSTEM member.
None.
FSA_MORE_CACHE - Add more cache buffers to the file system.
Add the number io_NumBuffers of cache buffers to the file system. The size of the buffer should have been given during the initial file system open.
If the number of buffers is negative, then the result will be to remove buffers from the device. You can not have less than 0 buffers.
This command uses the io_Union.io_MORE_CACHE member.
The number of buffers will have been altered if possible.
FSA_FORMAT - Initialise a file system
Initialise a device to be used by this file system. The device media should have already been initialised, and this command simply gets the file system to write its own data.
This command uses the io_Union.io_FORMAT member.
The file system will have been initialised, and is ready for mounting.
FSA_MOUNT_MODE
Change or read the mount modes of the volume passed in io_Unit. The mask is used to select which modes are to be changed.
This command uses the io_Union.io_MOUNT_MODE member.