From: Waldemar Kozaczuk <[email protected]>
Committer: Waldemar Kozaczuk <[email protected]>
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 <[email protected]>
---
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);
--
You received this message because you are subscribed to the Google Groups "OSv
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/osv-dev/000000000000a53765060c90821d%40google.com.