/* Create a tar archive.
Copyright (C) 1985, 1992, 1993, 1994, 1996, 1997, 1999, 2000, 2001,
- 2003, 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
+ 2003, 2004, 2005, 2006, 2007, 2009, 2010 Free Software Foundation, Inc.
Written by John Gilmore, on 1985-08-25.
{
dev_t dev;
ino_t ino;
- size_t nlink;
+ nlink_t nlink;
char name[1];
};
message));
}
-enum exclusion_tag_type
+enum exclusion_tag_type
check_exclusion_tags (const char *dirname, const char **tag_file_name)
{
static char *tagname;
struct exclusion_tag *tag;
size_t dlen = strlen (dirname);
int addslash = !ISSLASH (dirname[dlen-1]);
- char *nptr = NULL;
-
+ size_t noff = 0;
+
for (tag = exclusion_tags; tag; tag = tag->next)
{
size_t size = dlen + addslash + tag->length + 1;
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)))
{
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,
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];
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,
return to_chars (v < 0, (uintmax_t) v, sizeof v, 0, p, s, "off_t");
}
-bool
-size_to_chars (size_t v, char *p, size_t s)
-{
- return to_chars (0, (uintmax_t) v, sizeof v, 0, p, s, "size_t");
-}
-
bool
time_to_chars (time_t v, char *p, size_t s)
{
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);
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)
{
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;
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)
}
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"),
char *p;
int type;
time_t t;
-
+
if (st->xhdr.buffer || st->xhdr.stk == NULL)
return old_header;
&& 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);
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);
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 ();
size_left),
quotearg_colon (st->orig_file_name),
STRINGIFY_BIGINT (size_left, buf)));
- if (! ignore_failed_read_option)
+ if (! ignore_failed_read_option)
set_exit_status (TAREXIT_DIFFERS);
pad_archive (size_left - (bufsize - count));
return dump_status_short;
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);
finish_header (st, blk, block_ordinal);
p_buffer = buffer;
size_left = totsize;
-
- mv_begin (st);
- mv_total_size (totsize);
+
+ mv_begin_write (st->file_name, totsize, totsize);
while (size_left > 0)
{
- mv_size_left (size_left);
blk = find_next_block ();
bufsize = available_space_after (blk);
if (size_left < bufsize)
p_buffer += bufsize;
set_next_block_after (blk + (bufsize - 1) / BLOCKSIZE);
}
- mv_end ();
}
return;
}
{
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;
if (!excluded_name (name_buf))
dump_file (name_buf, false, our_device);
}
-
+
free (name_buf);
}
break;
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"));
return true;
}
+\f
+/* Number of links a file can have without having to be entered into
+ the link table. Typically this is 1, but in trickier circumstances
+ it is 0. */
+static nlink_t trivial_link_count;
+
\f
/* Main functions of this module. */
{
struct name const *p;
+ trivial_link_count = name_count <= 1 && ! dereference_option;
+
open_archive (ACCESS_WRITE);
buffer_write_global_xheader ();
static bool
dump_hard_link (struct tar_stat_info *st)
{
- if (link_table && (st->stat.st_nlink > 1 || remove_files_option))
+ if (link_table
+ && (trivial_link_count < st->stat.st_nlink || remove_files_option))
{
struct link lp;
struct link *duplicate;
{
if (hard_dereference_option)
return;
- if (st->stat.st_nlink > 1)
+ if (trivial_link_count < st->stat.st_nlink)
{
struct link *duplicate;
char *linkname = NULL;
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->nlink = st->stat.st_nlink;
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--;
/* 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)
{
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. */
{
case dump_status_ok:
case dump_status_short:
- mv_end ();
file_count_links (st);
break;