bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: linkat, LINK_FOLLOWS_SYMLINKS, and Solaris


From: Bruno Haible
Subject: Re: linkat, LINK_FOLLOWS_SYMLINKS, and Solaris
Date: Mon, 27 Dec 2010 14:20:15 +0100
User-agent: KMail/1.9.9

[dropped autoconf and libtool mailing list CCs]

Paul Eggert wrote:
> the proposed change would appear to place a
> significant performance penalty for the (presumably more common) case
> of compiling and linking in the default mode.  I would suggest something
> like the following patch instead, with a similar patch for link_follow,
> and with the appropriate m4 magic to make LINK_FOLLOWS_SYMLINKS a
> runtime test (__xpg4) on hosts like Solaris that have the __xpg4 variable.

OK, to reduce the runtime cost, here's a new proposed patch. It passes the
tests on Solaris 10, with and without "-xc99=all".


2010-12-27  Bruno Haible  <address@hidden>
            Paul Eggert <address@hidden>

        linkat: Make implementation robust against system behaviour variations.
        * m4/link-follow.m4 (gl_FUNC_LINK_FOLLOWS_SYMLINK): Define
        LINK_FOLLOWS_SYMLINKS to -1 if it needs a runtime test in the Solaris
        way, and to -2 if it needs a generic runtime test.
        * lib/linkat.c (solaris_optimized_link_immediate,
        solaris_optimized_link_follow): New functions.
        * tests/test-linkat.c (EXPECT_LINK_HARDLINKS_SYMLINKS): New macro.
        (check_same_link): Use it.

--- lib/linkat.c.orig   Mon Dec 27 13:56:17 2010
+++ lib/linkat.c        Mon Dec 27 12:37:46 2010
@@ -166,6 +166,36 @@
 }
 # endif /* 0 < LINK_FOLLOWS_SYMLINKS */
 
+/* On Solaris, link() doesn't follow symlinks by default, but does so as soon
+   as a library or executable takes part in the program that has been compiled
+   with "c99" or "cc -xc99=all" or "cc ... /usr/lib/values-xpg4.o ...".  */
+# if LINK_FOLLOWS_SYMLINKS == -1
+
+/* Reduce the penalty of link_immediate and link_follow by incorporating the
+   knowledge that link()'s behaviour depends on the __xpg4 variable.  */
+extern int __xpg4;
+
+static int
+solaris_optimized_link_immediate (char const *file1, char const *file2)
+{
+  if (__xpg4 == 0)
+    return link (file1, file2);
+  return link_immediate (file1, file2);
+}
+
+static int
+solaris_optimized_link_follow (char const *file1, char const *file2)
+{
+  if (__xpg4 != 0)
+    return link (file1, file2);
+  return link_follow (file1, file2);
+}
+
+#  define link_immediate solaris_optimized_link_immediate
+#  define link_follow solaris_optimized_link_follow
+
+# endif
+
 /* Create a link to FILE1, in the directory open on descriptor FD1, to FILE2,
    in the directory open on descriptor FD2.  If FILE1 is a symlink, FLAG
    controls whether to dereference FILE1 first.  If possible, do it without
--- m4/link-follow.m4.orig      Mon Dec 27 13:56:17 2010
+++ m4/link-follow.m4   Mon Dec 27 13:26:51 2010
@@ -1,4 +1,4 @@
-# serial 15
+# serial 16
 dnl Run a program to determine whether link(2) follows symlinks.
 dnl Set LINK_FOLLOWS_SYMLINKS accordingly.
 
@@ -12,7 +12,8 @@
 dnl linkat(,AT_SYMLINK_FOLLOW) requires a readlink. If it is 1,
 dnl link matches linkat(,AT_SYMLINK_FOLLOW), and there is no way
 dnl to do linkat(,0) on symlinks (on all other file types,
-dnl link() is sufficient).  If it is -1, use a runtime test.
+dnl link() is sufficient).  If it is -1, use a Solaris specific
+dnl runtime test.  If it is -2, use a generic runtime test.
 AC_DEFUN([gl_FUNC_LINK_FOLLOWS_SYMLINK],
 [dnl
   AC_CHECK_FUNCS_ONCE([readlink])
@@ -22,12 +23,27 @@
   dnl linkat variants.  So, we set LINK_FOLLOWS_SYMLINKS to 0.
   gl_link_follows_symlinks=0 # assume GNU behavior
   if test $ac_cv_func_readlink = yes; then
-    AC_CACHE_CHECK([whether link(2) dereferences a symlink],
-                    gl_cv_func_link_follows_symlink,
-    [
-      # Create a regular file.
-      echo > conftest.file
-      AC_RUN_IFELSE([AC_LANG_SOURCE([[
+    dnl Solaris has an __xpg4 variable in libc, and it determines the
+    dnl behaviour of link(): It dereferences a symlink if and only if
+    dnl __xpg4 != 0.
+    AC_CACHE_CHECK([for __xpg4], [gl_cv_have___xpg4],
+      [AC_LINK_IFELSE(
+         [AC_LANG_PROGRAM(
+            [[extern int __xpg4;]],
+            [[return __xpg4;]])],
+         [gl_cv_have___xpg4=yes],
+         [gl_cv_have___xpg4=no])
+      ])
+    if test $gl_cv_have___xpg4 = yes; then
+      gl_link_follows_symlinks=-1
+    else
+      AC_CACHE_CHECK([whether link(2) dereferences a symlink],
+                     [gl_cv_func_link_follows_symlink],
+        [
+         # Create a regular file.
+         echo > conftest.file
+         AC_RUN_IFELSE(
+           [AC_LANG_SOURCE([[
 #       include <sys/types.h>
 #       include <sys/stat.h>
 #       include <unistd.h>
@@ -62,20 +78,22 @@
              the link call followed the symlink.  */
           return SAME_INODE (sb_hard, sb_file) ? 1 : 0;
         }
-      ]])],
-        [gl_cv_func_link_follows_symlink=no], dnl GNU behavior
-        [gl_cv_func_link_follows_symlink=yes], dnl Followed link/compile failed
-        [gl_cv_func_link_follows_symlink=unknown] dnl We're cross compiling.
-      )
-      rm -f conftest.file conftest.sym conftest.hard
-    ])
-    case $gl_cv_func_link_follows_symlink in
-      yes) gl_link_follows_symlinks=1 ;;
-      no) ;; # already defaulted to 0
-      *) gl_link_follows_symlinks=-1 ;;
-    esac
+           ]])],
+           [gl_cv_func_link_follows_symlink=no], dnl GNU behavior
+           [gl_cv_func_link_follows_symlink=yes], dnl Followed link/compile 
failed
+           [gl_cv_func_link_follows_symlink=unknown] dnl We're cross compiling.
+         )
+         rm -f conftest.file conftest.sym conftest.hard
+        ])
+      case $gl_cv_func_link_follows_symlink in
+        yes) gl_link_follows_symlinks=1 ;;
+        no) ;; # already defaulted to 0
+        *) gl_link_follows_symlinks=-2 ;;
+      esac
+    fi
   fi
   AC_DEFINE_UNQUOTED([LINK_FOLLOWS_SYMLINKS], [$gl_link_follows_symlinks],
     [Define to 1 if `link(2)' dereferences symbolic links, 0 if it
-     creates hard links to symlinks, and -1 if unknown.])
+     creates hard links to symlinks, -1 if it depends on the variable __xpg4,
+     and -2 if unknown.])
 ])
--- tests/test-linkat.c.orig    Mon Dec 27 13:56:17 2010
+++ tests/test-linkat.c Mon Dec 27 12:26:20 2010
@@ -53,6 +53,17 @@
   return linkat (dfd1, name1, dfd2, name2, flag);
 }
 
+/* Can we expect that link() and linkat(), when called on a symlink,
+   increment the link count of that symlink?  */
+#if LINK_FOLLOWS_SYMLINKS == 0
+# define EXPECT_LINK_HARDLINKS_SYMLINKS 1
+#elif LINK_FOLLOWS_SYMLINKS == -1
+extern int __xpg4;
+# define EXPECT_LINK_HARDLINKS_SYMLINKS (__xpg4 == 0)
+#else
+# define EXPECT_LINK_HARDLINKS_SYMLINKS 0
+#endif
+
 /* Wrapper to see if two symlinks act the same.  */
 static void
 check_same_link (char const *name1, char const *name2)
@@ -68,7 +79,7 @@
   ASSERT (contents1);
   ASSERT (contents2);
   ASSERT (strcmp (contents1, contents2) == 0);
-  if (!LINK_FOLLOWS_SYMLINKS)
+  if (EXPECT_LINK_HARDLINKS_SYMLINKS)
     ASSERT (SAME_INODE (st1, st2));
   free (contents1);
   free (contents2);



reply via email to

[Prev in Thread] Current Thread [Next in Thread]