X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fcreate.c;h=fbd7165aceee32e79a193e123148cfddca77dc45;hb=34795cedb7db68babf7eae672ba47fd486555be8;hp=de81639e2244f7c89afd0d6e597f77c4624adcc2;hpb=eaaadcfd366e8620385944a251da932cf9c843bc;p=chaz%2Ftar diff --git a/src/create.c b/src/create.c index de81639..fbd7165 100644 --- a/src/create.c +++ b/src/create.c @@ -1,7 +1,7 @@ /* Create a tar archive. Copyright (C) 1985, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001, - 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. + 2003, 2004, 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc. Written by John Gilmore, on 1985-08-25. @@ -63,23 +63,24 @@ exclusion_tag_warning (const char *dirname, const char *tagname, const char *message) { if (verbose_option) - WARN ((0, 0, - _("%s: contains a cache directory tag %s; %s"), - quotearg_colon (dirname), - quotearg_n (1, tagname), - message)); + WARNOPT (WARN_CACHEDIR, + (0, 0, + _("%s: contains a cache directory tag %s; %s"), + quotearg_colon (dirname), + quotearg_n (1, tagname), + message)); } -enum exclusion_tag_type -check_exclusion_tags (char *dirname, const char **tag_file_name) +enum exclusion_tag_type +check_exclusion_tags (const char *dirname, const char **tag_file_name) { static char *tagname; static size_t tagsize; struct exclusion_tag *tag; size_t dlen = strlen (dirname); - int addslash = dirname[dlen-1] != '/'; - char *nptr = NULL; - + int addslash = !ISSLASH (dirname[dlen-1]); + size_t noff = 0; + for (tag = exclusion_tags; tag; tag = tag->next) { size_t size = dlen + addslash + tag->length + 1; @@ -89,14 +90,14 @@ check_exclusion_tags (char *dirname, const char **tag_file_name) tagname = xrealloc (tagname, tagsize); } - if (!nptr) + if (noff == 0) { strcpy (tagname, dirname); - nptr = tagname + dlen; + noff = dlen; if (addslash) - *nptr++ = '/'; + tagname[noff++] = '/'; } - strcpy (nptr, tag->name); + strcpy (tagname + noff, tag->name); if (access (tagname, F_OK) == 0 && (!tag->predicate || tag->predicate (tagname))) { @@ -213,6 +214,14 @@ to_base256 (int negative, uintmax_t value, char *where, size_t size) while (i); } +#define GID_TO_CHARS(val, where) gid_to_chars (val, where, sizeof (where)) +#define MAJOR_TO_CHARS(val, where) major_to_chars (val, where, sizeof (where)) +#define MINOR_TO_CHARS(val, where) minor_to_chars (val, where, sizeof (where)) +#define MODE_TO_CHARS(val, where) mode_to_chars (val, where, sizeof (where)) +#define UID_TO_CHARS(val, where) uid_to_chars (val, where, sizeof (where)) +#define UINTMAX_TO_CHARS(val, where) uintmax_to_chars (val, where, sizeof (where)) +#define UNAME_TO_CHARS(name,buf) string_to_chars (name, buf, sizeof(buf)) +#define GNAME_TO_CHARS(name,buf) string_to_chars (name, buf, sizeof(buf)) static bool to_chars (int negative, uintmax_t value, size_t valsize, @@ -262,7 +271,7 @@ to_chars_subst (int negative, int gnu_format, uintmax_t value, size_t valsize, 1. In OLDGNU_FORMAT all strings in a tar header end in \0 2. Incremental archives use oldgnu_header. - + Apart from this they are completely identical. */ uintmax_t s = (negsub &= archive_format == GNU_FORMAT) ? - sub : sub; char subbuf[UINTMAX_STRSIZE_BOUND + 1]; @@ -367,25 +376,25 @@ gid_substitute (int *negative) return r; } -bool +static bool gid_to_chars (gid_t v, char *p, size_t s) { return to_chars (v < 0, (uintmax_t) v, sizeof v, gid_substitute, p, s, "gid_t"); } -bool +static bool major_to_chars (major_t v, char *p, size_t s) { return to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "major_t"); } -bool +static bool minor_to_chars (minor_t v, char *p, size_t s) { return to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "minor_t"); } -bool +static bool mode_to_chars (mode_t v, char *p, size_t s) { /* In the common case where the internal and external mode bits are the same, @@ -401,8 +410,7 @@ mode_to_chars (mode_t v, char *p, size_t s) && S_IROTH == TOREAD && S_IWOTH == TOWRITE && S_IXOTH == TOEXEC && archive_format != POSIX_FORMAT && archive_format != USTAR_FORMAT - && archive_format != GNU_FORMAT - && archive_format != OLDGNU_FORMAT) + && archive_format != GNU_FORMAT) { negative = v < 0; u = v; @@ -460,19 +468,19 @@ uid_substitute (int *negative) return r; } -bool +static bool uid_to_chars (uid_t v, char *p, size_t s) { return to_chars (v < 0, (uintmax_t) v, sizeof v, uid_substitute, p, s, "uid_t"); } -bool +static bool uintmax_to_chars (uintmax_t v, char *p, size_t s) { return to_chars (0, v, sizeof v, 0, p, s, "uintmax_t"); } -void +static void string_to_chars (char const *str, char *p, size_t s) { tar_copy_str (p, str, s); @@ -487,7 +495,7 @@ string_to_chars (char const *str, char *p, size_t s) a) it is empty *and* world-readable, or b) current archive is /dev/null */ -bool +static bool file_dumpable_p (struct tar_stat_info *st) { if (dev_null_output) @@ -515,9 +523,8 @@ write_eot (void) /* Write a "private" header */ union block * -start_private_header (const char *name, size_t size) +start_private_header (const char *name, size_t size, time_t t) { - time_t t; union block *header = find_next_block (); memset (header->buffer, 0, sizeof (union block)); @@ -525,7 +532,6 @@ start_private_header (const char *name, size_t size) tar_name_copy_str (header->header.name, name, NAME_FIELD_SIZE); OFF_TO_CHARS (size, header->header.size); - time (&t); TIME_TO_CHARS (t, header->header.mtime); MODE_TO_CHARS (S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, header->header.mode); UID_TO_CHARS (getuid (), header->header.uid); @@ -563,13 +569,13 @@ write_gnu_long_link (struct tar_stat_info *st, const char *p, char type) union block *header; char *tmpname; - header = start_private_header ("././@LongLink", size); - FILL(header->header.mtime, '0'); - FILL(header->header.mode, '0'); - FILL(header->header.uid, '0'); - FILL(header->header.gid, '0'); - FILL(header->header.devmajor, 0); - FILL(header->header.devminor, 0); + header = start_private_header ("././@LongLink", size, time (NULL)); + FILL (header->header.mtime, '0'); + FILL (header->header.mode, '0'); + FILL (header->header.uid, '0'); + FILL (header->header.gid, '0'); + FILL (header->header.devmajor, 0); + FILL (header->header.devminor, 0); uid_to_uname (0, &tmpname); UNAME_TO_CHARS (tmpname, header->header.uname); free (tmpname); @@ -604,8 +610,10 @@ split_long_name (const char *name, size_t length) { size_t i; - if (length > PREFIX_FIELD_SIZE) + if (length > PREFIX_FIELD_SIZE + 1) length = PREFIX_FIELD_SIZE + 1; + else if (ISSLASH (name[length - 1])) + length--; for (i = length - 1; i > 0; i--) if (ISSLASH (name[i])) break; @@ -616,7 +624,7 @@ static union block * write_ustar_long_name (const char *name) { size_t length = strlen (name); - size_t i; + size_t i, nlen; union block *header; if (length > PREFIX_FIELD_SIZE + NAME_FIELD_SIZE + 1) @@ -628,7 +636,7 @@ write_ustar_long_name (const char *name) } i = split_long_name (name, length); - if (i == 0 || length - i - 1 > NAME_FIELD_SIZE) + if (i == 0 || (nlen = length - i - 1) > NAME_FIELD_SIZE || nlen == 0) { ERROR ((0, 0, _("%s: file name is too long (cannot be split); not dumped"), @@ -712,6 +720,7 @@ write_extended (bool global, struct tar_stat_info *st, union block *old_header) union block *header, hp; char *p; int type; + time_t t; if (st->xhdr.buffer || st->xhdr.stk == NULL) return old_header; @@ -722,13 +731,15 @@ write_extended (bool global, struct tar_stat_info *st, union block *old_header) { type = XGLTYPE; p = xheader_ghdr_name (); + time (&t); } else { type = XHDTYPE; p = xheader_xhdr_name (st); + t = st->stat.st_mtime; } - xheader_write (type, p, &st->xhdr); + xheader_write (type, p, t, &st->xhdr); free (p); header = find_next_block (); memcpy (header, &hp.buffer, sizeof (hp.buffer)); @@ -993,11 +1004,9 @@ finish_header (struct tar_stat_info *st, && header->header.typeflag != XHDTYPE && header->header.typeflag != XGLTYPE) { - /* These globals are parameters to print_header, sigh. */ - - current_header = header; + /* FIXME: This global is used in print_header, sigh. */ current_format = archive_format; - print_header (st, block_ordinal); + print_header (st, header, block_ordinal); } header = write_extended (false, st, header); @@ -1011,7 +1020,6 @@ pad_archive (off_t size_left) union block *blk; while (size_left > 0) { - mv_size_left (size_left); blk = find_next_block (); memset (blk->buffer, 0, BLOCKSIZE); set_next_block_after (blk); @@ -1037,13 +1045,11 @@ dump_regular_file (int fd, struct tar_stat_info *st) finish_header (st, blk, block_ordinal); - mv_begin (st); + mv_begin_write (st->file_name, st->stat.st_size, st->stat.st_size); while (size_left > 0) { size_t bufsize, count; - mv_size_left (size_left); - blk = find_next_block (); bufsize = available_space_after (blk); @@ -1072,14 +1078,15 @@ dump_regular_file (int fd, struct tar_stat_info *st) { char buf[UINTMAX_STRSIZE_BOUND]; memset (blk->buffer + count, 0, bufsize - count); - WARN ((0, 0, - ngettext ("%s: File shrank by %s byte; padding with zeros", - "%s: File shrank by %s bytes; padding with zeros", - size_left), - quotearg_colon (st->orig_file_name), - STRINGIFY_BIGINT (size_left, buf))); - if (! ignore_failed_read_option) - exit_status = TAREXIT_DIFFERS; + WARNOPT (WARN_FILE_SHRANK, + (0, 0, + ngettext ("%s: File shrank by %s byte; padding with zeros", + "%s: File shrank by %s bytes; padding with zeros", + size_left), + quotearg_colon (st->orig_file_name), + STRINGIFY_BIGINT (size_left, buf))); + if (! ignore_failed_read_option) + set_exit_status (TAREXIT_DIFFERS); pad_archive (size_left - (bufsize - count)); return dump_status_short; } @@ -1090,79 +1097,71 @@ dump_regular_file (int fd, struct tar_stat_info *st) static void dump_dir0 (char *directory, - struct tar_stat_info *st, int top_level, dev_t parent_device) + struct tar_stat_info *st, bool top_level, dev_t parent_device) { dev_t our_device = st->stat.st_dev; const char *tag_file_name; - - if (!is_avoided_name (st->orig_file_name)) - { - union block *blk = NULL; - off_t block_ordinal = current_block_ordinal (); - st->stat.st_size = 0; /* force 0 size on dir */ + union block *blk = NULL; + off_t block_ordinal = current_block_ordinal (); - blk = start_header (st); - if (!blk) - return; + st->stat.st_size = 0; /* force 0 size on dir */ - if (incremental_option && archive_format != POSIX_FORMAT) - blk->header.typeflag = GNUTYPE_DUMPDIR; - else /* if (standard_option) */ - blk->header.typeflag = DIRTYPE; + blk = start_header (st); + if (!blk) + return; + + if (incremental_option && archive_format != POSIX_FORMAT) + blk->header.typeflag = GNUTYPE_DUMPDIR; + else /* if (standard_option) */ + blk->header.typeflag = DIRTYPE; - /* If we're gnudumping, we aren't done yet so don't close it. */ + /* If we're gnudumping, we aren't done yet so don't close it. */ - if (!incremental_option) - finish_header (st, blk, block_ordinal); - else if (gnu_list_name->dir_contents) + if (!incremental_option) + finish_header (st, blk, block_ordinal); + else if (gnu_list_name->directory) + { + if (archive_format == POSIX_FORMAT) { - if (archive_format == POSIX_FORMAT) - { - xheader_store ("GNU.dumpdir", st, gnu_list_name->dir_contents); - finish_header (st, blk, block_ordinal); - } - else + xheader_store ("GNU.dumpdir", st, + safe_directory_contents (gnu_list_name->directory)); + finish_header (st, blk, block_ordinal); + } + else + { + off_t size_left; + off_t totsize; + size_t bufsize; + ssize_t count; + const char *buffer, *p_buffer; + + block_ordinal = current_block_ordinal (); + buffer = safe_directory_contents (gnu_list_name->directory); + totsize = dumpdir_size (buffer); + OFF_TO_CHARS (totsize, blk->header.size); + finish_header (st, blk, block_ordinal); + p_buffer = buffer; + size_left = totsize; + + mv_begin_write (st->file_name, totsize, totsize); + while (size_left > 0) { - off_t size_left; - off_t totsize; - size_t bufsize; - ssize_t count; - const char *buffer, *p_buffer; - - block_ordinal = current_block_ordinal (); - buffer = gnu_list_name->dir_contents; - if (buffer) - totsize = dumpdir_size (buffer); - else - totsize = 0; - OFF_TO_CHARS (totsize, blk->header.size); - finish_header (st, blk, block_ordinal); - p_buffer = buffer; - size_left = totsize; - - mv_begin (st); - mv_total_size (totsize); - while (size_left > 0) + blk = find_next_block (); + bufsize = available_space_after (blk); + if (size_left < bufsize) { - mv_size_left (size_left); - blk = find_next_block (); - bufsize = available_space_after (blk); - if (size_left < bufsize) - { - bufsize = size_left; - count = bufsize % BLOCKSIZE; - if (count) - memset (blk->buffer + size_left, 0, BLOCKSIZE - count); - } - memcpy (blk->buffer, p_buffer, bufsize); - size_left -= bufsize; - p_buffer += bufsize; - set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE); + bufsize = size_left; + count = bufsize % BLOCKSIZE; + if (count) + memset (blk->buffer + size_left, 0, BLOCKSIZE - count); } - mv_end (); + memcpy (blk->buffer, p_buffer, bufsize); + size_left -= bufsize; + p_buffer += bufsize; + set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE); } - return; } + return; } if (!recursion_option) @@ -1173,21 +1172,22 @@ dump_dir0 (char *directory, && parent_device != st->stat.st_dev) { if (verbose_option) - WARN ((0, 0, - _("%s: file is on a different filesystem; not dumped"), - quotearg_colon (st->orig_file_name))); + WARNOPT (WARN_XDEV, + (0, 0, + _("%s: file is on a different filesystem; not dumped"), + quotearg_colon (st->orig_file_name))); } else { char *name_buf; size_t name_size; - + switch (check_exclusion_tags (st->orig_file_name, &tag_file_name)) { case exclusion_tag_all: /* Handled in dump_file0 */ break; - + case exclusion_tag_none: { char const *entry; @@ -1209,9 +1209,9 @@ dump_dir0 (char *directory, } strcpy (name_buf + name_len, entry); if (!excluded_name (name_buf)) - dump_file (name_buf, 0, our_device); + dump_file (name_buf, false, our_device); } - + free (name_buf); } break; @@ -1223,10 +1223,10 @@ dump_dir0 (char *directory, name_buf = xmalloc (name_size); strcpy (name_buf, st->orig_file_name); strcat (name_buf, tag_file_name); - dump_file (name_buf, 0, our_device); + dump_file (name_buf, false, our_device); free (name_buf); break; - + case exclusion_tag_under: exclusion_tag_warning (st->orig_file_name, tag_file_name, _("contents not dumped")); @@ -1249,7 +1249,8 @@ ensure_slash (char **pstr) } static bool -dump_dir (int fd, struct tar_stat_info *st, int top_level, dev_t parent_device) +dump_dir (int fd, struct tar_stat_info *st, bool top_level, + dev_t parent_device) { char *directory = fdsavedir (fd); if (!directory) @@ -1270,7 +1271,7 @@ dump_dir (int fd, struct tar_stat_info *st, int top_level, dev_t parent_device) void create_archive (void) { - const char *p; + struct name const *p; open_archive (ACCESS_WRITE); buffer_write_global_xheader (); @@ -1284,24 +1285,24 @@ create_archive (void) collect_and_sort_names (); while ((p = name_from_list ()) != NULL) - if (!excluded_name (p)) - dump_file (p, -1, (dev_t) 0); + if (!excluded_name (p->name)) + dump_file (p->name, p->cmdline, (dev_t) 0); blank_name_list (); while ((p = name_from_list ()) != NULL) - if (!excluded_name (p)) + if (!excluded_name (p->name)) { - size_t plen = strlen (p); + size_t plen = strlen (p->name); if (buffer_size <= plen) { while ((buffer_size *= 2) <= plen) continue; buffer = xrealloc (buffer, buffer_size); } - memcpy (buffer, p, plen); + memcpy (buffer, p->name, plen); if (! ISSLASH (buffer[plen - 1])) - buffer[plen++] = '/'; - q = gnu_list_name->dir_contents; + buffer[plen++] = DIRECTORY_SEPARATOR; + q = directory_contents (gnu_list_name->directory); if (q) while (*q) { @@ -1315,7 +1316,7 @@ create_archive (void) buffer = xrealloc (buffer, buffer_size); } strcpy (buffer + plen, q + 1); - dump_file (buffer, -1, (dev_t) 0); + dump_file (buffer, false, (dev_t) 0); } q += qlen + 1; } @@ -1324,14 +1325,15 @@ create_archive (void) } else { - while ((p = name_next (1)) != NULL) - if (!excluded_name (p)) - dump_file (p, 1, (dev_t) 0); + const char *name; + while ((name = name_next (1)) != NULL) + if (!excluded_name (name)) + dump_file (name, true, (dev_t) 0); } write_eot (); close_archive (); - + finish_deferred_unlinks (); if (listed_incremental_option) write_directory_file (); } @@ -1358,10 +1360,11 @@ compare_links (void const *entry1, void const *entry2) static void unknown_file_error (char const *p) { - WARN ((0, 0, _("%s: Unknown file type; file ignored"), - quotearg_colon (p))); + WARNOPT (WARN_FILE_IGNORED, + (0, 0, _("%s: Unknown file type; file ignored"), + quotearg_colon (p))); if (!ignore_failed_read_option) - exit_status = TAREXIT_FAILURE; + set_exit_status (TAREXIT_FAILURE); } @@ -1377,7 +1380,7 @@ static Hash_table *link_table; static bool dump_hard_link (struct tar_stat_info *st) { - if (link_table && st->stat.st_nlink > 1) + if (link_table && (st->stat.st_nlink > 1 || remove_files_option)) { struct link lp; struct link *duplicate; @@ -1410,8 +1413,8 @@ dump_hard_link (struct tar_stat_info *st) blk->header.typeflag = LNKTYPE; finish_header (st, blk, block_ordinal); - if (remove_files_option && unlink (st->orig_file_name) != 0) - unlink_error (st->orig_file_name); + if (remove_files_option) + queue_deferred_unlink (st->orig_file_name, false); return true; } @@ -1427,12 +1430,19 @@ file_count_links (struct tar_stat_info *st) if (st->stat.st_nlink > 1) { struct link *duplicate; - struct link *lp = xmalloc (offsetof (struct link, name) - + strlen (st->orig_file_name) + 1); + char *linkname = NULL; + struct link *lp; + + assign_string (&linkname, st->orig_file_name); + transform_name (&linkname, XFORM_LINK); + + lp = xmalloc (offsetof (struct link, name) + + strlen (linkname) + 1); lp->ino = st->stat.st_ino; lp->dev = st->stat.st_dev; lp->nlink = st->stat.st_nlink; - strcpy (lp->name, st->orig_file_name); + strcpy (lp->name, linkname); + free (linkname); if (! ((link_table || (link_table = hash_initialize (0, 0, hash_link, @@ -1461,12 +1471,11 @@ check_links (void) { if (lp->nlink) { - WARN ((0, 0, _("Missing links to %s.\n"), quote (lp->name))); + WARN ((0, 0, _("Missing links to %s."), quote (lp->name))); } } } - /* Dump a single file, recursing on directories. P is the file name to dump. TOP_LEVEL tells whether this is a top-level call; zero means no, positive means yes, and negative means the top level @@ -1478,7 +1487,7 @@ check_links (void) static void dump_file0 (struct tar_stat_info *st, const char *p, - int top_level, dev_t parent_device) + bool top_level, dev_t parent_device) { union block *header; char type; @@ -1495,11 +1504,11 @@ dump_file0 (struct tar_stat_info *st, const char *p, assign_string (&st->file_name, safer_name_suffix (p, false, absolute_names_option)); - transform_name (&st->file_name); + transform_name (&st->file_name, XFORM_REGFILE); if (deref_stat (dereference_option, p, &st->stat) != 0) { - stat_diag (p); + file_removed_diag (p, top_level, stat_diag); return; } st->archive_file_size = original_size = st->stat.st_size; @@ -1532,22 +1541,21 @@ dump_file0 (struct tar_stat_info *st, const char *p, && (!after_date_option || OLDER_TAR_STAT_TIME (*st, c))) { if (!incremental_option && verbose_option) - WARN ((0, 0, _("%s: file is unchanged; not dumped"), - quotearg_colon (p))); + WARNOPT (WARN_FILE_UNCHANGED, + (0, 0, _("%s: file is unchanged; not dumped"), + quotearg_colon (p))); return; } /* See if we are trying to dump the archive. */ if (sys_file_is_archive (st)) { - WARN ((0, 0, _("%s: file is the archive; not dumped"), - quotearg_colon (p))); + WARNOPT (WARN_IGNORE_ARCHIVE, + (0, 0, _("%s: file is the archive; not dumped"), + quotearg_colon (p))); return; } - if (is_avoided_name (p)) - return; - is_dir = S_ISDIR (st->stat.st_mode) != 0; if (!is_dir && dump_hard_link (st)) @@ -1569,11 +1577,7 @@ dump_file0 (struct tar_stat_info *st, const char *p, : 0))); if (fd < 0) { - if (!top_level && errno == ENOENT) - WARN ((0, 0, _("%s: File removed before we read it"), - quotearg_colon (p))); - else - open_diag (p); + file_removed_diag (p, top_level, open_diag); return; } } @@ -1589,9 +1593,11 @@ dump_file0 (struct tar_stat_info *st, const char *p, { exclusion_tag_warning (st->orig_file_name, tag_file_name, _("directory not dumped")); + if (fd >= 0) + close (fd); return; } - + ok = dump_dir (fd, st, top_level, parent_device); /* dump_dir consumes FD if successful. */ @@ -1615,7 +1621,7 @@ dump_file0 (struct tar_stat_info *st, const char *p, { case dump_status_ok: case dump_status_short: - mv_end (); + file_count_links (st); break; case dump_status_fail: @@ -1625,8 +1631,6 @@ dump_file0 (struct tar_stat_info *st, const char *p, abort (); } - file_count_links (st); - ok = status == dump_status_ok; } @@ -1644,7 +1648,7 @@ dump_file0 (struct tar_stat_info *st, const char *p, : fstat (fd, &final_stat)) != 0) { - stat_diag (p); + file_removed_diag (p, top_level, stat_diag); ok = false; } } @@ -1657,10 +1661,10 @@ dump_file0 (struct tar_stat_info *st, const char *p, && !(remove_files_option && is_dir)) || original_size < final_stat.st_size) { - WARN ((0, 0, _("%s: file changed as we read it"), - quotearg_colon (p))); - if (exit_status == TAREXIT_SUCCESS) - exit_status = TAREXIT_DIFFERS; + WARNOPT (WARN_FILE_CHANGED, + (0, 0, _("%s: file changed as we read it"), + quotearg_colon (p))); + set_exit_status (TAREXIT_DIFFERS); } else if (atime_preserve_option == replace_atime_preserve && set_file_atime (fd, p, restore_times) != 0) @@ -1674,18 +1678,7 @@ dump_file0 (struct tar_stat_info *st, const char *p, } if (ok && remove_files_option) - { - if (is_dir) - { - if (rmdir (p) != 0 && errno != ENOTEMPTY) - rmdir_error (p); - } - else - { - if (unlink (p) != 0) - unlink_error (p); - } - } + queue_deferred_unlink (p, is_dir); return; } @@ -1701,11 +1694,12 @@ dump_file0 (struct tar_stat_info *st, const char *p, size = readlink (p, buffer, linklen + 1); if (size < 0) { - readlink_diag (p); + file_removed_diag (p, top_level, readlink_diag); return; } buffer[size] = '\0'; assign_string (&st->link_name, buffer); + transform_name (&st->link_name, XFORM_SYMLINK); if (NAME_FIELD_SIZE - (archive_format == OLDGNU_FORMAT) < size) write_long_link (st); @@ -1714,16 +1708,14 @@ dump_file0 (struct tar_stat_info *st, const char *p, header = start_header (st); if (!header) return; - tar_copy_str (header->header.linkname, buffer, NAME_FIELD_SIZE); + tar_copy_str (header->header.linkname, st->link_name, NAME_FIELD_SIZE); header->header.typeflag = SYMTYPE; finish_header (st, header, block_ordinal); /* nothing more to do to it */ if (remove_files_option) - { - if (unlink (p) == -1) - unlink_error (p); - } + queue_deferred_unlink (p, false); + file_count_links (st); return; } @@ -1736,12 +1728,14 @@ dump_file0 (struct tar_stat_info *st, const char *p, type = FIFOTYPE; else if (S_ISSOCK (st->stat.st_mode)) { - WARN ((0, 0, _("%s: socket ignored"), quotearg_colon (p))); + WARNOPT (WARN_FILE_IGNORED, + (0, 0, _("%s: socket ignored"), quotearg_colon (p))); return; } else if (S_ISDOOR (st->stat.st_mode)) { - WARN ((0, 0, _("%s: door ignored"), quotearg_colon (p))); + WARNOPT (WARN_FILE_IGNORED, + (0, 0, _("%s: door ignored"), quotearg_colon (p))); return; } else @@ -1773,14 +1767,11 @@ dump_file0 (struct tar_stat_info *st, const char *p, finish_header (st, header, block_ordinal); if (remove_files_option) - { - if (unlink (p) == -1) - unlink_error (p); - } + queue_deferred_unlink (p, false); } void -dump_file (const char *p, int top_level, dev_t parent_device) +dump_file (const char *p, bool top_level, dev_t parent_device) { struct tar_stat_info st; tar_stat_init (&st);