/* POSIX extended headers for tar.
- Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
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
static void
xheader_set_single_keyword (char *kw)
{
- USAGE_ERROR ((0, 0, _("Keyword %s is unknown or not yet imlemented"), kw));
+ USAGE_ERROR ((0, 0, _("Keyword %s is unknown or not yet implemented"), kw));
}
static void
to the result of the basename
utility on the translated file name.
%p The process ID of the pax process.
+ %n The value of the 3rd argument.
%% A '%' character. */
-static char *
-xheader_format_name (struct tar_stat_info *st, const char *fmt, bool allow_n)
+char *
+xheader_format_name (struct tar_stat_info *st, const char *fmt, size_t n)
{
char *buf;
size_t len = strlen (fmt);
char *q;
const char *p;
+ char *dirp = NULL;
char *dir = NULL;
char *base = NULL;
char pidbuf[UINTMAX_STRSIZE_BOUND];
case 'd':
if (st)
{
- dir = safer_name_suffix (dir_name (st->orig_file_name),
- false, absolute_names_option);
- len += strlen (dir) - 1;
+ if (!dirp)
+ dirp = dir_name (st->orig_file_name);
+ dir = safer_name_suffix (dirp, false, absolute_names_option);
+ len += strlen (dir) - 2;
}
break;
if (st)
{
base = base_name (st->orig_file_name);
- len += strlen (base) - 1;
+ len += strlen (base) - 2;
}
break;
case 'p':
pptr = umaxtostr (getpid (), pidbuf);
- len += pidbuf + sizeof pidbuf - 1 - pptr - 1;
+ len += pidbuf + sizeof pidbuf - 1 - pptr - 2;
break;
case 'n':
- if (allow_n)
- {
- nptr = umaxtostr (global_header_count + 1, nbuf);
- len += nbuf + sizeof nbuf - 1 - nptr - 1;
- }
+ nptr = umaxtostr (n, nbuf);
+ len += nbuf + sizeof nbuf - 1 - nptr - 2;
break;
}
p++;
{
q = stpcpy (q, nptr);
p += 2;
+ break;
}
/* else fall through */
*q++ = *p++;
}
+ free (dirp);
+
/* Do not allow it to end in a slash */
while (q > buf && ISSLASH (q[-1]))
q--;
{
if (!exthdr_name)
assign_string (&exthdr_name, "%d/PaxHeaders.%p/%f");
- return xheader_format_name (st, exthdr_name, false);
+ return xheader_format_name (st, exthdr_name, 0);
}
#define GLOBAL_HEADER_TEMPLATE "/GlobalHead.%p.%n"
strcat(globexthdr_name, GLOBAL_HEADER_TEMPLATE);
}
- return xheader_format_name (NULL, globexthdr_name, true);
+ return xheader_format_name (NULL, globexthdr_name, global_header_count + 1);
}
void
}
while (size > 0);
xheader_destroy (xhdr);
+
+ if (type == XGLTYPE)
+ global_header_count++;
}
void
xheader_write (XGLTYPE, name = xheader_ghdr_name (),
&extended_header);
free (name);
- global_header_count++;
}
\f
{
char const *keyword;
void (*coder) (struct tar_stat_info const *, char const *,
- struct xheader *, void *data);
+ struct xheader *, void const *data);
void (*decoder) (struct tar_stat_info *, char const *, size_t);
bool protect;
};
}
void
-xheader_store (char const *keyword, struct tar_stat_info const *st, void *data)
+xheader_store (char const *keyword, struct tar_stat_info const *st,
+ void const *data)
{
struct xhdr_tab const *t;
void
xheader_string_end (char const *keyword)
-{
+{
size_t len;
size_t p;
size_t n = 0;
if (extended_header.buffer)
return;
extended_header_init ();
-
+
len = strlen (keyword) + string_length + 3; /* ' ' + '=' + '\n' */
-
+
do
{
p = n;
xheader_print (xhdr, keyword, code_timespec (t, buf));
}
-static bool
-decode_time (struct timespec *ts, char const *arg, char const *keyword)
+enum decode_time_status
+ {
+ decode_time_success,
+ decode_time_range,
+ decode_time_bad_header
+ };
+
+static enum decode_time_status
+_decode_time (struct timespec *ts, char const *arg, char const *keyword)
{
time_t s;
unsigned long int ns = 0;
{
intmax_t i = strtoimax (arg, &arg_lim, 10);
if (TYPE_SIGNED (time_t) ? i < TYPE_MINIMUM (time_t) : i < 0)
- goto out_of_range;
+ return decode_time_range;
s = i;
}
else
{
uintmax_t i = strtoumax (arg, &arg_lim, 10);
if (TYPE_MAXIMUM (time_t) < i)
- goto out_of_range;
+ return decode_time_range;
s = i;
}
p = arg_lim;
if (errno == ERANGE)
- goto out_of_range;
+ return decode_time_range;
if (*p == '.')
{
if (ns != 0)
{
if (s == TYPE_MINIMUM (time_t))
- goto out_of_range;
+ return decode_time_range;
s--;
ns = BILLION - ns;
}
{
ts->tv_sec = s;
ts->tv_nsec = ns;
- return true;
+ return decode_time_success;
}
}
- ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"),
- keyword, arg));
- return false;
+ return decode_time_bad_header;
+}
- out_of_range:
- out_of_range_header (keyword, arg, - (uintmax_t) TYPE_MINIMUM (time_t),
- TYPE_MAXIMUM (time_t));
- return false;
+static bool
+decode_time (struct timespec *ts, char const *arg, char const *keyword)
+{
+ switch (_decode_time (ts, arg, keyword))
+ {
+ case decode_time_success:
+ return true;
+ case decode_time_bad_header:
+ ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"),
+ keyword, arg));
+ return false;
+ case decode_time_range:
+ out_of_range_header (keyword, arg, - (uintmax_t) TYPE_MINIMUM (time_t),
+ TYPE_MAXIMUM (time_t));
+ return false;
+ }
+ return true;
}
+
+
static void
code_num (uintmax_t value, char const *keyword, struct xheader *xhdr)
{
dummy_coder (struct tar_stat_info const *st __attribute__ ((unused)),
char const *keyword __attribute__ ((unused)),
struct xheader *xhdr __attribute__ ((unused)),
- void *data __attribute__ ((unused)))
+ void const *data __attribute__ ((unused)))
{
}
static void
atime_coder (struct tar_stat_info const *st, char const *keyword,
- struct xheader *xhdr, void *data __attribute__ ((unused)))
+ struct xheader *xhdr, void const *data __attribute__ ((unused)))
{
code_time (st->atime, keyword, xhdr);
}
static void
gid_coder (struct tar_stat_info const *st, char const *keyword,
- struct xheader *xhdr, void *data __attribute__ ((unused)))
+ struct xheader *xhdr, void const *data __attribute__ ((unused)))
{
code_num (st->stat.st_gid, keyword, xhdr);
}
static void
gname_coder (struct tar_stat_info const *st, char const *keyword,
- struct xheader *xhdr, void *data __attribute__ ((unused)))
+ struct xheader *xhdr, void const *data __attribute__ ((unused)))
{
code_string (st->gname, keyword, xhdr);
}
static void
linkpath_coder (struct tar_stat_info const *st, char const *keyword,
- struct xheader *xhdr, void *data __attribute__ ((unused)))
+ struct xheader *xhdr, void const *data __attribute__ ((unused)))
{
code_string (st->link_name, keyword, xhdr);
}
static void
ctime_coder (struct tar_stat_info const *st, char const *keyword,
- struct xheader *xhdr, void *data __attribute__ ((unused)))
+ struct xheader *xhdr, void const *data __attribute__ ((unused)))
{
code_time (st->ctime, keyword, xhdr);
}
static void
mtime_coder (struct tar_stat_info const *st, char const *keyword,
- struct xheader *xhdr, void *data __attribute__ ((unused)))
+ struct xheader *xhdr, void const *data __attribute__ ((unused)))
{
code_time (st->mtime, keyword, xhdr);
}
static void
path_coder (struct tar_stat_info const *st, char const *keyword,
- struct xheader *xhdr, void *data __attribute__ ((unused)))
+ struct xheader *xhdr, void const *data __attribute__ ((unused)))
{
code_string (st->file_name, keyword, xhdr);
}
static void
size_coder (struct tar_stat_info const *st, char const *keyword,
- struct xheader *xhdr, void *data __attribute__ ((unused)))
+ struct xheader *xhdr, void const *data __attribute__ ((unused)))
{
code_num (st->stat.st_size, keyword, xhdr);
}
static void
uid_coder (struct tar_stat_info const *st, char const *keyword,
- struct xheader *xhdr, void *data __attribute__ ((unused)))
+ struct xheader *xhdr, void const *data __attribute__ ((unused)))
{
code_num (st->stat.st_uid, keyword, xhdr);
}
static void
uname_coder (struct tar_stat_info const *st, char const *keyword,
- struct xheader *xhdr, void *data __attribute__ ((unused)))
+ struct xheader *xhdr, void const *data __attribute__ ((unused)))
{
code_string (st->uname, keyword, xhdr);
}
static void
sparse_size_coder (struct tar_stat_info const *st, char const *keyword,
- struct xheader *xhdr, void *data)
+ struct xheader *xhdr, void const *data)
{
size_coder (st, keyword, xhdr, data);
}
static void
sparse_numblocks_coder (struct tar_stat_info const *st, char const *keyword,
struct xheader *xhdr,
- void *data __attribute__ ((unused)))
+ void const *data __attribute__ ((unused)))
{
code_num (st->sparse_map_avail, keyword, xhdr);
}
static void
sparse_offset_coder (struct tar_stat_info const *st, char const *keyword,
- struct xheader *xhdr, void *data)
+ struct xheader *xhdr, void const *data)
{
- size_t *pi = data;
+ size_t const *pi = data;
code_num (st->sparse_map[*pi].offset, keyword, xhdr);
}
static void
sparse_numbytes_coder (struct tar_stat_info const *st, char const *keyword,
- struct xheader *xhdr, void *data)
+ struct xheader *xhdr, void const *data)
{
- size_t *pi = data;
+ size_t const *pi = data;
code_num (st->sparse_map[*pi].numbytes, keyword, xhdr);
}
{
int offset = 1;
static char *keyword = "GNU.sparse.map";
-
+
st->sparse_map_avail = 0;
while (1)
{
uintmax_t u;
char *delim;
struct sp_array e;
-
+
if (!ISDIGIT (*arg))
{
ERROR ((0, 0, _("Malformed extended header: invalid %s=%s"),
else
{
ERROR ((0, 0, _("Malformed extended header: excess %s=%s"),
- "GNU.sparse.numbytes", arg));
+ keyword, arg));
return;
}
}
-
+
offset = !offset;
if (*delim == 0)
static void
dumpdir_coder (struct tar_stat_info const *st, char const *keyword,
- struct xheader *xhdr, void *data)
+ struct xheader *xhdr, void const *data)
{
xheader_print_n (xhdr, keyword, data, dumpdir_size (data));
}
memcpy (st->dumpdir, arg, size);
}
+static void
+volume_label_coder (struct tar_stat_info const *st, char const *keyword,
+ struct xheader *xhdr, void const *data)
+{
+ code_string (data, keyword, xhdr);
+}
+
+static void
+volume_label_decoder (struct tar_stat_info *st, char const *arg, size_t size)
+{
+ decode_string (&volume_label, arg);
+}
+
+static void
+volume_size_coder (struct tar_stat_info const *st, char const *keyword,
+ struct xheader *xhdr, void const *data)
+{
+ off_t v = *(off_t*)data;
+ code_num (v, keyword, xhdr);
+}
+
+static void
+volume_size_decoder (struct tar_stat_info *st, char const *arg, size_t size)
+{
+ uintmax_t u;
+ if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), "GNU.volume.size"))
+ continued_file_size = u;
+}
+
+/* FIXME: Merge with volume_size_coder */
+static void
+volume_offset_coder (struct tar_stat_info const *st, char const *keyword,
+ struct xheader *xhdr, void const *data)
+{
+ off_t v = *(off_t*)data;
+ code_num (v, keyword, xhdr);
+}
+
+static void
+volume_offset_decoder (struct tar_stat_info *st, char const *arg, size_t size)
+{
+ uintmax_t u;
+ if (decode_num (&u, arg, TYPE_MAXIMUM (uintmax_t), "GNU.volume.offset"))
+ continued_file_offset = u;
+}
+
+static void
+volume_filename_decoder (struct tar_stat_info *st, char const *arg,
+ size_t size)
+{
+ decode_string (&continued_file_name, arg);
+}
+
+static void
+sparse_major_coder (struct tar_stat_info const *st, char const *keyword,
+ struct xheader *xhdr, void const *data)
+{
+ code_num (st->sparse_major, keyword, xhdr);
+}
+
+static void
+sparse_major_decoder (struct tar_stat_info *st, char const *arg,
+ size_t size)
+{
+ uintmax_t u;
+ if (decode_num (&u, arg, TYPE_MAXIMUM (unsigned), "GNU.sparse.major"))
+ st->sparse_major = u;
+}
+
+static void
+sparse_minor_coder (struct tar_stat_info const *st, char const *keyword,
+ struct xheader *xhdr, void const *data)
+{
+ code_num (st->sparse_minor, keyword, xhdr);
+}
+
+static void
+sparse_minor_decoder (struct tar_stat_info *st, char const *arg,
+ size_t size)
+{
+ uintmax_t u;
+ if (decode_num (&u, arg, TYPE_MAXIMUM (unsigned), "GNU.sparse.minor"))
+ st->sparse_minor = u;
+}
+
struct xhdr_tab const xhdr_tab[] = {
{ "atime", atime_coder, atime_decoder, false },
{ "comment", dummy_coder, dummy_decoder, false },
{ "uname", uname_coder, uname_decoder, false },
/* Sparse file handling */
+ { "GNU.sparse.name", path_coder, path_decoder,
+ true },
+ { "GNU.sparse.major", sparse_major_coder, sparse_major_decoder,
+ true },
+ { "GNU.sparse.minor", sparse_minor_coder, sparse_minor_decoder,
+ true },
+ { "GNU.sparse.realsize", sparse_size_coder, sparse_size_decoder, true },
+
{ "GNU.sparse.size", sparse_size_coder, sparse_size_decoder, true },
{ "GNU.sparse.numblocks", sparse_numblocks_coder, sparse_numblocks_decoder,
true },
- /* tar 1.14 - 1.15.1 keywords. Multiplse instances of these appeared in 'x'
+ /* tar 1.14 - 1.15.1 keywords. Multiple instances of these appeared in 'x'
headers, and each of them was meaningful. It confilcted with POSIX specs,
which requires that "when extended header records conflict, the last one
given in the header shall take precedence." */
true },
{ "GNU.sparse.numbytes", sparse_numbytes_coder, sparse_numbytes_decoder,
true },
- /* tar >=1.16 keyword, introduced to remove the above-mentioned conflict. */
+ /* tar 1.15.90 keyword, introduced to remove the above-mentioned conflict. */
{ "GNU.sparse.map", NULL /* Unused, see pax_dump_header() */,
sparse_map_decoder, false },
{ "GNU.dumpdir", dumpdir_coder, dumpdir_decoder,
true },
-
-#if 0 /* GNU private keywords (not yet implemented) */
- /* Keeps the tape/volume header. May be present only in the global headers.
+ /* Keeps the tape/volume label. May be present only in the global headers.
Equivalent to GNUTYPE_VOLHDR. */
- { "GNU.volume.header", volume_header_coder, volume_header_decoder, false },
+ { "GNU.volume.label", volume_label_coder, volume_label_decoder, true },
/* These may be present in a first global header of the archive.
They provide the same functionality as GNUTYPE_MULTIVOL header.
otherwise kept in the size field of a multivolume header. The
GNU.volume.offset keeps the offset of the start of this volume,
otherwise kept in oldgnu_header.offset. */
- { "GNU.volume.size", volume_size_coder, volume_size_decoder, false },
- { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder, false },
-#endif
+ { "GNU.volume.filename", volume_label_coder, volume_filename_decoder,
+ true },
+ { "GNU.volume.size", volume_size_coder, volume_size_decoder, true },
+ { "GNU.volume.offset", volume_offset_coder, volume_offset_decoder, true },
{ NULL, NULL, NULL, false }
};