Old Or New Never Half

A service rewrites config.json in place while other processes read it. The requirement: after any power loss, a reader must find either the complete old file or the complete new file, never a truncated, zero-length, or half-written one.

More than one applies. Which sequences actually guarantee that on a standard journaling file system?

/* A */ fd = open("config.json", O_WRONLY|O_TRUNC);
        write(fd, buf, n); fsync(fd); close(fd);

/* B */ fd = open("config.json.tmp", O_WRONLY|O_CREAT|O_TRUNC, 0644);
        write(fd, buf, n); fsync(fd); close(fd);
        rename("config.json.tmp", "config.json");
        dfd = open(".", O_RDONLY); fsync(dfd); close(dfd);

/* C */ fd = open("config.json.tmp", O_WRONLY|O_CREAT|O_TRUNC, 0644);
        write(fd, buf, n); close(fd);
        rename("config.json.tmp", "config.json");
        dfd = open(".", O_RDONLY); fsync(dfd); close(dfd);

/* D */ fd = open("config.json", O_WRONLY);
        pwrite(fd, buf, n, 0); fsync(fd);
        ftruncate(fd, n); fsync(fd); close(fd);

/* E */ fd = open("config.json.tmp", O_WRONLY|O_CREAT|O_TRUNC, 0644);
        write(fd, buf, n); fsync(fd); close(fd);
        dfd = open(".", O_RDONLY); fsync(dfd);
        rename("config.json.tmp", "config.json"); fsync(dfd); close(dfd);
A

C

B

E

C

A

D

B

E

D