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:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user