Private
Public Access
Release 0.13.0
This commit is contained in:
1 parent
7f6eeab39e
commit
c0d891b372
49 files changed
+1523
-478
No files matched your search
@@ -0,0 +1,101 @@
|
||||
#define _DEFAULT_SOURCE
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
static bool interrupt_write, short_write, fail_write, fail_sync, fail_rename, fail_commit_sync;
|
||||
static unsigned directory_syncs;
|
||||
static ssize_t fixture_write(int fd, const void *data, size_t n) {
|
||||
if (interrupt_write) {
|
||||
interrupt_write = false;
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
if (fail_write) {
|
||||
errno = ENOSPC;
|
||||
return -1;
|
||||
}
|
||||
return write(fd, data, short_write && n > 2 ? 2 : n);
|
||||
}
|
||||
static int fixture_sync(int fd) {
|
||||
struct stat info;
|
||||
assert(!fstat(fd, &info));
|
||||
if (S_ISDIR(info.st_mode)) {
|
||||
directory_syncs++;
|
||||
if (fail_commit_sync && directory_syncs == 2) {
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
} else if (fail_sync) {
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
return fsync(fd);
|
||||
}
|
||||
static int fixture_rename(int from, const char *a, int to, const char *b) {
|
||||
if (fail_rename) {
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
return renameat(from, a, to, b);
|
||||
}
|
||||
#define ATOMIC_WRITE fixture_write
|
||||
#define ATOMIC_SYNC fixture_sync
|
||||
#define ATOMIC_RENAME fixture_rename
|
||||
#include "atomic_file.h"
|
||||
static void contents(const char *path, const char *expected) {
|
||||
char data[64] = {0};
|
||||
int fd = open(path, O_RDONLY);
|
||||
assert(fd >= 0);
|
||||
assert(read(fd, data, sizeof(data) - 1) == (ssize_t)strlen(expected));
|
||||
close(fd);
|
||||
assert(!strcmp(data, expected));
|
||||
}
|
||||
int main(void) {
|
||||
char directory[] = "/tmp/hyperdrm-save-XXXXXX";
|
||||
assert(mkdtemp(directory));
|
||||
char path[128], stale[128], link[128];
|
||||
snprintf(path, sizeof(path), "%s/settings.json", directory);
|
||||
snprintf(stale, sizeof(stale), "%s/settings.json.tmp", directory);
|
||||
snprintf(link, sizeof(link), "%s/link", directory);
|
||||
int fd = open(stale, O_CREAT | O_WRONLY, 0600);
|
||||
assert(fd >= 0);
|
||||
close(fd);
|
||||
assert(atomic_replace(path, "old", 3) == SAVE_DURABLE);
|
||||
interrupt_write = short_write = true;
|
||||
assert(atomic_replace(path, "partial writes handled", 22) == SAVE_DURABLE);
|
||||
contents(path, "partial writes handled");
|
||||
short_write = false;
|
||||
fail_write = true;
|
||||
assert(atomic_replace(path, "new", 3) == SAVE_UNCHANGED);
|
||||
fail_write = false;
|
||||
contents(path, "partial writes handled");
|
||||
fail_sync = true;
|
||||
assert(atomic_replace(path, "new", 3) == SAVE_UNCHANGED);
|
||||
fail_sync = false;
|
||||
fail_rename = true;
|
||||
assert(atomic_replace(path, "new", 3) == SAVE_UNCHANGED);
|
||||
fail_rename = false;
|
||||
contents(path, "partial writes handled");
|
||||
directory_syncs = 0;
|
||||
fail_commit_sync = true;
|
||||
assert(atomic_replace(path, "committed", 9) == SAVE_COMMITTED);
|
||||
contents(path, "committed");
|
||||
fail_commit_sync = false;
|
||||
assert(!symlink(path, link));
|
||||
assert(atomic_replace(link, "bad", 3) == SAVE_UNCHANGED);
|
||||
contents(path, "committed");
|
||||
struct stat info;
|
||||
assert(!stat(path, &info) && (info.st_mode & 0777) == 0600);
|
||||
assert(!access(stale, F_OK));
|
||||
unlink(link);
|
||||
unlink(path);
|
||||
unlink(stale);
|
||||
assert(!rmdir(directory));
|
||||
puts("PASS: interrupted/partial writes, write/sync/rename failures, atomic replacement, commit "
|
||||
"durability, private permissions, symlinks and stale files");
|
||||
}
|
||||
Reference in new issue
Block a user