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

34
NEWS
View File

@@ -1,4 +1,4 @@
GNU tar NEWS - User visible changes. 2009-09-08
GNU tar NEWS - User visible changes. 2009-10-07
Please send GNU tar bug reports to <bug-tar@gnu.org>
@@ -53,11 +53,43 @@ and sets the exit code to 1, which means "some files differ".
If the --warning=no-file-removed option is given, no warning
is issued and the exit code remains 0.
* Modification times of PAX extended headers.
Modification times in the ustar header blocks for the
extended headers are set to the mtimes of the corresponding archive
members. This can be overridden by the
--pax-opion='exthdr.mtime=STRING'
command line option. The STRING is either the number of seconds since
the Epoch or a `Time reference' (see below).
Modification times in the ustar header blocks for the global
extended headers are set to the time when tar was invoked.
This can be overridden by the
--pax-opion='globexthdr.mtime=STRING'
command line option. The STRING is either the number of seconds since
the Epoch or a `Time reference' (see below).
* Time references in --pax-option argument.
Any value from the --pax-option argument that is enclosed in a pair
of curly braces. In that case, the string between the braces is
understood either as a textual time representation, as described in
chapter 7, "Date input formats", of the Tar manual, or as a name of
the existing file, starting with `/' or `.'. In the latter
case, the value is replaced with the modification time of that file.
* Bugfixes
** Fix handling of hard link targets by -c --transform.
** Fix hard links recognition with -c --remove-files.
** Fix restoring files from backup (debian bug #508199).
** Correctly restore modes and permissions on existing directories.
** The --remove-files option removes the files only if they were
succesfully stored in the archive.
version 1.22 - Sergey Poznyakoff, 2009-03-05

View File

@@ -3055,8 +3055,8 @@ This option does not affect extraction from archives.
@opsummary{pax-option}
@item --pax-option=@var{keyword-list}
This option is meaningful only with @acronym{POSIX.1-2001} archives
(@pxref{posix}). It modifies the way @command{tar} handles the
This option enables creation of the archive in @acronym{POSIX.1-2001}
format (@pxref{posix}) and modifies the way @command{tar} handles the
extended header keywords. @var{Keyword-list} is a comma-separated
list of keyword options. @xref{PAX keywords}, for a detailed
discussion.
@@ -5400,7 +5400,7 @@ Name of the file owner group.
@vrindex TAR_ATIME, to-command environment
@item TAR_ATIME
Time of last access. It is a decimal number, representing seconds
since the epoch. If the archive provides times with nanosecond
since the Epoch. If the archive provides times with nanosecond
precision, the nanoseconds are appended to the timestamp after a
decimal point.
@@ -9409,6 +9409,13 @@ will use the following default value:
%d/PaxHeaders.%p/%f
@end smallexample
@item exthdr.mtime=@var{value}
This keyword defines the value of the @samp{mtime} field that
is written into the ustar header blocks for the extended headers.
By default, the @samp{mtime} field is set to the modification time
of the archive member described by that extended headers.
@item globexthdr.name=@var{string}
This keyword allows user control over the name that is written into
the ustar header blocks for global extended header records. The name
@@ -9438,6 +9445,13 @@ where @samp{$TMPDIR} represents the value of the @var{TMPDIR}
environment variable. If @var{TMPDIR} is not set, @command{tar}
uses @samp{/tmp}.
@item exthdr.mtime=@var{value}
This keyword defines the value of the @samp{mtime} field that
is written into the ustar header blocks for the global extended headers.
By default, the @samp{mtime} field is set to the time when
@command{tar} was invoked.
@item @var{keyword}=@var{value}
When used with one of archive-creation commands, these keyword/value pairs
will be included at the beginning of the archive in a global extended
@@ -9467,6 +9481,32 @@ the group name will be forced to a new value for all files
stored in the archive.
@end table
In any of the forms described above, the @var{value} may be
a string enclosed in curly braces. In that case, the string
between the braces is understood either as a textual time
representation, as described in @ref{Date input formats}, or a name of
the existing file, starting with @samp{/} or @samp{.}. In the latter
case, the modification time of that file is used.
For example, to set all modification times to the current date, you
use the following option:
@smallexample
--pax-option='mtime:=@{now@}'
@end smallexample
Note quoting of the option's argument.
@cindex archives, binary equivalent
@cindex binary equivalent archives, creating
As another example, here is the option that ensures that any two
archives created using it, will be binary equivalent if they have the
same contents:
@smallexample
--pax-option=exthdr.name=%d/PaxHeaders/%f,atime:=0
@end smallexample
@node Checksumming
@subsection Checksumming Problems

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);
}

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;