Provide a way to explicitly set mtime for extended header ustar blocks.

* src/tar.c (struct textual_date): ts is a copy of the structure,
not a pointer to it. Date is a copy as well, hence the `const' is
taken away.
(get_date_or_file): Return 0/1 depending on success/failure.
Copy timestamp to the `ts' member. Store a copy of the string
in `date'.
(report_textual_dates): Report only if verbose_option is set,
but always free the list.
(expand_pax_option): New function.
(parse_opt): Preprocess the argument to xheader_set_option with
expand_pax_option.
(decode_options): Call report_textual_dates unconditionally.
* src/xheader.c (exthdr_mtime_option, exthdr_mtime)
(globexthdr_mtime_option, globexthdr_mtime): New statics.
(xheader_set_keyword_equal): handle exthdr.mtime and globexthdr.mtime.
(xheader_write): Override `t' argument if a corresponding
exthdr.mtime or globexthdr.mtime option is set.
* NEWS: Update
* doc/tar.texi: Document the changes.
This commit is contained in:
Sergey Poznyakoff
2009-10-07 21:08:29 +03:00
parent 7cb84c25ee
commit 63e092548a
4 changed files with 189 additions and 17 deletions
+76 -13
View File
@@ -1002,12 +1002,12 @@ set_stat_signal (const char *name)
struct textual_date
{
struct textual_date *next;
struct timespec *ts;
struct timespec ts;
const char *option;
const char *date;
char *date;
};
static void
static int
get_date_or_file (struct tar_args *args, const char *option,
const char *str, struct timespec *ts)
{
@@ -1030,17 +1030,19 @@ get_date_or_file (struct tar_args *args, const char *option,
WARN ((0, 0, _("Substituting %s for unknown date format %s"),
tartime (*ts, false), quote (str)));
ts->tv_nsec = 0;
return 1;
}
else
{
struct textual_date *p = xmalloc (sizeof (*p));
p->ts = ts;
p->ts = *ts;
p->option = option;
p->date = str;
p->date = xstrdup (str);
p->next = args->textual_date;
args->textual_date = p;
}
}
return 0;
}
static void
@@ -1050,10 +1052,14 @@ report_textual_dates (struct tar_args *args)
for (p = args->textual_date; p; )
{
struct textual_date *next = p->next;
char const *treated_as = tartime (*p->ts, true);
if (strcmp (p->date, treated_as) != 0)
WARN ((0, 0, _("Option %s: Treating date `%s' as %s"),
p->option, p->date, treated_as));
if (verbose_option)
{
char const *treated_as = tartime (p->ts, true);
if (strcmp (p->date, treated_as) != 0)
WARN ((0, 0, _("Option %s: Treating date `%s' as %s"),
p->option, p->date, treated_as));
}
free (p->date);
free (p);
p = next;
}
@@ -1272,6 +1278,60 @@ tar_help_filter (int key, const char *text, void *input)
obstack_free (&stk, NULL);
return s;
}
static char *
expand_pax_option (struct tar_args *targs, const char *arg)
{
struct obstack stk;
char *res;
obstack_init (&stk);
while (*arg)
{
size_t seglen = strcspn (arg, ",");
char *p = memchr (arg, '=', seglen);
if (p)
{
size_t len = p - arg + 1;
obstack_grow (&stk, arg, len);
len = seglen - len;
for (++p; *p && isspace ((unsigned char) *p); p++)
len--;
if (*p == '{' && p[len-1] == '}')
{
struct timespec ts;
char *tmp = xmalloc (len);
memcpy (tmp, p + 1, len-2);
tmp[len-2] = 0;
if (get_date_or_file (targs, "--pax-option", tmp, &ts) == 0)
{
char buf[UINTMAX_STRSIZE_BOUND], *s;
s = umaxtostr (ts.tv_sec, buf);
obstack_grow (&stk, s, strlen (s));
}
else
obstack_grow (&stk, p, len);
free (tmp);
}
else
obstack_grow (&stk, p, len);
}
else
obstack_grow (&stk, arg, seglen);
arg += seglen;
if (*arg)
{
obstack_1grow (&stk, *arg);
arg++;
}
}
obstack_1grow (&stk, 0);
res = xstrdup (obstack_finish (&stk));
obstack_free (&stk, NULL);
return res;
}
static error_t
parse_opt (int key, char *arg, struct argp_state *state)
@@ -1840,8 +1900,12 @@ parse_opt (int key, char *arg, struct argp_state *state)
break;
case PAX_OPTION:
args->pax_option = true;
xheader_set_option (arg);
{
char *tmp = expand_pax_option (args, arg);
args->pax_option = true;
xheader_set_option (tmp);
free (tmp);
}
break;
case POSIX_OPTION:
@@ -2440,8 +2504,7 @@ decode_options (int argc, char **argv)
checkpoint_finish_compile ();
if (verbose_option)
report_textual_dates (&args);
report_textual_dates (&args);
}
+37
View File
@@ -96,9 +96,15 @@ static struct keyword_list *global_header_override_list;
/* 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)
{
@@ -156,6 +162,21 @@ xheader_set_single_keyword (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)
{
@@ -186,6 +207,10 @@ xheader_set_keyword_equal (char *kw, char *eq)
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))
@@ -371,6 +396,18 @@ xheader_write (char type, char *name, time_t t, struct xheader *xhdr)
char *p;
size = xhdr->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;