linux-sysprog · intermediate · ~15 min

Atomic-write checklist

Memorize the canonical atomic-write recipe.

Challenge

Write out the canonical step order for a crash-safe atomic file update. This is a pure-logic exercise — you fill an array with the step codes in the correct sequence; nothing is written to disk.

Task

Implement int atomic_write_steps(int *out, int max) that writes the atomic-write step codes, in order, into out.

Input

  • out, max: destination array and its capacity. The step codes are these fixed constants:
enum {
    STEP_WRITE_TMP = 1,    // write the new content to a temp file alongside the target
    STEP_FSYNC     = 2,    // fsync the temp file's contents to disk
    STEP_FSYNC_DIR = 3,    // fsync the parent directory so the rename will persist
    STEP_RENAME    = 4,    // atomically rename the temp file over the target
};

Output

Fills out with the 4 codes in order (STEP_WRITE_TMP, STEP_FSYNC, STEP_FSYNC_DIR, STEP_RENAME) and returns how many it wrote (at most max). The order matters: write+fsync make the new contents durable before the rename takes effect, and the directory fsync makes the rename itself survive a crash.

Example

atomic_write_steps(out, 8)   ->   4, out = [1, 2, 3, 4]
atomic_write_steps(out, 2)   ->   2, out = [1, 2]   (truncated to max)

Edge cases

  • max < 4: write only the first max steps and return max.
  • max == 0: return 0.

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

An output array out and its capacity max. The 4 step codes are the fixed STEP_* enum constants (1..4).

Output format

Fills out with the step codes in canonical order; returns the count written (min of 4 and max).

Constraints

The sequence is exactly STEP_WRITE_TMP, STEP_FSYNC, STEP_FSYNC_DIR, STEP_RENAME. Truncate to max.

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.