linux(4): Implement utimensat_time64 system call.

MFC after:	2 weeks
This commit is contained in:
Dmitry Chagin 2021-06-07 04:54:30 +03:00
parent bfcce1a9f6
commit e4bffb80bb
5 changed files with 134 additions and 63 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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);

View File

@ -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);