Master the fundamental concepts of file systems through this focused micro-challenge.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it worksCreating a file is open(path, O_CREAT|O_WRONLY, mode) followed by write and close. The kernel allocates an fd table slot, creates the inode on disk or tmpfs, and returns a small integer handle.
Sequence:
open returns fd 3 (after stdin/out/err)write(3, buf, len) copies to page cacheclose(3) drops reference countFor example, writing 5 bytes to /tmp/test.txt creates the dentry if missing when O_CREAT is set with mode 0644.
open(), write(), and close() are the exact three syscalls every C library's fopen()/fwrite()/fclose() eventually wraps, and the O_CREAT|O_TRUNC flag combination here is what tools like logrotate rely on to atomically replace files. Skipping the return-value check on open() is one of the most common real-world causes of silent data loss in production logging pipelines.
Before you call the implementation done, walk failure modes on purpose. Test empty structures, single-element edge cases, maximum concurrency, and errno paths that must not crash the program. OS code usually fails in production when happy-path tests pass but invariants break under contention or memory pressure.
Keep structures small and name fields after kernel counterparts when possible. That lets you read man pages and kernel source side by side while you work. Print observable events during development; remove noisy logs once tests pass reliably.
You will create files with raw syscalls or libc wrappers and verify contents with read. The task asks you to handle EEXIST when O_EXCL is requested on an existing path.
Create and modify files with the raw POSIX system calls open(), write(), read() and close(), using the flag combinations real programs use: O_CREAT | O_TRUNC to replace, O_APPEND to add, and O_CREAT | O_EXCL to create only if absent (how lock files and mkstemp avoid races). Check every return value and report failures by their errno name.
At start-up, create a private working directory with mkdtemp("/tmp/fsXXXXXX") (falling back to "fsXXXXXX" in the current directory if /tmp isn't writable), chdir into it and call umask(022). Every name in the input is a plain file name inside that directory. Delete everything you created before exiting. Never print the directory's path.
| Command | System calls | Success output |
|---|---|---|
create NAME TEXT... | open(O_WRONLY | O_CREAT | O_TRUNC, 0644), write, close | create NAME: wrote N bytes |
append NAME TEXT... | open(O_WRONLY | O_APPEND), write, close | append NAME: wrote N bytes |
excl NAME TEXT... | open(O_WRONLY | O_CREAT | O_EXCL, 0600), write, close | excl NAME: wrote N bytes |
cat NAME | open(O_RDONLY), read until 0, close | cat NAME: "CONTENT" |
stat NAME | stat | stat NAME: size S mode 0644 (permission bits, 4 octal digits) |
chmod NAME MODE | chmod (octal mode) | chmod NAME: ok |
writero NAME TEXT... | open(O_RDONLY), then write | (always fails with EBADF on the write) |
rm NAME | unlink | rm NAME: ok |
TEXT is the rest of the line after one space and may be empty. It is written without a newline.
Print COMMAND NAME: SYSCALL failed: ENAME, where SYSCALL is the call that failed (open, write, read, stat, chmod, unlink) and ENAME is the symbolic errno (ENOENT, EEXIST, EBADF, EISDIR, EACCES, …). Close any descriptor you opened even when a later step fails.
Input:
cLoading…
Output:
cLoading…
open/read/write/close from <fcntl.h> and <unistd.h>, not fopen.errno to its name yourself (a small table covering the codes above), and print on stdout.Hidden tests cover truncation by a second create, excl creating a new file with mode 0600, chmod, writing through a read-only descriptor (EBADF), rm of a missing file, and cat of an empty file.