/* 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.
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)
+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] != '/';
+ int addslash = !ISSLASH (dirname[dlen-1]);
char *nptr = NULL;
for (tag = exclusion_tags; tag; tag = tag->next)
while (size_left > 0)
{
size_t bufsize, count;
-
+
mv_size_left (size_left);
blk = find_next_block ();
{
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;
+ set_exit_status (TAREXIT_DIFFERS);
pad_archive (size_left - (bufsize - count));
return dump_status_short;
}
\f
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 (!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
{
}
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);
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;
}
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)
void
create_archive (void)
{
- const char *p;
+ struct name const *p;
open_archive (ACCESS_WRITE);
buffer_write_global_xheader ();
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)
{
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;
}
}
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 ();
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);
}
\f
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)));
}
}
}
-
/* 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
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;
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;
/* 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;
}
: 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;
}
}
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;
}
: fstat (fd, &final_stat))
!= 0)
{
- stat_diag (p);
+ file_removed_diag (p, top_level, stat_diag);
ok = false;
}
}
&& !(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)
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);
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
}
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);