/* $OpenBSD: fileops.c,v 1.2 2017/05/29 13:49:40 bluhm Exp $ */ /* * Copyright (c) 2017 Stefan Fritsch * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include #include #define BUFSIZE (16 * 1024) #define HOLESIZE (16 * BUFSIZE) static int debug = 0; static int fd = -1; static off_t curpos = 0; static char *fname; static char *gbuf; static char *mbuf; void gen_data(void *buf, size_t size, uint32_t seed) { assert(size % 4 == 0); if (debug) printf("%s: size %zd seed %#08x\n", __func__, size, seed); uint32_t *ibuf = buf; for (size_t i = 0; i < size / 4; i++) ibuf[i] = seed + i; } void check_data(const void *buf, size_t size, uint32_t seed) { assert(size % 4 == 0); const uint32_t *ibuf = buf; for (size_t i = 0; i < size / 4; i++) { if (ibuf[i] != seed + i) { errx(3, "%s: pos %zd/%zd: expected %#08zx got %#08x", __func__, 4 * i, size, seed + i, ibuf[i]); } } } void check_zero(const void *buf, size_t size) { assert(size % 4 == 0); const uint32_t *ibuf = buf; for (size_t i = 0; i < size / 4; i++) { if (ibuf[i] != 0) { errx(3, "%s: pos %zd/%zd: expected 0 got %#08x", __func__, 4 * i, size, ibuf[i]); } } } void check(const char *what, int64_t have, int64_t want) { if (have != want) { if (have == -1) err(2, "%s returned %lld, expected %lld", what, have, want); else errx(2, "%s returned %lld, expected %lld", what, have, want); } if (debug) printf("%s returned %lld\n", what, have); } void c_write(void *buf, size_t size) { ssize_t ret = write(fd, buf, size); check("write", ret, size); curpos += ret; } void c_read(void *buf, size_t size) { ssize_t ret = read(fd, buf, size); check("read", ret, size); curpos += ret; } void c_fsync(void) { int ret = fsync(fd); check("fsync", ret, 0); } void c_lseek(off_t offset, int whence) { off_t ret = lseek(fd, offset, whence); switch (whence) { case SEEK_SET: curpos = offset; break; case SEEK_CUR: curpos += offset; break; default: errx(1, "c_lseek not supported"); } check("lseek", ret, curpos); if (debug) printf("curpos: %lld\n", (long long int)curpos); } void c_mmap(size_t size) { mbuf = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, curpos); if (mbuf == MAP_FAILED) err(2, "mmap %zd pos %lld failed", size, (long long)curpos); curpos += size; if (debug) printf("mmap: %p\n", mbuf); } void c_munmap(size_t size) { int ret = munmap(mbuf, size); if (ret != 0) err(2, "munmap"); } void c_open(int flags) { fd = open(fname, flags, S_IRUSR|S_IWUSR); if (fd == -1) err(1, "open"); } void check_read(size_t size, int hole) { size_t pos = 0; while (pos < size) { size_t to_read = size - pos; uint32_t seed = curpos; if (to_read > BUFSIZE) to_read = BUFSIZE; c_read(gbuf, to_read); if (hole) check_zero(gbuf, to_read); else check_data(gbuf, to_read, seed); pos += to_read; } } /* XXX this assumes size is a multiple of the page size */ void check_mmap(size_t size, int hole) { size_t pos = 0; while (pos < size) { size_t to_read = size - pos; uint32_t seed = curpos; if (to_read > BUFSIZE) to_read = BUFSIZE; c_mmap(to_read); if (hole) check_zero(mbuf, to_read); else check_data(mbuf, to_read, seed); c_munmap(to_read); pos += to_read; } } void do_create(void) { unlink(fname); c_open(O_EXCL|O_CREAT|O_RDWR); gen_data(gbuf, BUFSIZE, curpos); c_write(gbuf, BUFSIZE); c_lseek(HOLESIZE, SEEK_CUR); gen_data(gbuf, BUFSIZE, curpos); c_write(gbuf, BUFSIZE); c_fsync(); } void do_read(void) { c_open(O_RDWR); check_read(BUFSIZE, 0); check_read(HOLESIZE, 1); check_read(BUFSIZE, 0); } void do_mmap(void) { c_open(O_RDWR); check_mmap(BUFSIZE, 0); check_mmap(HOLESIZE, 1); check_mmap(BUFSIZE, 0); } void usage(void) { errx(1, "usage: fileops (create|read|mmap) filename"); } int main(int argc, char **argv) { if (argc != 3) usage(); fname = argv[2]; gbuf = malloc(BUFSIZE); if (gbuf == NULL) err(1, "malloc"); if (strcmp(argv[1], "create") == 0) { do_create(); } else if (strcmp(argv[1], "read") == 0) { do_read(); } else if (strcmp(argv[1], "mmap") == 0) { do_mmap(); } else { usage(); } printf("pass\n"); return 0; }