Browse Source

feat(open): open() can now create new files

greatbridf 1 year ago
parent
commit
6d321f5eac

+ 1 - 0
gblibc/include/fcntl.h

@@ -7,6 +7,7 @@
 #define O_WRONLY          01
 #define O_RDWR            02
 #define O_CREAT         0100
+#define O_EXCL          0200
 #define O_TRUNC        01000
 #define O_APPEND       02000
 #define O_DIRECTORY  0200000

+ 17 - 14
include/kernel/errno.h

@@ -15,19 +15,22 @@ extern uint32_t* _get_errno(void);
 }
 #endif
 
-#define ENOMEM (1 << 0)
-#define EEXIST (1 << 1)
-#define ENOENT (1 << 2)
-#define EINVAL (1 << 3)
-#define EISDIR (1 << 4)
-#define ENOTDIR (1 << 5)
-#define ENOTFOUND (1 << 6)
-#define ECHILD (1 << 7)
-#define EBADF (1 << 8)
-#define EPERM (1 << 9)
-#define ESRCH (1 << 10)
-#define EINTR (1 << 11)
-#define EPIPE (1 << 12)
-#define ENOTTY (1 << 13)
+#define EPERM 1
+#define ENOENT 2
+#define ESRCH 3
+#define EINTR 4
+#define EBADF 9
+#define ECHILD 10
+#define ENOMEM 12
+#define EACCES 13
+#define EEXIST 17
+#define ENOTDIR 20
+#define EISDIR 21
+#define EINVAL 22
+#define ENOTTY 25
+#define EPIPE 32
+
+// non-standard errors
+#define ENOTFOUND 200
 
 #endif

+ 1 - 1
include/kernel/process.hpp

@@ -245,7 +245,7 @@ public:
         return 0;
     }
 
-    int open(const process& current, const types::path& filepath, uint32_t flags);
+    int open(const process& current, const types::path& filepath, int flags, mode_t mode);
 
     constexpr void close(int fd)
     {

+ 2 - 2
include/kernel/vfs.hpp

@@ -202,7 +202,7 @@ public:
 
     virtual size_t inode_read(inode* file, char* buf, size_t buf_size, size_t offset, size_t n);
     virtual size_t inode_write(inode* file, const char* buf, size_t offset, size_t n);
-    virtual int inode_mkfile(dentry* dir, const char* filename);
+    virtual int inode_mkfile(dentry* dir, const char* filename, mode_t mode);
     virtual int inode_mknode(dentry* dir, const char* filename, union node_t sn);
     virtual int inode_rmfile(dentry* dir, const char* filename);
     virtual int inode_mkdir(dentry* dir, const char* dirname);
@@ -289,7 +289,7 @@ vfs* register_fs(vfs* fs);
 
 size_t vfs_read(inode* file, char* buf, size_t buf_size, size_t offset, size_t n);
 size_t vfs_write(inode* file, const char* buf, size_t offset, size_t n);
-int vfs_mkfile(fs::vfs::dentry* dir, const char* filename);
+int vfs_mkfile(fs::vfs::dentry* dir, const char* filename, mode_t mode);
 int vfs_mknode(fs::vfs::dentry* dir, const char* filename, node_t sn);
 int vfs_rmfile(fs::vfs::dentry* dir, const char* filename);
 int vfs_mkdir(fs::vfs::dentry* dir, const char* dirname);

+ 40 - 10
src/kernel/process.cpp

@@ -1,5 +1,7 @@
 #include <utility>
 
+#include <bits/alltypes.h>
+
 #include <asm/port_io.h>
 #include <asm/sys.h>
 #include <assert.h>
@@ -92,19 +94,47 @@ void kernel::tasks::thread::free_kstack(uint32_t p)
 }
 
 // TODO: file opening permissions check
-int filearr::open(const process &current, const types::path& filepath, uint32_t flags)
+int filearr::open(const process &current,
+    const types::path& filepath, int flags, mode_t mode)
 {
     auto* dentry = fs::vfs_open(*current.root, filepath);
 
-    if (!dentry) {
-        errno = ENOTFOUND;
-        return -1;
+    if (flags & O_CREAT) {
+        if (!dentry) {
+            // create file
+            auto filename = filepath.last_name();
+            auto parent_path = filepath;
+            parent_path.remove_last();
+
+            auto* parent = fs::vfs_open(*current.root, parent_path);
+            if (!parent)
+                return -EINVAL;
+            int ret = fs::vfs_mkfile(parent, filename.c_str(), mode);
+            if (ret != GB_OK)
+                return ret;
+            dentry = fs::vfs_open(*current.root, filepath);
+            assert(dentry);
+        } else {
+            // file already exists
+            if (flags & O_EXCL)
+                return -EEXIST;
+
+            if (flags & O_TRUNC) {
+                // TODO: truncate file
+            }
+        }
+    } else {
+        if (!dentry)
+            return -ENOENT;
     }
 
     // check whether dentry is a file if O_DIRECTORY is set
-    if ((flags & O_DIRECTORY) && !S_ISDIR(dentry->ind->mode)) {
-        errno = ENOTDIR;
-        return -1;
+    if (flags & O_DIRECTORY) {
+        if (!S_ISDIR(dentry->ind->mode))
+            return -ENOTDIR;
+    } else {
+        if (S_ISDIR(dentry->ind->mode) && (flags & (O_WRONLY | O_RDWR)))
+            return -EISDIR;
     }
 
     auto iter = files->emplace(files->cend(), fs::file {
@@ -358,9 +388,9 @@ void NORETURN init_scheduler(void)
     assert(inserted);
     auto& thd = *iter_thd;
 
-    init.files.open(init, "/dev/console", O_RDONLY);
-    init.files.open(init, "/dev/console", O_WRONLY);
-    init.files.open(init, "/dev/console", O_WRONLY);
+    init.files.open(init, "/dev/console", O_RDONLY, 0);
+    init.files.open(init, "/dev/console", O_WRONLY, 0);
+    init.files.open(init, "/dev/console", O_WRONLY, 0);
 
     // we need interrupts enabled for cow mapping so now we disable it
     // in case timer interrupt mess things up

+ 4 - 3
src/kernel/syscall.cpp

@@ -316,11 +316,12 @@ int _syscall_getdents(interrupt_stack* data)
 
 int _syscall_open(interrupt_stack* data)
 {
-    SYSCALL_ARG1(const char*, path);
-    SYSCALL_ARG2(uint32_t, flags);
+    SYSCALL_ARG1(const char* __user, path);
+    SYSCALL_ARG2(int, flags);
+    SYSCALL_ARG3(mode_t, mode);
 
     return current_process->files.open(*current_process,
-        types::make_path(path, current_process->pwd), flags);
+        types::make_path(path, current_process->pwd), flags, mode);
 }
 
 int _syscall_getcwd(interrupt_stack* data)

+ 13 - 34
src/kernel/vfs.cpp

@@ -177,40 +177,19 @@ int fs::vfs::mount(dentry* mnt, vfs* new_fs)
     return GB_OK;
 }
 size_t fs::vfs::inode_read(inode*, char*, size_t, size_t, size_t)
-{
-    assert(false);
-    return 0xffffffff;
-}
+{ return -EINVAL; }
 size_t fs::vfs::inode_write(inode*, const char*, size_t, size_t)
-{
-    assert(false);
-    return 0xffffffff;
-}
-int fs::vfs::inode_mkfile(dentry*, const char*)
-{
-    assert(false);
-    return GB_FAILED;
-}
+{ return -EINVAL; }
+int fs::vfs::inode_mkfile(dentry*, const char*, mode_t)
+{ return -EINVAL; }
 int fs::vfs::inode_mknode(dentry*, const char*, node_t)
-{
-    assert(false);
-    return GB_FAILED;
-}
+{ return -EINVAL; }
 int fs::vfs::inode_rmfile(dentry*, const char*)
-{
-    assert(false);
-    return GB_FAILED;
-}
+{ return -EINVAL; }
 int fs::vfs::inode_mkdir(dentry*, const char*)
-{
-    assert(false);
-    return GB_FAILED;
-}
+{ return -EINVAL; }
 int fs::vfs::inode_stat(dentry*, statx*, unsigned int)
-{
-    assert(false);
-    return GB_FAILED;
-}
+{ return -EINVAL; }
 uint32_t fs::vfs::inode_getnode(fs::inode*)
 {
     assert(false);
@@ -319,9 +298,9 @@ public:
         register_root_node(&in);
     }
 
-    virtual int inode_mkfile(dentry* dir, const char* filename) override
+    virtual int inode_mkfile(dentry* dir, const char* filename, mode_t mode) override
     {
-        auto& file = *cache_inode(0, _savedata(mk_data_vector()), S_IFREG | 0777, 0, 0);
+        auto& file = *cache_inode(0, _savedata(mk_data_vector()), S_IFREG | mode, 0, 0);
         mklink(dir->ind, &file, filename);
         dir->append(get_inode(file.ino), filename, true);
         return GB_OK;
@@ -487,9 +466,9 @@ size_t fs::vfs_write(fs::inode* file, const char* buf, size_t offset, size_t n)
         return file->fs->inode_write(file, buf, offset, n);
     }
 }
-int fs::vfs_mkfile(fs::vfs::dentry* dir, const char* filename)
+int fs::vfs_mkfile(fs::vfs::dentry* dir, const char* filename, mode_t mode)
 {
-    return dir->ind->fs->inode_mkfile(dir, filename);
+    return dir->ind->fs->inode_mkfile(dir, filename, mode);
 }
 int fs::vfs_mknode(fs::vfs::dentry* dir, const char* filename, fs::node_t sn)
 {
@@ -681,7 +660,7 @@ void init_vfs(void)
     vfs_mkdir(fs_root, "dev");
     vfs_mkdir(fs_root, "root");
     vfs_mkdir(fs_root, "mnt");
-    vfs_mkfile(fs_root, "init");
+    vfs_mkfile(fs_root, "init", 0755);
 
     auto* init = vfs_open(*fs_root, "/init");
     assert(init);