|
@@ -982,18 +982,12 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_links)
|
|
|
|
|
|
|
|
|
static bool
|
|
|
-is_directory_link (const char *file_name)
|
|
|
+is_directory_link (char const *file_name, struct stat *st)
|
|
|
{
|
|
|
- struct stat st;
|
|
|
- int e = errno;
|
|
|
- int res;
|
|
|
-
|
|
|
- res = (fstatat (chdir_fd, file_name, &st, AT_SYMLINK_NOFOLLOW) == 0 &&
|
|
|
- S_ISLNK (st.st_mode) &&
|
|
|
- fstatat (chdir_fd, file_name, &st, 0) == 0 &&
|
|
|
- S_ISDIR (st.st_mode));
|
|
|
- errno = e;
|
|
|
- return res;
|
|
|
+ char buf[1];
|
|
|
+ return (0 <= readlinkat (chdir_fd, file_name, buf, sizeof buf)
|
|
|
+ && fstatat (chdir_fd, file_name, st, 0) == 0
|
|
|
+ && S_ISDIR (st->st_mode));
|
|
|
}
|
|
|
|
|
|
/* Given struct stat of a directory (or directory member) whose ownership
|
|
@@ -1066,11 +1060,14 @@ extract_dir (char *file_name, int typeflag)
|
|
|
|| old_files_option == OVERWRITE_OLD_FILES))
|
|
|
{
|
|
|
struct stat st;
|
|
|
+ st.st_mode = 0;
|
|
|
|
|
|
- if (keep_directory_symlink_option && is_directory_link (file_name))
|
|
|
+ if (keep_directory_symlink_option
|
|
|
+ && is_directory_link (file_name, &st))
|
|
|
return 0;
|
|
|
|
|
|
- if (deref_stat (file_name, &st) == 0)
|
|
|
+ if ((st.st_mode != 0 && fstatat_flags == 0)
|
|
|
+ || deref_stat (file_name, &st) == 0)
|
|
|
{
|
|
|
current_mode = st.st_mode;
|
|
|
current_mode_mask = ALL_MODE_BITS;
|
|
@@ -1178,9 +1175,8 @@ open_output_file (char const *file_name, int typeflag, mode_t mode,
|
|
|
if (! HAVE_WORKING_O_NOFOLLOW
|
|
|
&& overwriting_old_files && ! dereference_option)
|
|
|
{
|
|
|
- struct stat st;
|
|
|
- if (fstatat (chdir_fd, file_name, &st, AT_SYMLINK_NOFOLLOW) == 0
|
|
|
- && S_ISLNK (st.st_mode))
|
|
|
+ char buf[1];
|
|
|
+ if (0 <= readlinkat (chdir_fd, file_name, buf, sizeof buf))
|
|
|
{
|
|
|
errno = ELOOP;
|
|
|
return -1;
|