Import upstream version 1.29
[debian/tar] / gnu / linkat.c
index 1f855cb06bc83b01b0cc2b40a533b2dd4f960b1d..4bdbae677a6ef8703c7930d66e20b3657c9df354 100644 (file)
@@ -1,7 +1,5 @@
-/* -*- buffer-read-only: t -*- vi: set ro: */
-/* DO NOT EDIT! GENERATED AUTOMATICALLY! */
 /* Create a hard link relative to open directories.
-   Copyright (C) 2009-2010 Free Software Foundation, Inc.
+   Copyright (C) 2009-2015 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -25,7 +23,6 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <limits.h>
-#include <stdint.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
@@ -46,7 +43,7 @@
 # endif
 #endif
 
-#if !HAVE_LINKAT
+#if !HAVE_LINKAT || LINKAT_SYMLINK_NOTSUP
 
 /* Create a link.  If FILE1 is a symlink, either create a hardlink to
    that symlink, or fake it by creating an identical symlink.  */
@@ -168,6 +165,40 @@ link_follow (char const *file1, char const *file2)
 }
 # 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
+
+#endif /* !HAVE_LINKAT || LINKAT_SYMLINK_NOTSUP  */
+
+#if !HAVE_LINKAT
+
 /* 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
@@ -270,7 +301,7 @@ rpl_linkat (int fd1, char const *file1, int fd2, char const *file2, int flag)
       return -1;
     }
 
-#if LINKAT_TRAILING_SLASH_BUG
+# if LINKAT_TRAILING_SLASH_BUG
   /* Reject trailing slashes on non-directories.  */
   {
     size_t len1 = strlen (file1);
@@ -291,10 +322,20 @@ rpl_linkat (int fd1, char const *file1, int fd2, char const *file2, int flag)
           }
       }
   }
-#endif
+# endif
 
   if (!flag)
-    return linkat (fd1, file1, fd2, file2, flag);
+    {
+      int result = linkat (fd1, file1, fd2, file2, flag);
+# if LINKAT_SYMLINK_NOTSUP
+      /* OS X 10.10 has linkat() but it doesn't support
+         hardlinks to symlinks.  Fallback to our emulation
+         in that case.  */
+      if (result == -1 && (errno == ENOTSUP || errno == EOPNOTSUPP))
+        return at_func2 (fd1, file1, fd2, file2, link_immediate);
+# endif
+      return result;
+    }
 
   /* Cache the information on whether the system call really works.  */
   {