mirror of
https://git.savannah.gnu.org/git/tar.git
synced 2026-09-18 22:24:15 +00:00
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:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user