bug-tar
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Bug-tar] mtime in x header


From: Sergey Poznyakoff
Subject: Re: [Bug-tar] mtime in x header
Date: Thu, 01 Oct 2009 10:46:17 +0300

Hi Michael,

>  (1) Is this behavior in conformance with the POSIX-2001 spec?

As far as I can tell, yes, it is. POSIX says that the fields of
a pax extended header block, other than its size, are not
meaningful and should be selected such as to provide reasonable
file access and times for the case when the archive is read by
a tar utility not aware of pax extensions, in which case extended
blocks will be extracted as regular files.

>  (2) Is there a way to work around this?

Try the attached patch.  It introduces the exthdr.mtime argument
to the --pax-option.  Its value is either a time in one of the
formats described in [1] or a full path name to the reference file
(just as with the --mtime option). For example, the following invocation
should create binary equivalent archives:

tar \
 --pax-option=exthdr.name=%d/PaxHeaders/%f \
 --pax-option=globexthdr.name=GlobalHead,exthdr.mtime='1 jan 1970',atime:=0 \
 -c -f test.tar test.txt

Regards,
Sergey

[1] http://www.gnu.org/software/tar/manual/html_node/absolute.html

diff --git a/src/common.h b/src/common.h
index 73865ec..e0137af 100644
--- a/src/common.h
+++ b/src/common.h
@@ -453,7 +453,7 @@ void finish_header (struct tar_stat_info *st, union block 
*header,
 void simple_finish_header (union block *header);
 union block * write_extended (bool global, struct tar_stat_info *st,
                              union block *old_header);
-union block *start_private_header (const char *name, size_t size);
+union block *start_private_header (const char *name, size_t size, time_t t);
 void write_eot (void);
 void check_links (void);
 void exclusion_tag_warning (const char *dirname, const char *tagname,
@@ -703,6 +703,10 @@ const char *archive_format_string (enum archive_format 
fmt);
 const char *subcommand_string (enum subcommand c);
 void set_exit_status (int val);
 
+struct tar_args;
+void get_date_or_file (struct tar_args *args, const char *option,
+                      const char *str, struct timespec *ts);
+
 /* Module update.c.  */
 
 extern char *output_start;
@@ -723,7 +727,7 @@ void xheader_finish (struct xheader *hdr);
 void xheader_destroy (struct xheader *hdr);
 char *xheader_xhdr_name (struct tar_stat_info *st);
 char *xheader_ghdr_name (void);
-void xheader_set_option (char *string);
+void xheader_set_option (char *string, struct tar_args *args);
 void xheader_string_begin (struct xheader *xhdr);
 void xheader_string_add (struct xheader *xhdr, char const *s);
 bool xheader_string_end (struct xheader *xhdr, char const *keyword);
diff --git a/src/create.c b/src/create.c
index 6f3113e..a3a08f0 100644
--- a/src/create.c
+++ b/src/create.c
@@ -516,9 +516,8 @@ write_eot (void)
 
 /* Write a "private" header */
 union block *
-start_private_header (const char *name, size_t size)
+start_private_header (const char *name, size_t size, time_t t)
 {
-  time_t t;
   union block *header = find_next_block ();
 
   memset (header->buffer, 0, sizeof (union block));
@@ -526,7 +525,6 @@ start_private_header (const char *name, size_t size)
   tar_name_copy_str (header->header.name, name, NAME_FIELD_SIZE);
   OFF_TO_CHARS (size, header->header.size);
 
-  time (&t);
   TIME_TO_CHARS (t, header->header.mtime);
   MODE_TO_CHARS (S_IFREG|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, header->header.mode);
   UID_TO_CHARS (getuid (), header->header.uid);
@@ -563,8 +561,10 @@ write_gnu_long_link (struct tar_stat_info *st, const char 
*p, char type)
   size_t bufsize;
   union block *header;
   char *tmpname;
-
-  header = start_private_header ("././@LongLink", size);
+  time_t t;
+  
+  time (&t);
+  header = start_private_header ("././@LongLink", size, t);
   FILL(header->header.mtime, '0');
   FILL(header->header.mode, '0');
   FILL(header->header.uid, '0');
diff --git a/src/tar.c b/src/tar.c
index e3300fb..d73fc35 100644
--- a/src/tar.c
+++ b/src/tar.c
@@ -1007,7 +1007,7 @@ struct textual_date
   const char *date;
 };
 
-static void
+void
 get_date_or_file (struct tar_args *args, const char *option,
                  const char *str, struct timespec *ts)
 {
@@ -1841,7 +1841,7 @@ parse_opt (int key, char *arg, struct argp_state *state)
       
     case PAX_OPTION:
       args->pax_option = true;
-      xheader_set_option (arg);
+      xheader_set_option (arg, args);
       break;
       
     case POSIX_OPTION:
diff --git a/src/xheader.c b/src/xheader.c
index c779c0a..e292f50 100644
--- a/src/xheader.c
+++ b/src/xheader.c
@@ -25,6 +25,8 @@
 
 #include "common.h"
 
+struct timespec exthdr_mtime_option;
+
 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));
@@ -157,7 +159,7 @@ xheader_set_single_keyword (char *kw)
 }
 
 static void
-xheader_set_keyword_equal (char *kw, char *eq)
+xheader_set_keyword_equal (char *kw, char *eq, struct tar_args *tar_args)
 {
   bool global = true;
   char *p = eq;
@@ -184,6 +186,9 @@ xheader_set_keyword_equal (char *kw, char *eq)
     }
   else if (strcmp (kw, "exthdr.name") == 0)
     assign_string (&exthdr_name, p);
+  else if (strcmp (kw, "exthdr.mtime") == 0)
+    get_date_or_file (tar_args,
+                     "--pax-option=exthdr.mtime", p, &exthdr_mtime_option);
   else if (strcmp (kw, "globexthdr.name") == 0)
     assign_string (&globexthdr_name, p);
   else
@@ -198,7 +203,7 @@ xheader_set_keyword_equal (char *kw, char *eq)
 }
 
 void
-xheader_set_option (char *string)
+xheader_set_option (char *string, struct tar_args *tar_args)
 {
   char *token;
   for (token = strtok (string, ","); token; token = strtok (NULL, ","))
@@ -207,7 +212,7 @@ xheader_set_option (char *string)
       if (!p)
        xheader_set_single_keyword (token);
       else
-       xheader_set_keyword_equal (token, p);
+       xheader_set_keyword_equal (token, p, tar_args);
     }
 }
 
@@ -369,9 +374,14 @@ xheader_write (char type, char *name, struct xheader *xhdr)
   union block *header;
   size_t size;
   char *p;
-
+  time_t t;
+  
   size = xhdr->size;
-  header = start_private_header (name, size);
+  if (exthdr_mtime_option.tv_sec)
+    t = exthdr_mtime_option.tv_sec;
+  else
+    time (&t);
+  header = start_private_header (name, size, t);
   header->header.typeflag = type;
 
   simple_finish_header (header);

reply via email to

[Prev in Thread] Current Thread [Next in Thread]