diff --git a/src/extract.c b/src/extract.c index fda4617d..6d2543f0 100644 --- a/src/extract.c +++ b/src/extract.c @@ -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;