Device: File

The file devices provide access to heirarchical file-oriented persistent storage.

PortNameDescriptionReadWrite
0xA0EntryOpen a filesystem entry.
0xA1ActionPerform a filesystem action.
0xA2PathPath of the open entry.
0xA3TypeType of the open entry.
0xA4HeadRead and write to the open file.
0xA5aliasedaliased
0xA6Child pathPath of the selected child entry.
0xA7Child typeType of the selected child entry.
0xA8PointerPointer into the open entry.
0xA9continuedcontinued
0xAAcontinuedcontinued
0xABcontinuedcontinued
0xACLengthLength of the open entry.
0xADcontinuedcontinued
0xAEcontinuedcontinued
0xAFcontinuedcontinued
PortNameDescriptionReadWrite
0xB0EntryOpen a filesystem entry.
0xB1ActionPerform a filesystem action.
0xB2PathPath of the open entry.
0xB3TypeType of the open entry.
0xB4HeadRead and write to the open file.
0xB5aliasedaliased
0xB6Child pathPath of the selected child entry.
0xB7Child typeType of the selected child entry.
0xB8PointerPointer into the open entry.
0xB9continuedcontinued
0xBAcontinuedcontinued
0xBBcontinuedcontinued
0xBCLengthLength of the open entry.
0xBDcontinuedcontinued
0xBEcontinuedcontinued
0xBFcontinuedcontinued

The devices specification specifies two identical but independent file devices. The first file device is called the primary file device, and the second file device is called the secondary file device. On host systems where no more than one filesystem entry can be open at any one time, only the primary file device will be available. The behaviour when opening a file on one file device while the same file is open on the other file device is implementation defined.

Concepts

Paths

A filesystem path identifies a filesystem entry.

Bedrock defines the concept of a Bedrock-encoding for path in order to facilitate interoperability across a vast range of incompatible filesystems. This is contrasted with a host-encoding for paths, which is the path encoding used by the host system.

A Bedrock-encoded path is a non-empty UTF-8 encoded bytestring no greater than 255 bytes in length, with the first byte being the forward-slash character 0x2F, and the path component separator being the forward-slash character 0x2F. Directory paths are not terminated by a trailing forward-slash character. The root directory of a filesystem is represented as a bytestring of length 1 containing the forward-slash character 0x2F. Empty path components are invalid. Relative path components are invalid. Components are absolute and will not be expanded.

In most cases, the filesystem used by the host system will use a different encoding to Bedrock, and paths will need to be translated between host-encoding and Bedrock-encoding. Any path which cannot be Bedrock-encoded is invalid. Any filesystem entry which is identified by an invalid path will be unable to be opened, will be omitted from directory listings, and will be unable to be created, moved, or deleted. The mapping between a host-encoded path and a Bedrock-encoded path is implementation defined.

A path buffer is a 255-byte buffer which contains the bytes representing a Bedrock-encoded path. TODO: Elaborate on this. invalid if full

Entries

A filesystem entry is a file or directory stored in the filesystem. A file contains a block of memory, and a directory contains a collection of files.

If the host filesystem supports symbolic links, these links will be treated as regular files and directories. Symbolic links cannot be created. Move and delete operations will affect the link, not the linked entry. The path will be the path of the link, not the linked entry. The type will be the type of the linked entry. The parent directory will be the parent directory of the link, not the linked file. The parent directory of a child entry of a linked directory will be the parent of the link, not the linked entry.

A filesystem entry is either a file or a directory. Initially, no entry will be open.

Children

TODO: currently selected child entry

TODO: child entries in general

The sort order of child entries in a directory is implementation defined. The sort order must not change while a directory is open. If it is possible to define a custom sort order, directories should be sorted before files, and then entries should be sorted in ascending case-insensitive order. TODO: Define this more rigorously

TODO: The order of child entries in a directory should be calculated when the directory is opened and cached until the directory is closed.

Ports

Entry

This port is associated with a path buffer.

Reading a byte from this port will return the value 0xFF if an entry is currently open, and will return zero otherwise. Initially, no entry will be open.

Writing a non-zero byte to this port will append that byte to the path buffer associated with this port.

Writing a zero byte to this port will close the current entry and then will attempt to open an entry. The entry at the path represented by the contents of the path buffer associated with this port will be opened if it exists, then the path buffers associated with this port and the action port will be cleared, and then the value of the pointer port will be set to zero. The entry will be opened for both reading and writing, if supported by the host system.

If the current entry is moved or deleted by an external process, it will remain open, but all operations on the entry will fail.

Action

This port is associated with a path buffer.

Reading a byte from this port will return the value 0xFF if the most recent filesystem operation succeeded, and will return 0x00 otherwise. Filesystem operations are performed when writing a zero byte to the entry port, writing a zero byte to the action port, writing to the type port, writing to the child type port, writing to the length port, and reading or writing from a head port. After a head port is read from or written to, each subsequent operation of the same type will only set the success value on failure.

Writing a non-zero byte to this port will append that byte to the path buffer associated with this port.

Writing a zero byte to this port will attempt to perform a filesystem action. If an entry is currently open, the current entry and children will be moved to the path represented by the contents of the path buffer associated with this port, if no entry already exists at that path. If the path buffer associated with this port is empty, the current entry and children will instead be deleted. If no entry is currently open, an empty file will be created at the path represented by the contents of the path buffer associated with this port, if no entry already exists at that path. Intermediate directories are created as needed when moving an entry or creating an empty file. The current entry will then be closed, the path buffers associated with this port and the entry port will be cleared, and then the value of the pointer port will be set to zero.

Path

Reading a byte from this port while an entry is currently open will return the next byte of the Bedrock-encoded path of the current entry. Each subsequent read of this port past the end of the path will return zero.

Reading a byte from this port while no entry is currently open will return zero.

Writing a non-zero byte to this port while an entry is currently open will set the index of the next byte to be returned to the index of the byte which directly follows the last occurrence of byte 0x2F, representing a forward-slash character. If the path of the current entry does not contain a forward-slash character, the index of the next byte to be returned will be zero.

Writing a zero byte to this port while an entry is currently open will set the index of the next byte to be returned to zero.

Writing a byte to this port while no entry is currently open will have no effect.

After an entry is opened, the index of the next byte to be returned will be set to zero.

Type

Reading a byte from this port will return the value 0xFF if the current entry is a directory, and will return zero otherwise.

Writing a byte to this port while an entry is currently open will attempt to open the parent directory of the current entry. If this fails, or if the current entry is the root directory of the filesystem, the current entry will remain open.

TODO: Clear path buffers? Set pointer to zero?

Writing a byte to this port while no entry is open will attempt to open the default directory. The default directory is the directory from which the Bedrock system was booted, otherwise it is the directory designated as the home directory of the system user, otherwise it is the root directory of the filesystem.

Reading a byte from either port of the pair while the current entry is a file will return the value of the file byte addressed by the value of the pointer port, and then will increment the value of the pointer port by 1. The value of the pointer port on overflow is implementation defined. When the value of the pointer port is equal to or greater than the value of the length port, the value returned will be zero.

Reading a byte from either port while no file is open will return zero.

Writing a byte to either port of the pair while the current entry is a file will set the value of the file byte addressed by the value of the pointer port to the value of the byte written, and then will increment the value of the pointer port by 1. The value of the pointer port on overflow is implementation defined. When the value of the pointer port is equal to or greater than the value of the length port, the file will first be resized to a length equal to one less than the value of the pointer port. The initial value of each byte added to the file by the resize operation is zero.

Writing a byte to either port while no file is open will have no effect.

Child path

Reading a byte from this port while the current entry is a directory and a child entry is selected will return the next byte of the Bedrock-encoded path of the currently selected child entry. Each subsequent read of this port past the end of the path will return zero.

Reading a byte from this port while no child entry is selected or while no directory is open will return zero.

Writing a non-zero byte to this port will set the index of the next byte to be returned to be that of the byte which directly follows the last occurrence of byte 0x2F, representing a forward-slash character. If the path of the currently selected child entry does not contain a forward-slash character, the index of the next byte to be returned will be zero.

Writing a zero byte to this port will set the index of the next byte to be returned to zero.

Writing a byte to this port while no child entry is selected or while no directory is open will have no effect.

After an entry is opened or a child entry is selected, the index of the next byte to be returned will be set to zero.

Child type

Reading a byte from this port will return the value 0xFF if the current entry is a directory and the currently selected child entry is a directory, and will return zero otherwise.

Writing a byte to this port while the current entry is a directory will attempt to open the currently selected child entry. If this fails. or if no child entry is selected, or if no directory is open, the current entry will remain open.

TODO: Clear path buffers? Set pointer to zero?

Writing a byte to this port while no entry is open will have no effect.

Pointer

The value of this port is a 32-bit value representing the currently-selected element of the current entry. While the current entry is a file, the value of this port is equal to the address of the next byte of the file to be read from by a read operation or written to by a write operation. While the current entry is a directory, the value of this port is equal to the index of the currently-selected child entry of the directory. While no entry is open, the value of this port is zero.

TODO: Writing to either of the four ports will set the corresponding byte of a 32-bit cached value. When the final port is written to, the value of this port will be set equal to the value of this cached value, and then the name and type ports will be populated if a directory is open. I’m missing better language for 32-bit values and for cached reads/writes. I need to define cached reads/writes on a cover page, and maybe read/write values too.

After an entry is opened or closed, the value of this port will be set to zero.

Length

The value of this port is a 32-bit value representing the length of the current entry. While the current entry is a file, the value of this port is equal to the length of the current file in bytes, saturating at bounds on overflow. While the current entry is a directory, the value of this port is equal to the number of child entries with valid paths belonging to the current directory. While no entry is open, the value of this port is zero.

TODO: same as for pointer

Writing to this port while a file is open will resize the currently-open file. If the written length is smaller than the original file length, the file will be truncated. If the written length is larger than the original file length, the end of the file will be zero-padded to achieve the new length. The resize operation will only be carried out when the lowest port is written to, in order to prevent premature truncation. The value written is kept separate to the value read, so reading from this port while a file is open will always return the current size of the currently-open file.

If the capacity of the storage medium used by the host system is smaller than the capacity required for a resize operation, the resize operation will fail. The value of this port can be read back after the resize operation in order to confirm whether the resize operation was successful.

Writing to this port while no file is open will have no effect.