<pre style='margin:0'>
Ken (kencu) pushed a commit to branch master
in repository macports-legacy-support.

</pre>
<p><a href="https://github.com/macports/macports-legacy-support/commit/e34009691ebc7cebc0b8e07e9f6ffbb93cb1c573">https://github.com/macports/macports-legacy-support/commit/e34009691ebc7cebc0b8e07e9f6ffbb93cb1c573</a></p>
<pre style="white-space: pre; background: #F8F8F8">The following commit(s) were added to refs/heads/master by this push:
<span style='display:block; white-space:pre;color:#404040;'>     new e340096  Support utimensat (theoretically on 10.4 to 10.12) (#34)
</span>e340096 is described below

<span style='display:block; white-space:pre;color:#808000;'>commit e34009691ebc7cebc0b8e07e9f6ffbb93cb1c573
</span>Author: Mihai Moldovan <ionic@ionic.de>
AuthorDate: Wed Mar 17 00:17:14 2021 +0100

<span style='display:block; white-space:pre;color:#404040;'>    Support utimensat (theoretically on 10.4 to 10.12) (#34)
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    * setattrlistat: add new function as new file
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    this is needed to support utimensat
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    it has different availability needs compared to
</span><span style='display:block; white-space:pre;color:#404040;'>    the other atcalls
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    * utimensat, futimens: add source and hook up into headers
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    * utimensat: add test.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    Direct copy of xnu-4570.71.2/tools/tests/darwintests/utimensat.c with
</span><span style='display:block; white-space:pre;color:#404040;'>    licence information added.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    * utimensat: test fixups.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    Add darwintest emulation macros (as far as we need them) and debugging
</span><span style='display:block; white-space:pre;color:#404040;'>    messages to see where things fail.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    This test is known to work on 10.13 + APFS (which uses the native OS
</span><span style='display:block; white-space:pre;color:#404040;'>    implementation of utimensat), but known to fail on HFS+, regardless of
</span><span style='display:block; white-space:pre;color:#404040;'>    the utimensat implementation.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    Hence, it needs to be rewritten to test for microsecond accuracy on
</span><span style='display:block; white-space:pre;color:#404040;'>    non-APFS file systems.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    * utimensat: support tests on non-APFS.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    On other file systems, we'll just test if the time set by utimensat is
</span><span style='display:block; white-space:pre;color:#404040;'>    within microseconds range - or, more specifically, check that
</span><span style='display:block; white-space:pre;color:#404040;'>    utimensat() does what utimes() does.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    We're mostly interested in HFS+, which doesn't even support sub-second
</span><span style='display:block; white-space:pre;color:#404040;'>    timestamp precision, so the microsecond precision provides by utimes()
</span><span style='display:block; white-space:pre;color:#404040;'>    sounds good enough.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    Make sure that we only execute utimes() on a secondary, copied file
</span><span style='display:block; white-space:pre;color:#404040;'>    (especially with stat attributes copied). Otherwise, utimes() behavior
</span><span style='display:block; white-space:pre;color:#404040;'>    (which, especially on older systems won't support all features such as
</span><span style='display:block; white-space:pre;color:#404040;'>    UTIMES_NOW/UTIMES_NOW) would change our test file's timestamps (compared
</span><span style='display:block; white-space:pre;color:#404040;'>    to what utimensat() did), which is not desirable.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    * utimensat: add bug-for-bug workaround on non-APFS file systems with mtime = UTIME_OMIT.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    Iff the mtime is set to UTIME_OMIT and the file system is at least HFS+
</span><span style='display:block; white-space:pre;color:#404040;'>    (for safety, change that to non-APFS), Apple's implementation of
</span><span style='display:block; white-space:pre;color:#404040;'>    utimensat (and ours) is buggy in that it does not seem to update the
</span><span style='display:block; white-space:pre;color:#404040;'>    atime, even though it may have been explicitly provided.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    Make the test pass in this buggy case and alert users to report
</span><span style='display:block; white-space:pre;color:#404040;'>    discrepancies if this behavior ever changes (since I can only test on
</span><span style='display:block; white-space:pre;color:#404040;'>    10.9 and 10.13 currently).
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    * setattrlistat: emulate 10.8 behavior in older systems.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    Starting with 10.8, the internal setattrlist code checks if no
</span><span style='display:block; white-space:pre;color:#404040;'>    attributes to set have been given and exits early, fixing a bug where an
</span><span style='display:block; white-space:pre;color:#404040;'>    attribute buffer size of zero leads to it exiting with an error (which,
</span><span style='display:block; white-space:pre;color:#404040;'>    really, should be mostly a no-op).
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    This should fix the utimensat test case on 10.7 and below.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    * fsetattrlist: add new function for 10.5 and below.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    We need this compatibility function especially for futimens().
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    * utimensat: delete temporary files created in test.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    We can't reasonably do this in the Makefile, since the file is created
</span><span style='display:block; white-space:pre;color:#404040;'>    at cwd, which could be... anywhere.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    Hence, do that in the program that creates them in the first place.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    * utimensat: disable bug-for-bug workaround on 10.5 and below.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    Older systems do not seem to exhibit the bug.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    I have no idea why and diffing the relevant sections for the XNU source
</span><span style='display:block; white-space:pre;color:#404040;'>    code for 10.5 and 10.6 didn't lead to any insights.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    Leave a comment and just disable it for good.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    Co-authored-by: Ken Cunningham <kencu@macports.org>
</span>---
 include/MacportsLegacySupport.h |  14 +-
 include/sys/stat.h              |  22 ++-
 include/sys/unistd.h            |  13 +-
 include/unistd.h                |  71 +++++++++
 src/fsetattrlist.c              |  77 ++++++++++
 src/setattrlistat.c             |  76 ++++++++++
 src/utimensat.c                 | 144 ++++++++++++++++++
 test/test_utimensat.c           | 327 ++++++++++++++++++++++++++++++++++++++++
 8 files changed, 739 insertions(+), 5 deletions(-)

<span style='display:block; white-space:pre;color:#808080;'>diff --git a/include/MacportsLegacySupport.h b/include/MacportsLegacySupport.h
</span><span style='display:block; white-space:pre;color:#808080;'>index 5f3e5c8..1cb4d37 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/include/MacportsLegacySupport.h
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/include/MacportsLegacySupport.h
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -37,6 +37,12 @@
</span> /* fsgetpath */
 #define __MP_LEGACY_SUPPORT_FSGETPATH__       (__APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101300)
 
<span style='display:block; white-space:pre;background:#e0ffe0;'>+/* **setattrlistat */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define __MP_LEGACY_SUPPORT_SETATTRLISTAT__   (__APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101300)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* ** utimensat, futimens, UTIME_NOW, UTIME_OMIT */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define __MP_LEGACY_SUPPORT_UTIMENSAT__       (__APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101300)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> /* clock_gettime */
 #define __MP_LEGACY_SUPPORT_GETTIME__         (__APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101200)
 
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -46,7 +52,6 @@
</span> /* fdopendir */
 #define __MP_LEGACY_SUPPORT_FDOPENDIR__       (__APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101000)
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span> /* this header is automatically included by <net/if.h> on systems 10.9 and up.
    It is therefore expected to be included by most current software. */
 /* <net/if.h> include <sys/socket.h> */
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -96,6 +101,9 @@
</span>                                                !__DISABLE_MP_LEGACY_SUPPORT_REALPATH_WRAP__      && \
                                                     __MP_LEGACY_SUPPORT_REALPATH_WRAP__)
 
<span style='display:block; white-space:pre;background:#e0ffe0;'>+/* setattrlistat */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define __MP_LEGACY_SUPPORT_FSETATTRLIST__    (__APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1060)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> /* lsmod does not exist on Tiger */
 #define __MP_LEGACY_SUPPORT_LSMOD__           (__APPLE__ && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1050)
 
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -145,9 +153,9 @@
</span> 
 
 /* Compound macros, bundling functionality needed by multiple single features. */
<span style='display:block; white-space:pre;background:#ffe0e0;'>-#define __MP_LEGACY_SUPPORT_NEED_ATCALL_MACROS__  (__MP_LEGACY_SUPPORT_ATCALLS__)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define __MP_LEGACY_SUPPORT_NEED_ATCALL_MACROS__  (__MP_LEGACY_SUPPORT_ATCALLS__ || __MP_LEGACY_SUPPORT_SETATTRLISTAT__)
</span> 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-#define __MP_LEGACY_SUPPORT_NEED_BEST_FCHDIR__    (__MP_LEGACY_SUPPORT_FDOPENDIR__ || __MP_LEGACY_SUPPORT_ATCALLS__)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define __MP_LEGACY_SUPPORT_NEED_BEST_FCHDIR__    (__MP_LEGACY_SUPPORT_FDOPENDIR__ || __MP_LEGACY_SUPPORT_ATCALLS__ || __MP_LEGACY_SUPPORT_SETATTRLISTAT__)
</span> 
 
 #endif /* _MACPORTS_LEGACYSUPPORTDEFS_H_ */
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/include/sys/stat.h b/include/sys/stat.h
</span><span style='display:block; white-space:pre;color:#808080;'>index 2871659..b569e6f 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/include/sys/stat.h
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/include/sys/stat.h
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -1,7 +1,7 @@
</span> 
 /*
  * Copyright (c) 2018 Chris Jones <jonesc@macports.org>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- * Copyright (c) 2018 Ken Cunningham <kencu@macports.org>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Copyright (c) 2020 Ken Cunningham <kencu@macports.org>
</span>  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -25,6 +25,26 @@
</span> /* Include the primary system stat.h */
 #include_next <sys/stat.h>
 
<span style='display:block; white-space:pre;background:#e0ffe0;'>+#if __MP_LEGACY_SUPPORT_UTIMENSAT__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if !defined(UTIME_NOW)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define UTIME_NOW -1
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if !defined(UTIME_OMIT)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define UTIME_OMIT -2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+__MP__BEGIN_DECLS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+extern int futimens(int fd, const struct timespec _times_in[2]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+extern int utimensat(int fd, const char *path, const struct timespec _times_in[2], int flags);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+__MP__END_DECLS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif /* __MP_LEGACY_SUPPORT_UTIMENSAT__ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> #if __MP_LEGACY_SUPPORT_ATCALLS__
 
 __MP__BEGIN_DECLS
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/include/sys/unistd.h b/include/sys/unistd.h
</span><span style='display:block; white-space:pre;color:#808080;'>index 8f23dbe..edbfaf2 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/include/sys/unistd.h
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/include/sys/unistd.h
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -1,7 +1,7 @@
</span> 
 /*
  * Copyright (c) 2018 Chris Jones <jonesc@macports.org>
<span style='display:block; white-space:pre;background:#ffe0e0;'>- * Copyright (c) 2018 Ken Cunningham <kencu@macports.org>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Copyright (c) 2020 Ken Cunningham <kencu@macports.org>
</span>  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -25,6 +25,9 @@
</span> /* Include the primary system unistd.h */
 #include_next <sys/unistd.h>
 
<span style='display:block; white-space:pre;background:#e0ffe0;'>+/* For types such as uint32_t. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdint.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> #if __MP_LEGACY_SUPPORT_ATCALLS__
 
 /*
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -66,4 +69,12 @@ __MP__END_DECLS
</span> 
 #endif /* __MP_LEGACY_SUPPORT_ATCALLS__ */
 
<span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if __MP_LEGACY_SUPPORT_SETATTRLISTAT__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+extern int setattrlistat(int dirfd, const char *pathname, void *a,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    void *buf, size_t size, uint32_t flags);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif /* __MP_LEGACY_SUPPORT_SETATTRLISTAT__ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> #endif /* _MACPORTS_SYSUNISTD_H_ */
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/include/unistd.h b/include/unistd.h
</span><span style='display:block; white-space:pre;color:#808080;'>index ce45255..cb00a3a 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/include/unistd.h
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/include/unistd.h
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -14,6 +14,66 @@
</span>  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
<span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Copyright (c) 2000, 2002-2006, 2008-2010, 2012 Apple Inc. All rights reserved.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @APPLE_LICENSE_HEADER_START@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * This file contains Original Code and/or Modifications of Original Code
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * as defined in and that are subject to the Apple Public Source License
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Version 2.0 (the 'License'). You may not use this file except in
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * compliance with the License. Please obtain a copy of the License at
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * http://www.opensource.apple.com/apsl/ and read it before using this
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * file.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * The Original Code and all software distributed under the License are
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Please see the License for the specific language governing rights and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * limitations under the License.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @APPLE_LICENSE_HEADER_END@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*-
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Copyright (c) 1998-1999 Apple Computer, Inc. All Rights Reserved
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Copyright (c) 1991, 1993, 1994
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * The Regents of the University of California.  All rights reserved.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Redistribution and use in source and binary forms, with or without
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * modification, are permitted provided that the following conditions
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * are met:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * 1. Redistributions of source code must retain the above copyright
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *    notice, this list of conditions and the following disclaimer.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * 2. Redistributions in binary form must reproduce the above copyright
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *    notice, this list of conditions and the following disclaimer in the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *    documentation and/or other materials provided with the distribution.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * 3. All advertising materials mentioning features or use of this software
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *    must display the following acknowledgement:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * This product includes software developed by the University of
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * California, Berkeley and its contributors.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * 4. Neither the name of the University nor the names of its contributors
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *    may be used to endorse or promote products derived from this software
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *    without specific prior written permission.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * SUCH DAMAGE.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @(#)unistd.h    8.12 (Berkeley) 4/27/95
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *  Copyright (c)  1998 Apple Compter, Inc.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *  All Rights Reserved
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span> 
 #ifndef _MACPORTS_UNISTD_H_
 #define _MACPORTS_UNISTD_H_
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -43,4 +103,15 @@ __MP__END_DECLS
</span> 
 #endif /* __ENABLE_MP_LEGACY_SUPPORT_SYSCONF_WRAP__ */
 
<span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if __MP_LEGACY_SUPPORT_FSETATTRLIST__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#ifdef __LP64__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int   fsetattrlist(int,void*,void*,size_t,unsigned int);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#else /* defined (__LP64__) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int   fsetattrlist(int,void*,void*,size_t,unsigned long);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif /* defined (__LP64__) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif  /* __MP_LEGACY_SUPPORT_FSETATTRLIST__ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> #endif /* _MACPORTS_UNISTD_H_ */
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/fsetattrlist.c b/src/fsetattrlist.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 0000000..245a129
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/fsetattrlist.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,77 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Copyright (c) 2021 Mihai Moldovan <ionic@ionic.de>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Permission to use, copy, modify, and distribute this software for any
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * purpose with or without fee is hereby granted, provided that the above
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * copyright notice and this permission notice appear in all copies.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* MP support header */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include "MacportsLegacySupport.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if __MP_LEGACY_SUPPORT_FSETATTRLIST__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/attr.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/fcntl.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/param.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <fcntl.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <string.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#ifdef __LP64__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int fsetattrlist(int fd, void *a, void *buf, size_t size, unsigned int flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#else /* defined (__LP64__) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int fsetattrlist(int fd, void *a, void *buf, size_t size, unsigned long flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif /* defined (__LP64__) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int cont = 1,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        ret = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    char fpath[MAXPATHLEN];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    memset (fpath, 0, MAXPATHLEN);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (-1 == fcntl(fd, F_GETPATH, fpath)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        ret = EBADF;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        cont = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1080
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Older systems don't correctly check if no attributes are to be set, which usually
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * means a buffer size of zero and return an error since they malloc a block of
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * memory with size zero, leading to ENOMEM.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Emulate the fix from 10.8 for those.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    const struct attrlist *al = a;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (al->commonattr == 0 &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        (al->volattr & ~ATTR_VOL_INFO) == 0 &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        al->dirattr == 0 &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        al->fileattr == 0 &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        al->forkattr == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        cont = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         * Explicitly let the potential error from above pass through, since that's what
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         * the original function seems to do as well.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (cont) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        ret = setattrlist(fpath, a, buf, size, flags);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif  /* __MP_LEGACY_SUPPORT_FSETATTRLIST__ */
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/setattrlistat.c b/src/setattrlistat.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 0000000..bf1fff1
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/setattrlistat.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,76 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * setattrlistat.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Copyright (c) 2013-2015 Apple Inc. All rights reserved.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @APPLE_LICENSE_HEADER_START@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * This file contains Original Code and/or Modifications of Original Code
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * as defined in and that are subject to the Apple Public Source License
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Version 2.0 (the 'License'). You may not use this file except in
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * compliance with the License. Please obtain a copy of the License at
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * http://www.opensource.apple.com/apsl/ and read it before using this
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * file.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * The Original Code and all software distributed under the License are
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Please see the License for the specific language governing rights and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * limitations under the License.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @APPLE_LICENSE_HEADER_END@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  * NOTICE: This file was modified by Ken Cunningham in September 2020 to allow
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  * for use as a supporting file for MacPorts legacy support library. This notice
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  * is included in support of clause 2.2 (b) of the Apple Public License,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  * Version 2.0.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* MP support header */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include "MacportsLegacySupport.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if __MP_LEGACY_SUPPORT_SETATTRLISTAT__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include "common-priv.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/attr.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <assert.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdint.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int setattrlistat(int dirfd, const char *pathname, void *a,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                  void *buf, size_t size, uint32_t flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    int cont = 1,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        ret = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1080
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Older systems don't correctly check if no attributes are to be set, which usually
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * means a buffer size of zero and return an error since they malloc a block of
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * memory with size zero, leading to ENOMEM.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     * Emulate the fix from 10.8 for those.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    const struct attrlist *al = a;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (al->commonattr == 0 &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        (al->volattr & ~ATTR_VOL_INFO) == 0 &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        al->dirattr == 0 &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        al->fileattr == 0 &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        al->forkattr == 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        cont = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (cont) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        ret = ATCALL(dirfd, pathname, setattrlist(pathname, a, buf, size, flags));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif  /* __MP_LEGACY_SUPPORT_SETATTRLISTAT__ */
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/src/utimensat.c b/src/utimensat.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 0000000..858b422
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/src/utimensat.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,144 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Copyright (c) 2006, 2017 Apple Computer, Inc. All rights reserved.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @APPLE_LICENSE_HEADER_START@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * This file contains Original Code and/or Modifications of Original Code
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * as defined in and that are subject to the Apple Public Source License
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Version 2.0 (the 'License'). You may not use this file except in
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * compliance with the License. Please obtain a copy of the License at
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * http://www.opensource.apple.com/apsl/ and read it before using this
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * file.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * The Original Code and all software distributed under the License are
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Please see the License for the specific language governing rights and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * limitations under the License.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @APPLE_LICENSE_HEADER_END@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  * NOTICE: This file was modified by Ken Cunningham in September 2020 to allow
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  * for use as a supporting file for MacPorts legacy support library. This notice
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  * is included in support of clause 2.2 (b) of the Apple Public License,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  * Version 2.0.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/types.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/stat.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/attr.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/time.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/fcntl.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <strings.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static struct timespec times_now[2] = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   { .tv_nsec = UTIME_NOW },
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   { .tv_nsec = UTIME_NOW }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Resolve any UTIME_NOW or UTIME_OMIT and return the attributes buffer and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * attributes to pass.  Assumes times_in is writable.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+prepare_times_array_and_attrs(struct timespec times_in[2],
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           struct timespec times_out[2], size_t *times_out_size)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (times_in[0].tv_nsec == UTIME_OMIT &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   times_in[1].tv_nsec == UTIME_OMIT) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (times_in[0].tv_nsec == UTIME_NOW ||
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   times_in[1].tv_nsec == UTIME_NOW) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           struct timespec now = {};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    * TODO: Replace with nanosecond time when available
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   struct timeval tv;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    * The original code uses __commpage_gettimeofday() with a
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    * fallback to __gettimeofday() here, but that's only relevant
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    * in its XNU kernel context.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    * Userspace code can comfortably use gettimeofday(), which
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    * wraps this stuff nicely.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   gettimeofday(&tv, NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   TIMEVAL_TO_TIMESPEC(&tv, &now);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (times_in[0].tv_nsec == UTIME_NOW) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   times_in[0] = now;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (times_in[1].tv_nsec == UTIME_NOW) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   times_in[1] = now;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   int attrs = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   *times_out_size = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   struct timespec *times_cursor = times_out;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (times_in[1].tv_nsec != UTIME_OMIT) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           attrs |= ATTR_CMN_MODTIME;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           *times_cursor++ = times_in[1];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           *times_out_size += sizeof(struct timespec);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (times_in[0].tv_nsec != UTIME_OMIT) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           attrs |= ATTR_CMN_ACCTIME;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           *times_cursor = times_in[0];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           *times_out_size += sizeof(struct timespec);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return attrs;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+futimens(int fd, const struct timespec _times_in[2])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   struct timespec times_in[2];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (_times_in != NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           memcpy(&times_in, _times_in, sizeof(times_in));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           memcpy(&times_in, times_now, sizeof(times_in));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   size_t attrbuf_size = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   struct timespec times_out[2] = {};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   struct attrlist a = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           .bitmapcount = ATTR_BIT_MAP_COUNT
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   a.commonattr = prepare_times_array_and_attrs(times_in, times_out, &attrbuf_size);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return fsetattrlist(fd, &a, &times_out, attrbuf_size, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+utimensat(int fd, const char *path, const struct timespec _times_in[2], int flags)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   struct timespec times_in[2];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (_times_in != NULL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           memcpy(&times_in, _times_in, sizeof(times_in));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           memcpy(&times_in, times_now, sizeof(times_in));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   size_t attrbuf_size = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   struct timespec times_out[2] = {};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   struct attrlist a = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           .bitmapcount = ATTR_BIT_MAP_COUNT
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   a.commonattr = prepare_times_array_and_attrs(times_in, times_out, &attrbuf_size);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   int flags_out = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (flags & AT_SYMLINK_NOFOLLOW) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           flags_out |= FSOPT_NOFOLLOW;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return setattrlistat(fd, path, &a, &times_out, attrbuf_size, flags_out);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/test/test_utimensat.c b/test/test_utimensat.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 0000000..40dd504
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/test/test_utimensat.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,327 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Copyright (c) 2006, 2017 Apple Computer, Inc. All rights reserved.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @APPLE_LICENSE_HEADER_START@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * This file contains Original Code and/or Modifications of Original Code
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * as defined in and that are subject to the Apple Public Source License
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Version 2.0 (the 'License'). You may not use this file except in
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * compliance with the License. Please obtain a copy of the License at
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * http://www.opensource.apple.com/apsl/ and read it before using this
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * file.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * The Original Code and all software distributed under the License are
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Please see the License for the specific language governing rights and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * limitations under the License.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * @APPLE_LICENSE_HEADER_END@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  * NOTICE: This file was modified by Ken Cunningham in September 2020 and Mihai
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  * Moldovan in February 2021 to allow for use as a supporting file for MacPorts legacy
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  * support library. This notice is included in support of clause 2.2 (b) of the Apple
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  * Public License, Version 2.0.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/cdefs.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/param.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/mount.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/stat.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/time.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <fcntl.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <limits.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <paths.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <string.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdbool.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * darwintest seems to be private.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * No source code could be located for it.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * However, there seems to be a different but compatible implementation in
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * xnu-6153.141.1/osfmk/tests/ktest.{c,h}.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * http://web.archive.org/web/20210201212906/https://opensource.apple.com/source/xnu/xnu-6153.141.1/osfmk/tests/ktest.h.auto.html
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Usually, darwintests would provide a dynamic library called darwintest_utils which
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * includes... who knows what exactly.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ktest seems to be more complicated and tightly integrated.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Long story short: we won't even try to reimplement the full darwintest suite here.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * We can, however, take some of the ktest definitions as inspirations for what the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * macros we actually use are supposed to do.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <darwintest.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <darwintest_utils.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+*/
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define FILENAME "utimensat"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define T_LOG(...)                 \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   do {                            \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           printf("Testing: ");  \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           printf(__VA_ARGS__);    \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           printf("\n");         \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } while (0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Yes, we know that b can't be NULL when we use it, but some compilers (most notably older GCC,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * but also more recent versions like 8) wrongly assume that it could be, triggering a bug and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * superfluous warning.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Work around that locally.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define T_ASSERT_POSIX_ZERO(a,b)                           \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   do {                                                    \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if ((a) != 0) {                                 \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   printf("assert zero failed");         \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (b != NULL) {                        \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           printf(": %s", (b) ? (b) : "");     \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }                                       \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   printf("\n");                         \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   goto err;                               \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }                                               \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } while (0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define T_ASSERT_POSIX_SUCCESS(a,b)                                \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   do {                                                    \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if ((a) < 0) {                                       \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   printf("assert success failed");      \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if ((b) != NULL) {                      \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           printf(": %s", (b) ? (b) : "");     \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }                                       \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   printf("\n");                         \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   goto err;                               \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }                                               \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } while (0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define T_ASSERT_GE(a,b,c)                                                 \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   do {                                                                    \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (!((a) >= (b))) {                                         \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   printf("assert GE failed {%ld, %ld}", (a), (b));      \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if ((c) != NULL) {                                      \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           printf(": %s", (c) ? (c) : "");                     \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }                                                       \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   printf("\n");                                         \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   goto err;                                               \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }                                                               \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } while (0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define T_ASSERT_EQ(a,b,c)                                                 \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   do {                                                                    \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (!((a) == (b))) {                                            \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   printf("assert EQ failed {%ld, %ld}", (a), (b));      \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if ((c) != NULL) {                                      \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           printf(": %s", (c) ? (c) : "");                     \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }                                                       \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   printf("\n");                                         \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   goto err;                                               \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }                                                               \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } while (0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define T_SKIP(msg)                                                \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   do {                                                    \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           printf("Test skipped");                               \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if ((msg)) {                                    \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   printf(": %s", (msg) ? (msg) : ""); \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }                                               \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           printf("\n");                                 \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           goto out;                                       \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   } while (0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define T_DECL(a,b) int main(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define T_SETUPBEGIN
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define T_SETUPEND
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define T_QUIET
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define dt_tmpdir tmpdir
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+struct bug_for_bug {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  size_t pos;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  bool enable;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static const struct timespec tptr[][2] = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   { { 0x12345678, 987654321 }, { 0x15263748, 123456789 }, },
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   { { 0, UTIME_NOW }, { 0x15263748, 123456789 }, },
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   { { 0x12345678, 987654321 }, { 0, UTIME_NOW }, },
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   { { 0, UTIME_NOW }, { 0, UTIME_NOW }, },
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   { { 0, UTIME_OMIT }, { 0x15263748, 123456789 }, },
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   { { 0x12345678, 987654321 }, { 0, UTIME_OMIT }, },
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   { { 0, UTIME_OMIT }, { 0, UTIME_OMIT }, },
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   { { 0, UTIME_NOW }, { 0, UTIME_OMIT }, },
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   { { 0, UTIME_OMIT }, { 0, UTIME_NOW }, },
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+T_DECL(utimensat, "Try various versions of utimensat")
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   T_SETUPBEGIN;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   /* T_ASSERT_POSIX_ZERO(chdir(dt_tmpdir()), NULL); */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   // Skip the test if the current working directory is not on APFS.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   struct statfs sfs = { 0 };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   bool apfs = true;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   T_QUIET; T_ASSERT_POSIX_SUCCESS(statfs(".", &sfs), NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (memcmp(&sfs.f_fstypename[0], "apfs", strlen("apfs")) != 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           apfs = false;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           /* T_SKIP("utimensat is APFS-only, but working directory is non-APFS"); */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   T_SETUPEND;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   struct stat pre_st, post_st, utimes_st;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   int fd, ret = EXIT_SUCCESS;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   struct bug_for_bug mtime_omit = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                     5,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1060
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * Older OS X versions do not seem to exhibit this bug.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * I've looked through the XNU kernel code and tried to diff the relevant
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * sections, including the HFS part, from 10.5 and 10.6 without success.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * I cannot explain what is triggering it and why it's only triggered on HFS+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * for OS X >= 10.6.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * My personal speculation is that this is an effect of some sort of caching or
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * the fact that atimes are only updated lazily. Though, if explicitly requested
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * by user-space and set to a custom time, this laziness shouldn't play a role.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * We'll take the shortcut here and disable the bug-for-bug compatibility for
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * older systems. We could, alternatively, emulate the buggy behavior in
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    * utimensat (or the setattrlistat emulation), but that wouldn't sound smart.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                     false
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                     (!(apfs))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   T_ASSERT_POSIX_SUCCESS((fd = open(FILENAME, O_CREAT|O_RDWR, 0644)), NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   T_ASSERT_POSIX_ZERO(close(fd), NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   if (!(apfs)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           T_ASSERT_POSIX_SUCCESS((fd = open(FILENAME "-utimes", O_CREAT|O_RDWR, 0644)), NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           T_ASSERT_POSIX_ZERO(close(fd), NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   for (size_t i = 0; i < sizeof(tptr)/sizeof(tptr[0]); i++) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           T_LOG("=== {%ld, %ld} {%ld, %ld} ===",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           tptr[i][0].tv_sec, tptr[i][0].tv_nsec,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           tptr[i][1].tv_sec, tptr[i][1].tv_nsec);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           struct timespec now;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           struct timeval utimes_tv[2] = { { 0 } };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           /* Convert current entry to microseconds-based structure. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           TIMESPEC_TO_TIMEVAL(utimes_tv, tptr[i]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           TIMESPEC_TO_TIMEVAL((utimes_tv + 1), (tptr[i] + 1));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           clock_gettime(CLOCK_REALTIME, &now);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           T_ASSERT_POSIX_ZERO(stat(FILENAME, &pre_st), "first stat failed");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           T_ASSERT_POSIX_ZERO(utimensat(AT_FDCWD, FILENAME, tptr[i], 0), "utimensat failed");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           T_ASSERT_POSIX_ZERO(stat(FILENAME, &post_st), "second stat failed");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (!(apfs)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    * Handle UTIME_NOW and UTIME_OMIT... uh... "correctly".
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    * By "correctly", we really mean to copy the file and then call
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    * utimes() on it.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    * The issue is that utimes() cannot generally handle the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    * UTIME_NOW/UTIME_OMIT macros (at least on older systems),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    * so we'll have to operate on a copy of the original file.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    * Avoid copyfile(), though, since it is not available on older
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    * systems. Instead, copy the timestamps directly via utimes().
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   struct timeval utimes_tv_copy[2] = { { 0 } };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   TIMESPEC_TO_TIMEVAL(utimes_tv_copy, &(pre_st.st_atimespec));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   TIMESPEC_TO_TIMEVAL((utimes_tv_copy + 1), &(pre_st.st_mtimespec));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   T_ASSERT_POSIX_ZERO(utimes(FILENAME "-utimes", utimes_tv_copy), "copying original timestamps via utimes failed");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   /* Then, set the actual times. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   T_ASSERT_POSIX_ZERO(utimes(FILENAME "-utimes", utimes_tv), "utimes failed");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   T_ASSERT_POSIX_ZERO(stat(FILENAME "-utimes", &utimes_st), "utimes stat failed");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (tptr[i][0].tv_nsec == UTIME_NOW) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   T_ASSERT_GE(post_st.st_atimespec.tv_sec, now.tv_sec, "post stat vs. now seconds (utimensat Atime nanoseconds UTIME_NOW)");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           } else if (tptr[i][0].tv_nsec == UTIME_OMIT) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   T_ASSERT_EQ(post_st.st_atimespec.tv_sec, pre_st.st_atimespec.tv_sec, "post stat vs. pre stat seconds (utimensat Atime nanoseconds UTIME_OMIT)");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   T_ASSERT_EQ(post_st.st_atimespec.tv_nsec, pre_st.st_atimespec.tv_nsec, "post stat vs. pre stat nanoseconds (utimensat Atime nanoseconds UTIME_OMIT)");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   /* Seconds must always match. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if ((mtime_omit.enable) && (mtime_omit.pos == i)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            * Unless we're on non-APFS and the mtime is set to
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            * UTIME_OMIT, which triggers a bug in Apple's
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            * implementation (even natively on 10.13 and higher),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            * which leads to the atime not being updated as well.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           T_ASSERT_EQ(pre_st.st_atimespec.tv_sec, post_st.st_atimespec.tv_sec, "pre stat vs. post stat Atime seconds (utimensat Atime explicit) - "
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                                                                                "if this test fails on 10.14 or higher, it means that Apple fixed "
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                                                                                "its buggy implementation on non-APFS file systems. Please report "
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                                                                                "this to the legacy-support project");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           T_ASSERT_EQ(post_st.st_atimespec.tv_sec, tptr[i][0].tv_sec, "post stat vs. utimensat Atime seconds (utimensat Atime explicit)");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   /* Nanoseconds, on the other hand... may not. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (apfs) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           /* But must on APFS. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           T_ASSERT_EQ(post_st.st_atimespec.tv_nsec, tptr[i][0].tv_nsec, "post stat vs. utimensat Atime nanoseconds (utimensat Atime explicit)");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            * On other file systems, we just make sure the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            * nanoseconds are within microseconds range compared to
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            * the utimes() call.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                            */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           T_ASSERT_EQ((post_st.st_atimespec.tv_nsec / 1000), (utimes_st.st_atimespec.tv_nsec / 1000), "post stat vs. utimes Atime nanoseconds (utimensat Atime explicit)");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           if (tptr[i][1].tv_nsec == UTIME_NOW) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   T_ASSERT_GE(post_st.st_mtimespec.tv_sec, now.tv_sec, "post stat vs. now seconds (utimensat Mtime nanoseconds UTIME_NOW)");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           } else if (tptr[i][1].tv_nsec == UTIME_OMIT) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   T_ASSERT_EQ(post_st.st_mtimespec.tv_sec, pre_st.st_mtimespec.tv_sec, "post stat vs. pre stat seconds (utimensat Mtime nanseconds UTIME_OMIT)");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   T_ASSERT_EQ(post_st.st_mtimespec.tv_nsec, pre_st.st_mtimespec.tv_nsec, "post stat vs. pre stat nanoseconds (utimensat Mtime nanoseconds UTIME_OMIT)");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   /* Same here, but for mtime. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   T_ASSERT_EQ(post_st.st_mtimespec.tv_sec, tptr[i][1].tv_sec, "post stat vs. utimensat Mtime seconds (utimensat Mtime explicit)");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   if (apfs) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           T_ASSERT_EQ(post_st.st_mtimespec.tv_nsec, tptr[i][1].tv_nsec, "post stat vs. utimensat Mtime nanoseconds (utimensat Mtime explicit)");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                           T_ASSERT_EQ((post_st.st_mtimespec.tv_nsec / 1000), (utimes_st.st_mtimespec.tv_nsec / 1000), "post stat vs. utimes Mtime nanoseconds (utimensat Mtime explicit)");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+out:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   unlink(FILENAME);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   unlink(FILENAME "-utimes");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+err:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   ret = EXIT_FAILURE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   goto out;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span></pre><pre style='margin:0'>

</pre>