aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitry Chagin <dchagin@FreeBSD.org>2021-06-07 01:54:30 +0000
committerDmitry Chagin <dchagin@FreeBSD.org>2021-06-07 01:54:30 +0000
commite4bffb80bbc6a2e4b3be89aefcbd5bb2c2fc0ba0 (patch)
tree7ee697552469e0988462e5c3fa6f5710f597b515
parentbfcce1a9f6e3c9defde10bb1f83d4ba9752c23f6 (diff)
downloadsrc-e4bffb80bbc6a2e4b3be89aefcbd5bb2c2fc0ba0.tar.gz
src-e4bffb80bbc6a2e4b3be89aefcbd5bb2c2fc0ba0.zip
linux(4): Implement utimensat_time64 system call.
MFC after: 2 weeks
-rw-r--r--sys/amd64/linux32/linux32_dummy_machdep.c1
-rw-r--r--sys/amd64/linux32/syscalls.master7
-rw-r--r--sys/compat/linux/linux_misc.c181
-rw-r--r--sys/i386/linux/linux_dummy_machdep.c1
-rw-r--r--sys/i386/linux/syscalls.master7
5 files changed, 134 insertions, 63 deletions
diff --git a/sys/amd64/linux32/linux32_dummy_machdep.c b/sys/amd64/linux32/linux32_dummy_machdep.c
index 5eb54fefd276..be07eb033e77 100644
--- a/sys/amd64/linux32/linux32_dummy_machdep.c
+++ b/sys/amd64/linux32/linux32_dummy_machdep.c
@@ -76,7 +76,6 @@ DUMMY(timer_gettime64);
DUMMY(timer_settime64);
DUMMY(timerfd_gettime64);
DUMMY(timerfd_settime64);
-DUMMY(utimensat_time64);
DUMMY(pselect6_time64);
DUMMY(ppoll_time64);
DUMMY(io_pgetevents_time64);
diff --git a/sys/amd64/linux32/syscalls.master b/sys/amd64/linux32/syscalls.master
index d7002ed5ac72..67591b487652 100644
--- a/sys/amd64/linux32/syscalls.master
+++ b/sys/amd64/linux32/syscalls.master
@@ -2368,7 +2368,12 @@
int linux_timerfd_settime64(void);
}
412 AUE_NULL STD {
- int linux_utimensat_time64(void);
+ int linux_utimensat_time64(
+ l_int dfd,
+ const char *pathname,
+ const struct l_timespec64 *times64,
+ l_int flags
+ );
}
413 AUE_NULL STD {
int linux_pselect6_time64(void);
diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c
index c3f783694d84..bfa7bb659d5f 100644
--- a/sys/compat/linux/linux_misc.c
+++ b/sys/compat/linux/linux_misc.c
@@ -130,7 +130,14 @@ struct l_pselect6arg {
l_size_t ss_len;
};
-static int linux_utimensat_nsec_valid(l_long);
+static int linux_utimensat_lts_to_ts(struct l_timespec *,
+ struct timespec *);
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+static int linux_utimensat_lts64_to_ts(struct l_timespec64 *,
+ struct timespec *);
+#endif
+static int linux_common_utimensat(struct thread *, int,
+ const char *, struct timespec *, int);
int
linux_sysinfo(struct thread *td, struct linux_sysinfo_args *args)
@@ -780,89 +787,66 @@ linux_utimes(struct thread *td, struct linux_utimes_args *args)
#endif
static int
-linux_utimensat_nsec_valid(l_long nsec)
+linux_utimensat_lts_to_ts(struct l_timespec *l_times, struct timespec *times)
{
- if (nsec == LINUX_UTIME_OMIT || nsec == LINUX_UTIME_NOW)
- return (0);
- if (nsec >= 0 && nsec <= 999999999)
- return (0);
- return (1);
+ if (l_times->tv_nsec != LINUX_UTIME_OMIT &&
+ l_times->tv_nsec != LINUX_UTIME_NOW &&
+ (l_times->tv_nsec < 0 || l_times->tv_nsec > 999999999))
+ return (EINVAL);
+
+ times->tv_sec = l_times->tv_sec;
+ switch (l_times->tv_nsec)
+ {
+ case LINUX_UTIME_OMIT:
+ times->tv_nsec = UTIME_OMIT;
+ break;
+ case LINUX_UTIME_NOW:
+ times->tv_nsec = UTIME_NOW;
+ break;
+ default:
+ times->tv_nsec = l_times->tv_nsec;
+ }
+
+ return (0);
}
-int
-linux_utimensat(struct thread *td, struct linux_utimensat_args *args)
+static int
+linux_common_utimensat(struct thread *td, int ldfd, const char *pathname,
+ struct timespec *timesp, int lflags)
{
- struct l_timespec l_times[2];
- struct timespec times[2], *timesp = NULL;
char *path = NULL;
int error, dfd, flags = 0;
- dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+ dfd = (ldfd == LINUX_AT_FDCWD) ? AT_FDCWD : ldfd;
- if (args->flags & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH))
+ if (lflags & ~(LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH))
return (EINVAL);
- if (args->times != NULL) {
- error = copyin(args->times, l_times, sizeof(l_times));
- if (error != 0)
- return (error);
-
- if (linux_utimensat_nsec_valid(l_times[0].tv_nsec) != 0 ||
- linux_utimensat_nsec_valid(l_times[1].tv_nsec) != 0)
- return (EINVAL);
-
- times[0].tv_sec = l_times[0].tv_sec;
- switch (l_times[0].tv_nsec)
- {
- case LINUX_UTIME_OMIT:
- times[0].tv_nsec = UTIME_OMIT;
- break;
- case LINUX_UTIME_NOW:
- times[0].tv_nsec = UTIME_NOW;
- break;
- default:
- times[0].tv_nsec = l_times[0].tv_nsec;
- }
-
- times[1].tv_sec = l_times[1].tv_sec;
- switch (l_times[1].tv_nsec)
- {
- case LINUX_UTIME_OMIT:
- times[1].tv_nsec = UTIME_OMIT;
- break;
- case LINUX_UTIME_NOW:
- times[1].tv_nsec = UTIME_NOW;
- break;
- default:
- times[1].tv_nsec = l_times[1].tv_nsec;
- break;
- }
- timesp = times;
-
+ if (timesp != NULL) {
/* This breaks POSIX, but is what the Linux kernel does
* _on purpose_ (documented in the man page for utimensat(2)),
* so we must follow that behaviour. */
- if (times[0].tv_nsec == UTIME_OMIT &&
- times[1].tv_nsec == UTIME_OMIT)
+ if (timesp[0].tv_nsec == UTIME_OMIT &&
+ timesp[1].tv_nsec == UTIME_OMIT)
return (0);
}
- if (args->flags & LINUX_AT_SYMLINK_NOFOLLOW)
+ if (lflags & LINUX_AT_SYMLINK_NOFOLLOW)
flags |= AT_SYMLINK_NOFOLLOW;
- if (args->flags & LINUX_AT_EMPTY_PATH)
+ if (lflags & LINUX_AT_EMPTY_PATH)
flags |= AT_EMPTY_PATH;
if (!LUSECONVPATH(td)) {
- if (args->pathname != NULL) {
- return (kern_utimensat(td, dfd, args->pathname,
+ if (pathname != NULL) {
+ return (kern_utimensat(td, dfd, pathname,
UIO_USERSPACE, timesp, UIO_SYSSPACE, flags));
}
}
- if (args->pathname != NULL)
- LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
- else if (args->flags != 0)
+ if (pathname != NULL)
+ LCONVPATHEXIST_AT(td, pathname, &path, dfd);
+ else if (lflags != 0)
return (EINVAL);
if (path == NULL)
@@ -876,6 +860,85 @@ linux_utimensat(struct thread *td, struct linux_utimensat_args *args)
return (error);
}
+int
+linux_utimensat(struct thread *td, struct linux_utimensat_args *args)
+{
+ struct l_timespec l_times[2];
+ struct timespec times[2], *timesp;
+ int error;
+
+ if (args->times != NULL) {
+ error = copyin(args->times, l_times, sizeof(l_times));
+ if (error != 0)
+ return (error);
+
+ error = linux_utimensat_lts_to_ts(&l_times[0], &times[0]);
+ if (error != 0)
+ return (error);
+ error = linux_utimensat_lts_to_ts(&l_times[1], &times[1]);
+ if (error != 0)
+ return (error);
+ timesp = times;
+ } else
+ timesp = NULL;
+
+ return (linux_common_utimensat(td, args->dfd, args->pathname,
+ timesp, args->flags));
+}
+
+#if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
+static int
+linux_utimensat_lts64_to_ts(struct l_timespec64 *l_times, struct timespec *times)
+{
+
+ if (l_times->tv_nsec != LINUX_UTIME_OMIT &&
+ l_times->tv_nsec != LINUX_UTIME_NOW &&
+ (l_times->tv_nsec < 0 || l_times->tv_nsec > 999999999))
+ return (EINVAL);
+
+ times->tv_sec = l_times->tv_sec;
+ switch (l_times->tv_nsec)
+ {
+ case LINUX_UTIME_OMIT:
+ times->tv_nsec = UTIME_OMIT;
+ break;
+ case LINUX_UTIME_NOW:
+ times->tv_nsec = UTIME_NOW;
+ break;
+ default:
+ times->tv_nsec = l_times->tv_nsec;
+ }
+
+ return (0);
+}
+
+int
+linux_utimensat_time64(struct thread *td, struct linux_utimensat_time64_args *args)
+{
+ struct l_timespec64 l_times[2];
+ struct timespec times[2], *timesp;
+ int error;
+
+ if (args->times64 != NULL) {
+ error = copyin(args->times64, l_times, sizeof(l_times));
+ if (error != 0)
+ return (error);
+
+ error = linux_utimensat_lts64_to_ts(&l_times[0], &times[0]);
+ if (error != 0)
+ return (error);
+ error = linux_utimensat_lts64_to_ts(&l_times[1], &times[1]);
+ if (error != 0)
+ return (error);
+ timesp = times;
+ } else
+ timesp = NULL;
+
+ return (linux_common_utimensat(td, args->dfd, args->pathname,
+ timesp, args->flags));
+}
+#endif /* __i386__ || (__amd64__ && COMPAT_LINUX32) */
+
#ifdef LINUX_LEGACY_SYSCALLS
int
linux_futimesat(struct thread *td, struct linux_futimesat_args *args)
diff --git a/sys/i386/linux/linux_dummy_machdep.c b/sys/i386/linux/linux_dummy_machdep.c
index dfcc691a3582..d479ecde7a01 100644
--- a/sys/i386/linux/linux_dummy_machdep.c
+++ b/sys/i386/linux/linux_dummy_machdep.c
@@ -78,7 +78,6 @@ DUMMY(timer_gettime64);
DUMMY(timer_settime64);
DUMMY(timerfd_gettime64);
DUMMY(timerfd_settime64);
-DUMMY(utimensat_time64);
DUMMY(pselect6_time64);
DUMMY(ppoll_time64);
DUMMY(io_pgetevents_time64);
diff --git a/sys/i386/linux/syscalls.master b/sys/i386/linux/syscalls.master
index e2732d211235..5ba21877f42c 100644
--- a/sys/i386/linux/syscalls.master
+++ b/sys/i386/linux/syscalls.master
@@ -2386,7 +2386,12 @@
int linux_timerfd_settime64(void);
}
412 AUE_NULL STD {
- int linux_utimensat_time64(void);
+ int linux_utimensat_time64(
+ l_int dfd,
+ const char *pathname,
+ const struct l_timespec64 *times64,
+ l_int flags
+ );
}
413 AUE_NULL STD {
int linux_pselect6_time64(void);