<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(×_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(×_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, ×_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(×_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(×_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, ×_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>