diff options
Diffstat (limited to 'm4/linkat.m4')
-rw-r--r-- | m4/linkat.m4 | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/m4/linkat.m4 b/m4/linkat.m4 new file mode 100644 index 0000000..6cefba4 --- /dev/null +++ b/m4/linkat.m4 @@ -0,0 +1,134 @@ +# serial 17 +# See if we need to provide linkat replacement. + +dnl Copyright (C) 2009-2023 Free Software Foundation, Inc. +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]) + AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles + AC_CHECK_FUNCS_ONCE([symlink]) + gl_CHECK_FUNCS_ANDROID([linkat], [[#include <unistd.h>]]) + if test $ac_cv_func_linkat = no; then + HAVE_LINKAT=0 + case "$gl_cv_onwards_func_linkat" in + future*) REPLACE_LINKAT=1 ;; + esac + else + 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); + ]])], + [gl_cv_func_linkat_nofollow=yes], + [gl_cv_func_linkat_nofollow=no], + [case "$host_os" in + darwin*) gl_cv_func_linkat_nofollow="guessing no" ;; + *) gl_cv_func_linkat_nofollow="guessing yes" ;; + esac]) + + rm -rf conftest.l1 conftest.l2]) + + case $gl_cv_func_linkat_nofollow in + *no) LINKAT_SYMLINK_NOTSUP=1 ;; + *yes) LINKAT_SYMLINK_NOTSUP=0 ;; + esac + + AC_CACHE_CHECK([whether linkat handles trailing slash correctly], + [gl_cv_func_linkat_slash], + [rm -rf conftest.a conftest.b conftest.c conftest.d conftest.e conftest.s + AC_RUN_IFELSE( + [AC_LANG_PROGRAM( + [[#include <unistd.h> + #include <fcntl.h> + #include <errno.h> + #include <stdio.h> + ]GL_MDA_DEFINES], + [[int result; + int fd; + /* 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; + result = 0; + /* Test whether a trailing "/" is treated like "/.". */ + if (linkat (AT_FDCWD, "conftest.a/", AT_FDCWD, "conftest.c", + AT_SYMLINK_FOLLOW) == 0) + result |= 4; + if (linkat (AT_FDCWD, "conftest.a", AT_FDCWD, "conftest.d/", + AT_SYMLINK_FOLLOW) == 0) + result |= 8; + + /* On Mac OS X 10.13 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; + } + + return result; + ]])], + [gl_cv_func_linkat_slash=yes], + [gl_cv_func_linkat_slash=no], + [ + case "$host_os" in + # Guess yes on Linux systems. + linux-* | linux) gl_cv_func_linkat_slash="guessing yes";; + # Guess yes on systems that emulate the Linux system calls. + midipix*) 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, obey --enable-cross-guesses. + *) gl_cv_func_linkat_slash="$gl_cross_guess_normal";; + esac + ]) + rm -rf conftest.a conftest.b conftest.c conftest.d conftest.e conftest.s]) + case "$gl_cv_func_linkat_slash" in + *yes) gl_linkat_slash_bug=0 ;; + *) gl_linkat_slash_bug=1 ;; + esac + + case "$gl_cv_func_linkat_nofollow" in + *yes) linkat_nofollow=yes ;; + *) linkat_nofollow=no ;; + esac + + if test "$linkat_nofollow" != yes \ + || test $gl_linkat_slash_bug = 1; then + REPLACE_LINKAT=1 + AC_DEFINE_UNQUOTED([LINKAT_TRAILING_SLASH_BUG], [$gl_linkat_slash_bug], + [Define to 1 if linkat fails to recognize a trailing slash.]) + AC_DEFINE_UNQUOTED([LINKAT_SYMLINK_NOTSUP], [$LINKAT_SYMLINK_NOTSUP], + [Define to 1 if linkat can create hardlinks to symlinks]) + fi + fi +]) |