Hi,

I noticed that apr_stat() on macOS gives only a resolution of seconds for
mtime/ctime/atime while running tests of Subversion on macOS. However,
according to man page of stat(2) [1], it provides a resolution of nanoseconds
for mtime/ctime/atime.

[[[
Process 62313 launched: '/tmp/stat' (x86_64)
Process 62313 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000100003e65 stat`main(argc=1, argv=<unavailable>) at 
stat.c:14:9 [opt]
   11           apr_finfo_t finfo;
   12           stat(filename, &statbuf);
   13           apr_stat(&finfo, filename, 0, NULL);
-> 14           printf("%s:\n", filename);
   15           printf("         %19s  %20s\n", "apr_stat", "stat");
   16           printf("  mtime: %19lld  %10lld.%09ld\n",
   17                  (int64_t) finfo.mtime,
Target 0: (stat) stopped.
warning: stat was compiled with optimization - stepping may behave oddly; 
variables may not be available.
(lldb) p finfo.mtime
(apr_time_t) 1704523440000000
(lldb) p statbuf.st_mtimespec
(timespec)  (tv_sec = 1704523440, tv_nsec = 172445899)
]]]

I think we could check `struct stat.st_{m,c,a}timespec.tv_nsec` in the
configure script.

[1] 
https://man.freebsd.org/cgi/man.cgi?query=stat&sektion=2&apropos=0&manpath=macOS+10.13.6#DESCRIPTION


Proposed patch:

[[[
Support microseconds of mtime/atime/ctime in apr_stat() on macOS.

* configure.in
  (Checking for File Info Support): Add struct stat.st_atimespec.tv_nsec,
  struct stat.st_mtimespec.tv_nsec, struct stat.st_ctimespec.tv_nsec.
* file_io/unix/filestat.c
  (fill_out_finfo): Use st_mtimespec.tv_nsec, st_atimensec.tv_nsec and
  st_ctimensec.tv_nsec if available.


Index: configure.in
===================================================================
--- configure.in        (revision 1915079)
+++ configure.in        (working copy)
@@ -2876,7 +2876,9 @@ AC_MSG_NOTICE([Checking for File Info Support...])
 AC_CHECK_MEMBERS([struct stat.st_blocks, struct stat.st_atimensec,
 struct stat.st_ctimensec, struct stat.st_mtimensec, struct 
stat.st_atim.tv_nsec,
 struct stat.st_ctim.tv_nsec, struct stat.st_mtim.tv_nsec,
-struct stat.st_atime_n, struct stat.st_ctime_n, struct stat.st_mtime_n],,,[
+struct stat.st_atime_n, struct stat.st_ctime_n, struct stat.st_mtime_n,
+struct stat.st_atimespec.tv_nsec, struct stat.st_mtimespec.tv_nsec,
+struct stat.st_ctimespec.tv_nsec],,,[
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
 #endif
Index: file_io/unix/filestat.c
===================================================================
--- file_io/unix/filestat.c     (revision 1915079)
+++ file_io/unix/filestat.c     (working copy)
@@ -96,6 +96,8 @@ static void fill_out_finfo(apr_finfo_t *finfo, str
     finfo->atime += info->st_atimensec / APR_TIME_C(1000);
 #elif defined(HAVE_STRUCT_STAT_ST_ATIME_N)
     finfo->atime += info->st_atime_n / APR_TIME_C(1000);
+#elif defined(HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC)
+    finfo->atime += info->st_atimespec.tv_nsec / APR_TIME_C(1000);
 #endif

     apr_time_ansi_put(&finfo->mtime, info->st_mtime);
@@ -105,6 +107,8 @@ static void fill_out_finfo(apr_finfo_t *finfo, str
     finfo->mtime += info->st_mtimensec / APR_TIME_C(1000);
 #elif defined(HAVE_STRUCT_STAT_ST_MTIME_N)
     finfo->mtime += info->st_mtime_n / APR_TIME_C(1000);
+#elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC)
+    finfo->mtime += info->st_mtimespec.tv_nsec / APR_TIME_C(1000);
 #endif

     apr_time_ansi_put(&finfo->ctime, info->st_ctime);
@@ -114,6 +118,8 @@ static void fill_out_finfo(apr_finfo_t *finfo, str
     finfo->ctime += info->st_ctimensec / APR_TIME_C(1000);
 #elif defined(HAVE_STRUCT_STAT_ST_CTIME_N)
     finfo->ctime += info->st_ctime_n / APR_TIME_C(1000);
+#elif defined(HAVE_STRUCT_STAT_ST_CTIMESPEC_TV_NSEC)
+    finfo->ctime += info->st_ctimespec.tv_nsec / APR_TIME_C(1000);
 #endif

 #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
]]]

-- 
Jun Omae <jun6...@gmail.com> (大前 潤)

Reply via email to