/* POSIX extended headers for tar.
- Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+ Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009 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
- 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
#include <hash.h>
#include <inttostr.h>
#include <quotearg.h>
-#include <stpcpy.h>
#include "common.h"
-#include <fnmatch.h>
-
static bool xheader_protected_pattern_p (char const *pattern);
static bool xheader_protected_keyword_p (char const *keyword);
static void xheader_set_single_keyword (char *) __attribute__ ((noreturn));
/* Used by xheader_finish() */
static void code_string (char const *string, char const *keyword,
struct xheader *xhdr);
-static void extended_header_init (void);
/* Number of global headers written so far. */
static size_t global_header_count;
/* Template for the name field of an 'x' type header */
static char *exthdr_name;
+static char *exthdr_mtime_option;
+static time_t exthdr_mtime;
+
/* Template for the name field of a 'g' type header */
static char *globexthdr_name;
+static char *globexthdr_mtime_option;
+static time_t globexthdr_mtime;
+
bool
xheader_keyword_deleted_p (const char *kw)
{
USAGE_ERROR ((0, 0, _("Keyword %s is unknown or not yet implemented"), kw));
}
+static void
+assign_time_option (char **sval, time_t *tval, const char *input)
+{
+ uintmax_t u;
+ char *p;
+ time_t t = u = strtoumax (input, &p, 10);
+ if (t != u || *p || errno == ERANGE)
+ ERROR ((0, 0, _("Time stamp is out of allowed range")));
+ else
+ {
+ *tval = t;
+ assign_string (sval, input);
+ }
+}
+
static void
xheader_set_keyword_equal (char *kw, char *eq)
{
global = false;
}
- while (p > kw && isspace (*p))
+ while (p > kw && isspace ((unsigned char) *p))
p--;
*p = 0;
- for (p = eq + 1; *p && isspace (*p); p++)
+ for (p = eq + 1; *p && isspace ((unsigned char) *p); p++)
;
if (strcmp (kw, "delete") == 0)
assign_string (&exthdr_name, p);
else if (strcmp (kw, "globexthdr.name") == 0)
assign_string (&globexthdr_name, p);
+ else if (strcmp (kw, "exthdr.mtime") == 0)
+ assign_time_option (&exthdr_mtime_option, &exthdr_mtime, p);
+ else if (strcmp (kw, "globexthdr.mtime") == 0)
+ assign_time_option (&globexthdr_mtime_option, &globexthdr_mtime, p);
else
{
if (xheader_protected_keyword_p (kw))
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.
+ %n The value of the 3rd argument.
%% A '%' character. */
char *
case 'f':
if (st)
{
- base = base_name (st->orig_file_name);
+ base = last_component (st->orig_file_name);
len += strlen (base) - 2;
}
break;
}
free (dirp);
-
+
/* Do not allow it to end in a slash */
while (q > buf && ISSLASH (q[-1]))
q--;
}
void
-xheader_write (char type, char *name, struct xheader *xhdr)
+xheader_write (char type, char *name, time_t t, struct xheader *xhdr)
{
union block *header;
size_t size;
char *p;
size = xhdr->size;
- header = start_private_header (name, size);
+ switch (type)
+ {
+ case XGLTYPE:
+ if (globexthdr_mtime_option)
+ t = globexthdr_mtime;
+ break;
+
+ case XHDTYPE:
+ if (exthdr_mtime_option)
+ t = exthdr_mtime;
+ break;
+ }
+ header = start_private_header (name, size, t);
header->header.typeflag = type;
simple_finish_header (header);
}
void
-xheader_write_global (void)
+xheader_write_global (struct xheader *xhdr)
{
char *name;
struct keyword_list *kp;
if (!keyword_global_override_list)
return;
- extended_header_init ();
+ xheader_init (xhdr);
for (kp = keyword_global_override_list; kp; kp = kp->next)
- code_string (kp->value, kp->pattern, &extended_header);
- xheader_finish (&extended_header);
- xheader_write (XGLTYPE, name = xheader_ghdr_name (),
- &extended_header);
+ code_string (kp->value, kp->pattern, xhdr);
+ xheader_finish (xhdr);
+ xheader_write (XGLTYPE, name = xheader_ghdr_name (), time (NULL), xhdr);
free (name);
}
/* Decode a single extended header record, advancing *PTR to the next record.
Return true on success, false otherwise. */
static bool
-decode_record (char **ptr,
+decode_record (struct xheader *xhdr,
+ char **ptr,
void (*handler) (void *, char const *, char const *, size_t),
void *data)
{
char *len_lim;
char const *keyword;
char *nextp;
- size_t len_max = extended_header.buffer + extended_header.size - start;
+ size_t len_max = xhdr->buffer + xhdr->size - start;
while (*p == ' ' || *p == '\t')
p++;
ERROR ((0, 0, _("Extended header length is out of allowed range")));
return false;
}
-
+
if (len_max < len)
{
int len_len = len_lim - p;
if (t)
t->decoder (st, keyword, value, size);
else
- ERROR((0, 0, _("Ignoring unknown extended header keyword `%s'"),
- keyword));
+ WARNOPT (WARN_UNKNOWN_KEYWORD,
+ (0, 0, _("Ignoring unknown extended header keyword `%s'"),
+ keyword));
}
void
run_override_list (keyword_global_override_list, st);
run_override_list (global_header_override_list, st);
- if (extended_header.size)
+ if (st->xhdr.size)
{
- char *p = extended_header.buffer + BLOCKSIZE;
- while (decode_record (&p, decx, st))
+ char *p = st->xhdr.buffer + BLOCKSIZE;
+ while (decode_record (&st->xhdr, &p, decx, st))
continue;
}
run_override_list (keyword_override_list, st);
}
void
-xheader_decode_global (void)
+xheader_decode_global (struct xheader *xhdr)
{
- if (extended_header.size)
+ if (xhdr->size)
{
- char *p = extended_header.buffer + BLOCKSIZE;
+ char *p = xhdr->buffer + BLOCKSIZE;
xheader_list_destroy (&global_header_override_list);
- while (decode_record (&p, decg, &global_header_override_list))
+ while (decode_record (xhdr, &p, decg, &global_header_override_list))
continue;
}
}
-static void
-extended_header_init (void)
+void
+xheader_init (struct xheader *xhdr)
{
- if (!extended_header.stk)
+ if (!xhdr->stk)
{
- extended_header.stk = xmalloc (sizeof *extended_header.stk);
- obstack_init (extended_header.stk);
+ xhdr->stk = xmalloc (sizeof *xhdr->stk);
+ obstack_init (xhdr->stk);
}
}
void
-xheader_store (char const *keyword, struct tar_stat_info const *st,
+xheader_store (char const *keyword, struct tar_stat_info *st,
void const *data)
{
struct xhdr_tab const *t;
- if (extended_header.buffer)
+ if (st->xhdr.buffer)
return;
t = locate_handler (keyword);
if (!t || !t->coder)
if (xheader_keyword_deleted_p (keyword)
|| xheader_keyword_override_p (keyword))
return;
- extended_header_init ();
- t->coder (st, keyword, &extended_header, data);
+ xheader_init (&st->xhdr);
+ t->coder (st, keyword, &st->xhdr, data);
}
void
-xheader_read (union block *p, size_t size)
+xheader_read (struct xheader *xhdr, union block *p, size_t size)
{
size_t j = 0;
- size_t nblocks;
- free (extended_header.buffer);
+ xheader_init (xhdr);
size += BLOCKSIZE;
- extended_header.size = size;
- nblocks = (size + BLOCKSIZE - 1) / BLOCKSIZE;
- extended_header.buffer = xmalloc (size + 1);
- extended_header.buffer[size] = '\0';
+ xhdr->size = size;
+ xhdr->buffer = xmalloc (size + 1);
+ xhdr->buffer[size] = '\0';
do
{
if (len > BLOCKSIZE)
len = BLOCKSIZE;
- memcpy (&extended_header.buffer[j], p->buffer, len);
+ memcpy (&xhdr->buffer[j], p->buffer, len);
set_next_block_after (p);
p = find_next_block ();
\f
/* Buildable strings */
-static uintmax_t string_length;
void
-xheader_string_begin ()
+xheader_string_begin (struct xheader *xhdr)
{
- string_length = 0;
+ xhdr->string_length = 0;
}
void
-xheader_string_add (char const *s)
+xheader_string_add (struct xheader *xhdr, char const *s)
{
- if (extended_header.buffer)
+ if (xhdr->buffer)
return;
- extended_header_init ();
- string_length += strlen (s);
- x_obstack_grow (&extended_header, s, strlen (s));
+ xheader_init (xhdr);
+ xhdr->string_length += strlen (s);
+ x_obstack_grow (xhdr, s, strlen (s));
}
bool
-xheader_string_end (char const *keyword)
+xheader_string_end (struct xheader *xhdr, char const *keyword)
{
uintmax_t len;
uintmax_t p;
char const *np;
char *cp;
- if (extended_header.buffer)
+ if (xhdr->buffer)
return false;
- extended_header_init ();
+ xheader_init (xhdr);
- len = strlen (keyword) + string_length + 3; /* ' ' + '=' + '\n' */
+ len = strlen (keyword) + xhdr->string_length + 3; /* ' ' + '=' + '\n' */
do
{
ERROR ((0, 0,
_("Generated keyword/value pair is too long (keyword=%s, length=%s)"),
keyword, nbuf));
- obstack_free (extended_header.stk, obstack_finish (extended_header.stk));
+ obstack_free (xhdr->stk, obstack_finish (xhdr->stk));
return false;
}
- x_obstack_blank (&extended_header, p);
- x_obstack_1grow (&extended_header, '\n');
- cp = obstack_next_free (extended_header.stk) - string_length - p - 1;
- memmove (cp + p, cp, string_length);
+ x_obstack_blank (xhdr, p);
+ x_obstack_1grow (xhdr, '\n');
+ cp = obstack_next_free (xhdr->stk) - xhdr->string_length - p - 1;
+ memmove (cp + p, cp, xhdr->string_length);
cp = stpcpy (cp, np);
*cp++ = ' ';
cp = stpcpy (cp, keyword);
return true;
}
-
+
static void
code_num (uintmax_t value, char const *keyword, struct xheader *xhdr)
static void
mtime_coder (struct tar_stat_info const *st, char const *keyword,
- struct xheader *xhdr, void const *data __attribute__ ((unused)))
+ struct xheader *xhdr, void const *data)
{
- code_time (st->mtime, keyword, xhdr);
+ struct timespec const *mtime = data;
+ code_time (mtime ? *mtime : st->mtime, keyword, xhdr);
}
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);
+ off_t const *v = data;
+ code_num (*v, keyword, xhdr);
}
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);
+ off_t const *v = data;
+ code_num (*v, keyword, xhdr);
}
static void
if (decode_num (&u, arg, TYPE_MAXIMUM (unsigned), keyword))
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);
+ code_num (st->sparse_minor, keyword, xhdr);
}
static void
if (decode_num (&u, arg, TYPE_MAXIMUM (unsigned), keyword))
st->sparse_minor = u;
}
-
+
struct xhdr_tab const xhdr_tab[] = {
{ "atime", atime_coder, atime_decoder, false },
{ "comment", dummy_coder, dummy_decoder, false },