summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authordchagin <dchagin@FreeBSD.org>2016-01-09 17:41:00 +0000
committerdchagin <dchagin@FreeBSD.org>2016-01-09 17:41:00 +0000
commit1e80f16f0f3065e31e936081a69ab880a5266732 (patch)
treef4cfb7d676cfe801593bf44f091f4fe70d802cab /sys
parent48b0af056fc8895a654ad8e6f4b63f6cd1bd5128 (diff)
downloadFreeBSD-src-1e80f16f0f3065e31e936081a69ab880a5266732.zip
FreeBSD-src-1e80f16f0f3065e31e936081a69ab880a5266732.tar.gz
MFC r283480:
Add utimensat() system call.
Diffstat (limited to 'sys')
-rw-r--r--sys/amd64/linux/linux_dummy.c1
-rw-r--r--sys/amd64/linux/syscalls.master3
-rw-r--r--sys/amd64/linux32/linux32_dummy.c1
-rw-r--r--sys/amd64/linux32/syscalls.master3
-rw-r--r--sys/compat/linux/linux_misc.c81
-rw-r--r--sys/compat/linux/linux_misc.h3
-rw-r--r--sys/i386/linux/linux_dummy.c1
-rw-r--r--sys/i386/linux/syscalls.master3
8 files changed, 90 insertions, 6 deletions
diff --git a/sys/amd64/linux/linux_dummy.c b/sys/amd64/linux/linux_dummy.c
index 865cbfc..38c14ad 100644
--- a/sys/amd64/linux/linux_dummy.c
+++ b/sys/amd64/linux/linux_dummy.c
@@ -98,7 +98,6 @@ DUMMY(tee);
DUMMY(sync_file_range);
DUMMY(vmsplice);
DUMMY(move_pages);
-DUMMY(utimensat);
DUMMY(epoll_pwait);
DUMMY(signalfd);
DUMMY(timerfd);
diff --git a/sys/amd64/linux/syscalls.master b/sys/amd64/linux/syscalls.master
index 9399cf7..0a23114 100644
--- a/sys/amd64/linux/syscalls.master
+++ b/sys/amd64/linux/syscalls.master
@@ -468,7 +468,8 @@
277 AUE_NULL STD { int linux_sync_file_range(void); }
278 AUE_NULL STD { int linux_vmsplice(void); }
279 AUE_NULL STD { int linux_move_pages(void); }
-280 AUE_NULL STD { int linux_utimensat(void); }
+280 AUE_FUTIMESAT STD { int linux_utimensat(l_int dfd, const char *pathname, \
+ const struct l_timespec *times, l_int flags); }
281 AUE_NULL STD { int linux_epoll_pwait(l_int epfd, struct epoll_event *events, \
l_int maxevents, l_int timeout, l_sigset_t *mask); }
282 AUE_NULL STD { int linux_signalfd(void); }
diff --git a/sys/amd64/linux32/linux32_dummy.c b/sys/amd64/linux32/linux32_dummy.c
index 63b16cc..51b3207 100644
--- a/sys/amd64/linux32/linux32_dummy.c
+++ b/sys/amd64/linux32/linux32_dummy.c
@@ -105,7 +105,6 @@ DUMMY(move_pages);
DUMMY(getcpu);
DUMMY(epoll_pwait);
/* linux 2.6.22: */
-DUMMY(utimensat);
DUMMY(signalfd);
DUMMY(timerfd_create);
/* linux 2.6.25: */
diff --git a/sys/amd64/linux32/syscalls.master b/sys/amd64/linux32/syscalls.master
index 0dd1fb4..5413a33 100644
--- a/sys/amd64/linux32/syscalls.master
+++ b/sys/amd64/linux32/syscalls.master
@@ -533,7 +533,8 @@
319 AUE_NULL STD { int linux_epoll_pwait(l_int epfd, struct epoll_event *events, \
l_int maxevents, l_int timeout, l_osigset_t *mask); }
; linux 2.6.22:
-320 AUE_NULL STD { int linux_utimensat(void); }
+320 AUE_FUTIMESAT STD { int linux_utimensat(l_int dfd, const char *pathname, \
+ const struct l_timespec *times, l_int flags); }
321 AUE_NULL STD { int linux_signalfd(void); }
322 AUE_NULL STD { int linux_timerfd_create(void); }
323 AUE_NULL STD { int linux_eventfd(l_uint initval); }
diff --git a/sys/compat/linux/linux_misc.c b/sys/compat/linux/linux_misc.c
index b377f7f..1c626ad 100644
--- a/sys/compat/linux/linux_misc.c
+++ b/sys/compat/linux/linux_misc.c
@@ -823,6 +823,87 @@ linux_utimes(struct thread *td, struct linux_utimes_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 = NULL;
+ char *path = NULL;
+ int error, dfd, flags = 0;
+
+ dfd = (args->dfd == LINUX_AT_FDCWD) ? AT_FDCWD : args->dfd;
+
+#ifdef DEBUG
+ if (ldebug(utimensat))
+ printf(ARGS(utimensat, "%d, *"), dfd);
+#endif
+
+ if (args->flags & ~LINUX_AT_SYMLINK_NOFOLLOW)
+ return (EINVAL);
+
+ if (args->times != NULL) {
+ error = copyin(args->times, l_times, sizeof(l_times));
+ if (error != 0)
+ return (error);
+
+ if (l_times[0].tv_nsec > 999999999 ||
+ l_times[1].tv_nsec > 999999999)
+ 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 (times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT)
+ /* 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. */
+ return (0);
+
+ if (args->pathname != NULL)
+ LCONVPATHEXIST_AT(td, args->pathname, &path, dfd);
+ else if (args->flags != 0)
+ return (EINVAL);
+
+ if (args->flags & LINUX_AT_SYMLINK_NOFOLLOW)
+ flags |= AT_SYMLINK_NOFOLLOW;
+
+ if (path == NULL)
+ error = kern_futimens(td, dfd, timesp, UIO_SYSSPACE);
+ else {
+ error = kern_utimensat(td, dfd, path, UIO_SYSSPACE, timesp,
+ UIO_SYSSPACE, flags);
+ LFREEPATH(path);
+ }
+
+ return (error);
+}
+
int
linux_futimesat(struct thread *td, struct linux_futimesat_args *args)
{
diff --git a/sys/compat/linux/linux_misc.h b/sys/compat/linux/linux_misc.h
index 7202e4a..f969c4d 100644
--- a/sys/compat/linux/linux_misc.h
+++ b/sys/compat/linux/linux_misc.h
@@ -119,6 +119,9 @@ struct l_new_utsname {
#define LINUX_CLOCK_REALTIME_HR 4
#define LINUX_CLOCK_MONOTONIC_HR 5
+#define LINUX_UTIME_NOW 0x3FFFFFFF
+#define LINUX_UTIME_OMIT 0x3FFFFFFE
+
extern int stclohz;
#define LINUX_WNOHANG 0x00000001
diff --git a/sys/i386/linux/linux_dummy.c b/sys/i386/linux/linux_dummy.c
index d70a126..8b57c66 100644
--- a/sys/i386/linux/linux_dummy.c
+++ b/sys/i386/linux/linux_dummy.c
@@ -101,7 +101,6 @@ DUMMY(move_pages);
DUMMY(getcpu);
DUMMY(epoll_pwait);
/* linux 2.6.22: */
-DUMMY(utimensat);
DUMMY(signalfd);
DUMMY(timerfd_create);
/* linux 2.6.25: */
diff --git a/sys/i386/linux/syscalls.master b/sys/i386/linux/syscalls.master
index 72325f6..3864762 100644
--- a/sys/i386/linux/syscalls.master
+++ b/sys/i386/linux/syscalls.master
@@ -541,7 +541,8 @@
319 AUE_NULL STD { int linux_epoll_pwait(l_int epfd, struct epoll_event *events, \
l_int maxevents, l_int timeout, l_osigset_t *mask); }
; linux 2.6.22:
-320 AUE_NULL STD { int linux_utimensat(void); }
+320 AUE_FUTIMESAT STD { int linux_utimensat(l_int dfd, const char *pathname, \
+ const struct l_timespec *times, l_int flags); }
321 AUE_NULL STD { int linux_signalfd(void); }
322 AUE_NULL STD { int linux_timerfd_create(void); }
323 AUE_NULL STD { int linux_eventfd(l_uint initval); }
OpenPOWER on IntegriCloud