diff -urpN tar-1.20.orig/src/create.c tar-1.20/src/create.c --- tar-1.20.orig/src/create.c 2008-04-14 12:03:12 +0000 +++ tar-1.20/src/create.c 2008-12-23 12:18:20 +0000 @@ -1078,7 +1078,7 @@ dump_regular_file (int fd, struct tar_st size_left), quotearg_colon (st->orig_file_name), STRINGIFY_BIGINT (size_left, buf))); - if (! ignore_failed_read_option) + if (! ignore_failed_read_option && exit_status == TAREXIT_SUCCESS) exit_status = TAREXIT_DIFFERS; pad_archive (size_left - (bufsize - count)); return dump_status_short; @@ -1283,9 +1283,19 @@ create_archive (void) collect_and_sort_names (); + /* We assume that the collect_and_sort_names() call above has validated + all filenames passed as input to tar. In the calls to dump_file(), + we don't know where each filename came from. We choose to pass 0 for + top_level such that tar does not unnecessarily exit with + TAREXIT_FAILURE when a file in some deep directory disappears from + under us. Unfortunately, this also means that tar won't set this exit + code for files that were actually at "top level", and were accessible + when collect_and_sort_names() ran, but disappeared or turned out to be + otherwise inaccessible for dump_file(). */ + while ((p = name_from_list ()) != NULL) if (!excluded_name (p)) - dump_file (p, -1, (dev_t) 0); + dump_file (p, 0, (dev_t) 0); blank_name_list (); while ((p = name_from_list ()) != NULL) @@ -1315,7 +1325,7 @@ create_archive (void) buffer = xrealloc (buffer, buffer_size); } strcpy (buffer + plen, q + 1); - dump_file (buffer, -1, (dev_t) 0); + dump_file (buffer, 0, (dev_t) 0); } q += qlen + 1; } @@ -1499,7 +1509,11 @@ dump_file0 (struct tar_stat_info *st, co if (deref_stat (dereference_option, p, &st->stat) != 0) { - stat_diag (p); + if (!top_level && errno == ENOENT) + WARN ((0, 0, _("%s: File removed before we read it"), + quotearg_colon (p))); + else + stat_diag (p); return; } st->archive_file_size = original_size = st->stat.st_size; @@ -1643,7 +1657,8 @@ dump_file0 (struct tar_stat_info *st, co : fstat (fd, &final_stat)) != 0) { - stat_diag (p); + if (errno != ENOENT) + stat_diag (p); ok = false; } } @@ -1700,7 +1715,11 @@ dump_file0 (struct tar_stat_info *st, co size = readlink (p, buffer, linklen + 1); if (size < 0) { - readlink_diag (p); + if (!top_level && errno == ENOENT) + WARN ((0, 0, _("%s: File removed before we read it"), + quotearg_colon (p))); + else + readlink_diag (p); return; } buffer[size] = '\0'; diff -urpN tar-1.20.orig/src/incremen.c tar-1.20/src/incremen.c --- tar-1.20.orig/src/incremen.c 2008-04-14 12:03:13 +0000 +++ tar-1.20/src/incremen.c 2008-12-23 12:10:22 +0000 @@ -347,7 +347,10 @@ update_parent_directory (const char *nam { struct stat st; if (deref_stat (dereference_option, p, &st) != 0) - stat_diag (name); + { + if (errno != ENOENT) + stat_diag (name); + } else directory->mtime = get_stat_mtime (&st); } @@ -597,7 +600,8 @@ scan_directory (char *dir, dev_t device) if (deref_stat (dereference_option, name_buffer, &stat_data)) { - stat_diag (name_buffer); + if (errno != ENOENT) + stat_diag (name_buffer); /* FIXME: used to be children = CHANGED_CHILDREN; but changed to: */ @@ -639,7 +643,8 @@ scan_directory (char *dir, dev_t device) { if (deref_stat (dereference_option, name_buffer, &stat_data)) { - stat_diag (name_buffer); + if (errno != ENOENT) + stat_diag (name_buffer); *entry = 'N'; continue; }