From 5ed5df8e8f519a74992edd0b7a6021b05b4952cd Mon Sep 17 00:00:00 2001 From: Eric Blake Date: Wed, 9 Sep 2009 11:06:44 -0600 Subject: [PATCH] test-link: consolidate into single C program, test more cases * tests/test-link.sh: Delete. * tests/test-link.c: Test more error conditions. Exposes bugs on at least Cygwin and Solaris. * modules/link-tests (Files): Remove unused file. (Depends-on): Add errno, sys_stat. (Makefile.am): Simplify. Signed-off-by: Eric Blake --- ChangeLog | 10 ++++++ modules/link-tests | 6 ++-- tests/test-link.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++--- tests/test-link.sh | 37 ------------------- 4 files changed, 111 insertions(+), 45 deletions(-) delete mode 100755 tests/test-link.sh diff --git a/ChangeLog b/ChangeLog index f055a3cf5..8bfb08d12 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2009-09-09 Eric Blake + + test-link: consolidate into single C program, test more cases + * tests/test-link.sh: Delete. + * tests/test-link.c: Test more error conditions. Exposes bugs on + at least Cygwin and Solaris. + * modules/link-tests (Files): Remove unused file. + (Depends-on): Add errno, sys_stat. + (Makefile.am): Simplify. + 2009-09-08 Bruno Haible Work around towlower, towupper bug on mingw. diff --git a/modules/link-tests b/modules/link-tests index c1ec52cad..ca61deb70 100644 --- a/modules/link-tests +++ b/modules/link-tests @@ -1,12 +1,12 @@ Files: -tests/test-link.sh tests/test-link.c Depends-on: +errno +sys_stat configure.ac: Makefile.am: -TESTS += test-link.sh -TESTS_ENVIRONMENT += EXEEXT='@EXEEXT@' +TESTS += test-link check_PROGRAMS += test-link diff --git a/tests/test-link.c b/tests/test-link.c index 250a82118..fbc794a35 100644 --- a/tests/test-link.c +++ b/tests/test-link.c @@ -19,8 +19,12 @@ #include #include +#include #include #include +#include +#include +#include #define ASSERT(expr) \ do \ @@ -34,30 +38,119 @@ } \ while (0) +#define BASE "test-link.t" + int main (int argc, char **argv) { + int fd; int ret; - ASSERT (argc == 3); + /* Remove any garbage left from previous partial runs. */ + ASSERT (system ("rm -rf " BASE "*") == 0); + + /* Create first file. */ + fd = open (BASE "a", O_CREAT | O_EXCL | O_WRONLY, 0600); + ASSERT (0 <= fd); + ASSERT (write (fd, "hello", 5) == 5); + ASSERT (close (fd) == 0); - ret = link (argv[1], argv[2]); - if (ret < 0) + /* Not all file systems support link. Mingw doesn't have reliable + st_nlink on hard links, but our implementation does fail with + EPERM on poor file systems, and we can detect the inferior stat() + via st_ino. Cygwin 1.5.x copies rather than links files on those + file systems, but there, st_nlink and st_ino are reliable. */ + ret = link (BASE "a", BASE "b"); + if (!ret) + { + struct stat st; + ASSERT (stat (BASE "b", &st) == 0); + if (st.st_ino && st.st_nlink != 2) + { + ASSERT (unlink (BASE "b") == 0); + errno = EPERM; + ret = -1; + } + } + if (ret == -1) { /* If the device does not support hard links, errno is EPERM on Linux, EOPNOTSUPP on FreeBSD. */ switch (errno) { case EPERM: -#ifdef EOPNOTSUPP case EOPNOTSUPP: -#endif + fputs ("skipping test: " + "hard links are not supported on this file system\n", stderr); + ASSERT (unlink (BASE "a") == 0); return 77; default: perror ("link"); return 1; } } + ASSERT (ret == 0); + + /* Now, for some behavior tests. Modify the contents of 'b', and + ensure that 'a' can see it, both while 'b' exists and after. */ + fd = open (BASE "b", O_APPEND | O_WRONLY); + ASSERT (0 <= fd); + ASSERT (write (fd, "world", 5) == 5); + ASSERT (close (fd) == 0); + { + char buf[11] = { 0 }; + fd = open (BASE "a", O_RDONLY); + ASSERT (0 <= fd); + ASSERT (read (fd, buf, 10) == 10); + ASSERT (strcmp (buf, "helloworld") == 0); + ASSERT (close (fd) == 0); + ASSERT (unlink (BASE "b") == 0); + fd = open (BASE "a", O_RDONLY); + ASSERT (0 <= fd); + ASSERT (read (fd, buf, 10) == 10); + ASSERT (strcmp (buf, "helloworld") == 0); + ASSERT (close (fd) == 0); + } + + /* Test for various error conditions. Assumes hard links to + directories are not permitted. */ + ASSERT (mkdir (BASE "d", 0700) == 0); + errno = 0; + ASSERT (link (BASE "a", ".") == -1); + ASSERT (errno == EEXIST || errno == EINVAL); + errno = 0; + ASSERT (link (BASE "a", BASE "a") == -1); + ASSERT (errno == EEXIST); + ASSERT (link (BASE "a", BASE "b") == 0); + errno = 0; + ASSERT (link (BASE "a", BASE "b") == -1); + ASSERT (errno == EEXIST); + errno = 0; + ASSERT (link (BASE "a", BASE "d") == -1); + ASSERT (errno == EEXIST); + errno = 0; + ASSERT (link (BASE "c", BASE "e") == -1); + ASSERT (errno == ENOENT); + errno = 0; + ASSERT (link (BASE "a", BASE "c/.") == -1); + ASSERT (errno == ENOENT); + errno = 0; + ASSERT (link (BASE "a/", BASE "c") == -1); + ASSERT (errno == ENOTDIR); + errno = 0; + ASSERT (link (BASE "a", BASE "c/") == -1); + ASSERT (errno == ENOTDIR); + errno = 0; + ASSERT (link (BASE "d", BASE "c") == -1); + ASSERT (errno == EPERM || errno == EACCES); + + /* Clean up. */ + ASSERT (unlink (BASE "a") == 0); + ASSERT (unlink (BASE "b") == 0); + errno = 0; + ASSERT (unlink (BASE "c") == -1); + ASSERT (errno == ENOENT); + ASSERT (rmdir (BASE "d") == 0); return 0; } diff --git a/tests/test-link.sh b/tests/test-link.sh deleted file mode 100755 index 1519f9d9a..000000000 --- a/tests/test-link.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh - -tmpfiles="test-link-a.txt test-link-b.txt test-link-c.txt" -trap 'rm -fr $tmpfiles' 1 2 3 15 - -# Create a file. -echo "hello" > test-link-a.txt || exit 1 - -# Use link() to create a new name for it. -./test-link${EXEEXT} test-link-a.txt test-link-b.txt -case $? in - 0) ;; - 77) - echo "Skipping test: hard links are not supported on this file system" - rm -fr $tmpfiles - exit 77 - ;; - *) exit 1 ;; -esac -cmp test-link-a.txt test-link-b.txt || exit 1 - -# Modify the contents of the first file. -echo "world" >> test-link-a.txt || exit 1 -cmp test-link-a.txt test-link-b.txt || exit 1 - -# Modify the contents of the second file. -echo "some text" >> test-link-b.txt || exit 1 -cmp test-link-a.txt test-link-b.txt || exit 1 - -# Delete the first file, then verity the second file still has the same -# contents. -cp test-link-a.txt test-link-c.txt || exit 1 -rm test-link-a.txt || exit 1 -cmp test-link-b.txt test-link-c.txt || exit 1 - -rm -fr $tmpfiles -exit 0 -- 2.11.0