Преглед изворни кода

feat(syscall): add getdents64

greatbridf пре 1 година
родитељ
комит
0f9c6c4603
3 измењених фајлова са 66 додато и 5 уклоњено
  1. 7 2
      gblibc/include/fcntl.h
  2. 9 0
      include/kernel/vfs.hpp
  3. 50 3
      src/kernel/syscall.cpp

+ 7 - 2
gblibc/include/fcntl.h

@@ -20,8 +20,13 @@
 #define FD_CLOEXEC 1
 
 #define AT_FDCWD (-100)
-
-#define AT_STATX_SYNC_TYPE 0x6000
+#define AT_SYMLINK_NOFOLLOW   0x100
+#define AT_REMOVEDIR          0x200
+#define AT_SYMLINK_FOLLOW     0x400
+#define AT_STATX_SYNC_AS_STAT 0x0000
+#define AT_STATX_SYNC_TYPE    0x6000
+#define AT_STATX_SYNC_FORCE   0x8000
+#define AT_STATX_DONT_SYNC    0x2000
 
 #ifdef __cplusplus
 extern "C" {

+ 9 - 0
include/kernel/vfs.hpp

@@ -38,6 +38,7 @@
 
 namespace fs {
 using ino_t = size_t;
+using ino64_t = uint64_t;
 using blksize_t = size_t;
 using blkcnt_t = size_t;
 
@@ -86,6 +87,14 @@ struct PACKED user_dirent {
     // uint8_t d_type; // file type, with offset of (d_reclen - 1)
 };
 
+struct user_dirent64 {
+    ino64_t d_ino; // inode number
+    uint64_t d_off; // implementation-defined field, ignored
+    uint16_t d_reclen; // length of this struct user_dirent
+    uint8_t d_type; // file type, with offset of (d_reclen - 1)
+    char d_name[1]; // file name with a padding zero
+};
+
 class vfs {
 public:
     struct dentry {

+ 50 - 3
src/kernel/syscall.cpp

@@ -272,10 +272,13 @@ int _syscall_waitpid(interrupt_stack* data)
 int _syscall_getdents(interrupt_stack* data)
 {
     SYSCALL_ARG1(int, fd);
-    SYSCALL_ARG2(char*, buf);
+    SYSCALL_ARG2(char* __user, buf);
     SYSCALL_ARG3(size_t, cnt);
 
     auto* dir = current_process->files[fd];
+    if (!dir)
+        return -EBADF;
+
     if (dir->type != fs::file::types::ind || !S_ISDIR(dir->ptr.ind->mode))
         return -ENOTDIR;
 
@@ -689,8 +692,8 @@ int _syscall_statx(interrupt_stack* data)
     SYSCALL_ARG4(unsigned int, mask);
     SYSCALL_ARG5(statx* __user, statxbuf);
 
-    // AT_STATX_SYNC_TYPE is the default value
-    if (flags != 0 && !(flags & AT_STATX_SYNC_TYPE))
+    // AT_STATX_SYNC_AS_STAT is the default value
+    if (flags != AT_STATX_SYNC_AS_STAT && !(flags & AT_SYMLINK_NOFOLLOW))
         not_implemented();
 
     if (dirfd != AT_FDCWD)
@@ -728,6 +731,49 @@ int _syscall_fcntl64(interrupt_stack* data)
     }
 }
 
+int _syscall_getdents64(interrupt_stack* data)
+{
+    SYSCALL_ARG1(int, fd);
+    SYSCALL_ARG2(char* __user, buf);
+    SYSCALL_ARG3(size_t, cnt);
+
+    auto* dir = current_process->files[fd];
+    if (!dir)
+        return -EBADF;
+
+    if (dir->type != fs::file::types::ind || !S_ISDIR(dir->ptr.ind->mode))
+        return -ENOTDIR;
+
+    size_t orig_cnt = cnt;
+    int nread = dir->ptr.ind->fs->inode_readdir(dir->ptr.ind, dir->cursor,
+        [&buf, &cnt](const char* fn, size_t len, fs::ino_t ino, uint8_t type) -> int {
+            if (!len)
+                len = strlen(fn);
+
+            size_t reclen = sizeof(fs::user_dirent64) + len;
+            if (cnt < reclen)
+                return GB_FAILED;
+
+            auto* dirp = (fs::user_dirent64*)buf;
+            dirp->d_ino = ino;
+            dirp->d_off = 114514;
+            dirp->d_reclen = reclen;
+            dirp->d_type = type;
+            // TODO: use copy_to_user
+            memcpy(dirp->d_name, fn, len);
+            buf[reclen - 1] = 0;
+
+            buf += reclen;
+            cnt -= reclen;
+            return GB_OK;
+        });
+
+    if (nread > 0)
+        dir->cursor += nread;
+
+    return orig_cnt - cnt;
+}
+
 extern "C" void syscall_entry(interrupt_stack* data)
 {
     int syscall_no = SYSCALL_NO;
@@ -779,6 +825,7 @@ void init_syscall(void)
     syscall_handlers[0xb7] = _syscall_getcwd;
     syscall_handlers[0xc0] = _syscall_mmap_pgoff;
     syscall_handlers[0xc7] = _syscall_getuid;
+    syscall_handlers[0xdc] = _syscall_getdents64;
     syscall_handlers[0xdd] = _syscall_fcntl64;
     syscall_handlers[0xef] = _syscall_sendfile64;
     syscall_handlers[0xf3] = _syscall_set_thread_area;