diff options
Diffstat (limited to 'tests/encryption/frag.c')
-rw-r--r-- | tests/encryption/frag.c | 328 |
1 files changed, 328 insertions, 0 deletions
diff --git a/tests/encryption/frag.c b/tests/encryption/frag.c new file mode 100644 index 00000000000..86da037c607 --- /dev/null +++ b/tests/encryption/frag.c @@ -0,0 +1,328 @@ +/* + Copyright (c) 2008-2013 Red Hat, Inc. <http://www.redhat.com> + This file is part of GlusterFS. + + This file is licensed to you under your choice of the GNU Lesser + General Public License, version 3 or any later version (LGPLv3 or + later), or the GNU General Public License, version 2 (GPLv2), in all + cases as published by the Free Software Foundation. +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/syscall.h> +#include <unistd.h> +#include <fcntl.h> + +#define MAX_NUM_OPS (1 << 20) +#define MAX_FILE_SIZE (1 << 30) + +typedef enum { + READ_OP, + WRITE_OP, + TRUNC_OP, + LAST_OP +} frag_op; + +struct frag_ctx { + int test_fd; + int good_fd; + char *test_buf; + char *good_buf; + char *content; + int max_file_size; +}; + +typedef int (*frag_op_t)(struct frag_ctx *ctx, off_t offset, size_t count); + +static int doread(int fd, off_t offset, size_t count, + char *buf, int max_file_size) +{ + int ret = 0; + int was_read = 0; + + if (lseek(fd, offset, SEEK_SET) == -1) { + perror("lseek failed"); + return -1; + } + while (count) { + ret = read(fd, buf + offset + was_read, count); + if (ret < 0) + return -1; + if (ret == 0) + break; + if (ret > count) { + fprintf(stderr, "READ: read more than asked\n"); + return -1; + } + count -= ret; + was_read += ret; + } + return ret; +} + +static int dowrite(int fd, off_t offset, size_t count, char *buf) +{ + int ret; + + ret = lseek(fd, offset, SEEK_SET); + if (ret == -1) + return ret; + return write(fd, buf, count); +} + +static int dotrunc(int fd, off_t offset) +{ + int ret; + + ret = ftruncate(fd, offset); + if (ret == -1) + perror("truncate failed"); + return ret; +} + +static int prepare_file(char *filename, int *fd, char **buf, int max_file_size) +{ + int ret; + + *buf = malloc(max_file_size); + if (*buf == NULL) { + perror("malloc failed"); + return -1; + } + *fd = open(filename, O_CREAT | O_RDWR, S_IRWXU); + if (*fd == -1) { + perror("open failed"); + free(*buf); + *buf = NULL; + return -1; + } + return 0; +} + +/* + * @offset, @count: random values from [0, max_file_size - 1] + */ +static int frag_write(struct frag_ctx *ctx, off_t offset, size_t count) +{ + int ret; + struct stat test_stbuf; + struct stat good_stbuf; + + if (offset + count > ctx->max_file_size) + offset = offset / 2; + if (offset + count > ctx->max_file_size) + count = count / 2; + + if (fstat(ctx->test_fd, &test_stbuf)) { + fprintf(stderr, "WRITE: fstat of test file failed\n"); + return -1; + } + if (offset > test_stbuf.st_size) + printf("writing hole\n"); + + ret = dowrite(ctx->test_fd, offset, count, ctx->content); + if (ret < 0 || ret != count){ + fprintf(stderr, "WRITE: failed to write test file\n"); + return -1; + } + ret = dowrite(ctx->good_fd, offset, count, ctx->content); + if (ret < 0 || ret != count) { + fprintf(stderr, "WRITE: failed to write test file\n"); + return -1; + } + if (fstat(ctx->test_fd, &test_stbuf)) { + fprintf(stderr, "WRITE: fstat of test file failed\n"); + return -1; + } + if (fstat(ctx->good_fd, &good_stbuf)) { + fprintf(stderr, "WRITE: fstat of good file failed\n"); + return -1; + } + if (test_stbuf.st_size != good_stbuf.st_size) { + fprintf(stderr, + "READ: Bad file size %d (expected %d)\n", + (int)test_stbuf.st_size, + (int)good_stbuf.st_size); + return -1; + } + return 0; +} + +/* + * @offset, @count: random values from [0, max_file_size - 1] + */ +static int frag_read(struct frag_ctx *ctx, off_t offset, size_t count) +{ + ssize_t test_ret; + ssize_t good_ret; + + test_ret = doread(ctx->test_fd, + offset, count, ctx->test_buf, ctx->max_file_size); + if (test_ret < 0) { + fprintf(stderr, "READ: failed to read test file\n"); + return -1; + } + good_ret = doread(ctx->good_fd, + offset, count, ctx->good_buf, ctx->max_file_size); + if (good_ret < 0) { + fprintf(stderr, "READ: failed to read good file\n"); + return -1; + } + if (test_ret != good_ret) { + fprintf(stderr, + "READ: Bad return value %d (expected %d\n)", + test_ret, good_ret); + return -1; + } + if (memcmp(ctx->test_buf + offset, ctx->good_buf + offset, good_ret)) { + fprintf(stderr, "READ: bad data\n"); + return -1; + } + return 0; +} + +/* + * @offset: random value from [0, max_file_size - 1] + */ +static int frag_truncate(struct frag_ctx *ctx, + off_t offset, __attribute__((unused))size_t count) +{ + int ret; + struct stat test_stbuf; + struct stat good_stbuf; + + if (fstat(ctx->test_fd, &test_stbuf)) { + fprintf(stderr, "TRUNCATE: fstat of test file failed\n"); + return -1; + } + if (offset > test_stbuf.st_size) + printf("expanding truncate to %d\n", offset); + else if (offset < test_stbuf.st_size) + printf("shrinking truncate to %d\n", offset); + else + printf("trivial truncate\n"); + + ret = dotrunc(ctx->test_fd, offset); + if (ret == -1) { + fprintf(stderr, "TRUNCATE: failed for test file\n"); + return -1; + } + ret = dotrunc(ctx->good_fd, offset); + if (ret == -1) { + fprintf(stderr, "TRUNCATE: failed for good file\n"); + return -1; + } + if (fstat(ctx->test_fd, &test_stbuf)) { + fprintf(stderr, "TRUNCATE: fstat of test file failed\n"); + return -1; + } + if (fstat(ctx->good_fd, &good_stbuf)) { + fprintf(stderr, "TRUNCATE: fstat of good file failed\n"); + return -1; + } + if (test_stbuf.st_size != good_stbuf.st_size) { + fprintf(stderr, + "TRUNCATE: bad test file size %d (expected %d)\n", + test_stbuf.st_size, + good_stbuf.st_size); + return -1; + } + return 0; +} + +frag_op_t frag_ops[LAST_OP] = { + [READ_OP] = frag_read, + [WRITE_OP] = frag_write, + [TRUNC_OP] = frag_truncate +}; + +static void put_ctx(struct frag_ctx *ctx) +{ + if (ctx->test_buf) + free(ctx->test_buf); + if (ctx->good_buf) + free(ctx->good_buf); + if (ctx->content) + free(ctx->content); +} + +main (int argc, char *argv[]) +{ + int i; + int ret = 0; + struct frag_ctx ctx; + char *test_filename = NULL; + char *good_filename = NULL; + int num_ops; + int max_file_size; + + memset(&ctx, 0, sizeof(ctx)); + if (argc != 5) { + fprintf(stderr, + "usage: %s <test-file-name> <good-file-name> <max-file-size> <number-of-operations>\n", + argv[0]); + ret = -1; + goto exit; + } + test_filename = argv[1]; + good_filename = argv[2]; + max_file_size = atoi(argv[3]); + if (max_file_size > MAX_FILE_SIZE) + max_file_size = MAX_FILE_SIZE; + num_ops = atoi(argv[4]); + if (num_ops > MAX_NUM_OPS) + num_ops = MAX_NUM_OPS; + + ret = prepare_file(test_filename, + &ctx.test_fd, &ctx.test_buf, max_file_size); + if (ret) + goto exit; + ret = prepare_file(good_filename, + &ctx.good_fd, &ctx.good_buf, max_file_size); + if (ret) { + if (close(ctx.test_fd) == -1) + perror("close test_buf failed"); + goto exit; + } + ctx.content = malloc(max_file_size); + if (!ctx.content) { + perror("malloc failed"); + goto close; + } + ctx.max_file_size = max_file_size; + for (i = 0; i < max_file_size; i++) + ctx.content[i] = random() % 256; + + for (i = 0; i < num_ops; i++) { + ret = frag_ops[random() % LAST_OP](&ctx, + random() % max_file_size, /* offset */ + random() % max_file_size /* count */); + if (ret) + break; + } + close: + if (close(ctx.test_fd) == -1) + perror("close test_fd failed"); + if (close(ctx.good_fd) == -1) + perror("close good_fd failed"); + exit: + put_ctx(&ctx); + if (ret) + exit(1); + exit(0); +} + +/* + Local variables: + c-indentation-style: "K&R" + mode-name: "LC" + c-basic-offset: 8 + tab-width: 8 + fill-column: 80 + scroll-step: 1 + End: +*/ |