tar: --dereference consistency

This closes another race condition, that occurs when overwriting a
symlink with a regular file.
* NEWS (--dereference consistency): New section.
* doc/tar.texi (Option Summary): Describe new --deference behavior.
(dereference): Likewise.  Remove discussion that I didn't follow,
even before --dereference was changed.
* src/common.h (deref_stat, set_file_atime): Adjust signatures.
* src/compare.c (diff_file, diff_multivol): Respect open_read_flags
instead of rolling our own flags.  This implements the new behavior
for --dereference.
(diff_file, diff_dumpdir): Likewise, for fstatat_flags.
* src/create.c: Adjust to set_file_atime signature change.
* src/extract.c (mark_after_links, file_newer_p, extract_dir):
Likewise.
* src/incremen.c (try_purge_directory): Likewise.
* src/misc.c (maybe_backup_file): Likewise.
* src/extract.c (file_newer_p): New arg STP.  All callers changed.
(maybe_recoverable): New arg REGULAR.  All callers changed.
Handle the case of overwriting a symlink with a regular file,
when --overwrite is specified but --dereference is not.
(open_output_file): Add O_CLOEXEC, O_NOCTTY, O_NONBLOCK for
consistency with file creation.  Add O_NOFOLLOW if
overwriting_old_files && ! dereference_option.
* src/incremen.c (update_parent_directory): Use fstat, not fstatat;
there's less to go wrong.
* src/misc.c (deref_stat): Remove DEREF arg.  All callers changed.
Instead, use fstatat_flags.
(set_file_atime): Remove ATFLAG arg.  All callers changed.
Instead, use fstatat_flags.
* src/names.c, src/update.c: Adjust to deref_stat signature change.
* src/tar.c (get_date_or_file): Use stat, not deref_stat, as this
is not a file to be archived.
* tests/Makefile.am (TESTSUITE_AT): Add extrac13.at.
* tests/extrac13.at: New file.
* tests/testsuite.at: Include it.
This commit is contained in:
Paul Eggert
2010-09-23 19:41:47 -07:00
parent efe26f98ec
commit 14efeb9f95
14 changed files with 195 additions and 122 deletions
+5 -19
View File
@@ -151,7 +151,7 @@ read_and_process (struct tar_stat_info *st, int (*processor) (size_t, char *))
static int
get_stat_data (char const *file_name, struct stat *stat_data)
{
int status = deref_stat (dereference_option, file_name, stat_data);
int status = deref_stat (file_name, stat_data);
if (status != 0)
{
@@ -217,14 +217,7 @@ diff_file (void)
}
else
{
int atime_flag =
(atime_preserve_option == system_atime_preserve
? O_NOATIME
: 0);
diff_handle = openat (chdir_fd, file_name,
(O_RDONLY | O_BINARY | O_CLOEXEC | O_NOCTTY
| O_NONBLOCK | atime_flag));
diff_handle = openat (chdir_fd, file_name, open_read_flags);
if (diff_handle < 0)
{
@@ -244,8 +237,7 @@ diff_file (void)
if (atime_preserve_option == replace_atime_preserve)
{
struct timespec atime = get_stat_atime (&stat_data);
if (set_file_atime (diff_handle, chdir_fd, file_name,
atime, 0)
if (set_file_atime (diff_handle, chdir_fd, file_name, atime)
!= 0)
utime_error (file_name);
}
@@ -372,7 +364,7 @@ diff_dumpdir (void)
dev_t dev = 0;
struct stat stat_data;
if (deref_stat (true, current_stat_info.file_name, &stat_data))
if (deref_stat (current_stat_info.file_name, &stat_data) != 0)
{
if (errno == ENOENT)
stat_warn (current_stat_info.file_name);
@@ -399,10 +391,6 @@ diff_multivol (void)
struct stat stat_data;
int fd, status;
off_t offset;
int atime_flag =
(atime_preserve_option == system_atime_preserve
? O_NOATIME
: 0);
if (current_stat_info.had_trailing_slash)
{
@@ -429,9 +417,7 @@ diff_multivol (void)
}
fd = openat (chdir_fd, current_stat_info.file_name,
(O_RDONLY | O_BINARY | O_CLOEXEC | O_NOCTTY | O_NONBLOCK
| atime_flag));
fd = openat (chdir_fd, current_stat_info.file_name, open_read_flags);
if (fd < 0)
{