From: Waldemar Kozaczuk <
jwkoz...@gmail.com>
Committer: Waldemar Kozaczuk <
jwkoz...@gmail.com>
Branch: master
syscalls: fix utimensat
The Linux manual for utimensat states this:
"On Linux, futimens() is a library function implemented on top of
the utimensat() system call. To support this, the Linux
utimensat() system call implements a nonstandard feature: if
pathname is NULL, then the call modifies the timestamps of the
file referred to by the file descriptor dirfd (which may refer to
any type of file). Using this feature, the call
futimens(fd, times) is implemented as:
utimensat(fd, NULL, times, 0);
Note, however, that the glibc wrapper for utimensat() disallows
passing NULL as the value for pathname: the wrapper function
returns the error EINVAL in this case."
To accomodate it, we intruduce new function utimensat4() which is
what linux syscall wrapper delegates to. The new utimensat4() calls
modified sys_utimensat() with the syscall flag argument equal to true.
The modified sys_utimensat() treats the dirfd accordingly in such case.
Signed-off-by: Waldemar Kozaczuk <
jwkoz...@gmail.com>
---
diff --git a/fs/vfs/main.cc b/fs/vfs/main.cc
--- a/fs/vfs/main.cc
+++ b/fs/vfs/main.cc
@@ -2060,7 +2060,22 @@ int utimensat(int dirfd, const char *pathname, const struct timespec times[2], i
{
trace_vfs_utimensat(pathname);
- auto error = sys_utimensat(dirfd, pathname, times, flags);
+ auto error = sys_utimensat(dirfd, pathname, times, flags, false);
+ if (error) {
+ trace_vfs_utimensat_err(error);
+ errno = error;
+ return -1;
+ }
+
+ trace_vfs_utimensat_ret();
+ return 0;
+}
+
+int utimensat4(int dirfd, const char *pathname, const struct timespec times[2], int flags)
+{
+ trace_vfs_utimensat(pathname);
+
+ auto error = sys_utimensat(dirfd, pathname, times, flags, true);
if (error) {
trace_vfs_utimensat_err(error);
errno = error;
diff --git a/fs/vfs/vfs.h b/fs/vfs/vfs.h
--- a/fs/vfs/vfs.h
+++ b/fs/vfs/vfs.h
@@ -120,7 +120,7 @@ int sys_truncate(char *path, off_t length);
int sys_readlink(char *path, char *buf, size_t bufsize, ssize_t *size);
int sys_utimes(char *path, const struct timeval times[2], int flags);
int sys_utimensat(int dirfd, const char *pathname,
- const struct timespec times[2], int flags);
+ const struct timespec times[2], int flags, bool syscall);
int sys_futimens(int fd, const struct timespec times[2]);
int sys_fallocate(struct file *fp, int mode, loff_t offset, loff_t len);
diff --git a/fs/vfs/vfs_syscalls.cc b/fs/vfs/vfs_syscalls.cc
--- a/fs/vfs/vfs_syscalls.cc
+++ b/fs/vfs/vfs_syscalls.cc
@@ -1317,7 +1317,7 @@ void init_timespec(struct timespec &_times, const struct timespec *times)
}
int
-sys_utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags)
+sys_utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags, bool syscall)
{
int error;
std::string ap;
@@ -1356,7 +1356,7 @@ sys_utimensat(int dirfd, const char *pathname, const struct timespec times[2], i
if(!fp->f_dentry)
return EBADF;
- if (!(fp->f_dentry->d_vnode->v_type & VDIR))
+ if (!syscall && !(fp->f_dentry->d_vnode->v_type & VDIR))
return ENOTDIR;
if (pathname)
@@ -1407,7 +1407,7 @@ sys_futimens(int fd, const struct timespec times[2])
return EBADF;
std::string pathname = fp->f_dentry->d_path;
- auto error = sys_utimensat(AT_FDCWD, pathname.c_str(), times, 0);
+ auto error = sys_utimensat(AT_FDCWD, pathname.c_str(), times, 0, false);
return error;
}
diff --git a/linux.cc b/linux.cc
--- a/linux.cc
+++ b/linux.cc
@@ -574,6 +574,9 @@ static long sys_brk(void *addr)
}
}
+#define __NR_utimensat4 __NR_utimensat
+extern int utimensat4(int dirfd, const char *pathname, const struct timespec times[2], int flags);
+
#ifdef SYS_open
TRACEPOINT(trace_syscall_open, "%d <= \"%s\" 0x%x", int, const char *, int);
#endif
@@ -692,7 +695,7 @@ TRACEPOINT(trace_syscall_chdir, "%d <= \"%s\"", int, const char *);
TRACEPOINT(trace_syscall_faccessat, "%d <= %d \"%s\" %d %d", int, int, const char *, int, int);
TRACEPOINT(trace_syscall_kill, "%d <= %d %d", int, pid_t, int);
TRACEPOINT(trace_syscall_alarm, "%d <= %u", int, unsigned int);
-TRACEPOINT(trace_syscall_utimensat, "%d <= %d \"%s\" %p %d", int, int, const char *, const struct timespec*, int);
+TRACEPOINT(trace_syscall_utimensat4, "%d <= %d \"%s\" %p %d", int, int, const char *, const struct timespec*, int);
TRACEPOINT(trace_syscall_symlink, "%d <= \"%s\" \"%s\"", int, const char *, const char *);
TRACEPOINT(trace_syscall_rmdir, "%d <= \"%s\"", int, const char *);
TRACEPOINT(trace_syscall_sethostname, "%d <= \"%s\" %d", int, const char *, int);
@@ -843,7 +846,7 @@ OSV_LIBC_API long syscall(long number, ...)
SYSCALL4(faccessat, int, const char *, int, int);
SYSCALL2(kill, pid_t, int);
SYSCALL1(alarm, unsigned int);
- SYSCALL4(utimensat, int, const char *, const struct timespec*, int);
+ SYSCALL4(utimensat4, int, const char *, const struct timespec*, int);
SYSCALL2(symlink, const char *, const char *);
SYSCALL1(rmdir, const char *);
SYSCALL2(sethostname, const char *, int);