Use linkat() if available
authorWayne Davison <wayne@opencoder.net>
Mon, 27 Jul 2020 23:36:55 +0000 (16:36 -0700)
committerWayne Davison <wayne@opencoder.net>
Mon, 27 Jul 2020 23:36:55 +0000 (16:36 -0700)
Some OSes have a more capable linkat() function that can hard-link
syslinks, so use linkat() when it is available.

configure.ac
syscall.c

index 8030eebcae4f5a9faefd59b5595c97aa2e9f1ec9..b271e363874c1c8b01e0a60cc31de02e635e3ee1 100644 (file)
@@ -822,7 +822,7 @@ AC_FUNC_UTIME_NULL
 AC_FUNC_ALLOCA
 AC_CHECK_FUNCS(waitpid wait4 getcwd chown chmod lchmod mknod mkfifo \
     fchmod fstat ftruncate strchr readlink link utime utimes lutimes strftime \
-    chflags getattrlist mktime innetgr \
+    chflags getattrlist mktime innetgr linkat \
     memmove lchown vsnprintf snprintf vasprintf asprintf setsid strpbrk \
     strlcat strlcpy strtol mallinfo getgroups setgroups geteuid getegid \
     setlocale setmode open64 lseek64 mkstemp64 mtrace va_copy __va_copy \
@@ -946,6 +946,11 @@ fi
 
 AC_CACHE_CHECK([whether link() can hard-link symlinks],rsync_cv_can_hardlink_symlink,[
   AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#elif defined HAVE_SYS_FCNTL_H
+# include <sys/fcntl.h>
+#endif
 #if HAVE_UNISTD_H
 # include <unistd.h>
 #endif
@@ -956,7 +961,11 @@ int main(void) {
        unlink(FILENAME);
        if (symlink("conftest.no-such", FILENAME) < 0) abort();
        unlink(FILENAME "2");
+#ifdef HAVE_LINKAT
+       if (linkat(AT_FDCWD, FILENAME, AT_FDCWD, FILENAME "2", 0) < 0) return 1;
+#else
        if (link(FILENAME, FILENAME "2") < 0) return 1;
+#endif
        return 0;
     }]])],[rsync_cv_can_hardlink_symlink=yes],[rsync_cv_can_hardlink_symlink=no],[rsync_cv_can_hardlink_symlink=no])])
 if test $rsync_cv_can_hardlink_symlink = yes; then
index 80cac204bf3095a38de6fff8eea794d36cdef671..b9c3b4efc49763694f49e071e20d9ae69ab884b6 100644 (file)
--- a/syscall.c
+++ b/syscall.c
@@ -129,12 +129,16 @@ ssize_t do_readlink(const char *path, char *buf, size_t bufsiz)
 #endif
 #endif
 
-#ifdef HAVE_LINK
+#if defined HAVE_LINK || defined HAVE_LINKAT
 int do_link(const char *old_path, const char *new_path)
 {
        if (dry_run) return 0;
        RETURN_ERROR_IF_RO_OR_LO;
+#ifdef HAVE_LINKAT
+       return linkat(AT_FDCWD, old_path, AT_FDCWD, new_path, 0);
+#else
        return link(old_path, new_path);
+#endif
 }
 #endif