C++ / a working model

143 / 163   ·   C11   ·   8 min

Interlude: Files and Directories

Keep this sentence

This chapter presents an original view of how an operating system virtualizes persistent devices as two complementary abstractions—files and directories—and how the classic UNIX interface of open, read, write and unlink hides inode numbers behind human-readable path names.

In this lesson
  1. Files: Persistent Byte Streams Seen by the Kernel
  2. How Directories Assemble the Whole Name Tree
  3. The Small Integer Returned by open Is the Real Capability
  4. Mental Simplicity Gained from Uniform Naming
  5. Example
  6. Exercise

Official chapter PDF

Files: Persistent Byte Streams Seen by the Kernel

To the kernel every file is merely a randomly accessible sequence of bytes whose true identity is an integer inode number. User programs almost never mention that number; they rely on directories to translate convenient names into it. The file system never guesses whether the bytes encode a picture, source code or music; it only promises that the data survive power loss.

How Directories Assemble the Whole Name Tree

The contents of a directory are a plain lookup table: a user-visible name on the left and an inode number on the right. Placing directories inside other directories grows a tree of any depth whose root is always a lone slash. An absolute path is simply the sequence of names obtained by walking that table from the root, so two files both named report.txt can coexist as long as they live in different directories.

The Small Integer Returned by open Is the Real Capability

Passing O_CREAT to open creates the file and yields a file descriptor that is private to the calling process. Every later read, write or lseek refers solely to that integer. The descriptor vanishes when the process exits or close is called. The operation that actually removes a name is unlink; it merely decrements a link count, and the data disappear only after the count hits zero and no process still holds the file open.

Mental Simplicity Gained from Uniform Naming

Once almost everything—regular files, devices, pipes and even some process information—appears under a single directory tree, a programmer only has to remember one set of open/read/write rules. The “everything is a file” convention hides low-level differences and lets scripts and tools treat wildly different objects in exactly the same way.

Pitfalls

  • Treating the suffix after the last dot as a kernel-enforced type check rather than a mere convention
  • Believing a file descriptor can be passed around like an ordinary integer to another process
  • Expecting unlink to wipe disk blocks immediately, forgetting hard links and still-open descriptors

Run an example

Minimum C11 · complete program · Download .c

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int main(void) {
    const char *path = "ostep_ch39_demo.tmp";
    int fd = open(path, O_CREAT | O_RDWR | O_TRUNC, 0644);
    if (fd < 0) {
        perror("open");
        return 1;
    }
    const char msg[] = "hello from files\n";
    ssize_t n = write(fd, msg, sizeof(msg) - 1);
    if (n != (ssize_t)(sizeof(msg) - 1)) {
        perror("write");
        close(fd);
        unlink(path);
        return 1;
    }
    if (lseek(fd, 0, SEEK_SET) < 0) {
        perror("lseek");
        close(fd);
        unlink(path);
        return 1;
    }
    char buf[32];
    ssize_t r = read(fd, buf, sizeof(buf) - 1);
    if (r < 0) {
        perror("read");
        close(fd);
        unlink(path);
        return 1;
    }
    buf[r] = '\0';
    printf("wrote %zd bytes, read back: %s", n, buf);
    close(fd);
    if (unlink(path) != 0) {
        perror("unlink");
        return 1;
    }
    printf("unlinked successfully\n");
    return 0;
}

Compile locally

gcc -std=c11 -Wall -Wextra -Wpedantic -Werror ostep-39-files-directories.c -o example && ./example

Expected result

wrote 17 bytes, read back: hello from files
unlinked successfully

CHECK YOUR UNDERSTANDING

Close the answer. Explain it.

If two distinct directory entries point at the same inode, does the file’s content vanish immediately after one unlink? Explain the reasoning.

Show a reference answer

No, it does not vanish at once. unlink only removes one name and decrements the link count. As long as the count stays above zero or any process still holds an open file descriptor, the data blocks remain and the other name can still reach the same content.

Check the sources

Drafts and official chapters change. The version mark is only the example’s minimum.

Back to the catalog