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 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 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 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 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 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 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 108 c_fsync(void) 109 { 110 int ret = fsync(fd); 111 check("fsync", ret, 0); 112 } 113 114 void 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 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 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 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 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 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 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 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 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 233 usage(void) 234 { 235 errx(1, "usage: fileops (create|read|mmap) filename"); 236 } 237 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