]> Dogcows Code - chaz/tar/commitdiff
Provide a way to explicitly set mtime for extended header ustar blocks.
authorSergey Poznyakoff <gray@gnu.org.ua>
Wed, 7 Oct 2009 18:08:29 +0000 (21:08 +0300)
committerSergey Poznyakoff <gray@gnu.org.ua>
Wed, 7 Oct 2009 18:08:29 +0000 (21:08 +0300)
* 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.

NEWS
doc/tar.texi
src/tar.c
src/xheader.c

diff --git a/NEWS b/NEWS
index bf02a24b7e0614682d86b7a3c7a3dae224df2cba..7624d8022bc6b0232840907a957bec6bd661c441 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -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>
 
 \f
@@ -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.
 
 \f
 version 1.22 - Sergey Poznyakoff, 2009-03-05
index e6093685bfc04e83d082e8c259b5c6a71333df4f..1102e32aba26be6b71a67f033c5f1e1cd69e501f 100644 (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
 
index 0c59352dc2216432f43387b980e1a7a86508a5a0..a639974f49b1b55ef3fb8190c01b5e501a11eca2 100644 (file)
--- a/src/tar.c
+++ b/src/tar.c
@@ -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;
 }
+\f
+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;
+}
+
 \f
 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);
 }
 
 \f
index e8fd6a207171bf7111c9f19821aa745c3c7849fa..5eabdfb4318ecaae63b034cfb6138cc2b4868abf 100644 (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;
 
This page took 0.038456 seconds and 4 git commands to generate.