/GSYMS
/GTAGS
/test/test_setattr
+/build/
==========================
* Re-introduced examples/null.c.
-
+* Added experimental support for building with Meson.
libfuse 3.0.0 (2016-12-08)
==========================
fuse3.pc.in \
README* \
test/*.py \
- test/pytest.ini
+ test/pytest.ini \
+ meson.build \
+ meson_options.txt
pkgconfigdir = @pkgconfigdir@
pkgconfig_DATA = fuse3.pc
$(pkgconfig_DATA): config.status
-
-.PHONY: setuid_fusermount
-setuid_fusermount:
- @echo "Attempting to use sudo to make util/fusermount3 setuid root"
- @echo "If this fails, set permissions manually and re-run make test"
- test $$(ls -n util/fusermount3 | awk 'NR==1 {print $$3}') -eq 0 || \
- sudo chown root util/fusermount3
- test -u util/fusermount3 || \
- sudo chmod u+s util/fusermount3
-
-# If we are not root, util/fusermount3 needs to be setuid root
-# for tests to work.
-
-test_deps = $(shell [ "$${UID}" -eq 0 ] || echo setuid_fusermount)
-.PHONY: test
-test: all $(test_deps)
- python3 -m pytest test/
------------
You can download libfuse from
-https://github.com/libfuse/libfuse/releases. After extracting the
-tarball, build and install with
+https://github.com/libfuse/libfuse/releases. To build and install, we
+recommend to use [Meson](http://mesonbuild.com/) and
+[Ninja](https://ninja-build.org). After extracting the libfuse
+tarball, create a (temporary) build directory and run Meson:
- ./configure
- make -j8
- make install
+ $ md build; cd build
+ $ meson ..
-To run some self tests, you need a Python 3 environment with the
-[py.test](http://www.pytest.org/) module installed. To run the tests,
-execute
+Normally, the default build options will work fine. If you
+nevertheless want to adjust them, you can do so with the *mesonconf*
+command:
- python3 -m pytest test/
+ $ mesonconf # list options
+ $ mesonconf -D disable-mtab=true # set an option
-You may also need to add `/usr/local/lib` to `/etc/ld.so.conf` and/or
-run *ldconfig*. If you're building from the git repository (instead of
-using a release tarball), you also need to run `./makeconf.sh` to
-create the `configure` script.
+To build, test and install libfuse, you then use Ninja:
+
+ $ ninja
+ $ sudo ninja tests # requires pytest, see below
+ $ sudo ninja install
+
+Running the tests requires the [py.test](http://www.pytest.org/)
+Python module. Instead of running the tests as root, the majority of
+tests can also be run as a regular user if *util/fusermount3* is
+made setuid root first:
+
+ $ sudo chown root:root util/fusermount3
+ $ sudo chmod 4755 util/fusermount3
+ $ ninja tests
+
+
+Alternate Installation
+----------------------
+
+If you are not able to use Meson and Ninja, please report this to the
+libfuse mailing list. Until the problem is resolved, you may fall back
+to an in-source build using autotools:
+
+ $ ./configure
+ $ make
+ $ sudo make install
+
+Note that support for building with autotools may disappear at some
+point, so if you depend on using autotools for some reason please let
+the libfuse developers know!
-You'll also need a fuse kernel module (Linux kernels 2.6.14 or later
-contain FUSE support).
Security implications
---------------------
-If you run `make install`, the *fusermount3* program is installed
-set-user-id to root. This is done to allow normal users to mount
-their own filesystem implementations.
+The *fusermount3* program is installed setuid root. This is done to
+allow normal users to mount their own filesystem implementations.
To limit the harm that malicious users can do this way, *fusermount3*
enforces the following limitations:
dist_man_MANS = fusermount3.1 mount.fuse.8
-EXTRA_DIST = kernel.txt Doxyfile html README.NFS
+EXTRA_DIST = kernel.txt Doxyfile html README.NFS meson.build
--- /dev/null
+# Attention, emacs, please use -*- mode: python -*-
+# (even though this isn't actually Python code)
+
+install_man('fusermount3.1', 'mount.fuse.8')
+
poll_client_CPPFLAGS =
poll_client_LDFLAGS =
poll_client_LDADD =
+
+EXTRA_DIST = meson.build
--- /dev/null
+# Attention, emacs, please use -*- mode: python -*-
+# (even though this isn't actually Python code)
+
+examples = [ 'passthrough', 'passthrough_fh', 'null', 'hello', 'hello_ll',
+ 'ioctl', 'ioctl_client', 'poll_client',
+ 'passthrough_ll', 'cuse', 'cuse_client' ]
+
+threaded_examples = [ 'notify_inval_inode',
+ 'notify_store_retrieve',
+ 'notify_inval_entry',
+ 'poll' ]
+
+foreach ex : examples
+ executable(ex, ex + '.c',
+ include_directories: include_dirs,
+ link_with: [ libfuse ],
+ install: false)
+endforeach
+
+
+foreach ex : threaded_examples
+ executable(ex, ex + '.c',
+ include_directories: include_dirs,
+ link_with: [ libfuse ],
+ dependencies: thread_dep,
+ install: false)
+endforeach
+
+# TODO: Link passthrough_fh with ulockmgr if available
cuse_lowlevel.h
noinst_HEADERS = fuse_kernel.h
+
+EXTRA_DIST = meson.build
--- /dev/null
+# Attention, emacs, please use -*- mode: python -*-
+# (even though this isn't actually Python code)
+
+libfuse_headers = [ 'fuse.h', 'fuse_common.h', 'fuse_lowlevel.h',
+ 'fuse_opt.h', 'cuse_lowlevel.h' ]
+
+install_headers(libfuse_headers, subdir: 'fuse3')
+
libfuse3_la_LIBADD = -lperfuse -lpuffs
endif
-EXTRA_DIST = fuse_versionscript
+EXTRA_DIST = fuse_versionscript meson.build
--- /dev/null
+# Attention, emacs, please use -*- mode: python -*-
+# (even though this isn't actually Python code)
+
+libfuse_sources = ['fuse.c', 'fuse_i.h', 'fuse_loop.c', 'fuse_loop_mt.c',
+ 'fuse_lowlevel.c', 'fuse_misc.h', 'fuse_opt.c',
+ 'fuse_signals.c', 'buffer.c', 'cuse_lowlevel.c',
+ 'helper.c', 'modules/subdir.c' ]
+
+if host_machine.system().startswith('linux')
+ libfuse_sources += [ 'mount.c', 'mount_util.c' ]
+else
+ libfuse_sources += [ 'mount_bsd.c' ]
+endif
+
+if cfg.has('HAVE_ICONV')
+ libfuse_sources += [ 'modules/iconv.c' ]
+endif
+
+deps = [ thread_dep ]
+libdl = meson.get_compiler('c').find_library('dl')
+if libdl.found()
+ deps += [ libdl ]
+endif
+
+if host_machine.system().startswith('netbsd')
+ deps += [ cc.find_library('perfuse'),
+ cc.find_library('puffs') ]
+endif
+
+fusermount_path = join_paths(get_option('prefix'), get_option('bindir'))
+libfuse = library('fuse3', libfuse_sources, version: '3.0.0', install: true,
+ soversion: '3', include_directories: include_dirs,
+ dependencies: deps,
+ link_depends: 'fuse_versionscript',
+ c_args: [ '-DFUSE_USE_VERSION=30',
+ '-DFUSERMOUNT_DIR="{}"'.format(fusermount_path) ],
+ link_args: ['-Wl,--version-script,' + meson.current_source_dir()
+ + '/fuse_versionscript' ])
+
+pkg = import('pkgconfig')
+pkg.generate(libraries: [ libfuse, '-lpthread' ],
+ libraries_private: '-ldl',
+ version: meson.project_version(),
+ name: 'fuse3',
+ description: 'Filesystem in Userspace',
+ subdirs: 'fuse3')
+
--- /dev/null
+# Attention, emacs, please use -*- mode: python -*-
+# (even though this isn't actually Python code)
+
+project('libfuse3', 'c', version: '3.1.0',
+ default_options: [ 'buildtype=plain' ])
+
+#
+# Feature detection
+#
+cfg = configuration_data()
+cc = meson.get_compiler('c')
+
+# Default includes when checking for presence of functions and
+# struct members
+include_default = '
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+'
+
+cfg.set_quoted('PACKAGE_VERSION', meson.project_version())
+
+# Test for presence of some functions
+test_funcs = [ 'fork', 'fstatat', 'openat', 'readlinkat', 'pipe2',
+ 'splice', 'vmsplice', 'posix_fallocate', 'fdatasync',
+ 'utimensat' ]
+foreach func : test_funcs
+ cfg.set('HAVE_' + func.to_upper(),
+ cc.has_function(func, prefix: include_default))
+endforeach
+cfg.set('HAVE_SETXATTR',
+ cc.has_function('setxattr', prefix: '#include <sys/xattr.h>'))
+cfg.set('HAVE_ICONV',
+ cc.has_function('iconv', prefix: '#include <iconv.h>'))
+
+# Test if structs have specific member
+cfg.set('HAVE_STRUCT_STAT_ST_ATIM',
+ cc.has_member('struct stat', 'st_atim',
+ prefix: include_default))
+cfg.set('HAVE_STRUCT_STAT_ST_ATIMESPEC',
+ cc.has_member('struct stat', 'st_atimespec',
+ prefix: include_default))
+
+# Write the test results into config.h (stored in build directory)
+configure_file(output: 'config.h',
+ configuration : cfg)
+
+
+#
+# Compiler configuration
+#
+add_global_arguments('-D_REENTRANT', '-DHAVE_CONFIG_H', '-Wall', '-Wextra', '-Wno-sign-compare',
+ '-Wstrict-prototypes', '-Wmissing-declarations', '-Wwrite-strings',
+ '-O2', '-g', '-fno-strict-aliasing', language: 'c')
+
+# Some (stupid) GCC versions warn about unused return values even when they are
+# casted to void. This makes -Wunused-result pretty useless, since there is no
+# way to suppress the warning when we really *want* to ignore the value.
+code = '''
+__attribute__((warn_unused_result)) int get_4() {
+ return 4;
+}
+int main(void) {
+ (void) get_4();
+ return 0;
+}'''
+if not cc.compiles(code, args: [ '-O0', '-Werror=unused-result' ])
+ message('Compiler warns about unused result even when casting to void')
+ add_global_arguments('-Wno-unused-result', language: 'c')
+endif
+
+# current_build_dir() contains config.h
+include_dirs = include_directories('include', 'lib',
+ meson.current_build_dir())
+
+# Common dependencies
+thread_dep = dependency('threads')
+
+#
+# Read build files from sub-directories
+#
+subdirs = [ 'lib', 'include', 'util', 'example', 'doc', 'test' ]
+foreach n : subdirs
+ subdir(n)
+endforeach
--- /dev/null
+option('disable-mtab', type : 'boolean', value : false,
+ description: 'Disable and ignore usage of /etc/mtab')
## Process this file with automake to produce Makefile.in
AM_CPPFLAGS = -I$(top_srcdir)/include -D_REENTRANT
-noinst_PROGRAMS = test test_write_cache test_setattr
+noinst_PROGRAMS = test_syscalls test_write_cache test_setattr
test_write_cache_LDADD = ../lib/libfuse3.la
test_setattr_LDADD = ../lib/libfuse3.la
+
+EXTRA_DIST = meson.build wrong_command.c
+
--- /dev/null
+# Attention, emacs, please use -*- mode: python -*-
+# (even though this isn't actually Python code)
+
+# Compile helper programs
+td = []
+foreach prog: [ 'test_write_cache', 'test_setattr' ]
+ td += executable(prog, prog + '.c',
+ include_directories: include_dirs,
+ link_with: [ libfuse ],
+ dependencies: thread_dep,
+ install: false)
+endforeach
+td += executable('test_syscalls', 'test_syscalls.c',
+ include_directories: include_dirs,
+ install: false)
+
+# Actual tests are written in Python and can simply be copied.
+foreach fname : [ 'conftest.py', 'pytest.ini', 'test_examples.py',
+ 'util.py' ]
+ td += custom_target(fname, input: fname, output: fname,
+ command: ['cp', '-fP', '--preserve=mode',
+ '@INPUT@', '@OUTPUT@'])
+endforeach
+
+# Create a new 'tests' target that we can run with Ninja
+run_target('tests', depends: td,
+ command: [ 'python3', '-m', 'pytest',
+ meson.current_build_dir() ])
+
+
+# Provide something helpful when running 'ninja test'
+wrong_cmd = executable('wrong_command', 'wrong_command.c',
+ install: false)
+test('wrong_cmd', wrong_cmd)
+
+++ /dev/null
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <utime.h>
-#include <errno.h>
-#include <assert.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-
-static char testfile[1024];
-static char testfile2[1024];
-static char testdir[1024];
-static char testdir2[1024];
-static char subfile[1024];
-
-static char testfile_r[1024];
-static char testfile2_r[1024];
-static char testdir_r[1024];
-static char testdir2_r[1024];
-static char subfile_r[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 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)
-
-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_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_r, 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;
- res = check_nonexist(testfile_r);
- 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 message: '%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_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;
- const char *realpath;
- int err = 0;
- int a;
- int is_root;
-
- umask(0);
- if (argc < 2 || argc > 4) {
- fprintf(stderr, "usage: %s testdir [:realdir] [[-]test#]\n", argv[0]);
- return 1;
- }
- basepath = argv[1];
- realpath = basepath;
- for (a = 2; a < argc; a++) {
- char *endptr;
- char *arg = argv[a];
- if (arg[0] == ':') {
- realpath = arg + 1;
- } else {
- if (arg[0] == '-') {
- arg++;
- skip_test = strtoul(arg, &endptr, 10);
- } else {
- select_test = strtoul(arg, &endptr, 10);
- }
- if (arg[0] == '\0' || *endptr != '\0') {
- fprintf(stderr, "invalid number: '%s'\n", arg);
- return 1;
- }
- }
- }
- assert(strlen(basepath) < 512);
- assert(strlen(realpath) < 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);
-
- sprintf(testfile_r, "%s/testfile", realpath);
- sprintf(testfile2_r, "%s/testfile2", realpath);
- sprintf(testdir_r, "%s/testdir", realpath);
- sprintf(testdir2_r, "%s/testdir2", realpath);
- sprintf(subfile_r, "%s/subfile", testdir2_r);
-
- is_root = (geteuid() == 0);
-
- 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_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_WRONLY, 0200, 0);
- if(!is_root) {
- 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_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;
-}
wait_for_mount(mount_process, mnt_dir)
work_dir = pjoin(mnt_dir, src_dir)
- subprocess.check_call([ os.path.join(basename, 'test', 'test'),
+ subprocess.check_call([ os.path.join(basename, 'test', 'test_syscalls'),
work_dir, ':' + src_dir ])
tst_write(work_dir)
--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <utime.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+
+static char testfile[1024];
+static char testfile2[1024];
+static char testdir[1024];
+static char testdir2[1024];
+static char subfile[1024];
+
+static char testfile_r[1024];
+static char testfile2_r[1024];
+static char testdir_r[1024];
+static char testdir2_r[1024];
+static char subfile_r[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 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)
+
+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_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_r, 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;
+ res = check_nonexist(testfile_r);
+ 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 message: '%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_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;
+ const char *realpath;
+ int err = 0;
+ int a;
+ int is_root;
+
+ umask(0);
+ if (argc < 2 || argc > 4) {
+ fprintf(stderr, "usage: %s testdir [:realdir] [[-]test#]\n", argv[0]);
+ return 1;
+ }
+ basepath = argv[1];
+ realpath = basepath;
+ for (a = 2; a < argc; a++) {
+ char *endptr;
+ char *arg = argv[a];
+ if (arg[0] == ':') {
+ realpath = arg + 1;
+ } else {
+ if (arg[0] == '-') {
+ arg++;
+ skip_test = strtoul(arg, &endptr, 10);
+ } else {
+ select_test = strtoul(arg, &endptr, 10);
+ }
+ if (arg[0] == '\0' || *endptr != '\0') {
+ fprintf(stderr, "invalid number: '%s'\n", arg);
+ return 1;
+ }
+ }
+ }
+ assert(strlen(basepath) < 512);
+ assert(strlen(realpath) < 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);
+
+ sprintf(testfile_r, "%s/testfile", realpath);
+ sprintf(testfile2_r, "%s/testfile2", realpath);
+ sprintf(testdir_r, "%s/testdir", realpath);
+ sprintf(testdir2_r, "%s/testdir2", realpath);
+ sprintf(subfile_r, "%s/subfile", testdir2_r);
+
+ is_root = (geteuid() == 0);
+
+ 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_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_WRONLY, 0200, 0);
+ if(!is_root) {
+ 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_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;
+}
return pytest.mark.uses_fuse()
-# If valgrind and libtool are available, use them
+# If valgrind is available, use it
def has_program(name):
try:
ret = subprocess.call([name, '--version'],
return False
return ret == 0
-if has_program('valgrind') and has_program('libtool'):
- base_cmdline = [ 'libtool', '--mode=execute',
- 'valgrind', '-q', '--' ]
+if has_program('valgrind'):
+ base_cmdline = [ 'valgrind', '-q', '--' ]
else:
base_cmdline = []
--- /dev/null
+#include <stdio.h>
+
+int main(void) {
+ fprintf(stderr, "\x1B[31m\e[1m"
+ "This is not the command you are looking for.\n"
+ "You probably want to run 'ninja tests' instead "
+ "(note the 's' at the end).\n"
+ "\e[0m");
+ return 1;
+}
mknod $(DESTDIR)/dev/fuse -m 0666 c 10 229 || true; \
fi
-EXTRA_DIST = udev.rules init_script
+EXTRA_DIST = udev.rules init_script meson.build install_helper.sh
MOUNT_FUSE_PATH = @MOUNT_FUSE_PATH@
UDEV_RULES_PATH = @UDEV_RULES_PATH@
--- /dev/null
+#!/bin/sh
+#
+# Don't call this script. It is used internally by the Meson
+# build system. Thank you for your cooperation.
+#
+
+set -e
+
+sysconfdir="$1"
+bindir="$2"
+prefix="${MESON_INSTALL_DESTDIR_PREFIX}"
+
+chown root:root "${prefix}/${bindir}/fusermount3"
+chmod u+s "${prefix}/${bindir}/fusermount3"
+
+if test ! -e "${DESTDIR}/dev/fuse"; then
+ mkdir -p "${DESTDIR}/dev"
+ mknod "${DESTDIR}/dev/fuse" -m 0666 c 10 229
+fi
+
+install -D -m 644 "${MESON_SOURCE_ROOT}/util/udev.rules" \
+ "${prefix}/lib/udev/rules.d/99-fuse3.rules"
+
+install -D -m 755 "${MESON_SOURCE_ROOT}/util/init_script" \
+ "${prefix}/${sysconfdir}/init.d/fuse3"
+
+if test -x /usr/sbin/update-rc.d; then
+ # May fail for a DESTDIR installation
+ /usr/sbin/update-rc.d fuse3 start 34 S . start 41 0 6 . || /bin/true
+fi
+
+
--- /dev/null
+# Attention, emacs, please use -*- mode: python -*-
+# (even though this isn't actually Python code)
+
+# we re-use mount_util.c from the library, but do want to keep ourself
+# as stand-alone as possible. in order to make an out-of-source build
+# possible, we "generate" the file from its original location by
+# copying it over.
+mount_util_c = custom_target('mount_util',
+ input : '../lib/mount_util.c',
+ output : 'mount_util.c',
+ command : ['cp', '-a', '@INPUT@', '@OUTPUT@'],
+)
+
+executable('fusermount3', ['fusermount.c', mount_util_c],
+ include_directories: include_dirs,
+ install: true,
+ install_dir: get_option('bindir'))
+
+executable('mount.fuse3', ['mount.fuse.c'],
+ include_directories: include_dirs,
+ install: true,
+ install_dir: get_option('sbindir'))
+
+meson.add_install_script('install_helper.sh', get_option('sysconfdir'),
+ get_option('bindir'), get_option('libdir'))
+
+