The Pedigree Project 0.1
records.c
1#define _GNU_SOURCE
2#include <limits.h>
3#include <string.h>
4#include <unistd.h>
5
6#include "contract.h"
7#include <sys/mman.h>
8
9static int ranges(void) {
10 int failed = 0, a = -1, b = -1;
11 char path[128] = {0};
12 CHECK((a = fl_file(path, "/tmp")) >= 0 && (b = open(path, O_RDWR)) >= 0);
13 CHECK(fl_record(a, F_OFD_SETLK, F_WRLCK, SEEK_SET, 100, 20) == 0);
14 CHECK(fl_query(b, F_GETLK, 110, 1, F_WRLCK, 100, 20, -1) == 0);
15 CHECK(fl_query(a, F_OFD_GETLK, 110, 1, F_UNLCK, 0, 0, 0) == 0);
16 struct flock own = {.l_type = F_UNLCK, .l_whence = SEEK_SET, .l_start = 110, .l_len = 1};
17 CHECK(fcntl(a, F_OFD_GETLK, &own) == 0 && own.l_type == F_WRLCK && own.l_whence == SEEK_SET &&
18 own.l_start == 100 && own.l_len == 20 && own.l_pid == -1);
19 own = (struct flock){.l_type = F_UNLCK, .l_whence = SEEK_SET, .l_start = 110, .l_len = 1};
20 CHECK(fcntl(b, F_OFD_GETLK, &own) == 0 && own.l_type == F_UNLCK);
21 CHECK(fl_record(b, F_SETLK, F_WRLCK, SEEK_SET, 110, 1) == -1 && errno == EAGAIN);
22 CHECK(fl_lock(a, FL_OFD, F_UNLCK, 0) == 0);
23 CHECK(fl_record(a, F_SETLK, F_WRLCK, SEEK_SET, 20, 10) == 0);
24 CHECK(fl_query(b, F_OFD_GETLK, 20, 1, F_WRLCK, 20, 10, getpid()) == 0);
25 CHECK(fl_query(b, F_GETLK, 20, 1, F_UNLCK, 0, 0, 0) == 0);
26 CHECK(fl_lock(a, FL_CLASSIC, F_UNLCK, 0) == 0);
27
28 CHECK(lseek(a, 40, SEEK_SET) == 40);
29 CHECK(fl_record(a, F_OFD_SETLK, F_WRLCK, SEEK_CUR, -10, -10) == 0);
30 CHECK(fl_query(b, F_OFD_GETLK, 20, 1, F_WRLCK, 20, 10, -1) == 0);
31 CHECK(lseek(a, 0, SEEK_CUR) == 40);
32 CHECK(fl_lock(a, FL_OFD, F_UNLCK, 0) == 0);
33 CHECK(fl_record(a, F_OFD_SETLK, F_WRLCK, SEEK_END, -8, 0) == 0);
34 CHECK(ftruncate(a, 256) == 0);
35 CHECK(fl_query(b, F_GETLK, 1000, 1, F_WRLCK, 120, 0, -1) == 0);
36 CHECK(fl_lock(a, FL_OFD, F_UNLCK, 0) == 0);
37
38 CHECK(fl_record(a, F_OFD_SETLK, F_WRLCK, SEEK_SET, 0, 100) == 0);
39 CHECK(fl_record(a, F_OFD_SETLK, F_RDLCK, SEEK_SET, 20, 20) == 0);
40 CHECK(fl_record(b, F_OFD_SETLK, F_RDLCK, SEEK_SET, 20, 20) == 0);
41 CHECK(fl_record(a, F_OFD_SETLK, F_WRLCK, SEEK_SET, 20, 20) == -1 && errno == EAGAIN);
42 CHECK(fl_lock(b, FL_OFD, F_UNLCK, 0) == 0);
43 CHECK(fl_query(b, F_GETLK, 0, 1, F_WRLCK, 0, 20, -1) == 0);
44 CHECK(fl_query(b, F_GETLK, 20, 1, F_RDLCK, 20, 20, -1) == 0);
45 CHECK(fl_query(b, F_GETLK, 40, 1, F_WRLCK, 40, 60, -1) == 0);
46 CHECK(fl_record(a, F_OFD_SETLK, F_UNLCK, SEEK_SET, 25, 10) == 0);
47 CHECK(fl_record(b, F_OFD_SETLK, F_WRLCK, SEEK_SET, 25, 10) == 0);
48 CHECK(fl_record(a, F_OFD_SETLK, F_WRLCK, SEEK_SET, 20, 20) == -1 && errno == EAGAIN);
49 CHECK(fl_query(b, F_GETLK, 20, 1, F_RDLCK, 20, 5, -1) == 0);
50 CHECK(fl_query(b, F_GETLK, 35, 1, F_RDLCK, 35, 5, -1) == 0);
51 CHECK(fl_lock(b, FL_OFD, F_UNLCK, 0) == 0);
52 CHECK(fl_record(a, F_OFD_SETLK, F_WRLCK, SEEK_SET, 20, 20) == 0);
53 CHECK(fl_query(b, F_GETLK, 80, 1, F_WRLCK, 0, 100, -1) == 0);
54out:
55 if (b >= 0)
56 close(b);
57 if (a >= 0)
58 close(a);
59 if (*path)
60 unlink(path);
61 return failed;
62}
63
64static int errors(void) {
65 int failed = 0, a = -1, b = -1, ro = -1, wo = -1;
66 char path[128] = {0};
67 const size_t page = (size_t)sysconf(_SC_PAGESIZE);
68 struct flock* wire = mmap(NULL, page, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
69 CHECK(wire != MAP_FAILED);
70 CHECK((a = fl_file(path, "/tmp")) >= 0 && (b = open(path, O_RDWR)) >= 0);
71 CHECK((ro = open(path, O_RDONLY)) >= 0 && (wo = open(path, O_WRONLY)) >= 0);
72 CHECK(fl_record(-1, F_SETLK, F_WRLCK, SEEK_SET, 0, 1) == -1 && errno == EBADF);
73 CHECK(fl_record(a, F_SETLK, 99, SEEK_SET, 0, 1) == -1 && errno == EINVAL);
74 CHECK(fl_record(a, F_SETLK, F_WRLCK, 99, 0, 1) == -1 && errno == EINVAL);
75 CHECK(fl_record(a, F_SETLK, F_WRLCK, SEEK_SET, -1, 1) == -1 && errno == EINVAL);
76 CHECK(fl_record(a, F_SETLK, F_WRLCK, SEEK_SET, 0, -1) == -1 && errno == EINVAL);
77 CHECK(fl_record(a, F_SETLK, F_WRLCK, SEEK_SET, INT64_MAX, 2) == -1 && errno == EOVERFLOW);
78 CHECK(lseek(a, 1, SEEK_SET) == 1);
79 CHECK(fl_record(a, F_SETLK, F_WRLCK, SEEK_CUR, INT64_MAX, 1) == -1 && errno == EOVERFLOW);
80 for (int n = 0; n < 2; ++n) {
81 const int command = n ? F_OFD_SETLK : F_SETLK;
82 CHECK(fl_record(ro, command, F_WRLCK, SEEK_SET, 0, 1) == -1 && errno == EBADF);
83 CHECK(fl_record(wo, command, F_RDLCK, SEEK_SET, 0, 1) == -1 && errno == EBADF);
84 }
85 CHECK(fl_query(ro, F_OFD_GETLK, 0, 1, F_UNLCK, 0, 0, 0) == 0);
86 *wire = (struct flock){.l_type = F_WRLCK, .l_whence = SEEK_SET, .l_len = 1, .l_pid = 9};
87 CHECK(fcntl(a, F_OFD_SETLK, wire) == -1 && errno == EINVAL);
88 CHECK(fcntl(a, F_OFD_GETLK, wire) == -1 && errno == EINVAL);
89 CHECK(fcntl(a, F_OFD_SETLKW, wire) == -1 && errno == EINVAL);
90
91 memset(wire, 0xa5, sizeof(*wire));
92 wire->l_type = F_WRLCK;
93 wire->l_whence = SEEK_SET;
94 wire->l_start = 7;
95 wire->l_len = 3;
96 wire->l_pid = 0;
97 struct flock expected;
98 memcpy(&expected, wire, sizeof(expected));
99 expected.l_type = F_UNLCK;
100 CHECK(fcntl(a, F_OFD_GETLK, wire) == 0 && !memcmp(wire, &expected, sizeof(expected)));
101 CHECK(fl_record(a, F_OFD_SETLK, F_WRLCK, SEEK_SET, 0, 10) == 0);
102 *wire = (struct flock){.l_type = F_WRLCK, .l_whence = SEEK_SET, .l_len = 1};
103 CHECK(mprotect(wire, page, PROT_READ) == 0);
104 CHECK(fcntl(b, F_OFD_GETLK, wire) == -1 && errno == EFAULT);
105 CHECK(fl_query(b, F_OFD_GETLK, 0, 1, F_WRLCK, 0, 10, -1) == 0);
106 CHECK(mprotect(wire, page, PROT_NONE) == 0);
107 CHECK(fcntl(b, F_SETLK, wire) == -1 && errno == EFAULT);
108 CHECK(fcntl(b, F_GETLK, wire) == -1 && errno == EFAULT);
109out:
110 if (wire != MAP_FAILED)
111 munmap(wire, page);
112 if (wo >= 0)
113 close(wo);
114 if (ro >= 0)
115 close(ro);
116 if (b >= 0)
117 close(b);
118 if (a >= 0)
119 close(a);
120 if (*path)
121 unlink(path);
122 return failed;
123}
124int file_lock_records(void) {
125 return ranges() || errors();
126}