[Top][All Lists]
[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);
- linkat, LINK_FOLLOWS_SYMLINKS, and Solaris, Bruno Haible, 2010/12/26
- Re: linkat, LINK_FOLLOWS_SYMLINKS, and Solaris, Paul Eggert, 2010/12/26
- Re: linkat, LINK_FOLLOWS_SYMLINKS, and Solaris, Bruno Haible, 2010/12/27
- Re: linkat, LINK_FOLLOWS_SYMLINKS, and Solaris, Bob Friesenhahn, 2010/12/27
- Re: linkat, LINK_FOLLOWS_SYMLINKS, and Solaris, Paul Eggert, 2010/12/27
- Re: linkat, LINK_FOLLOWS_SYMLINKS, and Solaris, Paul Eggert, 2010/12/28
- Re: linkat, LINK_FOLLOWS_SYMLINKS, and Solaris,
Bruno Haible <=