# DanOS Filesystem Hierarchy Standard (DFHS)

Most modern Unix and Unix-like operating systems follow the FHS. DanOS has its own FHS structure which extends the unix FHS. This is provided by virtual file system driver (VFS).

## Directory structure

| Path             | Description                                                                                                                                                         |
|------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| /                | Primary hierarchy root and root directory of the entire file system hierarchy.                                                                                      |
| /bin             | Essential command binaries that need to be available in single-user mode, including to bring up the system or repair it, for all users (e.g., cat, ls, cp).         |
| /boot            | Boot loader files (e.g., EFI, initial-ramdisk.img ).                                                                                                                |
| /dev             | POSIX Device files (e.g., /dev/null, /dev/disk0, /dev/tty, /dev/random).                                                                                            |
| /etc             | Host-specific system-wide configuration files.                                                                                                                      |
| /home            | Users' home directories, containing saved files, personal settings, etc.                                                                                            |
| /lib             | Libraries essential for the binaries in /bin and /sbin. eg realtime, system, ipc etc.                                                                               |
| /sbin            | Essential system binaries (e.g init)                                                                                                                                |
| /srv             | Site-specific data served by this system, such as data and scripts for web servers, data offered by FTP servers, and repositories for version control systems       |
| /system          | DanOS operating system files (similar idea to C:\Windows). A true representation of danos — its layout mirrors the source tree, so `/system` is what danos *is*.    |
| /system/devices  | danos virtual device tree e.g. similar to /sys on linux but with danos device tree conventions (the structures in the devices module)                               |
| /system/drivers  | driver binaries, one sub-project each (e.g. /system/drivers/pci-bus, /system/drivers/ps2-bus)                                                                       |
| /system/services | system-service binaries — the VFS server, init, and other user-mode servers (e.g. /system/services/vfs, /system/services/init)                                      |
| /system/kernel   | the kernel image                                                                                                                                                    |
| /tmp             | Directory for temporary files (see also /var/tmp). Often not preserved between system reboots and may be severely size-restricted.                                  |
| /usr             | Secondary hierarchy for read-only user data; contains the majority of (multi-)user utilities and applications. Should be shareable and read-only.                   |
| /var             | Variable files: files whose content is expected to continually change during normal operation of the system, such as logs, spool files, and temporary e-mail files. |

## File types

POSIX specifies the long format of the ls command to represent the Unix file type as the first letter for an entry.

| type              | symbol | Description                                                                                                                                                           |
|-------------------|--------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| regular           | -      | An ordinary file holding an uninterpreted byte stream. Reads and writes are positional, and the file grows on demand (e.g., a binary in /bin, a config file in /etc). |
| directory         | d      | A container mapping names to other files. It may only be modified through directory operations, never written to directly.                                            |
| symbolic link     | l      | A file whose contents are a path that is resolved in its place. The target need not exist, and may cross mount points.                                                |
| FIFO special      | p      | A named pipe: an in-order byte stream between processes, where writers block until a reader opens the other end.                                                      |
| block special     | b      | A device node addressed in fixed-size blocks with the kernel free to buffer and reorder access (e.g., /dev/disk0).                                                    |
| character special | c      | A device node addressed as an unbuffered byte stream, delivered to the driver in order (e.g., /dev/tty, /dev/null).                                                   |
| socket            | s      | A named endpoint for bidirectional message-passing between processes, bound to a path rather than an address.                                                         |

## /dev

`/dev` holds the names through which processes reach devices. It is deliberately not
the device tree: the tree — every node discovered by ACPI or PCI enumeration, with its
resources and its parent — lives under [/system/devices](#directory-structure) and is
addressed by device id. `/dev` is the much smaller set of devices that have a driver
willing to serve them, addressed by name.

A device node is not a file the VFS can read. The bytes live in a driver process
([drivers.md](drivers.md)), so opening a `/dev` name has to resolve to that driver's
IPC endpoint, and subsequent reads and writes are calls against it. This is what
`system/services/vfs/vfs.zig` reserves for M10 and what the `Stat.kind` field is for; **none of it is
implemented today.** The current VFS is a flat, in-memory ramfs of eight nodes, with no
directories at all and `kind` hardcoded to zero. The three sections below describe the
intended shape, and are honest about which parts the kernel can already support.

### Character devices

A character device is a byte stream with no addressable position: bytes are delivered
to the driver in the order written, and a read consumes what is there. Terminals,
serial lines, keyboards and mice are all of this shape. These are the natural first
device nodes in danos, because a character driver needs nothing the kernel doesn't
already provide — it claims its device, maps its registers with `mmio_map`, and blocks
on `replyWait` for either an interrupt or a client request. `system/drivers/ps2-bus/ps2-bus.zig`
is already that program, minus the file-node client half.

The obstacle was never the file type; it is which hardware a ring-3 driver can reach.
Direct `in`/`out` from user space is still a #GP (no TSS I/O bitmap, IOPL never raised),
but a driver no longer needs it: **`io_read`/`io_write`** grant port access the same way
`mmio_map` grants memory — gated by `device_claim` and the device's discovered `io_port`
resource. So the 16550 UART at `0x3F8` and the PS/2 controller at `0x60`/`0x64` (and thus
`/dev/ttyS0` and a keyboard node) are now writable as ordinary ring-3 drivers; the
low-rate legacy hardware that needs port I/O is fine with a syscall per access. A
memory-mapped device such as the framebuffer, needing no port I/O at all, remains the
easiest first entry.

### Block devices

A block device is addressed in fixed-size blocks and, unlike a character device, the
layer above is free to buffer, reorder, coalesce and retry requests against it. Disks
and other persistent storage are the whole population of this class.

A block driver is now **writable, but not yet memory-safe.** Every storage controller
worth naming is a bus master: it is programmed by handing it the physical address of a
descriptor ring and left to read and write memory on its own. That ring is exactly what
**`dma_alloc`** now provides — physically contiguous, pinned, uncacheable, with its
physical address disclosed — and **`/lib/mmio`**'s barriers order the descriptor writes
against the doorbell, and **`msi_bind`** delivers completions. So an AHCI or NVMe driver
can be written today (the M14/M15 work in [driver-model.md](driver-model.md); the earlier
"cannot host a block driver at all" is no longer true).

What is *not* yet true is that it is safe. A device programmed with an arbitrary physical
address writes to arbitrary physical memory, and page tables do not sit between a device
and RAM — an IOMMU does. The IOMMU is now *detected* (M16), but no translation domains
are programmed, so granting a DMA-capable device to a driver process is still equivalent
to granting ring 0. Until per-device domains confine a driver's DMA to the buffers it
`dma_alloc`'d, a block driver works but forfeits the isolation that motivates user-space
drivers — enforcement is the next step, and lands with that first driver. A ramdisk over
the initial ramdisk remains the one block-shaped thing that needs no driver process at all.

### Pseudo-devices

A pseudo-device has the interface of a device and no hardware behind it: `/dev/null`
discarding writes and reading as end-of-file, `/dev/zero` reading as an endless run of
zero bytes, `/dev/full` failing writes with `ENOSPC`, `/dev/random` and `/dev/urandom`
yielding unpredictable bytes.

These are the only `/dev` entries danos can implement immediately, and they are the
sensible place to start, because they are exactly the entries that need no driver
process, no `device_claim`, no MMIO grant and no interrupt. The VFS server answers them
out of its own address space — `null` and `zero` are a few lines each in
`system/services/vfs/vfs.zig`'s `read` and `write` handlers. Doing so forces the two pieces of
structure that every later device node depends on and that the flat ramfs currently
lacks: a directory, so that `/dev/null` is a path rather than a name; and a populated
`Stat.kind`, so that a caller can tell a character device from a regular file.

`/dev/random` is the one that is not free. It needs an entropy source, and the honest
options on this kernel are `RDRAND`/`RDSEED` where CPUID advertises them, and the HPET
counter's low bits as a poor fallback. Neither is a seeded CSPRNG, and a `/dev/random`
that is merely unpredictable-looking is worse than none — nothing should be keyed from
it until it is a real one.