If you like, you could try the following patch to pax to more gracefully
handle filesystems with time resolution more granular than nanoseconds.
The whitespace will presumably be mauled by gmail so use patch's -l option.

Philip Guenther


Index: ar_subs.c
===================================================================
RCS file: /data/src/openbsd/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   14 May 2024 17:19:15 -0000
@@ -146,23 +146,59 @@ 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 (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 +878,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';
                }

                /*

On Thu, May 2, 2024 at 6:54 AM Walter Alejandro Iglesias <w...@roquesor.com>
wrote:

> On Thu, 2 May 2024 12:03:10, Stuart Henderson wrote
> > I don't have a suitable filesystem handy to test, but does OpenBSD's
> > implementation of ext2fs support sub-second timestamps?
> >
> > stat -f %Fm $filename
> >
> > If not, that's a probable explanation for the difference in behaviour.
> > You could probably confirm by forcing timestamps with no nanosecond
> > components, e.g. touch -t yyyymmddhhmm.ss $filename, or copy to ext2fs
> > and back again.
>
> $ doas mount -t ext2fs /dev/sd0i /mnt
> $ touch ~/test.txt
> $ cp ~/test.txt /mnt
> $ stat -f %Fm /mnt/test.txt
> 1714657214.000000000
> $ cp ~/test.txt /mnt
> $ stat -f %Fm /mnt/test.txt
> 1714657409.000000000
> 癘m
>

Reply via email to