The filesystem¶
The filesystem is three layers: a block device abstraction
(fs/block.ik), a mount table (fs/mount.ik), and the hierarchical
tree filesystem (fs/treefs.ik) that runs on top of any block device.
Block devices¶
fs/block.ik exposes byte read/write to two devices and hides where the
bytes actually live:
device 0 is the whole 1 KB on-chip EEPROM (the root filesystem), reached with
@eeprom_read/@eeprom_write;device 2 is an external 24Cxx I2C EEPROM at
0x50, reached over the TWI bus with a 16-bit word address.
- @blk_read($dev: u8, $addr: u16) -> u8¶
Read one byte at
$addrwithin device$dev.
- @blk_write($dev: u8, $addr: u16, $val: u8)¶
Write one byte at
$addrwithin device$dev.
On-disk layout¶
Each device holds a flat array of fixed-size nodes, then a FAT, then a
pool of fixed-size data clusters. A node is FS_NODESZ (16) bytes: a type
byte (free / file / directory), a parent node index, a 16-bit length, an 8-byte
name (FS_NAMELEN), and the index of the file’s first cluster. Node 0 is the
device’s root directory.
File data is allocated dynamically: a file is a chain of clusters threaded
through the FAT (one next-pointer byte per cluster, 0xFF free, 0xFE
end-of-chain), so a file grows to whatever free space allows instead of a fixed
slot. The internal volume holds 8 nodes and 52 sixteen-byte clusters (files up
to ~832 B); the external EEPROM holds 64 nodes with fixed 256-byte slots. The
exact byte ranges are in Memory maps.
- @fs_format($dev: u8)¶
Initialise
$devas an empty filesystem: free every node, mark every FAT cluster free, and make node 0 an empty directory.
- @fs_mknode($dev: u8, $parent: u16, $name: ptr ram u8, $type: u8) -> u16¶
Allocate a node under
$parentwith$nameand$type, and return its node index (not a packed location). Returns0xFFFFif the name already exists or the device is full.
- @fs_append_byte($dev: u8, $i: u16, $c: u8)¶
Append one byte to file
$i, allocating and linking a fresh cluster from the pool when the current one fills. Silently stops if the pool is exhausted.
- @fs_truncate($dev: u8, $i: u16)¶
Truncate a file to zero length, returning its cluster chain to the free pool.
>overwrite uses this before writing.
- @fs_resolve($path: u16, $start: u16) -> u16¶
Resolve a path (absolute from the root, or relative to
$start) to a packed(device, node)location, crossing mount points. Returns0xFFFFif it does not exist.
Note
@fs_mknode returns a bare node index. Callers that need a location must
pack it with the node’s device — @loc(dev, node) — before treating it as
one.
Mounting¶
fs/mount.ik keeps a small table mapping a directory (a packed location) to a
device whose root tree is shown there. Path resolution consults it so a path can
descend from one device into another. @mount_add and @mount_remove_dev
manage the table; @mount_mp_of finds where a device is mounted.
Redirection target¶
Output redirection (> / >>) resolves the target path, creating the file
if needed on the resolved device, and stores the destination device and node in
REDIRECT_DEV / REDIRECT_NODE. While redirection is active every console
byte is appended to that file via @fs_append_byte instead of going to the
UART.