From 8148dc2eab154e94d2c9e041cc0abbba9845ce51 Mon Sep 17 00:00:00 2001 From: Ravishankar N Date: Wed, 29 Jan 2014 12:09:42 +0000 Subject: storage/posix: perform chmod after chown. Problem: When a replica brick is added to a volume, set-user-ID and set-group-ID permission bits of files are not set correctly in the new brick. The issue is in the posix_setattr() call where we do a chmod followed by a chown. But according to the man pages for chown: When the owner or group of an executable file are changed by an unprivileged user the S_ISUID and S_ISGID mode bits are cleared. POSIX does not specify whether this also should happen when root does the chown(). Fix: Swap the chmod and chown calls in posix_setattr() Change-Id: I094e47a995c210d2fdbc23ae7a5718286e7a9cf8 BUG: 1058797 Signed-off-by: Ravishankar N Reviewed-on: http://review.gluster.org/6862 Tested-by: Gluster Build System Reviewed-by: Pranith Kumar Karampuri Reviewed-by: Anand Avati --- tests/bugs/bug-1058797.t | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 tests/bugs/bug-1058797.t (limited to 'tests') diff --git a/tests/bugs/bug-1058797.t b/tests/bugs/bug-1058797.t new file mode 100644 index 000000000..2b80794cf --- /dev/null +++ b/tests/bugs/bug-1058797.t @@ -0,0 +1,45 @@ +#!/bin/bash +#Test that the setuid bit is healed correctly. + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; +#Basic checks +TEST glusterd + +#Create a 1x2 replica volume +TEST $CLI volume create $V0 replica 2 $H0:$B0/brick{0,1}; +TEST $CLI volume start $V0 +TEST $CLI volume set $V0 cluster.self-heal-daemon off + +# FUSE mount;create a file +TEST glusterfs -s $H0 --volfile-id $V0 $M0 +TEST touch $M0/file + +#Kill brick1 and set S_ISUID and S_ISGID bits from mount point +kill_brick $V0 $H0 $B0/brick1 +TEST chmod +x,+s $M0/file + +#Get file permissions from backend brick0 and verify that S_ISUID is indeed set +file_permissions1=`ls -l $B0/brick0/file | awk '{print $1}'| cut -d. -f1 | cut -d- -f2,3,4,5,6` +setuid_bit1=`echo $file_permissions1 | cut -b3` +EXPECT "s" echo $setuid_bit1 + +#Restart volume and do lookup from mount to trigger heal +TEST $CLI volume start $V0 force +EXPECT_WITHIN 20 "1" afr_child_up_status $V0 1 +TEST ls -l $M0/file + +#Get file permissions from healed brick1 and verify that S_ISUID is indeed set +file_permissions2=`ls -l $B0/brick1/file | awk '{print $1}' | cut -d. -f1 | cut -d- -f2,3,4,5,6` +setuid_bit2=`echo $file_permissions2 | cut -b3` +EXPECT "s" echo $setuid_bit2 + +#Also compare the entire permission string,just to be sure +EXPECT $file_permissions1 echo $file_permissions2 +TEST umount $M0 +TEST $CLI volume stop $V0 +TEST $CLI volume delete $V0; + +cleanup; -- cgit From a78dfebb7343671b0a3a0af8b46951894a3cf7a4 Mon Sep 17 00:00:00 2001 From: Krishnan Parthasarathi Date: Wed, 12 Feb 2014 17:23:28 +0530 Subject: add build-gfid option to enable pgfid tracking ... .. for inode to pathname mapping Change-Id: I0486d85b02e86d739fc1d8ea16d118fb666abf60 BUG: 1064863 Signed-off-by: Krishnan Parthasarathi Reviewed-on: http://review.gluster.org/6989 Tested-by: Gluster Build System Reviewed-by: Vijay Bellur --- tests/basic/pgfid-feat.t | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tests/basic/pgfid-feat.t (limited to 'tests') diff --git a/tests/basic/pgfid-feat.t b/tests/basic/pgfid-feat.t new file mode 100644 index 000000000..8784cc7bf --- /dev/null +++ b/tests/basic/pgfid-feat.t @@ -0,0 +1,36 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +function get_ancestry_path() { + local path=$1 + local ancestry=$(getfattr --absolute-names -e text -n glusterfs.ancestry.path "$M0/$path" | grep "^glusterfs.ancestry.path" | cut -d"=" -f2 | tr -d \"); + echo $ancestry; +} + +TEST glusterd +TEST pidof glusterd +TEST $CLI volume info; + +TEST $CLI volume create $V0 replica 2 $H0:$B0/${V0}{1,2,3,4}; +TEST $CLI volume start $V0; +TEST glusterfs -s $H0 --volfile-id $V0 $M0; + +TEST $CLI volume set $V0 build-pgfid on; + +TEST mkdir $M0/a; +TEST touch $M0/a/b; + +getfattr -e text -n glusterfs.ancestry.path "$M0/a/b" | grep "^glusterfs.ancestry.path" | cut -d"=" -f2 | tr -d \"; +EXPECT "/a/b" get_ancestry_path "/a/b"; + +TEST $CLI volume set $V0 build-pgfid off; +TEST ! getfattr -e text -n "glusterfs.ancestry.path" $M0/a/b; + +TEST $CLI volume stop $V0; +TEST $CLI volume delete $V0; + +cleanup; -- cgit From f69e85511645fcbd0526e38ca88dd3e5bf0ed917 Mon Sep 17 00:00:00 2001 From: Prashanth Pai Date: Mon, 17 Feb 2014 20:42:42 +0530 Subject: feature/compress: Validate option and enable doc * Validate network.compression option * Enable descriptions of xlator configurable options * Improve indentation in code * Make network.compression.mode not configurable by user. This is similar to "iam-self-heal-daemon" option in AFR xlator. Fixes BUGs: 1065658, 1065640, 1065655 Change-Id: I99d82b574ee0e5c8c2baf5f5d52dbf8d015d330a BUG: 1065640 Signed-off-by: Prashanth Pai Reviewed-on: http://review.gluster.org/7024 Tested-by: Gluster Build System Reviewed-by: Vijay Bellur --- tests/basic/cdc.t | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'tests') diff --git a/tests/basic/cdc.t b/tests/basic/cdc.t index 69f39f7d1..70d2171a8 100755 --- a/tests/basic/cdc.t +++ b/tests/basic/cdc.t @@ -21,18 +21,16 @@ EXPECT 'off' volinfo_field $V0 'performance.io-cache' TEST $CLI volume set $V0 performance.quick-read off EXPECT 'off' volinfo_field $V0 'performance.quick-read' -TEST $CLI volume set $V0 strict-write-ordering on +TEST $CLI volume set $V0 performance.strict-write-ordering on EXPECT 'on' volinfo_field $V0 'performance.strict-write-ordering' ## Turn on cdc xlator by setting network.compression to on TEST $CLI volume set $V0 network.compression on EXPECT 'on' volinfo_field $V0 'network.compression' -EXPECT 'server' volinfo_field $V0 'network.compression.mode' ## Make sure that user cannot change network.compression.mode ## This would break the cdc xlator if allowed! -TEST $CLI volume set $V0 network.compression.mode client -EXPECT 'server' volinfo_field $V0 'network.compression.mode' +TEST ! $CLI volume set $V0 network.compression.mode client ## Turn on network.compression.debug option ## This will dump compressed data onto disk as gzip file @@ -44,6 +42,7 @@ EXPECT 'on' volinfo_field $V0 'network.compression.debug' TEST $CLI volume start $V0; EXPECT 'Started' volinfo_field $V0 'Status'; +sleep 2 ## Mount FUSE with caching disabled TEST glusterfs --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0; @@ -121,7 +120,6 @@ TEST umount $M0 ## Reset the network.compression options TEST $CLI volume reset $V0 network.compression.debug TEST $CLI volume reset $V0 network.compression.min-size -TEST $CLI volume reset $V0 network.compression.mode TEST $CLI volume reset $V0 network.compression ## Stop the volume -- cgit From b0515e2a4a08b657ef7e9715fb8c6222c700e78c Mon Sep 17 00:00:00 2001 From: Niels de Vos Date: Tue, 28 Jan 2014 10:06:13 +0100 Subject: write-behind: track filesize when doing extending writes A program that calls mmap() on a newly created sparse file, may receive a SIGBUS signal. If SIGBUS is not handled, a segmentation fault will occur and the program will exit. A bug in the write-behind translator can cause the creation of a sparse file created with open(), seek(), write() to be cached. The last write() may not be sent to the server, until write-behind deems this necessary. * open(.., O_TRUNC, ...)/creat() the file, it is 0 bytes big * seek() into the file, use offset 31 * write() 1 byte to the file * the range from byte 0-30 are unwritten so called 'sparse' The following illustration tries to capture this: Legend: [ = start of file _ = unallocated/unwritten bytes # = allocated bytes in the file ] = end of file [_______________#] | | '- byte 0 '- byte 31 Without this change, reading from byte 0-30 will return an error, and reading the same area through an mmap()'d pointer will trigger a SIGBUS. Reading from this range did not trigger the outstanding write() to be flushed. The brick that receives the read() (translated over the network from mmap()) does not know that the file has been extended, and returns -EINVAL. This error gets transported back from the brick to the glusterfs-fuse client, and translated by the Linux kernel/VFS into SIGBUS triggered by mmap(). In order to solve this, a new attribute to the wb_inode structure is introduced; the current size of the file. All FOPs that can modify the size, are expected to update wb_inode->size. This makes it possible for extending writes with an offset bigger than EOF to mark the unwritten area as modified/pending. Change-Id: If5ba6646732e6be26568541ea9b12852a5d0b988 BUG: 1058663 Signed-off-by: Niels de Vos Reviewed-on: http://review.gluster.org/6835 Tested-by: Gluster Build System Reviewed-by: Raghavendra G Reviewed-by: Anand Avati --- tests/bugs/bug-1058663.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++ tests/bugs/bug-1058663.t | 29 +++++++++++++ 2 files changed, 140 insertions(+) create mode 100644 tests/bugs/bug-1058663.c create mode 100644 tests/bugs/bug-1058663.t (limited to 'tests') diff --git a/tests/bugs/bug-1058663.c b/tests/bugs/bug-1058663.c new file mode 100644 index 000000000..631afecce --- /dev/null +++ b/tests/bugs/bug-1058663.c @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include +#include +#include + +#define FILE_SIZE 1048576 + +/* number of tests to run */ +#define RUN_LOOP 1000 + +/* number of SIGBUS before exiting */ +#define MAX_SIGBUS 1 +static int expect_sigbus = 0; +static int sigbus_received = 0; + +/* test for truncate()/seek()/write()/mmap() + * There should ne no SIGBUS triggered. + */ +void seek_write(char *filename) +{ + int fd; + uint8_t* map; + int i; + + fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0600); + lseek(fd, FILE_SIZE - 1, SEEK_SET); + write(fd, "\xff", 1); + + map = mmap(NULL, FILE_SIZE, PROT_READ, MAP_PRIVATE, fd, 0); + for (i = 0; i < (FILE_SIZE - 1); i++) { + if (map[i] != 0) /* should never be true */ + abort(); + } + munmap(map, FILE_SIZE); + + close(fd); +} + +int read_after_eof(char *filename) +{ + int ret = 0; + int fd; + char* data; + uint8_t* map; + + fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0600); + lseek(fd, FILE_SIZE - 1, SEEK_SET); + write(fd, "\xff", 1); + + /* trigger verify that reading after EOF fails */ + ret = read(fd, data, FILE_SIZE / 2); + if (ret != 0) + return 1; + + /* map an area of 1 byte after FILE_SIZE */ + map = mmap(NULL, 1, PROT_READ, MAP_PRIVATE, fd, FILE_SIZE); + /* map[0] is an access after EOF, it should trigger SIGBUS */ + if (map[0] != 0) + /* it is expected that we exit before we get here */ + if (!sigbus_received) + return 1; + munmap(map, FILE_SIZE); + + close(fd); + + return ret; +} + +/* signal handler for SIGBUS */ +void catch_sigbus(int signum) +{ + switch (signum) { + case SIGBUS: + sigbus_received++; + if (!expect_sigbus) + exit(EXIT_FAILURE); + if (sigbus_received >= MAX_SIGBUS) + exit(EXIT_SUCCESS); + break; + default: + printf("Unexpected signal received: %d\n", signum); + } +} + +int main(int argc, char** argv) +{ + int i = 0; + + if (argc == 1) { + printf("Usage: %s \n", argv[0]); + return EXIT_FAILURE; + } + + signal(SIGBUS, catch_sigbus); + + /* the next test should not trigger SIGBUS */ + expect_sigbus = 0; + for (i = 0; i < RUN_LOOP; i++) { + seek_write(argv[1]); + } + + /* the next test should trigger SIGBUS */ + expect_sigbus = 1; + if (read_after_eof(argv[1])) + return EXIT_FAILURE; + + return EXIT_SUCCESS; +} diff --git a/tests/bugs/bug-1058663.t b/tests/bugs/bug-1058663.t new file mode 100644 index 000000000..5ca348e77 --- /dev/null +++ b/tests/bugs/bug-1058663.t @@ -0,0 +1,29 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +## Start and create a volume +TEST glusterd; +TEST pidof glusterd; +TEST $CLI volume info; + +TEST $CLI volume create $V0 $H0:$B0/$V0; +TEST $CLI volume start $V0; + +TEST glusterfs --entry-timeout=0 --attribute-timeout=0 -s $H0 --volfile-id $V0 $M0 + +# compile the test program and run it +gcc $(dirname $0)/bug-1058663.c -o $(dirname $0)/bug-1058663; +TEST $(dirname $0)/bug-1058663 $M0/bug-1058663.bin; +rm -f $(dirname $0)/M0/bug-1058663.bin; + +TEST umount $M0; + +TEST $CLI volume stop $V0; +TEST $CLI volume delete $V0; + +cleanup; + -- cgit From 2010fb2bc620e6f66ed769b140d92e1d94da1439 Mon Sep 17 00:00:00 2001 From: Edward Shishkin Date: Fri, 13 Dec 2013 21:17:44 +0100 Subject: Added test case for crypt translator Change-Id: I7a28a1285c19c3279c2f71e9d9914cf14c761858 BUG: 1030058 Signed-off-by: Edward Shishkin Reviewed-on: http://review.gluster.org/6504 Tested-by: Gluster Build System Reviewed-by: Anand Avati --- tests/encryption/crypt.t | 87 +++++++++++++ tests/encryption/frag.c | 328 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 415 insertions(+) create mode 100755 tests/encryption/crypt.t create mode 100644 tests/encryption/frag.c (limited to 'tests') diff --git a/tests/encryption/crypt.t b/tests/encryption/crypt.t new file mode 100755 index 000000000..aa46bd429 --- /dev/null +++ b/tests/encryption/crypt.t @@ -0,0 +1,87 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc +. $(dirname $0)/../volume.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd + +## Create a volume with one brick +TEST $CLI volume create $V0 $H0:$B0/${V0}1; +EXPECT "$V0" volinfo_field $V0 'Volume Name'; +EXPECT 'Created' volinfo_field $V0 'Status'; +EXPECT '1' brick_count $V0 + +## Turn off performance translators + +TEST $CLI volume set $V0 performance.quick-read off +EXPECT 'off' volinfo_field $V0 'performance.quick-read' +TEST $CLI volume set $V0 performance.write-behind off +EXPECT 'off' volinfo_field $V0 'performance.write-behind' +TEST $CLI volume set $V0 performance.open-behind off +EXPECT 'off' volinfo_field $V0 'performance.open-behind' + +## Turn on crypt xlator by setting features.encryption to on +TEST $CLI volume set $V0 encryption on +EXPECT 'on' volinfo_field $V0 'features.encryption' + +## Specify location of master key +TEST $CLI volume set $V0 encryption.master-key /tmp/$V0-master-key + +## Create a file with master key + +echo "0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff" > /tmp/$V0-master-key + +## Start the volume +TEST $CLI volume start $V0; +EXPECT 'Started' volinfo_field $V0 'Status'; + +## Mount the volume +TEST glusterfs --volfile-server=$H0 --volfile-id=$V0 $M0; + +## Testing writev, readv, ftruncate: +## Create fragmented files and compare them with the reference files + +build_tester $(dirname $0)/frag.c +TEST $(dirname $0)/frag $M0/testfile /tmp/$V0-goodfile 262144 500 + +## Testing link, unlink, symlink, rename + +TEST ln $M0/testfile $M0/testfile-link +TEST mv $M0/testfile $M0/testfile-renamed +TEST ln -s $M0/testfile-link $M0/testfile-symlink +TEST rm -f $M0/testfile-renamed + +## Remount the volume +TEST umount $M0 +TEST glusterfs --volfile-server=$H0 --volfile-id=$V0 $M0; + +TEST diff -u $M0/testfile-symlink /tmp/$V0-goodfile +EXPECT '' + +TEST rm -f $M0/testfile-symlink +TEST rm -f $M0/testfile-link + +## Cleanup files + +TEST rm -f /tmp/$V0-master-key +TEST rm -f /tmp/$V0-goodfile + +TEST umount $M0 + +## Reset crypt options +TEST $CLI volume reset $V0 encryption.block-size +TEST $CLI volume reset $V0 encryption.data-key-size + +## Stop the volume +TEST $CLI volume stop $V0; +EXPECT 'Stopped' volinfo_field $V0 'Status'; + +## Delete the volume +TEST $CLI volume delete $V0; +TEST ! $CLI volume info $V0; + +TEST rm -rf $(dirname $0)/frag +cleanup; diff --git a/tests/encryption/frag.c b/tests/encryption/frag.c new file mode 100644 index 000000000..86da037c6 --- /dev/null +++ b/tests/encryption/frag.c @@ -0,0 +1,328 @@ +/* + Copyright (c) 2008-2013 Red Hat, Inc. + 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 +#include +#include +#include +#include +#include +#include +#include + +#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 \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: +*/ -- cgit