/* 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
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
else
{
ERROR ((0, 0, _("Malformed extended header: excess %s=%s"),
- "GNU.sparse.numbytes", arg));
+ keyword, arg));
return;
}
}
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);
+}
+
+
struct xhdr_tab const xhdr_tab[] = {
{ "atime", atime_coder, atime_decoder, false },
{ "comment", dummy_coder, dummy_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 }
};