On Wed May 15 10:20:04 2024 Philip Guenther wrote:
> I think you've managed to hit a spot where the POSIX standard doesn't
> provide a way for a program to find the information it needs to do its job
> correctly.  I've filed a ticket there
>    https://austingroupbugs.net/view.php?id=1831
>
> We'll see if my understanding of pathconf() is incorrect or if someone has
> a great idea for how to get around this...
>
>
> Philip Guenther
>

Hi Philip,

I get it working but I don't know if what I did is fine.

As I'd told you the problem was ctime (when using -Y), so I added one
conditional to your diff where it checks only mtime and it works:


Index: ar_subs.c
===================================================================
RCS file: /cvs/src/bin/pax/ar_subs.c,v
diff -u -p -r1.51 ar_subs.c
--- ar_subs.c   10 Jul 2023 16:28:33 -0000      1.51
+++ ar_subs.c   15 May 2024 08:19:08 -0000
@@ -146,23 +146,61 @@ list(void)
 }
 
 static int
-cmp_file_times(int mtime_flag, int ctime_flag, ARCHD *arcn, struct stat *sbp)
+cmp_file_times(int mtime_flag, int ctime_flag, ARCHD *arcn, const char *path)
 {
        struct stat sb;
+       long res;
 
-       if (sbp == NULL) {
-               if (lstat(arcn->name, &sb) != 0)
-                       return (0);
-               sbp = &sb;
+       if (path == NULL)
+               path = arcn->name;
+       if (lstat(path, &sb) != 0)
+               return (0);
+
+       /*
+        * The target (sb) mtime might be rounded down due to the limitations
+        * of the FS it's on.  If it's strictly greater or we don't care about
+        * mtime, then precision doesn't matter, so check those cases first.
+        */
+       if (ctime_flag && mtime_flag) {
+               if (timespeccmp(&arcn->sb.st_mtim, &sb.st_mtim, <=))
+                       return timespeccmp(&arcn->sb.st_ctim, &sb.st_ctim, <=);
+               if (!timespeccmp(&arcn->sb.st_ctim, &sb.st_ctim, <=))
+                       return 0;
+               /* <= ctim, but >= mtim */
+       } else if (mtime_flag) {
+               return timespeccmp(&arcn->sb.st_mtim, &sb.st_mtim, <=);
+       } else if (ctime_flag)
+               return timespeccmp(&arcn->sb.st_ctim, &sb.st_ctim, <=);
+       else if (timespeccmp(&arcn->sb.st_mtim, &sb.st_mtim, <=))
+               return 1;
+
+       /*
+        * If we got here then the target arcn > sb for mtime *and* that's
+        * the deciding factor.  Check whether they're equal after rounding
+        * down the arcn mtime to the precision of the target path.
+        */
+       res = pathconf(path, _PC_TIMESTAMP_RESOLUTION);
+       if (res == -1)
+               return 0;
+
+       /* nanosecond resolution?  previous comparisons were accurate */
+       if (res == 1)
+               return 0;
+
+       /* common case: second accuracy */
+       if (res == 1000000000)
+               return arcn->sb.st_mtime <= sb.st_mtime;
+
+       if (res < 1000000000) {
+               struct timespec ts = arcn->sb.st_mtim;
+               ts.tv_nsec = (ts.tv_nsec / res) * res;
+               return timespeccmp(&ts, &sb.st_mtim, <=);
+       } else {
+               /* not a POSIX compliant FS */
+               res /= 1000000000;
+               return ((arcn->sb.st_mtime / res) * res) <= sb.st_mtime;
+               return arcn->sb.st_mtime <= ((sb.st_mtime / res) * res);
        }
-
-       if (ctime_flag && mtime_flag)
-               return (timespeccmp(&arcn->sb.st_mtim, &sbp->st_mtim, <=) &&
-                       timespeccmp(&arcn->sb.st_ctim, &sbp->st_ctim, <=));
-       else if (ctime_flag)
-               return (timespeccmp(&arcn->sb.st_ctim, &sbp->st_ctim, <=));
-       else
-               return (timespeccmp(&arcn->sb.st_mtim, &sbp->st_mtim, <=));
 }
 
 /*
@@ -842,14 +880,12 @@ copy(void)
                        /*
                         * if existing file is same age or newer skip
                         */
-                       res = lstat(dirbuf, &sb);
-                       *dest_pt = '\0';
-
-                       if (res == 0) {
+                       if (cmp_file_times(uflag, Dflag, arcn, dirbuf)) {
+                               *dest_pt = '\0';
                                ftree_skipped_newer(arcn);
-                               if (cmp_file_times(uflag, Dflag, arcn, &sb))
-                                       continue;
+                               continue;
                        }
+                       *dest_pt = '\0';
                }
 
                /*

Reply via email to