From: Waldemar Kozaczuk <jwkozac...@gmail.com> Committer: Waldemar Kozaczuk <jwkozac...@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 <jwkozac...@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); -- 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 osv-dev+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/osv-dev/000000000000a53765060c90821d%40google.com.