Fix savannah bug #63123
The bug was introduced by commit79d1ac38c1, which didn't take into account all the consequences of returning RECOVER_OK on EEXIST, in particular interactions with the delayed_set_stat logic. The commit79d1ac38c1is reverted (the bug it was intended to fix was actually fixed by79a442d7b0). Instead: * src/extract.c (maybe_recoverable): Don't call maybe_recoverable if EEXIST is reported when UNLINK_FIRST_OLD_FILES option is set.
This commit is contained in:
110
src/extract.c
110
src/extract.c
@@ -679,9 +679,10 @@ fixup_delayed_set_stat (char const *src, char const *dst)
|
||||
|
||||
/* After a file/link/directory creation has failed due to ENOENT,
|
||||
create all required directories. Return zero if all the required
|
||||
directories were created, nonzero (issuing a diagnostic) otherwise. */
|
||||
directories were created, nonzero (issuing a diagnostic) otherwise.
|
||||
Set *INTERDIR_MADE if at least one directory was created. */
|
||||
static int
|
||||
make_directories (char *file_name)
|
||||
make_directories (char *file_name, bool *interdir_made)
|
||||
{
|
||||
char *cursor0 = file_name + FILE_SYSTEM_PREFIX_LEN (file_name);
|
||||
char *cursor; /* points into the file name */
|
||||
@@ -725,6 +726,7 @@ make_directories (char *file_name)
|
||||
desired_mode, AT_SYMLINK_NOFOLLOW);
|
||||
|
||||
print_for_mkdir (file_name, cursor - file_name, desired_mode);
|
||||
*interdir_made = true;
|
||||
parent_end = NULL;
|
||||
}
|
||||
else
|
||||
@@ -879,12 +881,9 @@ maybe_recoverable (char *file_name, bool regular, bool *interdir_made)
|
||||
FALLTHROUGH;
|
||||
|
||||
case ENOENT:
|
||||
/* Attempt creating missing intermediate directories. */
|
||||
if (make_directories (file_name) == 0)
|
||||
{
|
||||
*interdir_made = true;
|
||||
return RECOVER_OK;
|
||||
}
|
||||
/* Attempt creating missing intermediate directories. */
|
||||
if (make_directories (file_name, interdir_made) == 0)
|
||||
return RECOVER_OK;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1072,61 +1071,69 @@ extract_dir (char *file_name, int typeflag)
|
||||
break;
|
||||
}
|
||||
|
||||
if (errno == EEXIST
|
||||
&& (interdir_made
|
||||
if (errno == EEXIST)
|
||||
{
|
||||
if (interdir_made
|
||||
|| keep_directory_symlink_option
|
||||
|| old_files_option == NO_OVERWRITE_DIR_OLD_FILES
|
||||
|| old_files_option == DEFAULT_OLD_FILES
|
||||
|| old_files_option == OVERWRITE_OLD_FILES))
|
||||
{
|
||||
struct stat st;
|
||||
st.st_mode = 0;
|
||||
|
||||
if (keep_directory_symlink_option
|
||||
&& is_directory_link (file_name, &st))
|
||||
return 0;
|
||||
|
||||
if ((st.st_mode != 0 && fstatat_flags == 0)
|
||||
|| deref_stat (file_name, &st) == 0)
|
||||
|| old_files_option == OVERWRITE_OLD_FILES)
|
||||
{
|
||||
current_mode = st.st_mode;
|
||||
current_mode_mask = ALL_MODE_BITS;
|
||||
struct stat st;
|
||||
st.st_mode = 0;
|
||||
|
||||
if (S_ISDIR (current_mode))
|
||||
if (keep_directory_symlink_option
|
||||
&& is_directory_link (file_name, &st))
|
||||
return 0;
|
||||
|
||||
if ((st.st_mode != 0 && fstatat_flags == 0)
|
||||
|| deref_stat (file_name, &st) == 0)
|
||||
{
|
||||
if (interdir_made)
|
||||
current_mode = st.st_mode;
|
||||
current_mode_mask = ALL_MODE_BITS;
|
||||
|
||||
if (S_ISDIR (current_mode))
|
||||
{
|
||||
repair_delayed_set_stat (file_name, &st);
|
||||
return 0;
|
||||
}
|
||||
else if (old_files_option == NO_OVERWRITE_DIR_OLD_FILES)
|
||||
{
|
||||
/* Temporarily change the directory mode to a safe
|
||||
value, to be able to create files in it, should
|
||||
the need be.
|
||||
*/
|
||||
mode = safe_dir_mode (&st);
|
||||
status = fd_chmod(-1, file_name, mode,
|
||||
AT_SYMLINK_NOFOLLOW, DIRTYPE);
|
||||
if (status == 0)
|
||||
if (interdir_made)
|
||||
{
|
||||
/* Store the actual directory mode, to be restored
|
||||
later.
|
||||
repair_delayed_set_stat (file_name, &st);
|
||||
return 0;
|
||||
}
|
||||
else if (old_files_option == NO_OVERWRITE_DIR_OLD_FILES)
|
||||
{
|
||||
/* Temporarily change the directory mode to a safe
|
||||
value, to be able to create files in it, should
|
||||
the need be.
|
||||
*/
|
||||
current_stat_info.stat = st;
|
||||
current_mode = mode & ~ current_umask;
|
||||
current_mode_mask = MODE_RWX;
|
||||
atflag = AT_SYMLINK_NOFOLLOW;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
chmod_error_details (file_name, mode);
|
||||
mode = safe_dir_mode (&st);
|
||||
status = fd_chmod (-1, file_name, mode,
|
||||
AT_SYMLINK_NOFOLLOW, DIRTYPE);
|
||||
if (status == 0)
|
||||
{
|
||||
/* Store the actual directory mode, to be restored
|
||||
later.
|
||||
*/
|
||||
current_stat_info.stat = st;
|
||||
current_mode = mode & ~ current_umask;
|
||||
current_mode_mask = MODE_RWX;
|
||||
atflag = AT_SYMLINK_NOFOLLOW;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
chmod_error_details (file_name, mode);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (old_files_option == UNLINK_FIRST_OLD_FILES)
|
||||
{
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
errno = EEXIST;
|
||||
}
|
||||
|
||||
@@ -1978,11 +1985,12 @@ rename_directory (char *src, char *dst)
|
||||
else
|
||||
{
|
||||
int e = errno;
|
||||
bool interdir_made;
|
||||
|
||||
switch (e)
|
||||
{
|
||||
case ENOENT:
|
||||
if (make_directories (dst) == 0)
|
||||
if (make_directories (dst, &interdir_made) == 0)
|
||||
{
|
||||
if (renameat (chdir_fd, src, chdir_fd, dst) == 0)
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user