+2010-12-28 Bruno Haible <bruno@clisp.org>
+ Paul Eggert <eggert@cs.ucla.edu>
+
+ 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.
+
2010-12-26 Ben Pfaff <blp@cs.stanford.edu>
New module 'unigbrk/base'.
}
# 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
-# serial 15
+# serial 16
dnl Run a program to determine whether link(2) follows symlinks.
dnl Set LINK_FOLLOWS_SYMLINKS accordingly.
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])
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>
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.])
])
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)
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);