X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fcreate.c;h=6f3113e7f64fafbc222a5d805f8491426477385f;hb=0d8e3249123ecf0175b60c7b43056ac811eb6921;hp=eaaf8a75af5b3894f686e9b000395864b379abc8;hpb=17ef61b2fd942bf45c98f7ec4159dc06ebacf9dd;p=chaz%2Ftar diff --git a/src/create.c b/src/create.c index eaaf8a7..6f3113e 100644 --- a/src/create.c +++ b/src/create.c @@ -1,13 +1,13 @@ /* 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 Free Software Foundation, Inc. Written by John Gilmore, on 1985-08-25. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any later + Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but @@ -58,31 +58,32 @@ add_exclusion_tag (const char *name, enum exclusion_tag_type type, exclusion_tags = tag; } -static void +void 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)); } -static 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 = !ISSLASH (dirname[dlen-1]); char *nptr = NULL; - char *ret = NULL; for (tag = exclusion_tags; tag; tag = tag->next) { - size_t size = dlen + tag->length + 1; + size_t size = dlen + addslash + tag->length + 1; if (size > tagsize) { tagsize = size; @@ -93,6 +94,8 @@ check_exclusion_tags (char *dirname, const char **tag_file_name) { strcpy (tagname, dirname); nptr = tagname + dlen; + if (addslash) + *nptr++ = '/'; } strcpy (nptr, tag->name); if (access (tagname, F_OK) == 0 @@ -711,10 +714,10 @@ write_extended (bool global, struct tar_stat_info *st, union block *old_header) char *p; int type; - if (extended_header.buffer || extended_header.stk == NULL) + if (st->xhdr.buffer || st->xhdr.stk == NULL) return old_header; - xheader_finish (&extended_header); + xheader_finish (&st->xhdr); memcpy (hp.buffer, old_header, sizeof (hp)); if (global) { @@ -726,7 +729,7 @@ write_extended (bool global, struct tar_stat_info *st, union block *old_header) type = XHDTYPE; p = xheader_xhdr_name (st); } - xheader_write (type, p, &extended_header); + xheader_write (type, p, &st->xhdr); free (p); header = find_next_block (); memcpy (header, &hp.buffer, sizeof (hp.buffer)); @@ -1039,7 +1042,7 @@ dump_regular_file (int fd, struct tar_stat_info *st) while (size_left > 0) { size_t bufsize, count; - + mv_size_left (size_left); blk = find_next_block (); @@ -1064,22 +1067,22 @@ dump_regular_file (int fd, struct tar_stat_info *st) return dump_status_short; } size_left -= count; - if (count) - set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE); + set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE); if (count != bufsize) { 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))); + 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) - exit_status = TAREXIT_DIFFERS; - pad_archive (size_left - (bufsize-count)); + set_exit_status (TAREXIT_DIFFERS); + pad_archive (size_left - (bufsize - count)); return dump_status_short; } } @@ -1089,7 +1092,7 @@ 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; @@ -1113,11 +1116,12 @@ dump_dir0 (char *directory, if (!incremental_option) finish_header (st, blk, block_ordinal); - else if (gnu_list_name->dir_contents) + else if (gnu_list_name->directory) { if (archive_format == POSIX_FORMAT) { - xheader_store ("GNU.dumpdir", st, gnu_list_name->dir_contents); + xheader_store ("GNU.dumpdir", st, + safe_directory_contents (gnu_list_name->directory)); finish_header (st, blk, block_ordinal); } else @@ -1129,11 +1133,8 @@ dump_dir0 (char *directory, 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; + 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; @@ -1172,9 +1173,10 @@ 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 { @@ -1183,8 +1185,11 @@ dump_dir0 (char *directory, switch (check_exclusion_tags (st->orig_file_name, &tag_file_name)) { - case exclusion_tag_none: case exclusion_tag_all: + /* Handled in dump_file0 */ + break; + + case exclusion_tag_none: { char const *entry; size_t entry_len; @@ -1205,7 +1210,7 @@ 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); @@ -1219,7 +1224,7 @@ 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; @@ -1245,7 +1250,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) @@ -1266,10 +1272,10 @@ 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); - xheader_write_global (); + buffer_write_global_xheader (); if (incremental_option) { @@ -1280,24 +1286,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) { @@ -1311,7 +1317,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; } @@ -1320,9 +1326,10 @@ 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 (); @@ -1354,10 +1361,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); } @@ -1373,7 +1381,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; @@ -1418,22 +1426,31 @@ dump_hard_link (struct tar_stat_info *st) static void file_count_links (struct tar_stat_info *st) { + if (hard_dereference_option) + return; 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, compare_links, 0))) && (duplicate = hash_insert (link_table, lp)))) xalloc_die (); - + if (duplicate != lp) abort (); lp->nlink--; @@ -1455,12 +1472,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 @@ -1472,7 +1488,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; @@ -1489,11 +1505,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; @@ -1516,26 +1532,28 @@ dump_file0 (struct tar_stat_info *st, const char *p, /* See if we want only new files, and check if this one is too old to put in the archive. - + This check is omitted if incremental_option is set *and* the requested file is not explicitely listed in the command line. */ - + if (!(incremental_option && !is_individual_file (p)) && !S_ISDIR (st->stat.st_mode) && OLDER_TAR_STAT_TIME (*st, m) && (!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; } @@ -1563,11 +1581,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; } } @@ -1610,6 +1624,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: @@ -1619,8 +1634,6 @@ dump_file0 (struct tar_stat_info *st, const char *p, abort (); } - file_count_links (st); - ok = status == dump_status_ok; } @@ -1638,7 +1651,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; } } @@ -1651,10 +1664,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) @@ -1695,11 +1708,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); @@ -1708,7 +1722,7 @@ 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 */ @@ -1730,12 +1744,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 @@ -1774,7 +1790,7 @@ dump_file0 (struct tar_stat_info *st, const char *p, } 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);