From 703721374fbf9b4b78ddedd928902fc7680325e3 Mon Sep 17 00:00:00 2001 From: zhanchengbin Date: Mon, 11 Apr 2022 16:21:49 +0800 Subject: [PATCH] add fuse test dir --- 0003-add-fuse-test-dir.patch | 2018 ++++++++++++++++++++++++++++++++++ fuse.spec | 6 +- 2 files changed, 2023 insertions(+), 1 deletion(-) create mode 100644 0003-add-fuse-test-dir.patch diff --git a/0003-add-fuse-test-dir.patch b/0003-add-fuse-test-dir.patch new file mode 100644 index 0000000..88b525a --- /dev/null +++ b/0003-add-fuse-test-dir.patch @@ -0,0 +1,2018 @@ +From fb127ec92c105c35a695b1da0c5f17f1ed68cdb6 Mon Sep 17 00:00:00 2001 +From: zhanchengbin +Date: Wed, 6 Apr 2022 17:15:31 +0800 +Subject: [PATCH] addtest + +--- + test/.gitignore | 2 + + test/Makefile | 7 + + test/stracedecode.c | 197 ++++++ + test/test.c | 1769 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 1975 insertions(+) + create mode 100644 test/.gitignore + create mode 100644 test/Makefile + create mode 100644 test/stracedecode.c + create mode 100644 test/test.c + +diff --git a/test/.gitignore b/test/.gitignore +new file mode 100644 +index 0000000..7b95378 +--- /dev/null ++++ b/test/.gitignore +@@ -0,0 +1,2 @@ ++!Makefile ++test +diff --git a/test/Makefile b/test/Makefile +new file mode 100644 +index 0000000..738dd53 +--- /dev/null ++++ b/test/Makefile +@@ -0,0 +1,7 @@ ++CC=gcc ++CFLAGS=-Wall -W ++ ++all: test ++ ++clean: ++ rm -f *.o test +diff --git a/test/stracedecode.c b/test/stracedecode.c +new file mode 100644 +index 0000000..27b883c +--- /dev/null ++++ b/test/stracedecode.c +@@ -0,0 +1,197 @@ ++#include ++#include ++#include "fuse_kernel.h" ++ ++static struct { ++ const char *name; ++} fuse_ll_ops[] = { ++ [FUSE_LOOKUP] = { "LOOKUP" }, ++ [FUSE_FORGET] = { "FORGET" }, ++ [FUSE_GETATTR] = { "GETATTR" }, ++ [FUSE_SETATTR] = { "SETATTR" }, ++ [FUSE_READLINK] = { "READLINK" }, ++ [FUSE_SYMLINK] = { "SYMLINK" }, ++ [FUSE_MKNOD] = { "MKNOD" }, ++ [FUSE_MKDIR] = { "MKDIR" }, ++ [FUSE_UNLINK] = { "UNLINK" }, ++ [FUSE_RMDIR] = { "RMDIR" }, ++ [FUSE_RENAME] = { "RENAME" }, ++ [FUSE_LINK] = { "LINK" }, ++ [FUSE_OPEN] = { "OPEN" }, ++ [FUSE_READ] = { "READ" }, ++ [FUSE_WRITE] = { "WRITE" }, ++ [FUSE_STATFS] = { "STATFS" }, ++ [FUSE_RELEASE] = { "RELEASE" }, ++ [FUSE_FSYNC] = { "FSYNC" }, ++ [FUSE_SETXATTR] = { "SETXATTR" }, ++ [FUSE_GETXATTR] = { "GETXATTR" }, ++ [FUSE_LISTXATTR] = { "LISTXATTR" }, ++ [FUSE_REMOVEXATTR] = { "REMOVEXATTR" }, ++ [FUSE_FLUSH] = { "FLUSH" }, ++ [FUSE_INIT] = { "INIT" }, ++ [FUSE_OPENDIR] = { "OPENDIR" }, ++ [FUSE_READDIR] = { "READDIR" }, ++ [FUSE_RELEASEDIR] = { "RELEASEDIR" }, ++ [FUSE_FSYNCDIR] = { "FSYNCDIR" }, ++ [FUSE_GETLK] = { "GETLK" }, ++ [FUSE_SETLK] = { "SETLK" }, ++ [FUSE_SETLKW] = { "SETLKW" }, ++ [FUSE_ACCESS] = { "ACCESS" }, ++ [FUSE_CREATE] = { "CREATE" }, ++ [FUSE_INTERRUPT] = { "INTERRUPT" }, ++ [FUSE_BMAP] = { "BMAP" }, ++ [FUSE_DESTROY] = { "DESTROY" }, ++}; ++ ++#define FUSE_MAXOP (sizeof(fuse_ll_ops) / sizeof(fuse_ll_ops[0])) ++ ++static const char *opname(enum fuse_opcode opcode) ++{ ++ if (opcode >= FUSE_MAXOP || !fuse_ll_ops[opcode].name) ++ return "???"; ++ else ++ return fuse_ll_ops[opcode].name; ++} ++ ++ ++static void process_buf(int dir, char *buf, int len) ++{ ++ static unsigned long long prevuniq = -1; ++ static int prevopcode; ++ ++ if (!dir) { ++ struct fuse_in_header *in = (struct fuse_in_header *) buf; ++ buf += sizeof(struct fuse_in_header); ++ ++ printf("unique: %llu, opcode: %s (%i), nodeid: %lu, len: %i, insize: %i\n", ++ (unsigned long long) in->unique, ++ opname((enum fuse_opcode) in->opcode), in->opcode, ++ (unsigned long) in->nodeid, in->len, len); ++ ++ switch (in->opcode) { ++ case FUSE_READ: { ++ struct fuse_read_in *arg = (struct fuse_read_in *) buf; ++ printf("-READ fh:%llu off:%llu siz:%u rfl:%u own:%llu fl:%u\n", ++ arg->fh, arg->offset, arg->size, arg->read_flags, ++ arg->lock_owner, arg->flags); ++ break; ++ } ++ case FUSE_WRITE: { ++ struct fuse_write_in *arg = (struct fuse_write_in *) buf; ++ printf("-WRITE fh:%llu off:%llu siz:%u wfl:%u own:%llu fl:%u\n", ++ arg->fh, arg->offset, arg->size, arg->write_flags, ++ arg->lock_owner, arg->flags); ++ break; ++ } ++ } ++ prevuniq = in->unique; ++ prevopcode = in->opcode; ++ } else { ++ struct fuse_out_header *out = (struct fuse_out_header *) buf; ++ buf += sizeof(struct fuse_out_header); ++ ++ printf(" unique: %llu, error: %i (%s), len: %i, outsize: %i\n", ++ (unsigned long long) out->unique, out->error, ++ strerror(-out->error), out->len, len); ++ ++ if (out->unique == prevuniq) { ++ switch (prevopcode) { ++ case FUSE_GETATTR: { ++ struct fuse_attr_out *arg = (struct fuse_attr_out *) buf; ++ printf("+ATTR v:%llu.%09u i:%llu s:%llu b:%llu\n", ++ arg->attr_valid, arg->attr_valid_nsec, ++ arg->attr.ino, arg->attr.size, arg->attr.blocks); ++ break; ++ } ++ case FUSE_LOOKUP: { ++ struct fuse_entry_out *arg = (struct fuse_entry_out *) buf; ++ printf("+ENTRY nodeid:%llu v:%llu.%09u i:%llu s:%llu b:%llu\n", ++ arg->nodeid, arg->attr_valid, arg->attr_valid_nsec, ++ arg->attr.ino, arg->attr.size, arg->attr.blocks); ++ break; ++ } ++ } ++ } ++ } ++ ++} ++ ++int main(void) ++{ ++ FILE *in = stdin; ++ while (1) { ++ int dir; ++ int res; ++ char buf[1048576]; ++ unsigned len = 0; ++ ++ memset(buf, 0, sizeof(buf)); ++ while (1) { ++ char str[32]; ++ ++ res = fscanf(in, "%30s", str); ++ if (res != 1 && feof(in)) ++ return 0; ++ ++ if (res == 0) ++ continue; ++ ++ if (strncmp(str, "read(", 5) == 0) { ++ dir = 0; ++ break; ++ } else if (strncmp(str, "writev(", 7) == 0) { ++ dir = 1; ++ break; ++ } ++ } ++ ++ while (1) { ++ int c = getc(in); ++ if (c == '"') { ++ while (1) { ++ int val; ++ ++ c = getc(in); ++ if (c == EOF) { ++ fprintf(stderr, "eof in string\n"); ++ break; ++ } ++ if (c == '\n') { ++ fprintf(stderr, "eol in string\n"); ++ break; ++ } ++ if (c == '"') ++ break; ++ if (c != '\\') { ++ val = c; ++ } else { ++ c = getc(in); ++ switch (c) { ++ case 'n': val = '\n'; break; ++ case 'r': val = '\r'; break; ++ case 't': val = '\t'; break; ++ case '"': val = '"'; break; ++ case '\\': val = '\\'; break; ++ case 'x': ++ res = scanf("%x", &val); ++ if (res != 1) { ++ fprintf(stderr, "parse error\n"); ++ continue; ++ } ++ break; ++ default: ++ fprintf(stderr, "unknown sequence: '\\%c'\n", c); ++ continue; ++ } ++ } ++ buf[len++] = val; ++ } ++ } ++ if (c == '\n') ++ break; ++ } ++ process_buf(dir, buf, len); ++ memset(buf, 0, len); ++ len = 0; ++ } ++} +diff --git a/test/test.c b/test/test.c +new file mode 100644 +index 0000000..9dc0eed +--- /dev/null ++++ b/test/test.c +@@ -0,0 +1,1769 @@ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++static char testfile[1024]; ++static char testfile2[1024]; ++static char testdir[1024]; ++static char testdir2[1024]; ++static char subfile[1024]; ++static char testname[256]; ++static char testdata[] = "abcdefghijklmnopqrstuvwxyz"; ++static char testdata2[] = "1234567890-=qwertyuiop[]\asdfghjkl;'zxcvbnm,./"; ++static const char *testdir_files[] = { "f1", "f2", NULL}; ++static long seekdir_offsets[4]; ++static char zerodata[4096]; ++static int testdatalen = sizeof(testdata) - 1; ++static int testdata2len = sizeof(testdata2) - 1; ++static unsigned int testnum = 1; ++static unsigned int select_test = 0; ++static unsigned int skip_test = 0; ++ ++#define MAX_ENTRIES 1024 ++ ++static void test_perror(const char *func, const char *msg) ++{ ++ fprintf(stderr, "%s %s() - %s: %s\n", testname, func, msg, ++ strerror(errno)); ++} ++ ++static void test_error(const char *func, const char *msg, ...) ++ __attribute__ ((format (printf, 2, 3))); ++ ++static void __start_test(const char *fmt, ...) ++ __attribute__ ((format (printf, 1, 2))); ++ ++static void test_error(const char *func, const char *msg, ...) ++{ ++ va_list ap; ++ fprintf(stderr, "%s %s() - ", testname, func); ++ va_start(ap, msg); ++ vfprintf(stderr, msg, ap); ++ va_end(ap); ++ fprintf(stderr, "\n"); ++} ++ ++static void success(void) ++{ ++ fprintf(stderr, "%s OK\n", testname); ++} ++ ++static void __start_test(const char *fmt, ...) ++{ ++ unsigned int n; ++ va_list ap; ++ n = sprintf(testname, "%3i [", testnum++); ++ va_start(ap, fmt); ++ n += vsprintf(testname + n, fmt, ap); ++ va_end(ap); ++ sprintf(testname + n, "]"); ++} ++ ++#define start_test(msg, args...) { \ ++ if ((select_test && testnum != select_test) || \ ++ (testnum == skip_test)) { \ ++ testnum++; \ ++ return 0; \ ++ } \ ++ __start_test(msg, ##args); \ ++} ++ ++#define PERROR(msg) test_perror(__FUNCTION__, msg) ++#define ERROR(msg, args...) test_error(__FUNCTION__, msg, ##args) ++ ++#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) ++ ++static int check_size(const char *path, int len) ++{ ++ struct stat stbuf; ++ int res = stat(path, &stbuf); ++ if (res == -1) { ++ PERROR("stat"); ++ return -1; ++ } ++ if (stbuf.st_size != len) { ++ ERROR("length %u instead of %u", (int) stbuf.st_size, ++ (int) len); ++ return -1; ++ } ++ return 0; ++} ++ ++static int fcheck_size(int fd, int len) ++{ ++ struct stat stbuf; ++ int res = fstat(fd, &stbuf); ++ if (res == -1) { ++ PERROR("fstat"); ++ return -1; ++ } ++ if (stbuf.st_size != len) { ++ ERROR("length %u instead of %u", (int) stbuf.st_size, ++ (int) len); ++ return -1; ++ } ++ return 0; ++} ++ ++static int check_type(const char *path, mode_t type) ++{ ++ struct stat stbuf; ++ int res = lstat(path, &stbuf); ++ if (res == -1) { ++ PERROR("lstat"); ++ return -1; ++ } ++ if ((stbuf.st_mode & S_IFMT) != type) { ++ ERROR("type 0%o instead of 0%o", stbuf.st_mode & S_IFMT, type); ++ return -1; ++ } ++ return 0; ++} ++ ++static int fcheck_type(int fd, mode_t type) ++{ ++ struct stat stbuf; ++ int res = fstat(fd, &stbuf); ++ if (res == -1) { ++ PERROR("fstat"); ++ return -1; ++ } ++ if ((stbuf.st_mode & S_IFMT) != type) { ++ ERROR("type 0%o instead of 0%o", stbuf.st_mode & S_IFMT, type); ++ return -1; ++ } ++ return 0; ++} ++ ++static int check_mode(const char *path, mode_t mode) ++{ ++ struct stat stbuf; ++ int res = lstat(path, &stbuf); ++ if (res == -1) { ++ PERROR("lstat"); ++ return -1; ++ } ++ if ((stbuf.st_mode & 07777) != mode) { ++ ERROR("mode 0%o instead of 0%o", stbuf.st_mode & 07777, mode); ++ return -1; ++ } ++ return 0; ++} ++ ++static int fcheck_mode(int fd, mode_t mode) ++{ ++ struct stat stbuf; ++ int res = fstat(fd, &stbuf); ++ if (res == -1) { ++ PERROR("fstat"); ++ return -1; ++ } ++ if ((stbuf.st_mode & 07777) != mode) { ++ ERROR("mode 0%o instead of 0%o", stbuf.st_mode & 07777, mode); ++ return -1; ++ } ++ return 0; ++} ++ ++static int check_times(const char *path, time_t atime, time_t mtime) ++{ ++ int err = 0; ++ struct stat stbuf; ++ int res = lstat(path, &stbuf); ++ if (res == -1) { ++ PERROR("lstat"); ++ return -1; ++ } ++ if (stbuf.st_atime != atime) { ++ ERROR("atime %li instead of %li", stbuf.st_atime, atime); ++ err--; ++ } ++ if (stbuf.st_mtime != mtime) { ++ ERROR("mtime %li instead of %li", stbuf.st_mtime, mtime); ++ err--; ++ } ++ if (err) ++ return -1; ++ ++ return 0; ++} ++ ++#if 0 ++static int fcheck_times(int fd, time_t atime, time_t mtime) ++{ ++ int err = 0; ++ struct stat stbuf; ++ int res = fstat(fd, &stbuf); ++ if (res == -1) { ++ PERROR("fstat"); ++ return -1; ++ } ++ if (stbuf.st_atime != atime) { ++ ERROR("atime %li instead of %li", stbuf.st_atime, atime); ++ err--; ++ } ++ if (stbuf.st_mtime != mtime) { ++ ERROR("mtime %li instead of %li", stbuf.st_mtime, mtime); ++ err--; ++ } ++ if (err) ++ return -1; ++ ++ return 0; ++} ++#endif ++ ++static int check_nlink(const char *path, nlink_t nlink) ++{ ++ struct stat stbuf; ++ int res = lstat(path, &stbuf); ++ if (res == -1) { ++ PERROR("lstat"); ++ return -1; ++ } ++ if (stbuf.st_nlink != nlink) { ++ ERROR("nlink %li instead of %li", (long) stbuf.st_nlink, ++ (long) nlink); ++ return -1; ++ } ++ return 0; ++} ++ ++static int fcheck_nlink(int fd, nlink_t nlink) ++{ ++ struct stat stbuf; ++ int res = fstat(fd, &stbuf); ++ if (res == -1) { ++ PERROR("fstat"); ++ return -1; ++ } ++ if (stbuf.st_nlink != nlink) { ++ ERROR("nlink %li instead of %li", (long) stbuf.st_nlink, ++ (long) nlink); ++ return -1; ++ } ++ return 0; ++} ++ ++static int check_nonexist(const char *path) ++{ ++ struct stat stbuf; ++ int res = lstat(path, &stbuf); ++ if (res == 0) { ++ ERROR("file should not exist"); ++ return -1; ++ } ++ if (errno != ENOENT) { ++ ERROR("file should not exist: %s", strerror(errno)); ++ return -1; ++ } ++ return 0; ++} ++ ++static int check_buffer(const char *buf, const char *data, unsigned len) ++{ ++ if (memcmp(buf, data, len) != 0) { ++ ERROR("data mismatch"); ++ return -1; ++ } ++ return 0; ++} ++ ++static int check_data(const char *path, const char *data, int offset, ++ unsigned len) ++{ ++ char buf[4096]; ++ int res; ++ int fd = open(path, O_RDONLY); ++ if (fd == -1) { ++ PERROR("open"); ++ return -1; ++ } ++ if (lseek(fd, offset, SEEK_SET) == (off_t) -1) { ++ PERROR("lseek"); ++ close(fd); ++ return -1; ++ } ++ while (len) { ++ int rdlen = len < sizeof(buf) ? len : sizeof(buf); ++ res = read(fd, buf, rdlen); ++ if (res == -1) { ++ PERROR("read"); ++ close(fd); ++ return -1; ++ } ++ if (res != rdlen) { ++ ERROR("short read: %u instead of %u", res, rdlen); ++ close(fd); ++ return -1; ++ } ++ if (check_buffer(buf, data, rdlen) != 0) { ++ close(fd); ++ return -1; ++ } ++ data += rdlen; ++ len -= rdlen; ++ } ++ res = close(fd); ++ if (res == -1) { ++ PERROR("close"); ++ return -1; ++ } ++ return 0; ++} ++ ++static int fcheck_data(int fd, const char *data, int offset, ++ unsigned len) ++{ ++ char buf[4096]; ++ int res; ++ if (lseek(fd, offset, SEEK_SET) == (off_t) -1) { ++ PERROR("lseek"); ++ return -1; ++ } ++ while (len) { ++ int rdlen = len < sizeof(buf) ? len : sizeof(buf); ++ res = read(fd, buf, rdlen); ++ if (res == -1) { ++ PERROR("read"); ++ return -1; ++ } ++ if (res != rdlen) { ++ ERROR("short read: %u instead of %u", res, rdlen); ++ return -1; ++ } ++ if (check_buffer(buf, data, rdlen) != 0) { ++ return -1; ++ } ++ data += rdlen; ++ len -= rdlen; ++ } ++ return 0; ++} ++ ++static int check_dir_contents(const char *path, const char **contents) ++{ ++ int i; ++ int res; ++ int err = 0; ++ int found[MAX_ENTRIES]; ++ const char *cont[MAX_ENTRIES]; ++ DIR *dp; ++ ++ for (i = 0; contents[i]; i++) { ++ assert(i < MAX_ENTRIES - 3); ++ found[i] = 0; ++ cont[i] = contents[i]; ++ } ++ found[i] = 0; ++ cont[i++] = "."; ++ found[i] = 0; ++ cont[i++] = ".."; ++ cont[i] = NULL; ++ ++ dp = opendir(path); ++ if (dp == NULL) { ++ PERROR("opendir"); ++ return -1; ++ } ++ memset(found, 0, sizeof(found)); ++ while(1) { ++ struct dirent *de; ++ errno = 0; ++ de = readdir(dp); ++ if (de == NULL) { ++ if (errno) { ++ PERROR("readdir"); ++ closedir(dp); ++ return -1; ++ } ++ break; ++ } ++ for (i = 0; cont[i] != NULL; i++) { ++ assert(i < MAX_ENTRIES); ++ if (strcmp(cont[i], de->d_name) == 0) { ++ if (found[i]) { ++ ERROR("duplicate entry <%s>", ++ de->d_name); ++ err--; ++ } else ++ found[i] = 1; ++ break; ++ } ++ } ++ if (!cont[i]) { ++ ERROR("unexpected entry <%s>", de->d_name); ++ err --; ++ } ++ } ++ for (i = 0; cont[i] != NULL; i++) { ++ if (!found[i]) { ++ ERROR("missing entry <%s>", cont[i]); ++ err--; ++ } ++ } ++ res = closedir(dp); ++ if (res == -1) { ++ PERROR("closedir"); ++ return -1; ++ } ++ if (err) ++ return -1; ++ ++ return 0; ++} ++ ++static int create_file(const char *path, const char *data, int len) ++{ ++ int res; ++ int fd; ++ ++ unlink(path); ++ fd = creat(path, 0644); ++ if (fd == -1) { ++ PERROR("creat"); ++ return -1; ++ } ++ if (len) { ++ res = write(fd, data, len); ++ if (res == -1) { ++ PERROR("write"); ++ close(fd); ++ return -1; ++ } ++ if (res != len) { ++ ERROR("write is short: %u instead of %u", res, len); ++ close(fd); ++ return -1; ++ } ++ } ++ res = close(fd); ++ if (res == -1) { ++ PERROR("close"); ++ return -1; ++ } ++ res = check_type(path, S_IFREG); ++ if (res == -1) ++ return -1; ++ res = check_mode(path, 0644); ++ if (res == -1) ++ return -1; ++ res = check_nlink(path, 1); ++ if (res == -1) ++ return -1; ++ res = check_size(path, len); ++ if (res == -1) ++ return -1; ++ ++ if (len) { ++ res = check_data(path, data, 0, len); ++ if (res == -1) ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int cleanup_dir(const char *path, const char **dir_files, int quiet) ++{ ++ int i; ++ int err = 0; ++ ++ for (i = 0; dir_files[i]; i++) { ++ int res; ++ char fpath[1024]; ++ sprintf(fpath, "%s/%s", path, dir_files[i]); ++ res = unlink(fpath); ++ if (res == -1 && !quiet) { ++ PERROR("unlink"); ++ err --; ++ } ++ } ++ if (err) ++ return -1; ++ ++ return 0; ++} ++ ++static int create_dir(const char *path, const char **dir_files) ++{ ++ int res; ++ int i; ++ ++ rmdir(path); ++ res = mkdir(path, 0755); ++ if (res == -1) { ++ PERROR("mkdir"); ++ return -1; ++ } ++ res = check_type(path, S_IFDIR); ++ if (res == -1) ++ return -1; ++ res = check_mode(path, 0755); ++ if (res == -1) ++ return -1; ++ ++ for (i = 0; dir_files[i]; i++) { ++ char fpath[1024]; ++ sprintf(fpath, "%s/%s", path, dir_files[i]); ++ res = create_file(fpath, "", 0); ++ if (res == -1) { ++ cleanup_dir(path, dir_files, 1); ++ return -1; ++ } ++ } ++ res = check_dir_contents(path, dir_files); ++ if (res == -1) { ++ cleanup_dir(path, dir_files, 1); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int test_truncate(int len) ++{ ++ const char *data = testdata; ++ int datalen = testdatalen; ++ int res; ++ ++ start_test("truncate(%u)", (int) len); ++ res = create_file(testfile, data, datalen); ++ if (res == -1) ++ return -1; ++ ++ res = truncate(testfile, len); ++ if (res == -1) { ++ PERROR("truncate"); ++ return -1; ++ } ++ res = check_size(testfile, len); ++ if (res == -1) ++ return -1; ++ ++ if (len > 0) { ++ if (len <= datalen) { ++ res = check_data(testfile, data, 0, len); ++ if (res == -1) ++ return -1; ++ } else { ++ res = check_data(testfile, data, 0, datalen); ++ if (res == -1) ++ return -1; ++ res = check_data(testfile, zerodata, datalen, ++ len - datalen); ++ if (res == -1) ++ return -1; ++ } ++ } ++ res = unlink(testfile); ++ if (res == -1) { ++ PERROR("unlink"); ++ return -1; ++ } ++ res = check_nonexist(testfile); ++ if (res == -1) ++ return -1; ++ ++ success(); ++ return 0; ++} ++ ++static int test_ftruncate(int len, int mode) ++{ ++ const char *data = testdata; ++ int datalen = testdatalen; ++ int res; ++ int fd; ++ ++ start_test("ftruncate(%u) mode: 0%03o", len, mode); ++ res = create_file(testfile, data, datalen); ++ if (res == -1) ++ return -1; ++ ++ fd = open(testfile, O_WRONLY); ++ if (fd == -1) { ++ PERROR("open"); ++ return -1; ++ } ++ ++ res = fchmod(fd, mode); ++ if (res == -1) { ++ PERROR("fchmod"); ++ close(fd); ++ return -1; ++ } ++ res = check_mode(testfile, mode); ++ if (res == -1) { ++ close(fd); ++ return -1; ++ } ++ res = ftruncate(fd, len); ++ if (res == -1) { ++ PERROR("ftruncate"); ++ close(fd); ++ return -1; ++ } ++ close(fd); ++ res = check_size(testfile, len); ++ if (res == -1) ++ return -1; ++ ++ if (len > 0) { ++ if (len <= datalen) { ++ res = check_data(testfile, data, 0, len); ++ if (res == -1) ++ return -1; ++ } else { ++ res = check_data(testfile, data, 0, datalen); ++ if (res == -1) ++ return -1; ++ res = check_data(testfile, zerodata, datalen, ++ len - datalen); ++ if (res == -1) ++ return -1; ++ } ++ } ++ res = unlink(testfile); ++ if (res == -1) { ++ PERROR("unlink"); ++ return -1; ++ } ++ res = check_nonexist(testfile); ++ if (res == -1) ++ return -1; ++ ++ success(); ++ return 0; ++} ++ ++static int test_seekdir(void) ++{ ++ int i; ++ int res; ++ DIR *dp; ++ struct dirent *de; ++ ++ start_test("seekdir"); ++ res = create_dir(testdir, testdir_files); ++ if (res == -1) ++ return res; ++ ++ dp = opendir(testdir); ++ if (dp == NULL) { ++ PERROR("opendir"); ++ return -1; ++ } ++ ++ /* Remember dir offsets */ ++ for (i = 0; i < ARRAY_SIZE(seekdir_offsets); i++) { ++ seekdir_offsets[i] = telldir(dp); ++ errno = 0; ++ de = readdir(dp); ++ if (de == NULL) { ++ if (errno) { ++ PERROR("readdir"); ++ goto fail; ++ } ++ break; ++ } ++ } ++ ++ /* Walk until the end of directory */ ++ while (de) ++ de = readdir(dp); ++ ++ /* Start from the last valid dir offset and seek backwards */ ++ for (i--; i >= 0; i--) { ++ seekdir(dp, seekdir_offsets[i]); ++ de = readdir(dp); ++ if (de == NULL) { ++ ERROR("Unexpected end of directory after seekdir()"); ++ goto fail; ++ } ++ } ++ ++ closedir(dp); ++ res = cleanup_dir(testdir, testdir_files, 0); ++ if (!res) ++ success(); ++ return res; ++fail: ++ closedir(dp); ++ cleanup_dir(testdir, testdir_files, 1); ++ return -1; ++} ++ ++static int test_utime(void) ++{ ++ struct utimbuf utm; ++ time_t atime = 987631200; ++ time_t mtime = 123116400; ++ int res; ++ ++ start_test("utime"); ++ res = create_file(testfile, NULL, 0); ++ if (res == -1) ++ return -1; ++ ++ utm.actime = atime; ++ utm.modtime = mtime; ++ res = utime(testfile, &utm); ++ if (res == -1) { ++ PERROR("utime"); ++ return -1; ++ } ++ res = check_times(testfile, atime, mtime); ++ if (res == -1) { ++ return -1; ++ } ++ res = unlink(testfile); ++ if (res == -1) { ++ PERROR("unlink"); ++ return -1; ++ } ++ res = check_nonexist(testfile); ++ if (res == -1) ++ return -1; ++ ++ success(); ++ return 0; ++} ++ ++static int test_create(void) ++{ ++ const char *data = testdata; ++ int datalen = testdatalen; ++ int err = 0; ++ int res; ++ int fd; ++ ++ start_test("create"); ++ unlink(testfile); ++ fd = creat(testfile, 0644); ++ if (fd == -1) { ++ PERROR("creat"); ++ return -1; ++ } ++ res = write(fd, data, datalen); ++ if (res == -1) { ++ PERROR("write"); ++ close(fd); ++ return -1; ++ } ++ if (res != datalen) { ++ ERROR("write is short: %u instead of %u", res, datalen); ++ close(fd); ++ return -1; ++ } ++ res = close(fd); ++ if (res == -1) { ++ PERROR("close"); ++ return -1; ++ } ++ res = check_type(testfile, S_IFREG); ++ if (res == -1) ++ return -1; ++ err += check_mode(testfile, 0644); ++ err += check_nlink(testfile, 1); ++ err += check_size(testfile, datalen); ++ err += check_data(testfile, data, 0, datalen); ++ res = unlink(testfile); ++ if (res == -1) { ++ PERROR("unlink"); ++ return -1; ++ } ++ res = check_nonexist(testfile); ++ if (res == -1) ++ return -1; ++ if (err) ++ return -1; ++ ++ success(); ++ return 0; ++} ++ ++static int test_create_unlink(void) ++{ ++ const char *data = testdata; ++ int datalen = testdatalen; ++ int err = 0; ++ int res; ++ int fd; ++ ++ start_test("create+unlink"); ++ unlink(testfile); ++ fd = open(testfile, O_CREAT | O_RDWR | O_TRUNC, 0644); ++ if (fd == -1) { ++ PERROR("creat"); ++ return -1; ++ } ++ res = unlink(testfile); ++ if (res == -1) { ++ PERROR("unlink"); ++ close(fd); ++ return -1; ++ } ++ res = check_nonexist(testfile); ++ if (res == -1) ++ return -1; ++ res = write(fd, data, datalen); ++ if (res == -1) { ++ PERROR("write"); ++ close(fd); ++ return -1; ++ } ++ if (res != datalen) { ++ ERROR("write is short: %u instead of %u", res, datalen); ++ close(fd); ++ return -1; ++ } ++ err += fcheck_type(fd, S_IFREG); ++ err += fcheck_mode(fd, 0644); ++ err += fcheck_nlink(fd, 0); ++ err += fcheck_size(fd, datalen); ++ err += fcheck_data(fd, data, 0, datalen); ++ res = close(fd); ++ if (res == -1) { ++ PERROR("close"); ++ err--; ++ } ++ if (err) ++ return -1; ++ ++ success(); ++ return 0; ++} ++ ++static int test_mknod(void) ++{ ++ int err = 0; ++ int res; ++ ++ start_test("mknod"); ++ unlink(testfile); ++ res = mknod(testfile, 0644, 0); ++ if (res == -1) { ++ PERROR("mknod"); ++ return -1; ++ } ++ res = check_type(testfile, S_IFREG); ++ if (res == -1) ++ return -1; ++ err += check_mode(testfile, 0644); ++ err += check_nlink(testfile, 1); ++ err += check_size(testfile, 0); ++ res = unlink(testfile); ++ if (res == -1) { ++ PERROR("unlink"); ++ return -1; ++ } ++ res = check_nonexist(testfile); ++ if (res == -1) ++ return -1; ++ if (err) ++ return -1; ++ ++ success(); ++ return 0; ++} ++ ++#define test_open(exist, flags, mode) do_test_open(exist, flags, #flags, mode) ++ ++static int do_test_open(int exist, int flags, const char *flags_str, int mode) ++{ ++ char buf[4096]; ++ const char *data = testdata; ++ int datalen = testdatalen; ++ unsigned currlen = 0; ++ int err = 0; ++ int res; ++ int fd; ++ off_t off; ++ ++ start_test("open(%s, %s, 0%03o)", exist ? "+" : "-", flags_str, mode); ++ unlink(testfile); ++ if (exist) { ++ res = create_file(testfile, testdata2, testdata2len); ++ if (res == -1) ++ return -1; ++ ++ currlen = testdata2len; ++ } ++ ++ fd = open(testfile, flags, mode); ++ if ((flags & O_CREAT) && (flags & O_EXCL) && exist) { ++ if (fd != -1) { ++ ERROR("open should have failed"); ++ close(fd); ++ return -1; ++ } else if (errno == EEXIST) ++ goto succ; ++ } ++ if (!(flags & O_CREAT) && !exist) { ++ if (fd != -1) { ++ ERROR("open should have failed"); ++ close(fd); ++ return -1; ++ } else if (errno == ENOENT) ++ goto succ; ++ } ++ if (fd == -1) { ++ PERROR("open"); ++ return -1; ++ } ++ ++ if (flags & O_TRUNC) ++ currlen = 0; ++ ++ err += check_type(testfile, S_IFREG); ++ if (exist) ++ err += check_mode(testfile, 0644); ++ else ++ err += check_mode(testfile, mode); ++ err += check_nlink(testfile, 1); ++ err += check_size(testfile, currlen); ++ if (exist && !(flags & O_TRUNC) && (mode & 0400)) ++ err += check_data(testfile, testdata2, 0, testdata2len); ++ ++ res = write(fd, data, datalen); ++ if ((flags & O_ACCMODE) != O_RDONLY) { ++ if (res == -1) { ++ PERROR("write"); ++ err --; ++ } else if (res != datalen) { ++ ERROR("write is short: %u instead of %u", res, datalen); ++ err --; ++ } else { ++ if (datalen > (int) currlen) ++ currlen = datalen; ++ ++ err += check_size(testfile, currlen); ++ ++ if (mode & 0400) { ++ err += check_data(testfile, data, 0, datalen); ++ if (exist && !(flags & O_TRUNC) && ++ testdata2len > datalen) ++ err += check_data(testfile, ++ testdata2 + datalen, ++ datalen, ++ testdata2len - datalen); ++ } ++ } ++ } else { ++ if (res != -1) { ++ ERROR("write should have failed"); ++ err --; ++ } else if (errno != EBADF) { ++ PERROR("write"); ++ err --; ++ } ++ } ++ off = lseek(fd, SEEK_SET, 0); ++ if (off == (off_t) -1) { ++ PERROR("lseek"); ++ err--; ++ } else if (off != 0) { ++ ERROR("offset should have returned 0"); ++ err --; ++ } ++ res = read(fd, buf, sizeof(buf)); ++ if ((flags & O_ACCMODE) != O_WRONLY) { ++ if (res == -1) { ++ PERROR("read"); ++ err--; ++ } else { ++ int readsize = ++ currlen < sizeof(buf) ? currlen : sizeof(buf); ++ if (res != readsize) { ++ ERROR("read is short: %i instead of %u", ++ res, readsize); ++ err--; ++ } else { ++ if ((flags & O_ACCMODE) != O_RDONLY) { ++ err += check_buffer(buf, data, datalen); ++ if (exist && !(flags & O_TRUNC) && ++ testdata2len > datalen) ++ err += check_buffer(buf + datalen, ++ testdata2 + datalen, ++ testdata2len - datalen); ++ } else if (exist) ++ err += check_buffer(buf, testdata2, ++ testdata2len); ++ } ++ } ++ } else { ++ if (res != -1) { ++ ERROR("read should have failed"); ++ err --; ++ } else if (errno != EBADF) { ++ PERROR("read"); ++ err --; ++ } ++ } ++ ++ res = close(fd); ++ if (res == -1) { ++ PERROR("close"); ++ return -1; ++ } ++ res = unlink(testfile); ++ if (res == -1) { ++ PERROR("unlink"); ++ return -1; ++ } ++ res = check_nonexist(testfile); ++ if (res == -1) ++ return -1; ++ if (err) ++ return -1; ++ ++succ: ++ success(); ++ return 0; ++} ++ ++#define test_open_acc(flags, mode, err) \ ++ do_test_open_acc(flags, #flags, mode, err) ++ ++static int do_test_open_acc(int flags, const char *flags_str, int mode, int err) ++{ ++ const char *data = testdata; ++ int datalen = testdatalen; ++ int res; ++ int fd; ++ ++ start_test("open_acc(%s) mode: 0%03o error: '%s'", flags_str, mode, ++ strerror(err)); ++ unlink(testfile); ++ res = create_file(testfile, data, datalen); ++ if (res == -1) ++ return -1; ++ ++ res = chmod(testfile, mode); ++ if (res == -1) { ++ PERROR("chmod"); ++ return -1; ++ } ++ ++ res = check_mode(testfile, mode); ++ if (res == -1) ++ return -1; ++ ++ fd = open(testfile, flags); ++ if (fd == -1) { ++ if (err != errno) { ++ PERROR("open"); ++ return -1; ++ } ++ } else { ++ if (err) { ++ ERROR("open should have failed"); ++ close(fd); ++ return -1; ++ } ++ close(fd); ++ } ++ success(); ++ return 0; ++} ++ ++static int test_symlink(void) ++{ ++ char buf[1024]; ++ const char *data = testdata; ++ int datalen = testdatalen; ++ int linklen = strlen(testfile); ++ int err = 0; ++ int res; ++ ++ start_test("symlink"); ++ res = create_file(testfile, data, datalen); ++ if (res == -1) ++ return -1; ++ ++ unlink(testfile2); ++ res = symlink(testfile, testfile2); ++ if (res == -1) { ++ PERROR("symlink"); ++ return -1; ++ } ++ res = check_type(testfile2, S_IFLNK); ++ if (res == -1) ++ return -1; ++ err += check_mode(testfile2, 0777); ++ err += check_nlink(testfile2, 1); ++ res = readlink(testfile2, buf, sizeof(buf)); ++ if (res == -1) { ++ PERROR("readlink"); ++ err--; ++ } ++ if (res != linklen) { ++ ERROR("short readlink: %u instead of %u", res, linklen); ++ err--; ++ } ++ if (memcmp(buf, testfile, linklen) != 0) { ++ ERROR("link mismatch"); ++ err--; ++ } ++ err += check_size(testfile2, datalen); ++ err += check_data(testfile2, data, 0, datalen); ++ res = unlink(testfile2); ++ if (res == -1) { ++ PERROR("unlink"); ++ return -1; ++ } ++ res = check_nonexist(testfile2); ++ if (res == -1) ++ return -1; ++ if (err) ++ return -1; ++ ++ success(); ++ return 0; ++} ++ ++static int test_link(void) ++{ ++ const char *data = testdata; ++ int datalen = testdatalen; ++ int err = 0; ++ int res; ++ ++ start_test("link"); ++ res = create_file(testfile, data, datalen); ++ if (res == -1) ++ return -1; ++ ++ unlink(testfile2); ++ res = link(testfile, testfile2); ++ if (res == -1) { ++ PERROR("link"); ++ return -1; ++ } ++ res = check_type(testfile2, S_IFREG); ++ if (res == -1) ++ return -1; ++ err += check_mode(testfile2, 0644); ++ err += check_nlink(testfile2, 2); ++ err += check_size(testfile2, datalen); ++ err += check_data(testfile2, data, 0, datalen); ++ res = unlink(testfile); ++ if (res == -1) { ++ PERROR("unlink"); ++ return -1; ++ } ++ res = check_nonexist(testfile); ++ if (res == -1) ++ return -1; ++ ++ err += check_nlink(testfile2, 1); ++ res = unlink(testfile2); ++ if (res == -1) { ++ PERROR("unlink"); ++ return -1; ++ } ++ res = check_nonexist(testfile2); ++ if (res == -1) ++ return -1; ++ if (err) ++ return -1; ++ ++ success(); ++ return 0; ++} ++ ++static int test_link2(void) ++{ ++ const char *data = testdata; ++ int datalen = testdatalen; ++ int err = 0; ++ int res; ++ ++ start_test("link-unlink-link"); ++ res = create_file(testfile, data, datalen); ++ if (res == -1) ++ return -1; ++ ++ unlink(testfile2); ++ res = link(testfile, testfile2); ++ if (res == -1) { ++ PERROR("link"); ++ return -1; ++ } ++ res = unlink(testfile); ++ if (res == -1) { ++ PERROR("unlink"); ++ return -1; ++ } ++ res = check_nonexist(testfile); ++ if (res == -1) ++ return -1; ++ res = link(testfile2, testfile); ++ if (res == -1) { ++ PERROR("link"); ++ } ++ res = check_type(testfile, S_IFREG); ++ if (res == -1) ++ return -1; ++ err += check_mode(testfile, 0644); ++ err += check_nlink(testfile, 2); ++ err += check_size(testfile, datalen); ++ err += check_data(testfile, data, 0, datalen); ++ ++ res = unlink(testfile2); ++ if (res == -1) { ++ PERROR("unlink"); ++ return -1; ++ } ++ err += check_nlink(testfile, 1); ++ res = unlink(testfile); ++ if (res == -1) { ++ PERROR("unlink"); ++ return -1; ++ } ++ res = check_nonexist(testfile); ++ if (res == -1) ++ return -1; ++ if (err) ++ return -1; ++ ++ success(); ++ return 0; ++} ++ ++static int test_rename_file(void) ++{ ++ const char *data = testdata; ++ int datalen = testdatalen; ++ int err = 0; ++ int res; ++ ++ start_test("rename file"); ++ res = create_file(testfile, data, datalen); ++ if (res == -1) ++ return -1; ++ ++ unlink(testfile2); ++ res = rename(testfile, testfile2); ++ if (res == -1) { ++ PERROR("rename"); ++ return -1; ++ } ++ res = check_nonexist(testfile); ++ if (res == -1) ++ return -1; ++ res = check_type(testfile2, S_IFREG); ++ if (res == -1) ++ return -1; ++ err += check_mode(testfile2, 0644); ++ err += check_nlink(testfile2, 1); ++ err += check_size(testfile2, datalen); ++ err += check_data(testfile2, data, 0, datalen); ++ res = unlink(testfile2); ++ if (res == -1) { ++ PERROR("unlink"); ++ return -1; ++ } ++ res = check_nonexist(testfile2); ++ if (res == -1) ++ return -1; ++ if (err) ++ return -1; ++ ++ success(); ++ return 0; ++} ++ ++static int test_rename_dir(void) ++{ ++ int err = 0; ++ int res; ++ ++ start_test("rename dir"); ++ res = create_dir(testdir, testdir_files); ++ if (res == -1) ++ return -1; ++ ++ rmdir(testdir2); ++ res = rename(testdir, testdir2); ++ if (res == -1) { ++ PERROR("rename"); ++ cleanup_dir(testdir, testdir_files, 1); ++ return -1; ++ } ++ res = check_nonexist(testdir); ++ if (res == -1) { ++ cleanup_dir(testdir, testdir_files, 1); ++ return -1; ++ } ++ res = check_type(testdir2, S_IFDIR); ++ if (res == -1) { ++ cleanup_dir(testdir2, testdir_files, 1); ++ return -1; ++ } ++ err += check_mode(testdir2, 0755); ++ err += check_dir_contents(testdir2, testdir_files); ++ err += cleanup_dir(testdir2, testdir_files, 0); ++ res = rmdir(testdir2); ++ if (res == -1) { ++ PERROR("rmdir"); ++ return -1; ++ } ++ res = check_nonexist(testdir2); ++ if (res == -1) ++ return -1; ++ if (err) ++ return -1; ++ ++ success(); ++ return 0; ++} ++ ++static int test_rename_dir_loop(void) ++{ ++#define PATH(p) (snprintf(path, sizeof path, "%s/%s", testdir, p), path) ++#define PATH2(p) (snprintf(path2, sizeof path2, "%s/%s", testdir, p), path2) ++ ++ char path[1024], path2[1024]; ++ int err = 0; ++ int res; ++ ++ start_test("rename dir loop"); ++ ++ res = create_dir(testdir, testdir_files); ++ if (res == -1) ++ return -1; ++ ++ res = mkdir(PATH("a"), 0755); ++ if (res == -1) { ++ PERROR("mkdir"); ++ goto fail; ++ } ++ ++ res = rename(PATH("a"), PATH2("a")); ++ if (res == -1) { ++ PERROR("rename"); ++ goto fail; ++ } ++ ++ errno = 0; ++ res = rename(PATH("a"), PATH2("a/b")); ++ if (res == 0 || errno != EINVAL) { ++ PERROR("rename"); ++ goto fail; ++ } ++ ++ res = mkdir(PATH("a/b"), 0755); ++ if (res == -1) { ++ PERROR("mkdir"); ++ goto fail; ++ } ++ ++ res = mkdir(PATH("a/b/c"), 0755); ++ if (res == -1) { ++ PERROR("mkdir"); ++ goto fail; ++ } ++ ++ errno = 0; ++ res = rename(PATH("a"), PATH2("a/b/c")); ++ if (res == 0 || errno != EINVAL) { ++ PERROR("rename"); ++ goto fail; ++ } ++ ++ errno = 0; ++ res = rename(PATH("a"), PATH2("a/b/c/a")); ++ if (res == 0 || errno != EINVAL) { ++ PERROR("rename"); ++ goto fail; ++ } ++ ++ errno = 0; ++ res = rename(PATH("a/b/c"), PATH2("a")); ++ if (res == 0 || errno != ENOTEMPTY) { ++ PERROR("rename"); ++ goto fail; ++ } ++ ++ res = open(PATH("a/foo"), O_CREAT, 0644); ++ if (res == -1) { ++ PERROR("open"); ++ goto fail; ++ } ++ close(res); ++ ++ res = rename(PATH("a/foo"), PATH2("a/bar")); ++ if (res == -1) { ++ PERROR("rename"); ++ goto fail; ++ } ++ ++ res = rename(PATH("a/bar"), PATH2("a/foo")); ++ if (res == -1) { ++ PERROR("rename"); ++ goto fail; ++ } ++ ++ res = rename(PATH("a/foo"), PATH2("a/b/bar")); ++ if (res == -1) { ++ PERROR("rename"); ++ goto fail; ++ } ++ ++ res = rename(PATH("a/b/bar"), PATH2("a/foo")); ++ if (res == -1) { ++ PERROR("rename"); ++ goto fail; ++ } ++ ++ res = rename(PATH("a/foo"), PATH2("a/b/c/bar")); ++ if (res == -1) { ++ PERROR("rename"); ++ goto fail; ++ } ++ ++ res = rename(PATH("a/b/c/bar"), PATH2("a/foo")); ++ if (res == -1) { ++ PERROR("rename"); ++ goto fail; ++ } ++ ++ res = open(PATH("a/bar"), O_CREAT, 0644); ++ if (res == -1) { ++ PERROR("open"); ++ goto fail; ++ } ++ close(res); ++ ++ res = rename(PATH("a/foo"), PATH2("a/bar")); ++ if (res == -1) { ++ PERROR("rename"); ++ goto fail; ++ } ++ ++ unlink(PATH("a/bar")); ++ ++ res = rename(PATH("a/b"), PATH2("a/d")); ++ if (res == -1) { ++ PERROR("rename"); ++ goto fail; ++ } ++ ++ res = rename(PATH("a/d"), PATH2("a/b")); ++ if (res == -1) { ++ PERROR("rename"); ++ goto fail; ++ } ++ ++ res = mkdir(PATH("a/d"), 0755); ++ if (res == -1) { ++ PERROR("mkdir"); ++ goto fail; ++ } ++ ++ res = rename(PATH("a/b"), PATH2("a/d")); ++ if (res == -1) { ++ PERROR("rename"); ++ goto fail; ++ } ++ ++ res = rename(PATH("a/d"), PATH2("a/b")); ++ if (res == -1) { ++ PERROR("rename"); ++ goto fail; ++ } ++ ++ res = mkdir(PATH("a/d"), 0755); ++ if (res == -1) { ++ PERROR("mkdir"); ++ goto fail; ++ } ++ ++ res = mkdir(PATH("a/d/e"), 0755); ++ if (res == -1) { ++ PERROR("mkdir"); ++ goto fail; ++ } ++ ++ errno = 0; ++ res = rename(PATH("a/b"), PATH2("a/d")); ++ if (res == 0 || errno != ENOTEMPTY) { ++ PERROR("rename"); ++ goto fail; ++ } ++ ++ rmdir(PATH("a/d/e")); ++ rmdir(PATH("a/d")); ++ ++ rmdir(PATH("a/b/c")); ++ rmdir(PATH("a/b")); ++ rmdir(PATH("a")); ++ ++ err += cleanup_dir(testdir, testdir_files, 0); ++ res = rmdir(testdir); ++ if (res == -1) { ++ PERROR("rmdir"); ++ goto fail; ++ } ++ res = check_nonexist(testdir); ++ if (res == -1) ++ return -1; ++ if (err) ++ return -1; ++ ++ success(); ++ return 0; ++ ++fail: ++ unlink(PATH("a/bar")); ++ ++ rmdir(PATH("a/d/e")); ++ rmdir(PATH("a/d")); ++ ++ rmdir(PATH("a/b/c")); ++ rmdir(PATH("a/b")); ++ rmdir(PATH("a")); ++ ++ cleanup_dir(testdir, testdir_files, 1); ++ rmdir(testdir); ++ ++ return -1; ++ ++#undef PATH2 ++#undef PATH ++} ++ ++static int test_mkfifo(void) ++{ ++ int res; ++ int err = 0; ++ ++ start_test("mkfifo"); ++ unlink(testfile); ++ res = mkfifo(testfile, 0644); ++ if (res == -1) { ++ PERROR("mkfifo"); ++ return -1; ++ } ++ res = check_type(testfile, S_IFIFO); ++ if (res == -1) ++ return -1; ++ err += check_mode(testfile, 0644); ++ err += check_nlink(testfile, 1); ++ res = unlink(testfile); ++ if (res == -1) { ++ PERROR("unlink"); ++ return -1; ++ } ++ res = check_nonexist(testfile); ++ if (res == -1) ++ return -1; ++ if (err) ++ return -1; ++ ++ success(); ++ return 0; ++} ++ ++static int test_mkdir(void) ++{ ++ int res; ++ int err = 0; ++ const char *dir_contents[] = {NULL}; ++ ++ start_test("mkdir"); ++ rmdir(testdir); ++ res = mkdir(testdir, 0755); ++ if (res == -1) { ++ PERROR("mkdir"); ++ return -1; ++ } ++ res = check_type(testdir, S_IFDIR); ++ if (res == -1) ++ return -1; ++ err += check_mode(testdir, 0755); ++ err += check_nlink(testdir, 2); ++ err += check_dir_contents(testdir, dir_contents); ++ res = rmdir(testdir); ++ if (res == -1) { ++ PERROR("rmdir"); ++ return -1; ++ } ++ res = check_nonexist(testdir); ++ if (res == -1) ++ return -1; ++ if (err) ++ return -1; ++ ++ success(); ++ return 0; ++} ++ ++#define test_create_ro_dir(flags) \ ++ do_test_create_ro_dir(flags, #flags) ++ ++static int do_test_create_ro_dir(int flags, const char *flags_str) ++{ ++ int res; ++ int err = 0; ++ int fd; ++ ++ start_test("open(%s) in read-only directory", flags_str); ++ rmdir(testdir); ++ res = mkdir(testdir, 0555); ++ if (res == -1) { ++ PERROR("mkdir"); ++ return -1; ++ } ++ fd = open(subfile, flags, 0644); ++ if (fd != -1) { ++ close(fd); ++ unlink(subfile); ++ ERROR("open should have failed"); ++ err--; ++ } else { ++ res = check_nonexist(subfile); ++ if (res == -1) ++ err--; ++ } ++ unlink(subfile); ++ res = rmdir(testdir); ++ if (res == -1) { ++ PERROR("rmdir"); ++ return -1; ++ } ++ res = check_nonexist(testdir); ++ if (res == -1) ++ return -1; ++ if (err) ++ return -1; ++ ++ success(); ++ return 0; ++} ++ ++int main(int argc, char *argv[]) ++{ ++ const char *basepath; ++ int err = 0; ++ ++ umask(0); ++ if (argc < 2 || argc > 3) { ++ fprintf(stderr, "usage: %s testdir [test#]\n", argv[0]); ++ return 1; ++ } ++ basepath = argv[1]; ++ if (argc == 3) { ++ char *endptr; ++ char *arg = argv[2]; ++ if (arg[0] == '-') { ++ arg++; ++ skip_test = strtoul(arg, &endptr, 10); ++ } else { ++ select_test = strtoul(argv[2], &endptr, 10); ++ } ++ if (arg[0] == '\0' || *endptr != '\0') { ++ fprintf(stderr, "invalid number: '%s'\n", arg); ++ return 1; ++ } ++ } ++ assert(strlen(basepath) < 512); ++ if (basepath[0] != '/') { ++ fprintf(stderr, "testdir must be an absolute path\n"); ++ return 1; ++ } ++ ++ sprintf(testfile, "%s/testfile", basepath); ++ sprintf(testfile2, "%s/testfile2", basepath); ++ sprintf(testdir, "%s/testdir", basepath); ++ sprintf(testdir2, "%s/testdir2", basepath); ++ sprintf(subfile, "%s/subfile", testdir2); ++ err += test_create(); ++ err += test_create_unlink(); ++ err += test_mknod(); ++ err += test_symlink(); ++ err += test_link(); ++ err += test_link2(); ++ err += test_mkfifo(); ++ err += test_mkdir(); ++ err += test_rename_file(); ++ err += test_rename_dir(); ++ err += test_rename_dir_loop(); ++ err += test_seekdir(); ++ err += test_utime(); ++ err += test_truncate(0); ++ err += test_truncate(testdatalen / 2); ++ err += test_truncate(testdatalen); ++ err += test_truncate(testdatalen + 100); ++ err += test_ftruncate(0, 0600); ++ err += test_ftruncate(testdatalen / 2, 0600); ++ err += test_ftruncate(testdatalen, 0600); ++ err += test_ftruncate(testdatalen + 100, 0600); ++ err += test_ftruncate(0, 0400); ++ err += test_ftruncate(0, 0200); ++ err += test_ftruncate(0, 0000); ++ err += test_open(0, O_RDONLY, 0); ++ err += test_open(1, O_RDONLY, 0); ++ err += test_open(1, O_RDWR, 0); ++ err += test_open(1, O_WRONLY, 0); ++ err += test_open(0, O_RDWR | O_CREAT, 0600); ++ err += test_open(1, O_RDWR | O_CREAT, 0600); ++ err += test_open(0, O_RDWR | O_CREAT | O_TRUNC, 0600); ++ err += test_open(1, O_RDWR | O_CREAT | O_TRUNC, 0600); ++ err += test_open(0, O_RDONLY | O_CREAT, 0600); ++ err += test_open(0, O_RDONLY | O_CREAT, 0400); ++ err += test_open(0, O_RDONLY | O_CREAT, 0200); ++ err += test_open(0, O_RDONLY | O_CREAT, 0000); ++ err += test_open(0, O_WRONLY | O_CREAT, 0600); ++ err += test_open(0, O_WRONLY | O_CREAT, 0400); ++ err += test_open(0, O_WRONLY | O_CREAT, 0200); ++ err += test_open(0, O_WRONLY | O_CREAT, 0000); ++ err += test_open(0, O_RDWR | O_CREAT, 0400); ++ err += test_open(0, O_RDWR | O_CREAT, 0200); ++ err += test_open(0, O_RDWR | O_CREAT, 0000); ++ err += test_open(0, O_RDWR | O_CREAT | O_EXCL, 0600); ++ err += test_open(1, O_RDWR | O_CREAT | O_EXCL, 0600); ++ err += test_open(0, O_RDWR | O_CREAT | O_EXCL, 0000); ++ err += test_open(1, O_RDWR | O_CREAT | O_EXCL, 0000); ++ err += test_open_acc(O_RDONLY, 0600, 0); ++ err += test_open_acc(O_WRONLY, 0600, 0); ++ err += test_open_acc(O_RDWR, 0600, 0); ++ err += test_open_acc(O_RDONLY, 0400, 0); ++ err += test_open_acc(O_RDONLY | O_TRUNC, 0400, EACCES); ++ err += test_open_acc(O_WRONLY, 0400, EACCES); ++ err += test_open_acc(O_RDWR, 0400, EACCES); ++ err += test_open_acc(O_RDONLY, 0200, EACCES); ++ err += test_open_acc(O_WRONLY, 0200, 0); ++ err += test_open_acc(O_RDWR, 0200, EACCES); ++ err += test_open_acc(O_RDONLY, 0000, EACCES); ++ err += test_open_acc(O_WRONLY, 0000, EACCES); ++ err += test_open_acc(O_RDWR, 0000, EACCES); ++ err += test_create_ro_dir(O_CREAT); ++ err += test_create_ro_dir(O_CREAT | O_EXCL); ++ err += test_create_ro_dir(O_CREAT | O_WRONLY); ++ err += test_create_ro_dir(O_CREAT | O_TRUNC); ++ ++ unlink(testfile); ++ unlink(testfile2); ++ rmdir(testdir); ++ rmdir(testdir2); ++ ++ if (err) { ++ fprintf(stderr, "%i tests failed\n", -err); ++ return 1; ++ } ++ ++ return 0; ++} +-- +1.8.3.1 + diff --git a/fuse.spec b/fuse.spec index 40d43e2..08ac886 100644 --- a/fuse.spec +++ b/fuse.spec @@ -2,7 +2,7 @@ Name: fuse Version: %{fuse2ver} -Release: 9 +Release: 10 Summary: User space File System of fuse2 License: GPL+ and LGPLv2+ URL: http://fuse.sf.net @@ -11,6 +11,7 @@ Source0: https://github.com/libfuse/libfuse/archive/%{name}-%{fuse2ver}.tar.gz Patch0: 0000-fix-compile-error-because-of-ns-colliding.patch Patch1: 0001-libfuse-Assign-NULL-to-old-to-avoid-free-it-twice-52.patch Patch2: 0002-util-ulockmgr_server.c-conditionally-define-closefro.patch +Patch3: 0003-add-fuse-test-dir.patch BuildRequires: libselinux-devel, pkgconfig, systemd-udev, meson, fdupes BuildRequires: autoconf, automake, libtool, gettext-devel, ninja-build @@ -94,6 +95,9 @@ find %{buildroot} -type f -name "*.la" -delete -print %changelog +- Mon Apr 11 2022 zhanchengbin -2.9.9-10 +- add fuse test dir + - Wed Aug 11 2021 lixiaokeng -2.9.9-9 - fix double define closefrom