changeset 11980:0811c19e147f

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 <ebb9@byu.net>
author Eric Blake <ebb9@byu.net>
date Wed, 09 Sep 2009 11:06:44 -0600
parents 4dab439a2737
children 7e5f9267c62e
files ChangeLog modules/link-tests tests/test-link.c tests/test-link.sh
diffstat 4 files changed, 111 insertions(+), 45 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2009-09-09  Eric Blake  <ebb9@byu.net>
+
+	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  <bruno@clisp.org>
 
 	Work around towlower, towupper bug on mingw.
--- 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
--- a/tests/test-link.c
+++ b/tests/test-link.c
@@ -19,8 +19,12 @@
 #include <unistd.h>
 
 #include <errno.h>
+#include <fcntl.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
 #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;
 }
deleted file mode 100755
--- 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