The Pedigree Project 0.1
file-sync-contract-test/main.c
1#define _GNU_SOURCE
2#include <errno.h>
3#include <fcntl.h>
4#include <limits.h>
5#include <stdint.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <unistd.h>
10
11#include <sys/mman.h>
12
13#define CHECK(condition) \
14 do { \
15 if (!(condition)) { \
16 fprintf(stderr, "FILE-SYNC-CONTRACT: line=%d errno=%d\n", __LINE__, errno); \
17 goto fail; \
18 } \
19 } while (0)
20
21int main(int argc, char** argv) {
22 const char* directory = argc > 1 ? argv[1] : "/tmp";
23 char path[512];
24 snprintf(path, sizeof(path), "%s/file-sync-%ld", directory, (long)getpid());
25 const long page = sysconf(_SC_PAGESIZE);
26 const size_t length = 3 * (size_t)page;
27 int fd = -1, readonly = -1, writeonly = -1, pathfd = -1, pipes[2] = {-1, -1};
28 unsigned char* mapping = MAP_FAILED;
29 unsigned char resident[3] = {0};
30 unsigned char byte = 0;
31 int result = 1;
32
33 CHECK(page > 0);
34 fd = open(path, O_CREAT | O_EXCL | O_RDWR, 0600);
35 CHECK(fd >= 0 && ftruncate(fd, length) == 0);
36 readonly = open(path, O_RDONLY);
37 writeonly = open(path, O_WRONLY);
38 pathfd = open(path, O_PATH);
39 CHECK(readonly >= 0 && writeonly >= 0 && pathfd >= 0);
40 CHECK(lseek(fd, 19, SEEK_SET) == 19 && lseek(readonly, 23, SEEK_SET) == 23);
41
42 mapping = mmap(NULL, length, PROT_READ, MAP_PRIVATE, readonly, 0);
43 CHECK(mapping != MAP_FAILED);
44 CHECK(readahead(readonly, page + 7, 1) == 0);
45 CHECK(mincore(mapping, length, resident) == 0 && (resident[1] & 1));
46 errno = EDOM;
47 CHECK(posix_fadvise(readonly, 2 * page + 11, 1, POSIX_FADV_WILLNEED) == 0);
48 CHECK(errno == EDOM);
49 CHECK(mincore(mapping, length, resident) == 0 && (resident[2] & 1));
50 CHECK(readahead(readonly, 0, 0) == 0);
51 CHECK(mincore(mapping, length, resident) == 0 && (resident[0] & 1));
52 CHECK(lseek(readonly, 0, SEEK_CUR) == 23);
53 CHECK(readahead(readonly, length + page, 1) == 0);
54 CHECK(posix_fadvise(writeonly, 0, 0, POSIX_FADV_WILLNEED) == 0);
55 CHECK(munmap(mapping, length) == 0);
56 mapping = MAP_FAILED;
57
58 mapping = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
59 CHECK(mapping != MAP_FAILED);
60 mapping[0] = 31;
61 mapping[page] = 47;
62 mapping[2 * page] = 63;
63 CHECK(sync_file_range(fd, page - 1, 2, SYNC_FILE_RANGE_WRITE) == 0);
64 CHECK(sync_file_range(
65 fd, page + 1, 0,
66 SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE | SYNC_FILE_RANGE_WAIT_AFTER) == 0);
67 CHECK(sync_file_range(fd, 0, 0, 0) == 0);
68 CHECK(sync_file_range(readonly, 0, length, SYNC_FILE_RANGE_WAIT_AFTER) == 0);
69 CHECK(fdatasync(fd) == 0 && fdatasync(readonly) == 0);
70 CHECK(lseek(fd, 0, SEEK_CUR) == 19 && lseek(readonly, 0, SEEK_CUR) == 23);
71 CHECK(pread(readonly, &byte, 1, 0) == 1 && byte == 31);
72 CHECK(pread(readonly, &byte, 1, page) == 1 && byte == 47);
73 CHECK(pread(readonly, &byte, 1, 2 * page) == 1 && byte == 63);
74
75 errno = 0;
76 CHECK(fdatasync(-1) == -1 && errno == EBADF);
77 errno = 0;
78 CHECK(fdatasync(pathfd) == -1 && errno == EBADF);
79 errno = 0;
80 CHECK(readahead(writeonly, 0, 1) == -1 && errno == EBADF);
81 errno = 0;
82 CHECK(readahead(pathfd, 0, 1) == -1 && errno == EBADF);
83 errno = 0;
84 CHECK(readahead(readonly, -1, 1) == -1 && errno == EINVAL);
85 errno = 0;
86 CHECK(readahead(readonly, 0, SIZE_MAX) == -1 && errno == EINVAL);
87 errno = EDOM;
88 CHECK(posix_fadvise(-1, 0, 1, POSIX_FADV_WILLNEED) == EBADF && errno == EDOM);
89 CHECK(posix_fadvise(pathfd, 0, 1, POSIX_FADV_WILLNEED) == EBADF);
90 CHECK(posix_fadvise(readonly, -1, 1, POSIX_FADV_WILLNEED) == EINVAL);
91 CHECK(posix_fadvise(readonly, 0, -1, POSIX_FADV_WILLNEED) == EINVAL);
92 CHECK(posix_fadvise(readonly, 0, 1, 99) == EINVAL);
93 for (int advice = POSIX_FADV_NORMAL; advice <= POSIX_FADV_NOREUSE; ++advice)
94 if (advice != POSIX_FADV_WILLNEED)
95 CHECK(posix_fadvise(readonly, 0, 1, advice) == EOPNOTSUPP);
96 errno = 0;
97 CHECK(sync_file_range(fd, -1, 1, SYNC_FILE_RANGE_WRITE) == -1 && errno == EINVAL);
98 errno = 0;
99 CHECK(sync_file_range(fd, 0, -1, SYNC_FILE_RANGE_WRITE) == -1 && errno == EINVAL);
100 errno = 0;
101 CHECK(sync_file_range(fd, LLONG_MAX, 1, SYNC_FILE_RANGE_WRITE) == -1 && errno == EINVAL);
102 errno = 0;
103 CHECK(sync_file_range(fd, 0, 1, 8) == -1 && errno == EINVAL);
104 errno = 0;
105 CHECK(sync_file_range(pathfd, 0, 1, 0) == -1 && errno == EBADF);
106 CHECK(pipe(pipes) == 0);
107 errno = 0;
108 CHECK(fdatasync(pipes[0]) == -1 && errno == EINVAL);
109 errno = 0;
110 CHECK(readahead(pipes[0], 0, 1) == -1 && errno == EINVAL);
111 CHECK(posix_fadvise(pipes[0], 0, 1, POSIX_FADV_WILLNEED) == ESPIPE);
112 errno = 0;
113 CHECK(sync_file_range(pipes[1], 0, 1, SYNC_FILE_RANGE_WRITE) == -1 && errno == ESPIPE);
114
115 puts("FILE-SYNC-CONTRACT: PASS");
116 result = 0;
117fail:
118 if (mapping != MAP_FAILED)
119 munmap(mapping, length);
120 if (fd >= 0)
121 close(fd);
122 if (readonly >= 0)
123 close(readonly);
124 if (writeonly >= 0)
125 close(writeonly);
126 if (pathfd >= 0)
127 close(pathfd);
128 if (pipes[0] >= 0)
129 close(pipes[0]);
130 if (pipes[1] >= 0)
131 close(pipes[1]);
132 if (fd >= 0)
133 unlink(path);
134 return result;
135}