int linkat (int fd1, char const *file1, int fd2, char const *file2, int flag) { if (flag & ~AT_SYMLINK_FOLLOW) { errno = EINVAL; return -1; } return at_func2 (fd1, file1, fd2, file2, flag ? link_follow : link_immediate); }
int rpl_linkat (int fd1, char const *file1, int fd2, char const *file2, int flag) { if (flag & ~AT_SYMLINK_FOLLOW) { errno = EINVAL; return -1; } # if LINKAT_TRAILING_SLASH_BUG /* Reject trailing slashes on non-directories. */ { size_t len1 = strlen (file1); size_t len2 = strlen (file2); if ((len1 && file1[len1 - 1] == '/') || (len2 && file2[len2 - 1] == '/')) { /* Let linkat() decide whether hard-linking directories is legal. If fstatat() fails, then linkat() should fail for the same reason; if fstatat() succeeds, require a directory. */ struct stat st; if (fstatat (fd1, file1, &st, flag ? 0 : AT_SYMLINK_NOFOLLOW)) return -1; if (!S_ISDIR (st.st_mode)) { errno = ENOTDIR; return -1; } } } # endif if (!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. */ { static int have_follow_really; /* 0 = unknown, 1 = yes, -1 = no */ if (0 <= have_follow_really) { int result = linkat (fd1, file1, fd2, file2, flag); if (!(result == -1 && errno == EINVAL)) { have_follow_really = 1; return result; } have_follow_really = -1; } } return linkat_follow (fd1, file1, fd2, file2); }