/* 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
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;
{
strcpy (tagname, dirname);
nptr = tagname + dlen;
+ if (addslash)
+ *nptr++ = '/';
}
strcpy (nptr, tag->name);
if (access (tagname, F_OK) == 0
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)
{
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));
while (size_left > 0)
{
size_t bufsize, count;
-
+
mv_size_left (size_left);
blk = find_next_block ();
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));
+ pad_archive (size_left - (bufsize - count));
return dump_status_short;
}
}
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
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;
&& 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
{
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;
/* Now output all the files in the directory. */
/* FIXME: Should speed this up by cd-ing into the dir. */
-
for (entry = directory; (entry_len = strlen (entry)) != 0;
entry += entry_len + 1)
{
const char *p;
open_archive (ACCESS_WRITE);
- xheader_write_global ();
+ buffer_write_global_xheader ();
if (incremental_option)
{
}
memcpy (buffer, p, 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)
{
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;
}
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;
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--;
{
if (lp->nlink)
{
- WARN ((0, 0, _("Missing links to %s.\n"), quote (lp->name)));
+ WARN ((0, 0, _("Missing links to %s."), quote (lp->name)));
}
}
}
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)
{
/* 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;
}
if (fd < 0)
{
if (!top_level && errno == ENOENT)
- WARN ((0, 0, _("%s: File removed before we read it"),
- quotearg_colon (p)));
+ WARNOPT (WARN_FILE_REMOVED,
+ (0, 0, _("%s: File removed before we read it"),
+ quotearg_colon (p)));
else
open_diag (p);
return;
case dump_status_ok:
case dump_status_short:
mv_end ();
+ file_count_links (st);
break;
case dump_status_fail:
abort ();
}
- file_count_links (st);
-
ok = status == dump_status_ok;
}
if (ok)
{
- if (timespec_cmp (get_stat_ctime (&final_stat), original_ctime) != 0
+ if ((timespec_cmp (get_stat_ctime (&final_stat), original_ctime) != 0
+ /* Original ctime will change if the file is a directory and
+ --remove-files is given */
+ && !(remove_files_option && is_dir))
|| original_size < final_stat.st_size)
{
- WARN ((0, 0, _("%s: file changed as we read it"),
- quotearg_colon (p)));
+ WARNOPT (WARN_FILE_CHANGED,
+ (0, 0, _("%s: file changed as we read it"),
+ quotearg_colon (p)));
if (exit_status == TAREXIT_SUCCESS)
exit_status = TAREXIT_DIFFERS;
}
}
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);
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 */
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