/* Create a hard link relative to open directories.
- Copyright (C) 2009 Free Software Foundation, Inc.
+ Copyright (C) 2009-2010 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
int
rpl_linkat (int fd1, char const *file1, int fd2, char const *file2, int flag)
{
- if (!flag)
- return linkat (fd1, file1, fd2, file2, 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)
+ return linkat (fd1, file1, fd2, file2, flag);
+
/* Cache the information on whether the system call really works. */
{
static int have_follow_really; /* 0 = unknown, 1 = yes, -1 = no */