The Pedigree Project 0.1
handles.c
1#define _GNU_SOURCE
2#include <string.h>
3#include <unistd.h>
4
5#include "contract.h"
6#include <sys/stat.h>
7
8static int open_flags(void) {
9 int failed = 0, writer = -1, reader = -1;
10 struct fh_file file = {.fd = -1};
11 char bytes[20];
12 struct stat state;
13 CHECK(!fh_create(&file));
14 writer = open_by_handle_at(file.fd, (struct file_handle*)&file.handle,
15 O_WRONLY | O_APPEND | O_CLOEXEC | O_NONBLOCK | O_LARGEFILE);
16 CHECK(writer >= 0);
17 CHECK(fcntl(writer, F_GETFD) & FD_CLOEXEC);
18 CHECK((fcntl(writer, F_GETFL) & (O_ACCMODE | O_APPEND | O_NONBLOCK)) ==
19 (O_WRONLY | O_APPEND | O_NONBLOCK));
20 CHECK(write(writer, "Z", 1) == 1);
21 CHECK(!fstat(file.fd, &state) && state.st_size == 17);
22 CHECK(pread(file.fd, bytes, 1, 16) == 1 && bytes[0] == 'Z');
23 reader = open_by_handle_at(file.fd, (struct file_handle*)&file.handle, O_RDONLY);
24 CHECK(reader >= 0);
25 errno = 0;
26 CHECK(write(reader, "x", 1) == -1 && errno == EBADF);
27 close(writer);
28 writer = open_by_handle_at(file.fd, (struct file_handle*)&file.handle, O_RDWR | O_TRUNC);
29 CHECK(writer >= 0 && !fstat(file.fd, &state) && state.st_size == 0);
30 CHECK(write(writer, "new", 3) == 3);
31 CHECK(pread(reader, bytes, 3, 0) == 3 && !memcmp(bytes, "new", 3));
32out:
33 if (reader >= 0)
34 close(reader);
35 if (writer >= 0)
36 close(writer);
37 fh_close(&file);
38 return failed;
39}
40
41int fh_handles(void) {
42 int failed = 0, root = -1, first = -1, second = -1, duplicate = -1, alias_fd = -1, path_fd = -1;
43 struct fh_file file = {.fd = -1};
44 struct fh_handle query, exact, changed;
45 char alias[224] = {0}, moved[224] = {0}, bytes[8];
46 struct stat state, reopened;
47 int mount_id = -1;
48 CHECK(!fh_create(&file));
49 CHECK(file.mount_id > 0 && file.handle.handle_bytes && file.handle.handle_bytes <= 128);
50 memset(&query, 0xa5, sizeof(query));
51 query.handle_bytes = 0;
52 errno = 0;
53 CHECK(name_to_handle_at(AT_FDCWD, file.path, (struct file_handle*)&query, &mount_id, 0) == -1 &&
54 errno == EOVERFLOW);
55 CHECK(query.handle_bytes == file.handle.handle_bytes && mount_id == file.mount_id);
56 for (size_t n = 0; n < sizeof(query.bytes); ++n)
57 CHECK(query.bytes[n] == 0xa5);
58 query.handle_bytes = file.handle.handle_bytes - 1;
59 errno = 0;
60 CHECK(name_to_handle_at(AT_FDCWD, file.path, (struct file_handle*)&query, &mount_id, 0) == -1 &&
61 errno == EOVERFLOW && query.handle_bytes == file.handle.handle_bytes);
62 query.handle_bytes = sizeof(query.bytes);
63 CHECK(!name_to_handle_at(AT_FDCWD, file.path, (struct file_handle*)&query, &mount_id, 0));
64 CHECK(fh_equal(&query, &file.handle));
65 root = open("/", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
66 CHECK(root >= 0);
67 exact.handle_bytes = sizeof(exact.bytes);
68 CHECK(!name_to_handle_at(root, file.path + 1, (struct file_handle*)&exact, &mount_id, 0));
69 CHECK(fh_equal(&exact, &file.handle) && mount_id == file.mount_id);
70 path_fd = open(file.path, O_PATH | O_CLOEXEC);
71 CHECK(path_fd >= 0 && !fh_export(path_fd, &exact, &mount_id));
72 CHECK(fh_equal(&exact, &file.handle));
73 CHECK(lseek(file.fd, 7, SEEK_SET) == 7);
74 first = open_by_handle_at(root, (struct file_handle*)&file.handle, O_RDONLY);
75 second = open_by_handle_at(file.fd, (struct file_handle*)&file.handle, O_RDONLY);
76 CHECK(first >= 0 && second >= 0 && lseek(first, 0, SEEK_CUR) == 0);
77 CHECK(read(first, bytes, 2) == 2 && !memcmp(bytes, "01", 2));
78 CHECK(lseek(second, 0, SEEK_CUR) == 0 && lseek(file.fd, 0, SEEK_CUR) == 7);
79 duplicate = dup(first);
80 CHECK(duplicate >= 0 && read(duplicate, bytes, 1) == 1 && bytes[0] == '2');
81 CHECK(lseek(first, 0, SEEK_CUR) == 3);
82 CHECK(!fstat(file.fd, &state) && !fstat(first, &reopened) && state.st_ino == reopened.st_ino);
83 snprintf(alias, sizeof(alias), "%s.alias", file.path);
84 snprintf(moved, sizeof(moved), "%s.moved", file.path);
85 CHECK(!link(file.path, alias) && !rename(file.path, moved));
86 snprintf(file.path, sizeof(file.path), "%s", moved);
87 moved[0] = 0;
88 alias_fd = open(alias, O_RDONLY | O_CLOEXEC);
89 CHECK(alias_fd >= 0 && !fh_export(alias_fd, &exact, &mount_id));
90 CHECK(fh_equal(&exact, &file.handle));
91 CHECK(!unlink(file.path));
92 file.path[0] = 0;
93 close(second);
94 second = open_by_handle_at(root, (struct file_handle*)&file.handle, O_RDONLY);
95 CHECK(second >= 0 && pread(second, bytes, 4, 0) == 4 && !memcmp(bytes, "0123", 4));
96 changed = file.handle;
97 changed.handle_type ^= 0x01000000;
98 errno = 0;
99 CHECK(open_by_handle_at(root, (struct file_handle*)&changed, O_RDONLY) == -1 && errno == ESTALE);
100 changed = file.handle;
101 changed.bytes[0] ^= 0x80;
102 errno = 0;
103 CHECK(open_by_handle_at(root, (struct file_handle*)&changed, O_RDONLY) == -1 && errno == ESTALE);
104 CHECK(!unlink(alias));
105 alias[0] = 0;
106 errno = 0;
107 CHECK(open_by_handle_at(root, (struct file_handle*)&file.handle, O_RDONLY) == -1 &&
108 errno == ESTALE);
109 CHECK(pread(first, bytes, 4, 0) == 4 && !memcmp(bytes, "0123", 4));
110 CHECK(!open_flags());
111out:
112 if (path_fd >= 0)
113 close(path_fd);
114 if (alias_fd >= 0)
115 close(alias_fd);
116 if (duplicate >= 0)
117 close(duplicate);
118 if (second >= 0)
119 close(second);
120 if (first >= 0)
121 close(first);
122 if (root >= 0)
123 close(root);
124 if (alias[0])
125 unlink(alias);
126 if (moved[0])
127 unlink(moved);
128 fh_close(&file);
129 return failed;
130}
Definition waits.c:9