Avoid EOVERFLOW problems in some symlink tests

* src/extract.c (is_directory_link): New arg ST.  Caller changed.
(is_directory_link, open_output_file):
Use readlinkat, not fstatat, to determine whether a string
names a symlink.  This avoids EOVERFLOW issues.
(extract_dir): Avoid duplicate calls to fstatat when
keep_directory_symlink_option && fstatat_flags == 0
and the file is a symlink to an existing file.
This commit is contained in:
Paul Eggert
2022-06-13 17:02:54 -07:00
parent 9f0e54ab2f
commit d935dc7d1c

View File

@@ -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;