1 /* $OpenBSD: fileops.c,v 1.2 2017/05/29 13:49:40 bluhm Exp $ */
2 /*
3 * Copyright (c) 2017 Stefan Fritsch <sf@sfritsch.de>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17 #include <assert.h>
18 #include <err.h>
19 #include <fcntl.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/mman.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27
28 #define BUFSIZE (16 * 1024)
29 #define HOLESIZE (16 * BUFSIZE)
30
31 static int debug = 0;
32 static int fd = -1;
33 static off_t curpos = 0;
34 static char *fname;
35 static char *gbuf;
36 static char *mbuf;
37
38 void
gen_data(void * buf,size_t size,uint32_t seed)39 gen_data(void *buf, size_t size, uint32_t seed)
40 {
41 assert(size % 4 == 0);
42 if (debug)
43 printf("%s: size %zd seed %#08x\n", __func__, size, seed);
44 uint32_t *ibuf = buf;
45 for (size_t i = 0; i < size / 4; i++)
46 ibuf[i] = seed + i;
47 }
48
49 void
check_data(const void * buf,size_t size,uint32_t seed)50 check_data(const void *buf, size_t size, uint32_t seed)
51 {
52 assert(size % 4 == 0);
53 const uint32_t *ibuf = buf;
54 for (size_t i = 0; i < size / 4; i++) {
55 if (ibuf[i] != seed + i) {
56 errx(3, "%s: pos %zd/%zd: expected %#08zx got %#08x",
57 __func__, 4 * i, size, seed + i, ibuf[i]);
58 }
59 }
60 }
61
62 void
check_zero(const void * buf,size_t size)63 check_zero(const void *buf, size_t size)
64 {
65 assert(size % 4 == 0);
66 const uint32_t *ibuf = buf;
67 for (size_t i = 0; i < size / 4; i++) {
68 if (ibuf[i] != 0) {
69 errx(3, "%s: pos %zd/%zd: expected 0 got %#08x",
70 __func__, 4 * i, size, ibuf[i]);
71 }
72 }
73 }
74
75 void
check(const char * what,int64_t have,int64_t want)76 check(const char *what, int64_t have, int64_t want)
77 {
78 if (have != want) {
79 if (have == -1)
80 err(2, "%s returned %lld, expected %lld",
81 what, have, want);
82 else
83 errx(2, "%s returned %lld, expected %lld",
84 what, have, want);
85 }
86
87 if (debug)
88 printf("%s returned %lld\n", what, have);
89 }
90
91 void
c_write(void * buf,size_t size)92 c_write(void *buf, size_t size)
93 {
94 ssize_t ret = write(fd, buf, size);
95 check("write", ret, size);
96 curpos += ret;
97 }
98
99 void
c_read(void * buf,size_t size)100 c_read(void *buf, size_t size)
101 {
102 ssize_t ret = read(fd, buf, size);
103 check("read", ret, size);
104 curpos += ret;
105 }
106
107 void
c_fsync(void)108 c_fsync(void)
109 {
110 int ret = fsync(fd);
111 check("fsync", ret, 0);
112 }
113
114 void
c_lseek(off_t offset,int whence)115 c_lseek(off_t offset, int whence)
116 {
117 off_t ret = lseek(fd, offset, whence);
118 switch (whence) {
119 case SEEK_SET:
120 curpos = offset;
121 break;
122 case SEEK_CUR:
123 curpos += offset;
124 break;
125 default:
126 errx(1, "c_lseek not supported");
127 }
128 check("lseek", ret, curpos);
129 if (debug)
130 printf("curpos: %lld\n", (long long int)curpos);
131 }
132
133 void
c_mmap(size_t size)134 c_mmap(size_t size)
135 {
136 mbuf = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, curpos);
137 if (mbuf == MAP_FAILED)
138 err(2, "mmap %zd pos %lld failed", size, (long long)curpos);
139 curpos += size;
140 if (debug)
141 printf("mmap: %p\n", mbuf);
142 }
143
144 void
c_munmap(size_t size)145 c_munmap(size_t size)
146 {
147 int ret = munmap(mbuf, size);
148 if (ret != 0)
149 err(2, "munmap");
150 }
151
152 void
c_open(int flags)153 c_open(int flags)
154 {
155 fd = open(fname, flags, S_IRUSR|S_IWUSR);
156 if (fd == -1)
157 err(1, "open");
158 }
159
160 void
check_read(size_t size,int hole)161 check_read(size_t size, int hole)
162 {
163 size_t pos = 0;
164 while (pos < size) {
165 size_t to_read = size - pos;
166 uint32_t seed = curpos;
167 if (to_read > BUFSIZE)
168 to_read = BUFSIZE;
169 c_read(gbuf, to_read);
170 if (hole)
171 check_zero(gbuf, to_read);
172 else
173 check_data(gbuf, to_read, seed);
174 pos += to_read;
175 }
176 }
177
178 /* XXX this assumes size is a multiple of the page size */
179 void
check_mmap(size_t size,int hole)180 check_mmap(size_t size, int hole)
181 {
182 size_t pos = 0;
183 while (pos < size) {
184 size_t to_read = size - pos;
185 uint32_t seed = curpos;
186 if (to_read > BUFSIZE)
187 to_read = BUFSIZE;
188 c_mmap(to_read);
189 if (hole)
190 check_zero(mbuf, to_read);
191 else
192 check_data(mbuf, to_read, seed);
193 c_munmap(to_read);
194 pos += to_read;
195 }
196 }
197
198 void
do_create(void)199 do_create(void)
200 {
201 unlink(fname);
202 c_open(O_EXCL|O_CREAT|O_RDWR);
203
204 gen_data(gbuf, BUFSIZE, curpos);
205 c_write(gbuf, BUFSIZE);
206
207 c_lseek(HOLESIZE, SEEK_CUR);
208
209 gen_data(gbuf, BUFSIZE, curpos);
210 c_write(gbuf, BUFSIZE);
211 c_fsync();
212 }
213
214 void
do_read(void)215 do_read(void)
216 {
217 c_open(O_RDWR);
218 check_read(BUFSIZE, 0);
219 check_read(HOLESIZE, 1);
220 check_read(BUFSIZE, 0);
221 }
222
223 void
do_mmap(void)224 do_mmap(void)
225 {
226 c_open(O_RDWR);
227 check_mmap(BUFSIZE, 0);
228 check_mmap(HOLESIZE, 1);
229 check_mmap(BUFSIZE, 0);
230 }
231
232 void
usage(void)233 usage(void)
234 {
235 errx(1, "usage: fileops (create|read|mmap) filename");
236 }
237
main(int argc,char ** argv)238 int main(int argc, char **argv)
239 {
240 if (argc != 3)
241 usage();
242
243 fname = argv[2];
244 gbuf = malloc(BUFSIZE);
245 if (gbuf == NULL)
246 err(1, "malloc");
247
248 if (strcmp(argv[1], "create") == 0) {
249 do_create();
250 } else if (strcmp(argv[1], "read") == 0) {
251 do_read();
252 } else if (strcmp(argv[1], "mmap") == 0) {
253 do_mmap();
254 } else {
255 usage();
256 }
257
258 printf("pass\n");
259 return 0;
260 }
261