]> Dogcows Code - chaz/tar/commitdiff
Don't filter time stamps through the resolution supported
authorPaul Eggert <eggert@cs.ucla.edu>
Sat, 17 Sep 2005 06:41:55 +0000 (06:41 +0000)
committerPaul Eggert <eggert@cs.ucla.edu>
Sat, 17 Sep 2005 06:41:55 +0000 (06:41 +0000)
by struct stat; keep them to full nanosecond resolution.
This affects behavior only on older hosts or file systems
that have lower-resolution time stamps.
* src/common.h (OLDER_STAT_TIME): Parenthesize arg.
(OLDER_TAR_STAT_TIME): New macro.
(code_timespec): New function.
(BILLION, LOG10_BILLION, TIMESPEC_STRSIZE_BOUND): New constants.
* src/compare.c (diff_file): Use full time stamp resolution.
* src/create.c (start_header, dump_file0): Likewise.
(start_header, dump_file0): Adjust to new structure layout.
(dump_regular_finish): Simplify by using timespec_cmp.
* src/extract.c (struct delayed_set_stat): Don't store stat info
that we don't need, to save space.  All uses changed.
(struct delayed_set_stat, struct delayed_link, file_newer_p):
(create_placeholder_file, extract_link, apply_delayed_links):
Use full time stamp resolution.
(check_time): Use code_timespec rather than rolling our own code.
(set_stat, delay_set_stat): Arg now points to tar_stat_info to
avoid losing time information.  All callers changed.
* src/list.c (read_and, decode_header, print_heaeder):
Use full time stamp resolution.
* src/misc.c (code_timespec): New function.
* src/tar.h (struct tar_stat_info): Record atime, mtime, ctime
separately, for benefit of hosts with lower resolution.
* src/update.c (update_archive): Use full time stamp resolution.
* src/xheader.c (code_time): Use new code_timespec function
to simplify code.
(atime_coder, atime_decoder, ctime_coder, ctime_decoder):
(mtime_coder, mtime_decoder): Use full time stamp resolution.

Report time stamps to full resolution in environment.
Report memory allocation failures rather than ignoring them.
* src/system.c (time_to_env): New function.
(oct_to_env, str_to_env, chr_to_env): Report memory allocation failures.
(stat_to_env): Report full resolution in time stamps.

ChangeLog
src/common.h
src/compare.c
src/create.c
src/extract.c
src/list.c
src/misc.c
src/system.c
src/tar.h
src/update.c
src/xheader.c

index dcc627a53c9b9214d4b2611375a0dd549c9a433d..b35e183b98446e02faa26900e0bea8e82003c8ae 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,42 @@
+2005-09-16  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Don't filter time stamps through the resolution supported
+       by struct stat; keep them to full nanosecond resolution.
+       This affects behavior only on older hosts or file systems
+       that have lower-resolution time stamps.
+       * src/common.h (OLDER_STAT_TIME): Parenthesize arg.
+       (OLDER_TAR_STAT_TIME): New macro.
+       (code_timespec): New function.
+       (BILLION, LOG10_BILLION, TIMESPEC_STRSIZE_BOUND): New constants.
+       * src/compare.c (diff_file): Use full time stamp resolution.
+       * src/create.c (start_header, dump_file0): Likewise.
+       (start_header, dump_file0): Adjust to new structure layout.
+       (dump_regular_finish): Simplify by using timespec_cmp.
+       * src/extract.c (struct delayed_set_stat): Don't store stat info
+       that we don't need, to save space.  All uses changed.
+       (struct delayed_set_stat, struct delayed_link, file_newer_p):
+       (create_placeholder_file, extract_link, apply_delayed_links):
+       Use full time stamp resolution.
+       (check_time): Use code_timespec rather than rolling our own code.
+       (set_stat, delay_set_stat): Arg now points to tar_stat_info to
+       avoid losing time information.  All callers changed.
+       * src/list.c (read_and, decode_header, print_heaeder):
+       Use full time stamp resolution.
+       * src/misc.c (code_timespec): New function.
+       * src/tar.h (struct tar_stat_info): Record atime, mtime, ctime
+       separately, for benefit of hosts with lower resolution.
+       * src/update.c (update_archive): Use full time stamp resolution.
+       * src/xheader.c (code_time): Use new code_timespec function
+       to simplify code.
+       (atime_coder, atime_decoder, ctime_coder, ctime_decoder):
+       (mtime_coder, mtime_decoder): Use full time stamp resolution.
+
+       Report time stamps to full resolution in environment.
+       Report memory allocation failures rather than ignoring them.
+       * src/system.c (time_to_env): New function.
+       (oct_to_env, str_to_env, chr_to_env): Report memory allocation failures.
+       (stat_to_env): Report full resolution in time stamps.
+
 2005-09-16  Paul Eggert  <eggert@cs.ucla.edu>
 
        Merge changes from gnulib for file system sub-second time stamps.
index be7f35d15dbfa7f52c584c2eae362a1f7855fc20..a4352c3914a1d833782ed0c4298bd2ad6603cb06 100644 (file)
@@ -189,7 +189,11 @@ GLOBAL struct timespec newer_mtime_option;
 /* Return true if the struct stat ST's M time is less than
    newer_mtime_option.  */
 #define OLDER_STAT_TIME(st, m) \
-  (timespec_cmp (get_stat_##m##time (&st), newer_mtime_option) < 0)
+  (timespec_cmp (get_stat_##m##time (&(st)), newer_mtime_option) < 0)
+
+/* Likewise, for struct tar_stat_info ST.  */
+#define OLDER_TAR_STAT_TIME(st, m) \
+  (timespec_cmp ((st).m##time, newer_mtime_option) < 0)
 
 /* Zero if there is no recursion, otherwise FNM_LEADING_DIR.  */
 GLOBAL int recursion_option;
@@ -490,6 +494,10 @@ char *quote_copy_string (const char *);
 int unquote_string (char *);
 
 void code_ns_fraction (int, char *);
+char const *code_timespec (struct timespec, char *);
+enum { BILLION = 1000000000, LOG10_BILLION = 9 };
+enum { TIMESPEC_STRSIZE_BOUND =
+         UINTMAX_STRSIZE_BOUND + LOG10_BILLION + sizeof "-." - 1 };
 
 size_t dot_dot_prefix_len (char const *);
 
index 98a953bf403aa524ead280729c106f1379fd1e35..02240aa3bf953797e926ce920e181b1e888b8b4b 100644 (file)
@@ -224,7 +224,7 @@ diff_file (void)
       if (!sys_compare_gid (&stat_data, &current_stat_info.stat))
        report_difference (&current_stat_info, _("Gid differs"));
 
-      if (stat_data.st_mtime != current_stat_info.stat.st_mtime)
+      if (timespec_cmp (get_stat_mtime (&stat_data), current_stat_info.mtime))
        report_difference (&current_stat_info, _("Mod time differs"));
       if (current_header->header.typeflag != GNUTYPE_SPARSE &&
          stat_data.st_size != current_stat_info.stat.st_size)
index 9e3922dd9d3c0d895a642236b800ae85686041a3..c5a5d712ad4603f6933c7bbeff976a620e8b9ab4 100644 (file)
@@ -353,7 +353,7 @@ string_to_chars (char const *str, char *p, size_t s)
 /* A file is considered dumpable if it is sparse and both --sparse and --totals
    are specified.
    Otherwise, it is dumpable unless any of the following conditions occur:
-   
+
    a) it is empty *and* world-readable, or
    b) current archive is /dev/null */
 
@@ -698,7 +698,7 @@ start_header (struct tar_stat_info *st)
   }
 
   {
-    struct timespec mtime = get_stat_mtime (&st->stat);
+    struct timespec mtime = st->mtime;
     if (archive_format == POSIX_FORMAT)
       {
        if (MAX_OCTAL_VAL (header->header.mtime) < mtime.tv_sec
@@ -747,8 +747,8 @@ start_header (struct tar_stat_info *st)
   else if (incremental_option)
     if (archive_format == OLDGNU_FORMAT || archive_format == GNU_FORMAT)
       {
-       TIME_TO_CHARS (st->stat.st_atime, header->oldgnu_header.atime);
-       TIME_TO_CHARS (st->stat.st_ctime, header->oldgnu_header.ctime);
+       TIME_TO_CHARS (st->atime.tv_sec, header->oldgnu_header.atime);
+       TIME_TO_CHARS (st->ctime.tv_sec, header->oldgnu_header.ctime);
       }
 
   header->header.typeflag = archive_format == V7_FORMAT ? AREGTYPE : REGTYPE;
@@ -954,9 +954,8 @@ dump_regular_finish (int fd, struct tar_stat_info *st,
        {
          stat_diag (st->orig_file_name);
        }
-      else if (final_stat.st_ctime != original_ctime.tv_sec
-              || (get_stat_ctime (&final_stat).tv_nsec
-                  != original_ctime.tv_nsec))
+      else if (timespec_cmp (get_stat_ctime (&final_stat), original_ctime)
+              != 0)
        {
          WARN ((0, 0, _("%s: file changed as we read it"),
                 quotearg_colon (st->orig_file_name)));
@@ -1408,9 +1407,9 @@ dump_file0 (struct tar_stat_info *st, char *p,
       return;
     }
   st->archive_file_size = st->stat.st_size;
-  original_ctime = get_stat_ctime (&st->stat);
-  restore_times[0] = get_stat_atime (&st->stat);
-  restore_times[1] = get_stat_mtime (&st->stat);
+  st->atime = restore_times[0] = get_stat_atime (&st->stat);
+  st->mtime = restore_times[1] = get_stat_mtime (&st->stat);
+  st->ctime = original_ctime = get_stat_ctime (&st->stat);
 
 #ifdef S_ISHIDDEN
   if (S_ISHIDDEN (st->stat.st_mode))
@@ -1433,8 +1432,8 @@ dump_file0 (struct tar_stat_info *st, char *p,
 
   if (!(incremental_option && !is_individual_file (p))
       && !S_ISDIR (st->stat.st_mode)
-      && OLDER_STAT_TIME (st->stat, m)
-      && (!after_date_option || OLDER_STAT_TIME (st->stat, c)))
+      && OLDER_TAR_STAT_TIME (*st, m)
+      && (!after_date_option || OLDER_TAR_STAT_TIME (*st, c)))
     {
       if (!incremental_option && verbose_option)
        WARN ((0, 0, _("%s: file is unchanged; not dumped"),
index 80f2f9ceec68d1616d311680c6537e30cb83b348..d826371683a62a2f4d4ca5160a0a3f49974b75c4 100644 (file)
@@ -57,7 +57,13 @@ enum permstatus
 struct delayed_set_stat
   {
     struct delayed_set_stat *next;
-    struct stat stat_info;
+    dev_t dev;
+    ino_t ino;
+    mode_t mode;
+    uid_t uid;
+    gid_t gid;
+    struct timespec atime;
+    struct timespec mtime;
     size_t file_name_len;
     mode_t invert_permissions;
     enum permstatus permstatus;
@@ -76,7 +82,7 @@ struct delayed_link
     /* The device, inode number and last-modified time of the placeholder.  */
     dev_t dev;
     ino_t ino;
-    time_t mtime;
+    struct timespec mtime;
 
     /* True if the link is symbolic.  */
     bool is_symlink;
@@ -206,23 +212,23 @@ check_time (char const *file_name, struct timespec t)
       gettime (&now);
       if (timespec_cmp (now, t) < 0)
        {
-         unsigned long int ds = t.tv_sec - now.tv_sec;
-         int dns = t.tv_nsec - now.tv_nsec;
-         char dnsbuf[sizeof ".FFFFFFFFF"];
-         if (dns < 0)
+         char buf[TIMESPEC_STRSIZE_BOUND];
+         struct timespec diff;
+         diff.tv_sec = t.tv_sec - now.tv_sec;
+         diff.tv_nsec = t.tv_nsec - now.tv_nsec;
+         if (diff.tv_nsec < 0)
            {
-             dns += 1000000000;
-             ds--;
+             diff.tv_nsec += BILLION;
+             diff.tv_sec--;
            }
-         code_ns_fraction (dns, dnsbuf);
-         WARN ((0, 0, _("%s: time stamp %s is %lu%s s in the future"),
-                file_name, tartime (t, true), ds, dnsbuf));
+         WARN ((0, 0, _("%s: time stamp %s is %s s in the future"),
+                file_name, tartime (t, true), code_timespec (diff, buf)));
        }
     }
 }
 
 /* Restore stat attributes (owner, group, mode and times) for
-   FILE_NAME, using information given in *STAT_INFO.
+   FILE_NAME, using information given in *ST.
    If CUR_INFO is nonzero, *CUR_INFO is the
    file's currernt status.
    If not restoring permissions, invert the
@@ -237,7 +243,7 @@ check_time (char const *file_name, struct timespec t)
 
 static void
 set_stat (char const *file_name,
-         struct stat const *stat_info,
+         struct tar_stat_info const *st,
          struct stat const *cur_info,
          mode_t invert_permissions, enum permstatus permstatus,
          char typeflag)
@@ -256,8 +262,8 @@ set_stat (char const *file_name,
          /* FIXME: incremental_option should set ctime too, but how?  */
 
          struct timespec ts[2];
-         ts[0] = incremental_option ? get_stat_atime (stat_info) : start_time;
-         ts[1] = get_stat_mtime (stat_info);
+         ts[0] = incremental_option ? st->atime : start_time;
+         ts[1] = st->mtime;
 
          if (utimens (file_name, ts) != 0)
            utime_error (file_name);
@@ -272,7 +278,7 @@ set_stat (char const *file_name,
         done, it is not possible anymore to change file permissions, so we
         have to set permissions prior to possibly giving files away.  */
 
-      set_mode (file_name, stat_info, cur_info,
+      set_mode (file_name, &st->stat, cur_info,
                invert_permissions, permstatus, typeflag);
     }
 
@@ -286,48 +292,54 @@ set_stat (char const *file_name,
       if (typeflag == SYMTYPE)
        {
 #if HAVE_LCHOWN
-         if (lchown (file_name, stat_info->st_uid, stat_info->st_gid) < 0)
+         if (lchown (file_name, st->stat.st_uid, st->stat.st_gid) < 0)
            chown_error_details (file_name,
-                                stat_info->st_uid, stat_info->st_gid);
+                                st->stat.st_uid, st->stat.st_gid);
 #endif
        }
       else
        {
-         if (chown (file_name, stat_info->st_uid, stat_info->st_gid) < 0)
+         if (chown (file_name, st->stat.st_uid, st->stat.st_gid) < 0)
            chown_error_details (file_name,
-                                stat_info->st_uid, stat_info->st_gid);
+                                st->stat.st_uid, st->stat.st_gid);
 
          /* On a few systems, and in particular, those allowing to give files
             away, changing the owner or group destroys the suid or sgid bits.
             So let's attempt setting these bits once more.  */
-         if (stat_info->st_mode & (S_ISUID | S_ISGID | S_ISVTX))
-           set_mode (file_name, stat_info, 0,
+         if (st->stat.st_mode & (S_ISUID | S_ISGID | S_ISVTX))
+           set_mode (file_name, &st->stat, 0,
                      invert_permissions, permstatus, typeflag);
        }
     }
 }
 
 /* Remember to restore stat attributes (owner, group, mode and times)
-   for the directory FILE_NAME, using information given in *STAT_INFO,
+   for the directory FILE_NAME, using information given in *ST,
    once we stop extracting files into that directory.
    If not restoring permissions, remember to invert the
    INVERT_PERMISSIONS bits from the file's current permissions.
    PERMSTATUS specifies the status of the file's permissions.  */
 static void
-delay_set_stat (char const *file_name, struct stat const *stat_info,
+delay_set_stat (char const *file_name, struct tar_stat_info const *st,
                mode_t invert_permissions, enum permstatus permstatus)
 {
   size_t file_name_len = strlen (file_name);
   struct delayed_set_stat *data =
     xmalloc (offsetof (struct delayed_set_stat, file_name)
             + file_name_len + 1);
+  data->next = delayed_set_stat_head;
+  data->dev = st->stat.st_dev;
+  data->ino = st->stat.st_ino;
+  data->mode = st->stat.st_mode;
+  data->uid = st->stat.st_uid;
+  data->gid = st->stat.st_gid;
+  data->atime = st->atime;
+  data->mtime = st->mtime;
   data->file_name_len = file_name_len;
-  strcpy (data->file_name, file_name);
   data->invert_permissions = invert_permissions;
   data->permstatus = permstatus;
   data->after_links = 0;
-  data->stat_info = *stat_info;
-  data->next = delayed_set_stat_head;
+  strcpy (data->file_name, file_name);
   delayed_set_stat_head = data;
 }
 
@@ -352,7 +364,13 @@ repair_delayed_set_stat (char const *dir,
       if (st.st_dev == dir_stat_info->st_dev
          && st.st_ino == dir_stat_info->st_ino)
        {
-         data->stat_info = current_stat_info.stat;
+         data->dev = current_stat_info.stat.st_dev;
+         data->ino = current_stat_info.stat.st_ino;
+         data->mode = current_stat_info.stat.st_mode;
+         data->uid = current_stat_info.stat.st_uid;
+         data->gid = current_stat_info.stat.st_gid;
+         data->atime = current_stat_info.atime;
+         data->mtime = current_stat_info.mtime;
          data->invert_permissions =
            (MODE_RWX & (current_stat_info.stat.st_mode ^ st.st_mode));
          data->permstatus = ARCHIVED_PERMSTATUS;
@@ -408,7 +426,7 @@ make_directories (char *file_name)
             invert_permissions is zero, because
             repair_delayed_set_stat may need to update the struct.  */
          delay_set_stat (file_name,
-                         &current_stat_info.stat /* ignored */,
+                         &current_stat_info /* ignored */,
                          invert_permissions, INTERDIR_PERMSTATUS);
 
          print_for_mkdir (file_name, cursor - file_name, mode);
@@ -448,7 +466,7 @@ file_newer_p (const char *file_name, struct tar_stat_info *tar_stat)
       return errno != ENOENT;
     }
   if (!S_ISDIR (st.st_mode)
-      && st.st_mtime >= tar_stat->stat.st_mtime)
+      && timespec_cmp (tar_stat->mtime, get_stat_mtime (&st)) <= 0)
     {
       return true;
     }
@@ -551,8 +569,7 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_links)
              stat_error (data->file_name);
              skip_this_one = 1;
            }
-         else if (! (st.st_dev == data->stat_info.st_dev
-                     && (st.st_ino == data->stat_info.st_ino)))
+         else if (! (st.st_dev == data->dev && st.st_ino == data->ino))
            {
              ERROR ((0, 0,
                      _("%s: Directory renamed before its status could be extracted"),
@@ -562,8 +579,16 @@ apply_nonancestor_delayed_set_stat (char const *file_name, bool after_links)
        }
 
       if (! skip_this_one)
-       set_stat (data->file_name, &data->stat_info, cur_info,
-                 data->invert_permissions, data->permstatus, DIRTYPE);
+       {
+         struct tar_stat_info st;
+         st.stat.st_mode = data->mode;
+         st.stat.st_uid = data->uid;
+         st.stat.st_gid = data->gid;
+         st.atime = data->atime;
+         st.mtime = data->mtime;
+         set_stat (data->file_name, &st, cur_info,
+                   data->invert_permissions, data->permstatus, DIRTYPE);
+       }
 
       delayed_set_stat_head = data->next;
       free (data);
@@ -627,7 +652,7 @@ extract_dir (char *file_name, int typeflag)
   if (status == 0
       || old_files_option == DEFAULT_OLD_FILES
       || old_files_option == OVERWRITE_OLD_FILES)
-    delay_set_stat (file_name, &current_stat_info.stat,
+    delay_set_stat (file_name, &current_stat_info,
                    MODE_RWX & (mode ^ current_stat_info.stat.st_mode),
                    (status == 0
                     ? ARCHIVED_PERMSTATUS
@@ -771,7 +796,7 @@ extract_file (char *file_name, int typeflag)
   if (to_command_option)
     sys_wait_command ();
   else
-    set_stat (file_name, &current_stat_info.stat, 0, 0,
+    set_stat (file_name, &current_stat_info, NULL, 0,
              (old_files_option == OVERWRITE_OLD_FILES ?
               UNKNOWN_PERMSTATUS : ARCHIVED_PERMSTATUS),
              typeflag);
@@ -815,7 +840,7 @@ create_placeholder_file (char *file_name, bool is_symlink, int *interdir_made)
       delayed_link_head = p;
       p->dev = st.st_dev;
       p->ino = st.st_ino;
-      p->mtime = st.st_mtime;
+      p->mtime = get_stat_mtime (&st);
       p->is_symlink = is_symlink;
       if (is_symlink)
        {
@@ -842,8 +867,8 @@ create_placeholder_file (char *file_name, bool is_symlink, int *interdir_made)
                stat_error (h->file_name);
              else
                {
-                 h->stat_info.st_dev = st.st_dev;
-                 h->stat_info.st_ino = st.st_ino;
+                 h->dev = st.st_dev;
+                 h->ino = st.st_ino;
                }
            }
          while ((h = h->next) && ! h->after_links);
@@ -879,7 +904,7 @@ extract_link (char *file_name, int typeflag)
            for (; ds; ds = ds->next)
              if (ds->dev == st1.st_dev
                  && ds->ino == st1.st_ino
-                 && ds->mtime == st1.st_mtime)
+                 && timespec_cmp (ds->mtime, get_stat_mtime (&st1)) == 0)
                {
                  struct string_list *p =  xmalloc (offsetof (struct string_list, string)
                                                    + strlen (file_name) + 1);
@@ -926,7 +951,7 @@ extract_symlink (char *file_name, int typeflag)
       break;
 
   if (status == 0)
-    set_stat (file_name, &current_stat_info.stat, 0, 0, 0, SYMTYPE);
+    set_stat (file_name, &current_stat_info, NULL, 0, 0, SYMTYPE);
   else
     symlink_error (current_stat_info.link_name, file_name);
   return status;
@@ -958,7 +983,8 @@ extract_node (char *file_name, int typeflag)
   if (status != 0)
     mknod_error (file_name);
   else
-    set_stat (file_name, &current_stat_info.stat, 0, 0, ARCHIVED_PERMSTATUS, typeflag);
+    set_stat (file_name, &current_stat_info, NULL, 0,
+             ARCHIVED_PERMSTATUS, typeflag);
   return status;
 }
 #endif
@@ -975,7 +1001,7 @@ extract_fifo (char *file_name, int typeflag)
       break;
 
   if (status == 0)
-    set_stat (file_name, &current_stat_info.stat, NULL, 0,
+    set_stat (file_name, &current_stat_info, NULL, 0,
              ARCHIVED_PERMSTATUS, typeflag);
   else
     mkfifo_error (file_name);
@@ -1217,7 +1243,7 @@ apply_delayed_links (void)
          if (lstat (source, &st) == 0
              && st.st_dev == ds->dev
              && st.st_ino == ds->ino
-             && st.st_mtime == ds->mtime)
+             && timespec_cmp (get_stat_mtime (&st), ds->mtime) == 0)
            {
              /* Unlink the placeholder, then create a hard link if possible,
                 a symbolic link otherwise.  */
@@ -1234,10 +1260,11 @@ apply_delayed_links (void)
                symlink_error (ds->target, source);
              else
                {
+                 struct tar_stat_info st1;
+                 st1.stat.st_uid = ds->uid;
+                 st1.stat.st_gid = ds->gid;
+                 set_stat (source, &st1, NULL, 0, 0, SYMTYPE);
                  valid_source = source;
-                 st.st_uid = ds->uid;
-                 st.st_gid = ds->gid;
-                 set_stat (source, &st, 0, 0, 0, SYMTYPE);
                }
            }
        }
index 633713ac41d3e5093f3331385134e43b05066de9..d8591634380ed81e62264a16ad07f7612c9ccf9a 100644 (file)
@@ -99,8 +99,8 @@ read_and (void (*do_something) (void))
                      /* FIXME: Grab fractional time stamps from
                         extended header.  */
                      mtime.tv_nsec = 0,
-                     set_stat_mtime (&current_stat_info.stat, mtime),
-                     OLDER_STAT_TIME (current_stat_info.stat, m)))
+                     current_stat_info.mtime = mtime,
+                     OLDER_TAR_STAT_TIME (current_stat_info, m)))
              || excluded_name (current_stat_info.file_name))
            {
              switch (current_header->header.typeflag)
@@ -243,7 +243,7 @@ list_archive (void)
        }
       if (multi_volume_option)
        assign_string (&save_name, 0);
-      
+
       return;
     }
 
@@ -512,9 +512,6 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
               enum archive_format *format_pointer, int do_user_group)
 {
   enum archive_format format;
-  struct timespec atime;
-  struct timespec ctime;
-  struct timespec mtime;
 
   if (strcmp (header->header.magic, TMAGIC) == 0)
     {
@@ -536,9 +533,8 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
   *format_pointer = format;
 
   stat_info->stat.st_mode = MODE_FROM_HEADER (header->header.mode);
-  mtime.tv_sec = TIME_FROM_HEADER (header->header.mtime);
-  mtime.tv_nsec = 0;
-  set_stat_mtime (&stat_info->stat, mtime);
+  stat_info->mtime.tv_sec = TIME_FROM_HEADER (header->header.mtime);
+  stat_info->mtime.tv_nsec = 0;
   assign_string (&stat_info->uname,
                 header->header.uname[0] ? header->header.uname : NULL);
   assign_string (&stat_info->gname,
@@ -546,21 +542,18 @@ decode_header (union block *header, struct tar_stat_info *stat_info,
 
   if (format == OLDGNU_FORMAT && incremental_option)
     {
-      atime.tv_sec = TIME_FROM_HEADER (header->oldgnu_header.atime);
-      ctime.tv_sec = TIME_FROM_HEADER (header->oldgnu_header.ctime);
-      atime.tv_nsec = ctime.tv_nsec = 0;
+      stat_info->atime.tv_sec = TIME_FROM_HEADER (header->oldgnu_header.atime);
+      stat_info->ctime.tv_sec = TIME_FROM_HEADER (header->oldgnu_header.ctime);
+      stat_info->atime.tv_nsec = stat_info->ctime.tv_nsec = 0;
     }
   else if (format == STAR_FORMAT)
     {
-      atime.tv_sec = TIME_FROM_HEADER (header->star_header.atime);
-      ctime.tv_sec = TIME_FROM_HEADER (header->star_header.ctime);
-      atime.tv_nsec = ctime.tv_nsec = 0;
+      stat_info->atime.tv_sec = TIME_FROM_HEADER (header->star_header.atime);
+      stat_info->ctime.tv_sec = TIME_FROM_HEADER (header->star_header.ctime);
+      stat_info->atime.tv_nsec = stat_info->ctime.tv_nsec = 0;
     }
   else
-    atime = ctime = start_time;
-
-  set_stat_atime (&stat_info->stat, atime);
-  set_stat_ctime (&stat_info->stat, ctime);
+    stat_info->atime = stat_info->ctime = start_time;
 
   if (format == V7_FORMAT)
     {
@@ -1094,7 +1087,7 @@ print_header (struct tar_stat_info *st, off_t block_ordinal)
 
       /* Time stamp.  */
 
-      time_stamp = tartime (get_stat_mtime (&st->stat), false);
+      time_stamp = tartime (st->mtime, false);
       time_stamp_len = strlen (time_stamp);
       if (datewidth < time_stamp_len)
        datewidth = time_stamp_len;
index 55bedd2b2c901669ff4025feadbb2fd338984831..7322dd2a0f56c89cde3db3d24c14c51bb4ad1a4a 100644 (file)
@@ -239,6 +239,27 @@ code_ns_fraction (int ns, char *p)
        }
     }
 }
+
+char const *
+code_timespec (struct timespec t, char sbuf[TIMESPEC_STRSIZE_BOUND])
+{
+  time_t s = t.tv_sec;
+  int ns = t.tv_nsec;
+  char *np;
+  bool negative = s < 0;
+
+  if (negative && ns != 0)
+    {
+      s++;
+      ns = BILLION - ns;
+    }
+
+  np = umaxtostr (negative ? - (uintmax_t) s : (uintmax_t) s, sbuf + 1);
+  if (negative)
+    *--np = '-';
+  code_ns_fraction (ns, sbuf + UINTMAX_STRSIZE_BOUND);
+  return np;
+}
 \f
 /* File handling.  */
 
index b1e4eef78ba3c53c53110f63e5d569a2a0e562ea..05313db88a9190297ecd0ca90f9a0f742617c8c2 100644 (file)
@@ -611,7 +611,16 @@ dec_to_env (char *envar, uintmax_t num)
   char *numstr;
 
   numstr = STRINGIFY_BIGINT (num, buf);
-  setenv (envar, numstr, 1);
+  if (setenv (envar, numstr, 1) != 0)
+    xalloc_die ();
+}
+
+static void
+time_to_env (char *envar, struct timespec t)
+{
+  char buf[TIMESPEC_STRSIZE_BOUND];
+  if (setenv (envar, code_timespec (t, buf), 1) != 0)
+    xalloc_die ();
 }
 
 static void
@@ -620,14 +629,18 @@ oct_to_env (char *envar, unsigned long num)
   char buf[1+1+(sizeof(unsigned long)*CHAR_BIT+2)/3];
 
   snprintf (buf, sizeof buf, "0%lo", num);
-  setenv (envar, buf, 1);
+  if (setenv (envar, buf, 1) != 0)
+    xalloc_die ();
 }
 
 static void
 str_to_env (char *envar, char const *str)
 {
   if (str)
-    setenv (envar, str, 1);
+    {
+      if (setenv (envar, str, 1) != 0)
+       xalloc_die ();
+    }
   else
     unsetenv (envar);
 }
@@ -638,7 +651,8 @@ chr_to_env (char *envar, char c)
   char buf[2];
   buf[0] = c;
   buf[1] = 0;
-  setenv (envar, buf, 1);
+  if (setenv (envar, buf, 1) != 0)
+    xalloc_die ();
 }
 
 static void
@@ -650,9 +664,9 @@ stat_to_env (char *name, char type, struct tar_stat_info *st)
   str_to_env ("TAR_REALNAME", st->file_name);
   str_to_env ("TAR_UNAME", st->uname);
   str_to_env ("TAR_GNAME", st->gname);
-  dec_to_env ("TAR_MTIME", st->stat.st_mtime);
-  dec_to_env ("TAR_ATIME", st->stat.st_atime);
-  dec_to_env ("TAR_CTIME", st->stat.st_ctime);
+  time_to_env ("TAR_ATIME", st->atime);
+  time_to_env ("TAR_MTIME", st->mtime);
+  time_to_env ("TAR_CTIME", st->ctime);
   dec_to_env ("TAR_SIZE", st->stat.st_size);
   dec_to_env ("TAR_UID", st->stat.st_uid);
   dec_to_env ("TAR_GID", st->stat.st_gid);
index 225e7214ff404aaa705c34be3d0c4d55650913bc..78837be5e4371856932a11ae1e059e205d1ca5e3 100644 (file)
--- a/src/tar.h
+++ b/src/tar.h
@@ -281,6 +281,12 @@ struct tar_stat_info
   char          *gname;     /* group name of owner */
   struct stat   stat;       /* regular filesystem stat */
 
+  /* STAT doesn't always have access, data modification, and status
+     change times in a convenient form, so store them separately.  */
+  struct timespec atime;
+  struct timespec mtime;
+  struct timespec ctime;
+
   off_t archive_file_size;  /* Size of file as stored in the archive.
                               Equals stat.st_size for non-sparse files */
 
index 0db091de9a809d1b3b2d5c103b45dd7977f10307..f28c6dc3f3ca0a7e9c9c39852689fe03161607a2 100644 (file)
@@ -129,7 +129,7 @@ update_archive (void)
            decode_header (current_header, &current_stat_info,
                           &current_format, 0);
            archive_format = current_format;
-           
+
            if (subcommand_option == UPDATE_SUBCOMMAND
                && (name = name_scan (current_stat_info.file_name)) != NULL)
              {
@@ -138,7 +138,9 @@ update_archive (void)
                chdir_do (name->change_dir);
                if (deref_stat (dereference_option,
                                current_stat_info.file_name, &s) == 0
-                   && s.st_mtime <= current_stat_info.stat.st_mtime)
+                   && (timespec_cmp (get_stat_mtime (&s),
+                                     current_stat_info.mtime)
+                       <= 0))
                  add_avoided_name (current_stat_info.file_name);
              }
 
index 48c857f3f6fbbceda633f440a64218ee493e5f47..34b3c61656df30b9a111cc3432505dc365eda22d 100644 (file)
@@ -57,8 +57,6 @@ static size_t global_header_count;
 
    However it should wait until buffer.c is finally rewritten */
 
-enum { BILLION = 1000000000, LOG10_BILLION = 9 };
-
 \f
 /* Keyword options */
 
@@ -747,23 +745,8 @@ decode_string (char **string, char const *arg)
 static void
 code_time (struct timespec t, char const *keyword, struct xheader *xhdr)
 {
-  time_t s = t.tv_sec;
-  int ns = t.tv_nsec;
-  char sbuf[1/*"-"*/ + UINTMAX_STRSIZE_BOUND + 1/*"."*/ + LOG10_BILLION];
-  char *np;
-  bool negative = s < 0;
-
-  if (negative && ns != 0)
-    {
-      s++;
-      ns = BILLION - ns;
-    }
-
-  np = umaxtostr (negative ? - (uintmax_t) s : (uintmax_t) s, sbuf + 1);
-  if (negative)
-    *--np = '-';
-  code_ns_fraction (ns, sbuf + UINTMAX_STRSIZE_BOUND);
-  xheader_print (xhdr, keyword, np);
+  char buf[TIMESPEC_STRSIZE_BOUND];
+  xheader_print (xhdr, keyword, code_timespec (t, buf));
 }
 
 static bool
@@ -900,7 +883,7 @@ static void
 atime_coder (struct tar_stat_info const *st, char const *keyword,
             struct xheader *xhdr, void *data __attribute__ ((unused)))
 {
-  code_time (get_stat_atime (&st->stat), keyword, xhdr);
+  code_time (st->atime, keyword, xhdr);
 }
 
 static void
@@ -908,7 +891,7 @@ atime_decoder (struct tar_stat_info *st, char const *arg)
 {
   struct timespec ts;
   if (decode_time (&ts, arg, "atime"))
-    set_stat_atime (&st->stat, ts);
+    st->atime = ts;
 }
 
 static void
@@ -956,7 +939,7 @@ static void
 ctime_coder (struct tar_stat_info const *st, char const *keyword,
             struct xheader *xhdr, void *data __attribute__ ((unused)))
 {
-  code_time (get_stat_ctime (&st->stat), keyword, xhdr);
+  code_time (st->ctime, keyword, xhdr);
 }
 
 static void
@@ -964,14 +947,14 @@ ctime_decoder (struct tar_stat_info *st, char const *arg)
 {
   struct timespec ts;
   if (decode_time (&ts, arg, "ctime"))
-    set_stat_ctime (&st->stat, ts);
+    st->ctime = ts;
 }
 
 static void
 mtime_coder (struct tar_stat_info const *st, char const *keyword,
             struct xheader *xhdr, void *data __attribute__ ((unused)))
 {
-  code_time (get_stat_mtime (&st->stat), keyword, xhdr);
+  code_time (st->mtime, keyword, xhdr);
 }
 
 static void
@@ -979,7 +962,7 @@ mtime_decoder (struct tar_stat_info *st, char const *arg)
 {
   struct timespec ts;
   if (decode_time (&ts, arg, "mtime"))
-    set_stat_mtime (&st->stat, ts);
+    st->mtime = ts;
 }
 
 static void
This page took 0.06352 seconds and 4 git commands to generate.