Storage, profile directory and vault
FAQ › EUZOS Desktop › Storage · Nederlands
What is it?
The rule "nothing local" means: nothing local that is readable without logging in. EUZOS uses 8 GiB of the internal disk for the system; the rest is partition 2, Profielen (Profiles), with one encrypted directory (an area) per user. The key of that directory is not on the PC: it is in the user's vault on the profile server and is fetched at login. Without logging in, the disk shows nothing but an unencrypted header (how many directories, how large, when last used).
The parts:
- Disks: AHCI (internal SATA), NVMe (internal SSD on PCIe), virtio-blk (the disk of a virtual machine) and USB storage. Reading is always allowed; writing or wiping an internal disk needs a typed confirmation and is only possible until the next reboot.
- Partitions: GPT with entry 1 = EUZOS system (EFI), entry 2 = Profiles, entry 3 = EUZOS reserved.
- Profile directory (
profiledir): the logged-in user's encrypted directory; in the Explorer it is My files. - Vault (
vault): small secrets of the user, encrypted on the profile server (the data key of the directory, Microsoft refresh tokens). apps/: a shared, signed, unencrypted area on partition 2 for app packages such as Chromium (see Desktop and apps).
How do I…?
How do I see which disks the PC has?
disks: all USB storage (partitions, labels, the boot stick, which is protected, and whether it may be an install target) and the internal SATA disks (AHCI) and NVMe SSDs, read only: model, serial number, size, table. ahci and nvme show the controllers in detail. In the desktop: Settings › Hardware shows processor, memory, storage and devices.
Does EUZOS use UAS (USB Attached SCSI) for USB 3 disks?
Yes, when it can: a USB 3 SSD or enclosure that offers UAS (interface 08/06/62), on a SuperSpeed port of an xHCI controller with bulk streams, gets UAS with several commands in flight (disks shows UAS after the size; the boot log shows "UAS, N streams, depth D"). Otherwise, and for enclosures known to misbehave with UAS, the device uses Bulk-Only Transport (BOT), as before. On a USB 2.0 port UAS is not used yet. Built from the clean-room spec docs/drivers/specs/uas.md; hardware test pending.
How do I see the layout of the boot disk and partition 2?
storage (or storage plan): the boot disk (drive, model, serial, size), its GPT, the system requirement (8 GiB: ESP + reserved; profiles from sector …), the header of partition 2 (generation, directories, default quota, largest free piece) and, if partition 2 is missing, the exact command to create it.
How do I add partition 2 to an existing installation?
A new installation creates all three GPT entries and an empty header by itself. On an older installation:
storage planto see what would happen;storage create CONFIRM-<serial> [quota=<GiB>].
The command shows the GPT before and after. It writes only the GPT sectors (LBA 1–33 and the last 33 sectors: backup first, then primary, each flushed and read back) and the header of partition 2. Never LBA 0 (the protective MBR) and never anything of partition 1. Without the right code nothing is written. The default quota is a quarter of the partition, at most 64 GiB. quotum= is the legacy spelling of quota=.
How do I clean up old profile directories?
storage cleanup removes directories that have not been used for 90 days (also done on every open). Their checkpoints are overwritten with zeroes, so they cannot be opened even with the key. The open directory is never removed; without a credible clock nothing is removed.
How do I look inside my own profile directory?
profiledir (or profiledir info) shows whether it is open, the generation, number of files and bytes, blocks used and free space. profiledir usage shows MiB used of the quota. profiledir list [path], read <path> (size and SHA-256), stat <path>, and the writing commands write, mkdir, mkdirs, delete, deltree, rename, copy all work on the directory of the logged-in user only. In the desktop, the Explorer shows bestanden/ as My files; apps/ and systeem/ stay hidden.
How do I test the encryption on this PC?
profiledir test creates a temporary 64 MiB directory with a random key that is only in memory, writes 4 MiB, closes and reopens, reads back, writes and reads 20 MiB in 64 KiB chunks with SHA-256, renames, tries a wrong key and deletes it all again. It never touches the logged-in user's directory and leaves nothing behind.
How do I see or delete what is in my vault?
vault (or vault list) lists the kinds of secret stored for the logged-in user, without content and without account ids. vault delete <kind> deletes one. Deleting opslag-sleutel is crypto-shredding: the profile directory can then no longer be opened on any PC; at the next login the server creates a new key, so a new, empty directory.
Why can I not write to an internal disk?
The AHCI and NVMe drivers refuse every write by default (euzos_ata::allowed, libs/nvme::allowed). For SATA: ahci unlock <port> WIPE-<serial> unlocks one port until the reboot (never the boot disk); ahci lock <port> locks it again. For NVMe there is no separate unlock command: only the installer (install … n<nr> WIPE-<serial> WIPE-ALL or the graphical installer) unlocks it. Without the code, ahci unlock <port> only shows what the code would be.
How do I wipe an internal SATA disk?
After unlocking: ahci wipe <port> [--thorough] WIPE-<serial> WIPE-ALL. Without the words it only shows the plan. Fast (default): SANITIZE, Security Erase, TRIM that returns zeroes (with a sample check), only then overwrite. Thorough (--thorough, for a disk that leaves the company): only SANITIZE, Security Erase or overwrite, never TRIM. Afterwards it reads back samples. If a wipe was interrupted (e.g. power loss) and the disk is locked with the temporary wipe password, ahci wipelock <port> removes it. In the installer the same choice is fast or thorough wipe (see Installer).
Since 27-10-2026 EUZOS writes English config file names, keys, values and confirmation words (for example
WIPE-…,environment=inPROFILE.TXT); the old Dutch names (marked legacy here) are still read and accepted (docs/ENGLISH.md).
Details
Layout of the internal disk
| GPT entry | Range | Content | Access |
|---|---|---|---|
| 1. EUZOS system (EFI) | 1 MiB – 1 GiB + 1 MiB | boot loader, kernel, firmware, keys of the PC | only the kernel |
| 3. EUZOS reserved | end of ESP – 8 GiB | free for the system (A/B kernels, app packages); not in use yet | nobody |
| 2. Profiles | 8 GiB – end | one encrypted area per user | only the user's own directory, via the kernel |
The smallest supported internal disk is 32 GB. Partitions 2 and 3 have own type GUIDs (names EUZOS-profielen, EUZOS-gereserveerd) with the attributes "required partition" and "no block IO protocol", so no installer, partition program or the Explorer sees the space as free.
Header of partition 2
Blocks 0 and 1 are two copies (A/B) of the header, each with SHA-256 and a generation; the valid one with the highest generation counts. It holds the default quota and up to 56 areas: dir id, instance, first block, number of blocks (the quota), created and last-used day, kind (1 profile dir, 2 apps/). Blocks 2 and 3 hold the offline locker (see Login). The dir id is derived from the data key with HKDF, so directory names reveal nothing.
File system and encryption
libs/profiledir: a copy-on-write tree with two checkpoints, 4 KiB blocks. Every block is ChaCha20-Poly1305 (RFC 8439) with a key per session (HKDF-SHA256, RFC 5869) and a counter as nonce; the associated data binds the dir id, instance, block number and version. Each reference carries the Poly1305 tag of the block it points to (a Merkle tree). Writing is a transaction; power loss leaves the previous or the new state, never a broken one. The generation is saved in the vault (opslag-versie) every minute and at logout, so restoring an old copy of the whole directory is detected.
Open at login (profile_dir::on_login, own thread): fetch the data key from the vault, compute the dir id, find or create the area, check the generation, walk the tree. At most one directory is open at a time. Close on every logout path (profile_dir::close): keys out of memory (wiped on Drop), generation to the vault.
What is in the directory
| Path | What |
|---|---|
bestanden/ | My files (Documents, Pictures, Downloads, Desktop, …) |
apps/<app>/ | /data of a Linux app (e.g. the Chromium profile) |
systeem/microsoft/<id> | refresh token of a Microsoft account |
systeem/mail/<hash> | mail cache (bounded) |
systeem/instellingen/browsergegevens | on/off (legacy aan/uit, still read): Settings › Privacy › Keep browser data on this PC (default off) |
systeem/browser/geschiedenis | history of the EUZOS browser (only if browser data is on) |
These paths are on-disk names and stay Dutch.
What is and is not protected
Protected: a removed disk read without logging in; another user on the same PC; changed, swapped or old blocks; restoring the whole directory; a key deleted on the server. Not protected: damage to the header (availability), what the header reveals (count, size, days), the write pattern, someone with the key and write access, a compromised kernel or cold-memory attack while someone is logged in. See USER-STORAGE.md.
The vault
crate::vault calls the profile server with the PC token of the session. Kinds:
opslag-sleutel: the 32-byte data key of the profile directory. The server creates it on the first fetch; it cannot be set from the PC.opslag-versie: the generation of the profile directory (rollback protection).ms-refresh:<id>: the refresh token of a Microsoft account.
A secret is at most 8 KiB. Secrets are held in a self-wiping type; the log gets at most the kind, never the content or the id. A server without a vault answers 404 and the PC behaves as before the vault existed.
Disk drivers
- AHCI (
kernel/src/ahci.rs,libs/ata): set up only on first use (ahci,disks, the installer), not at boot. One command slot, a timeout on every wait; after an error the port is restarted. Reads (IDENTIFY, READ DMA EXT, READ VERIFY, SMART READ DATA / RETURN STATUS) are always allowed; writes (WRITE DMA EXT, FLUSH, TRIM) only with anUnlock; SANITIZE and SECURITY ERASE only with aWipeOrder; everything else never. - NVMe (
kernel/src/nvme.rs,libs/nvme): same model. Writes (Write, Flush, Write Zeroes, Dataset Management) only with anUnlock; Format NVM and Sanitize only with aWipeOrder. Install-time wipe: Format NVM with cryptographic erase, else user-data erase, else Write Zeroes, then a sample check (first and last 64 sectors and 1000 random ones) that must sayEMPTY. Blocks of 4096 bytes work via read-modify-write. With Intel RST (RAID mode) the NVMe is usually still visible as its own device; if it is hidden behind RST, the firmware must be switched to AHCI. - virtio-blk (
kernel/src/virtio_blk.rs,libs/virtio; supported since 28-10-2026, QEMU/KVM and cloud servers): same model as NVMe. Writes only afterWIPE-<serial> WIPE-ALL(a disk without a serial is never written) or inside the boot partition; the boot disk is never a target (inmake run-aarch64EUZOS boots from its own image as virtio disk[v0]). Installer wipe: overwrite with zeroes, then the sample check. See VIRTIO.md. - USB storage and the Explorer (
libs/storage): partitions (GPT, MBR or a bare volume) and one API over FAT32 and exFAT; NTFS is recognised but not read. See Explorer.
Reference
Console commands
| Command | Arguments | What it does |
|---|---|---|
disks | – | USB storage, internal SATA and NVMe disks (read only); legacy name schijven |
storage | [plan] | GPT of the boot disk, system layout, header of partition 2; legacy name opslag |
storage create | CONFIRM-<serial> [quota=<GiB>] | create partitions 2 and 3 on an existing installation; legacy maak, quotum= |
storage cleanup | – | remove directories unused for 90 days; legacy opruimen |
profiledir | [info] | state of the open directory; legacy name profielmap |
profiledir usage | – | MiB used of the quota; legacy gebruik |
profiledir list | [path] | list a directory (d = directory); legacy lijst |
profiledir read | <path> | size and SHA-256 of a file; legacy lees |
profiledir stat | <path> | kind, name, size |
profiledir write | <path> <text> | write text to a file; legacy schrijf |
profiledir mkdir | <path> | create one directory; legacy map |
profiledir mkdirs | <path> | create all directories of the path; legacy mappen |
profiledir delete | <path> | delete a file or empty directory; legacy wis |
profiledir deltree | <path> | delete with content; legacy wisboom |
profiledir rename | <from> <to> | rename; legacy hernoem |
profiledir copy | <from> <to> | copy chunk by chunk; legacy kopie |
profiledir data | – | Linux apps with /data in the directory |
profiledir test | – | self-test with a temporary directory; legacy proef |
vault | [list] | kinds stored in the vault; legacy name kluis, legacy lijst |
vault delete | <kind> | delete one secret; legacy wis |
ahci | – | controller and ports overview |
ahci identify | <port> | IDENTIFY data in hex |
ahci read | <port> <lba> [n] | n = 1..8 sectors in hex; legacy lees |
ahci unlock | <port> [WIPE-<serial>] | unlock for writing until reboot (never the boot disk); legacy ontgrendel |
ahci lock | <port> | back to read-only; legacy vergrendel |
ahci writetest | <port> <lba> | write one sector, read back, restore (unlocked port only); legacy schrijftest |
ahci wipe | <port> [--thorough] [WIPE-<serial> WIPE-ALL] | securely wipe the whole disk; without the words only the plan; legacy wis, --grondig |
ahci wipelock | <port> | remove the temporary wipe password after an interrupted wipe; legacy wisslot |
nvme | – | controller, version, CAP/CC/CSTS, Identify, namespace, last error, counters |
nvme read | <nr> <sector> [n] | n = 1..8 sectors of 512 bytes in hex (n<nr> also accepted); legacy lees |
nvme speed | <nr> [MiB] | read speed (default 256 MiB in 1 MiB chunks); legacy snelheid |
vblk | – | virtio disks: features, size, serial, queue, boot disk, counters (both architectures) |
vblk read | <nr> <sector> [n] | n = 1..8 sectors of 512 bytes in hex |
vblk speed | <nr> [MiB] | sequential read and 1000 random 4 KiB reads |
vblk check | <nr> | may this virtio disk be an installation target (never the boot disk) |
vblk test | <nr> WIPE-<serial> WIPE-ALL | test build only: destructive write/flush/read-back test on a scratch disk |
ahci and nvme (and so storage/profiledir) only exist on x86-64. Installing to an internal disk (install <url> a<port>|n<nr> …) is on the Installer page.
Functions and modules
| Function / module | Role |
|---|---|
crate::profile_dir::on_login, profile_dir::close, profile_dir::save_generation | open at login, close at logout, save the generation |
crate::profile_dir::read, write, list, delete, create_dir, is_open, usage | kernel API on the logged-in user's directory |
crate::profile_dir::Channel (read, write, create_dirs, list, info, create_dir, rename, delete, delete_tree), Reader, Writer | access per session, chunked streams |
crate::profile_dir::command, profile_dir::storage_command | profiledir and storage |
crate::profile_dir::open_offline, install_offline, offline_table | offline locker (offline login) |
crate::vault::fetch, vault::store, vault::delete, vault::list, vault::command | the vault client |
crate::ahci::command, crate::nvme::command, crate::install::disks | disk commands |
euzos_ata::unlock_code, euzos_ata::confirm_code, euzos_ata::WIPE_ALL, euzos_ata::GptLock, euzos_ata::WipeMode | confirmation codes and write locks |
euzos_nvme::GptLock, libs/nvme::allowed | NVMe write lock |
euzos_profiledir::header, block, dir, apps, offline, dir_id | partition header, block encryption, file system, apps/ area, offline locker |
euzos_disk::gpt (read, system_layout, plan_profiles) | GPT reading and planning |
euzos_storage::partitions, Volume, safe_name | USB storage for the Explorer |
Config files and on-disk data
| Where | Key / content | Meaning |
|---|---|---|
| GPT entry 2 / 3 | type GUIDs, names EUZOS-profielen, EUZOS-gereserveerd | Profiles and reserved partitions |
| Partition 2, blocks 0/1 | header A/B | areas and default quota |
| Partition 2, blocks 2/3 | offline locker A/B | offline login |
systeem/instellingen/browsergegevens (in the directory) | on / off (legacy aan / uit) | keep browser data on this PC |
Confirmation words
| Word | Used by | Meaning |
|---|---|---|
WIPE-<serial> (legacy WIS-<serial>) | ahci unlock, ahci wipe, install … a<port>/n<nr> | unlock exactly this internal disk (letters, digits and - of the serial; at least 4 characters) |
WIPE-ALL (legacy ALLES-WISSEN) | ahci wipe, install | permission to wipe everything |
CONFIRM-<serial> (legacy BEVESTIG-<serial>) | storage create | permission to update the GPT of the boot disk |
--thorough (legacy --grondig) | ahci wipe | thorough wipe (no TRIM) |
Since 27-10-2026 EUZOS writes English config file names, keys, values and confirmation words (for example
WIPE-…,environment=inPROFILE.TXT); the old Dutch names (marked legacy here) are still read and accepted (docs/ENGLISH.md).
API endpoints (used by the PC)
| Method | Path | Purpose |
|---|---|---|
GET | /api/kluis?token=<pc token> | list the kinds (soort= lines) |
GET | /api/kluis/<kind>?token=… | fetch a secret (opslag-sleutel is created on first fetch) |
PUT | /api/kluis/<kind>?token=… | store a secret |
DELETE | /api/kluis/<kind>?token=… | delete a secret |
These are the routes the kernel calls today: the legacy Dutch path /api/kluis (server/profile/src/legacy.rs). The server also serves the same handlers under the English path /api/vault and /api/vault/{kind} (server/profile/src/lib.rs). The full list is on the profile server API page. Errors: 401 token no longer valid, 404 server without a vault, 409 full, 413 too large, 429.
Protocol messages and formats
| Format | Where | Notes |
|---|---|---|
| Block (4096 bytes) | libs/profiledir/src/block.rs | 0..8 version, 8..24 session, 24..32 counter, 32..4080 ChaCha20 content, 4080..4096 Poly1305 tag |
| Associated data | same | EUZOS-PM1 ‖ dir id ‖ instance ‖ block number ‖ version |
| Vault list reply | crate::vault::list | lines soort=<kind> (at most 16 read) |
See also
- Login · Explorer · Installer · Desktop and apps
- docs/USER-STORAGE.md
- docs/NVME.md
- docs/OFFLINE-LOGIN.md
- docs/PROFILE-PROTOCOL.md, "The vault"
EUZOS