linkat.m4 4.89 KB
Newer Older
1
# serial 9
Eric Blake's avatar
Eric Blake committed
2 3
# See if we need to provide linkat replacement.

4
dnl Copyright (C) 2009-2018 Free Software Foundation, Inc.
Eric Blake's avatar
Eric Blake committed
5 6 7 8 9 10 11 12 13 14 15 16
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
dnl with or without modifications, as long as this notice is preserved.

# Written by Eric Blake.

AC_DEFUN([gl_FUNC_LINKAT],
[
  AC_REQUIRE([gl_FUNC_OPENAT])
  AC_REQUIRE([gl_FUNC_LINK_FOLLOWS_SYMLINK])
  AC_REQUIRE([gl_UNISTD_H_DEFAULTS])
  AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
17
  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
Eric Blake's avatar
Eric Blake committed
18 19 20 21
  AC_CHECK_FUNCS_ONCE([linkat symlink])
  AC_CHECK_HEADERS_ONCE([sys/param.h])
  if test $ac_cv_func_linkat = no; then
    HAVE_LINKAT=0
22
  else
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
    dnl OS X Yosemite has linkat() but it's not sufficient
    dnl to our needs since it doesn't support creating
    dnl hardlinks to symlinks.  Therefore check for that
    dnl capability before considering using the system version.
    AC_CACHE_CHECK([whether linkat() can link symlinks],
      [gl_cv_func_linkat_nofollow],
      [rm -rf conftest.l1 conftest.l2
       ln -s target conftest.l1
       AC_RUN_IFELSE([AC_LANG_PROGRAM(
                        [[#include <fcntl.h>
                          #include <unistd.h>
                        ]],
                        [return linkat (AT_FDCWD, "conftest.l1", AT_FDCWD,
                                            "conftest.l2", 0);
                        ])],
38 39
         [gl_cv_func_linkat_nofollow=yes],
         [gl_cv_func_linkat_nofollow=no],
40
         [case "$host_os" in
41 42
           darwin*) gl_cv_func_linkat_nofollow="guessing no" ;;
           *)       gl_cv_func_linkat_nofollow="guessing yes" ;;
43 44
          esac])

45 46
       rm -rf conftest.l1 conftest.l2])

47 48 49 50 51
    case $gl_cv_func_linkat_nofollow in
      *no) LINKAT_SYMLINK_NOTSUP=1 ;;
      *yes) LINKAT_SYMLINK_NOTSUP=0 ;;
    esac

52 53
    AC_CACHE_CHECK([whether linkat handles trailing slash correctly],
      [gl_cv_func_linkat_slash],
54
      [rm -rf conftest.a conftest.b conftest.c conftest.d conftest.e conftest.s
55 56 57 58 59 60 61
       AC_RUN_IFELSE(
         [AC_LANG_PROGRAM(
            [[#include <unistd.h>
              #include <fcntl.h>
              #include <errno.h>
              #include <stdio.h>
            ]],
62 63
            [[int result;
              int fd;
64 65 66 67 68 69 70 71 72 73 74 75 76
              /* Create a regular file.  */
              fd = open ("conftest.a", O_CREAT | O_EXCL | O_WRONLY, 0600);
              if (fd < 0)
                return 1;
              if (write (fd, "hello", 5) < 5)
                return 2;
              if (close (fd) < 0)
                return 3;
              /* Test whether hard links are supported on the current
                 device.  */
              if (linkat (AT_FDCWD, "conftest.a", AT_FDCWD, "conftest.b",
                          AT_SYMLINK_FOLLOW) < 0)
                return 0;
77
              result = 0;
78 79 80
              /* Test whether a trailing "/" is treated like "/.".  */
              if (linkat (AT_FDCWD, "conftest.a/", AT_FDCWD, "conftest.c",
                          AT_SYMLINK_FOLLOW) == 0)
81
                result |= 4;
82 83
              if (linkat (AT_FDCWD, "conftest.a", AT_FDCWD, "conftest.d/",
                          AT_SYMLINK_FOLLOW) == 0)
84
                result |= 8;
85 86 87 88 89 90 91 92 93 94

              /* On OS X 10.10 a trailing "/" will cause the second path to be
                 dereferenced, and thus will succeed on a dangling symlink.  */
              if (symlink ("conftest.e", "conftest.s") == 0)
                {
                  if (linkat (AT_FDCWD, "conftest.a", AT_FDCWD, "conftest.s/",
                      AT_SYMLINK_FOLLOW) == 0)
                    result |= 16;
                }

95
              return result;
96 97 98
            ]])],
         [gl_cv_func_linkat_slash=yes],
         [gl_cv_func_linkat_slash=no],
99
         [
100
          case "$host_os" in
101 102 103 104 105 106
                             # Guess yes on Linux systems.
            linux-* | linux) gl_cv_func_linkat_slash="guessing yes";;
                             # Guess yes on glibc systems.
            *-gnu* | gnu*)   gl_cv_func_linkat_slash="guessing yes";;
                             # If we don't know, assume the worst.
            *)               gl_cv_func_linkat_slash="guessing no";;
107 108
          esac
         ])
109
       rm -rf conftest.a conftest.b conftest.c conftest.d conftest.e conftest.s])
110 111 112 113
    case "$gl_cv_func_linkat_slash" in
      *yes) gl_linkat_slash_bug=0 ;;
      *)    gl_linkat_slash_bug=1 ;;
    esac
114

115 116 117 118 119 120
    case "$gl_cv_func_linkat_nofollow" in
      *yes) linkat_nofollow=yes ;;
      *) linkat_nofollow=no ;;
    esac

    if test "$linkat_nofollow" != yes \
121
       || test $gl_linkat_slash_bug = 1; then
122
      REPLACE_LINKAT=1
123 124
      AC_DEFINE_UNQUOTED([LINKAT_TRAILING_SLASH_BUG], [$gl_linkat_slash_bug],
        [Define to 1 if linkat fails to recognize a trailing slash.])
125 126
      AC_DEFINE_UNQUOTED([LINKAT_SYMLINK_NOTSUP], [$LINKAT_SYMLINK_NOTSUP],
        [Define to 1 if linkat can create hardlinks to symlinks])
127
    fi
Eric Blake's avatar
Eric Blake committed
128 129
  fi
])