about summary refs log tree commit diff
path: root/src/stat/utimensat.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/stat/utimensat.c')
-rw-r--r--src/stat/utimensat.c37
1 files changed, 31 insertions, 6 deletions
diff --git a/src/stat/utimensat.c b/src/stat/utimensat.c
index 49d74c22..730723a9 100644
--- a/src/stat/utimensat.c
+++ b/src/stat/utimensat.c
@@ -4,26 +4,51 @@
 #include <errno.h>
 #include "syscall.h"
 
+#define IS32BIT(x) !((x)+0x80000000ULL>>32)
+#define NS_SPECIAL(ns) ((ns)==UTIME_NOW || (ns)==UTIME_OMIT)
+
 int utimensat(int fd, const char *path, const struct timespec times[2], int flags)
 {
+	int r;
 	if (times && times[0].tv_nsec==UTIME_NOW && times[1].tv_nsec==UTIME_NOW)
 		times = 0;
-	int r = __syscall(SYS_utimensat, fd, path, times, flags);
+#ifdef SYS_utimensat_time64
+	r = -ENOSYS;
+	time_t s0=0, s1=0;
+	long ns0=0, ns1=0;
+	if (times) {
+		ns0 = times[0].tv_nsec;
+		ns1 = times[1].tv_nsec;
+		if (!NS_SPECIAL(ns0)) s0 = times[0].tv_sec;
+		if (!NS_SPECIAL(ns1)) s1 = times[1].tv_sec;
+	}
+	if (SYS_utimensat == SYS_utimensat_time64 || !IS32BIT(s0) || !IS32BIT(s1))
+		r = __syscall(SYS_utimensat_time64, fd, path, times ?
+			((long long[]){s0, ns0, s1, ns1}) : 0, flags);
+	if (SYS_utimensat == SYS_utimensat_time64 || r!=-ENOSYS)
+		return __syscall_ret(r);
+	if (!IS32BIT(s0) || !IS32BIT(s1))
+		return __syscall_ret(-ENOTSUP);
+	r = __syscall(SYS_utimensat, fd, path,
+		times ? ((long[]){s0, ns0, s1, ns1}) : 0, flags);
+#else
+	r = __syscall(SYS_utimensat, fd, path, times, flags);
+#endif
+
 #ifdef SYS_futimesat
 	if (r != -ENOSYS || flags) return __syscall_ret(r);
-	struct timeval *tv = 0, tmp[2];
+	long *tv=0, tmp[4];
 	if (times) {
 		int i;
 		tv = tmp;
 		for (i=0; i<2; i++) {
 			if (times[i].tv_nsec >= 1000000000ULL) {
-				if (times[i].tv_nsec == UTIME_NOW
-				 || times[i].tv_nsec == UTIME_OMIT)
+				if (NS_SPECIAL(times[i].tv_nsec))
 					return __syscall_ret(-ENOSYS);
 				return __syscall_ret(-EINVAL);
 			}
-			tmp[i].tv_sec = times[i].tv_sec;
-			tmp[i].tv_usec = times[i].tv_nsec / 1000;
+			tmp[2*i+0] = times[i].tv_sec;
+			tmp[2*i+1] = times[i].tv_nsec / 1000;
 		}
 	}