Pārlūkot izejas kodu

[LibOS] Implement newfstatat() system call

Isaku Yamahata 5 gadi atpakaļ
vecāks
revīzija
a45f3b8196

+ 3 - 1
LibOS/shim/include/shim_table.h

@@ -474,6 +474,8 @@ noreturn int shim_do_exit_group (int error_code);
 int shim_do_tgkill (int tgid, int pid, int sig);
 int shim_do_openat (int dfd, const char * filename, int flags, int mode);
 int shim_do_mkdirat (int dfd, const char * pathname, int mode);
+int shim_do_newfstatat (int dirfd, const char* pathname,
+                        struct stat* statbuf, int flags);
 int shim_do_unlinkat (int dfd, const char * pathname, int flag);
 int shim_do_renameat (int olddfd, const char * pathname, int newdfd,
                       const char * newname);
@@ -812,7 +814,7 @@ int shim_mknodat (int dfd, const char * filename, int mode, unsigned dev);
 int shim_fchownat (int dfd, const char * filename, uid_t user, gid_t group,
                    int flag);
 int shim_futimesat (int dfd, const char * filename, struct timeval * utimes);
-int shim_newfstatat (int dfd, const char * filename, struct stat * statbuf,
+int shim_newfstatat (int dfd, const char* filename, struct stat* statbuf,
                      int flag);
 int shim_unlinkat (int dfd, const char * pathname, int flag);
 int shim_renameat (int olddfd, const char * oldname, int newdfd,

+ 4 - 2
LibOS/shim/src/shim_syscalls.c

@@ -1004,8 +1004,10 @@ DEFINE_SHIM_SYSCALL (fchownat, 5, shim_do_fchownat, int, int, dfd,
 SHIM_SYSCALL_PASSTHROUGH (futimesat, 3, int, int, dfd, const char *, filename,
                           struct timeval *, utimes)
 
-SHIM_SYSCALL_PASSTHROUGH (newfstatat, 4, int, int, dfd, const char *, filename,
-                          struct stat *, statbuf, int, flag)
+/* fstatat: sys/shim_stat.c */
+DEFINE_SHIM_SYSCALL (newfstatat, 4, shim_do_newfstatat, int, int, dfd,
+                     const char*, filename, struct stat*, statbuf,
+                     int, flag)
 
 /* unlinkat: sys/shim_fs.c */
 DEFINE_SHIM_SYSCALL (unlinkat, 3, shim_do_unlinkat, int, int, dfd,

+ 57 - 0
LibOS/shim/src/sys/shim_stat.c

@@ -25,12 +25,15 @@
 #include <shim_handle.h>
 #include <shim_fs.h>
 #include <shim_profile.h>
+#include <shim_thread.h>
 
 #include <pal.h>
 #include <pal_error.h>
 
 #include <errno.h>
 
+#include <linux/fcntl.h>
+
 int shim_do_stat (const char * file, struct stat * stat)
 {
     if (!file || test_user_string(file))
@@ -195,3 +198,57 @@ int shim_do_fstatfs (int fd, struct statfs * buf)
     put_handle(hdl);
     return __do_statfs (fs, buf);
 }
+
+int shim_do_newfstatat(int dirfd, const char* pathname,
+                       struct stat* statbuf, int flags)
+{
+    if (flags & ~(AT_EMPTY_PATH | AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW))
+        return -EINVAL;
+    if (test_user_string(pathname))
+        return -EFAULT;
+    if (test_user_memory(statbuf, sizeof(*statbuf), true))
+        return -EFAULT;
+
+    int lookup_flags = LOOKUP_ACCESS | LOOKUP_FOLLOW;
+    if (flags & AT_SYMLINK_NOFOLLOW)
+        lookup_flags &= ~LOOKUP_FOLLOW;
+    if (flags & AT_NO_AUTOMOUNT) {
+        /* Do nothing as automount isn't supported */
+        debug("ignoring AT_NO_AUTOMOUNT.");
+    }
+
+    if (!*pathname){
+        if (!(flags & AT_EMPTY_PATH))
+            return -ENOENT;
+
+        if (dirfd == AT_FDCWD) {
+            struct shim_dentry * cwd = get_cur_thread()->cwd;
+            struct shim_d_ops* d_ops = cwd->fs->d_ops;
+            if (d_ops && d_ops->stat)
+                return d_ops->stat(cwd, statbuf);
+            return -EACCES;
+        }
+        return shim_do_fstat(dirfd, statbuf);
+    }
+
+    struct shim_dentry* dir = NULL;
+    if (*pathname != '/') {
+        int ret = path_startat(dirfd, &dir);
+        if (ret < 0)
+            return ret;
+    }
+
+    struct shim_dentry* dent;
+    int ret = path_lookupat(dir, pathname, lookup_flags, &dent, NULL);
+    if (ret >= 0) {
+        struct shim_d_ops* d_ops = dent->fs->d_ops;
+        if (d_ops && d_ops->stat)
+            ret = d_ops->stat(dent, statbuf);
+        else
+            ret = -EACCES;
+        put_dentry(dent);
+    }
+    if (dir)
+        put_dentry(dir);
+    return ret;
+}