linux-sysprog · intermediate · ~15 min

Atomic-write checklist

Memorize the canonical atomic-write recipe.

Challenge

Return the canonical atomic-write step sequence. Use the constants:

enum {
    STEP_WRITE_TMP = 1,    // 1. write the new content to a temp file alongside the target
    STEP_FSYNC = 2,        // 2. fsync the temp file's contents to disk
    STEP_FSYNC_DIR = 3,    // 3. fsync the parent directory so the rename will persist
    STEP_RENAME = 4,       // 4. atomically rename the temp file over the target
};

Implement int atomic_write_steps(int *out, int max) that fills out[] with the steps in order and returns the count (always 4).

The order matters: writing+fsync FIRST guarantees the new contents are durable before the rename takes effect. Fsync of the directory captures the rename itself.

Examples

int out[8];
atomic_write_steps(out, 8)
   -> 4, out == [STEP_WRITE_TMP, STEP_FSYNC, STEP_FSYNC_DIR, STEP_RENAME]
atomic_write_steps(out, 2)
   -> 2, out == [STEP_WRITE_TMP, STEP_FSYNC]  // truncated

Why this matters

Skipping fsync of the directory causes the rename to vanish on crash — your file may exist with old content or not at all. The Linux kernel devs and the SQLite docs both spell this out; learners almost never see it until they ship a bug.

Why this matters

Naïve fopen("w") + write can leave a half-written file on crash. The atomic-write pattern (write to temp, fsync, rename) is what every database, every text editor, and every config-rewriting tool actually does — and very few learners are taught it explicitly.

Input format

out[] array + max length.

Output format

Count of steps written.

Constraints

No syscalls actually executed — this is a recipe-encoding exercise.

Starter code

enum {
    STEP_WRITE_TMP = 1, STEP_FSYNC = 2, STEP_FSYNC_DIR = 3, STEP_RENAME = 4
};
int atomic_write_steps(int *out, int max) { /* TODO */ return 0; }

Common mistakes

Forgetting fsync of the directory (step 3). Writing the temp without fsync first (step 2). Renaming first then fsync (race window — leaves the file with old content visible).

Edge cases to handle

max < 4 — truncate. max == 0 — return 0.

Complexity

O(1).

Background lessons

Up next

Solve this exercise in the browser editor — compile and run against the test harness, no setup required.