Signed-off-by: David Smith <
d787...@gmail.com>
---
fs/vfs/main.cc | 36 ++++++++++++++++++++++++++++++++++++
fs/vfs/vfs.h | 1 +
fs/vfs/vfs_syscalls.cc | 27 +++++++++++++++++++++++++++
libc/syscall_to_function.h | 2 ++
linux.cc | 2 ++
5 files changed, 68 insertions(+)
diff --git a/fs/vfs/main.cc b/fs/vfs/main.cc
index 55031380..12461995 100644
--- a/fs/vfs/main.cc
+++ b/fs/vfs/main.cc
@@ -833,6 +833,42 @@ mkdir(const char *pathname, mode_t mode)
return -1;
}
+TRACEPOINT(trace_vfs_mkdirat, "%d \"%s\" 0%0o", int, const char*, mode_t);
+TRACEPOINT(trace_vfs_mkdirat_ret, "");
+TRACEPOINT(trace_vfs_mkdirat_err, "%d", int);
+
+int
+mkdirat(int dfd, const char *pathname, mode_t mode)
+{
+ struct task *t = main_task;
+ char path[PATH_MAX];
+ int error;
+
+ mode = apply_umask(mode);
+
+ trace_vfs_mkdirat(dfd, pathname, mode);
+ if ('/' == path[0] || AT_FDCWD == dfd) {
+ // Supplied path is either absolute or relative to cwd
+ // Convert supplied path to a clean fully qualified path
+ if ((error = task_conv(t, pathname, VWRITE, path)) != 0)
+ goto out_errno;
+
+ error = sys_mkdir(path, mode);
+ } else {
+ // Supplied path is relative to folder specified by dfd
+ error = sys_mkdirat(dfd, path, mode);
+ }
+
+ if (error)
+ goto out_errno;
+ trace_vfs_mkdirat_ret();
+ return 0;
+ out_errno:
+ trace_vfs_mkdirat_err(error);
+ errno = error;
+ return -1;
+}
+
TRACEPOINT(trace_vfs_rmdir, "\"%s\"", const char*);
TRACEPOINT(trace_vfs_rmdir_ret, "");
TRACEPOINT(trace_vfs_rmdir_err, "%d", int);
diff --git a/fs/vfs/vfs.h b/fs/vfs/vfs.h
index d86ef957..3fe3ae22 100644
--- a/fs/vfs/vfs.h
+++ b/fs/vfs/vfs.h
@@ -106,6 +106,7 @@ int sys_telldir(struct file *fp, long *loc);
int sys_fchdir(struct file *fp, char *path);
int sys_mkdir(char *path, mode_t mode);
+int sys_mkdirat(int dfd, char *path, mode_t mode);
int sys_rmdir(char *path);
int sys_mknod(char *path, mode_t mode);
int sys_rename(char *src, char *dest);
diff --git a/fs/vfs/vfs_syscalls.cc b/fs/vfs/vfs_syscalls.cc
index cd0d1745..aae6b037 100644
--- a/fs/vfs/vfs_syscalls.cc
+++ b/fs/vfs/vfs_syscalls.cc
@@ -547,6 +547,33 @@ sys_mkdir(char *path, mode_t mode)
return error;
}
+int
+sys_mkdirat(int dfd, char *path, mode_t mode)
+{
+ struct file *fp;
+ int error = fget(dfd, &fp);
+ if (error)
+ return error;
+
+ struct vnode *vp = fp->f_dentry->d_vnode;
+ vn_lock(vp);
+
+ std::unique_ptr<char []> up (new char[PATH_MAX]);
+ char *p = up.get();
+
+ /* build absolute path */
+ strlcpy(p, fp->f_dentry->d_mount->m_path, PATH_MAX);
+ strlcat(p, fp->f_dentry->d_path, PATH_MAX);
+ strlcat(p, "/", PATH_MAX);
+ strlcat(p, path, PATH_MAX);
+
+ vn_unlock(vp);
+ fdrop(fp);
+
+ error = sys_mkdir(p, mode);
+ return error;
+}
+
int
sys_rmdir(char *path)
{
diff --git a/libc/syscall_to_function.h b/libc/syscall_to_function.h
index 73525cfa..6862fe34 100644
--- a/libc/syscall_to_function.h
+++ b/libc/syscall_to_function.h
@@ -19,6 +19,8 @@
#define __OSV_TO_FUNCTION_SYS_writev writev
#define __OSV_TO_FUNCTION_SYS_fstatat fstatat
#define __OSV_TO_FUNCTION_SYS_unlinkat unlinkat
+#define __OSV_TO_FUNCTION_SYS_mkdir mkdir
+#define __OSV_TO_FUNCTION_SYS_mkdirat mkdirat
#undef __syscall
#define __syscall(sys_number, ...) (__OSV_TO_FUNCTION_##sys_number(__VA_ARGS__) < 0 ? -errno : 0)
diff --git a/linux.cc b/linux.cc
index 6eb9d3fe..71ec8da1 100644
--- a/linux.cc
+++ b/linux.cc
@@ -447,6 +447,8 @@ long syscall(long number, ...)
SYSCALL0(getpid);
SYSCALL3(set_mempolicy, int, unsigned long *, unsigned long);
SYSCALL3(sched_setaffinity_syscall, pid_t, unsigned, unsigned long *);
+ SYSCALL2(mkdir, char*, mode_t);
+ SYSCALL3(mkdirat, int, char*, mode_t);
}
debug_always("syscall(): unimplemented system call %d\n", number);
--
2.25.1