Pārlūkot izejas kodu

feat(types::path): add types::path to handle paths

greatbridf 1 gadu atpakaļ
vecāks
revīzija
b5faee6ded

+ 3 - 2
include/kernel/process.hpp

@@ -21,6 +21,7 @@
 #include <types/allocator.hpp>
 #include <types/cplusplus.hpp>
 #include <types/hash_map.hpp>
+#include <types/path.hpp>
 #include <types/status.h>
 #include <types/string.hpp>
 #include <types/types.h>
@@ -244,7 +245,7 @@ public:
         return 0;
     }
 
-    int open(const process& current, const char* filename, uint32_t flags);
+    int open(const process& current, const types::path& filepath, uint32_t flags);
 
     constexpr void close(int fd)
     {
@@ -294,7 +295,7 @@ public:
     std::list<wait_obj> waitlist;
     process_attr attr {};
     filearr files;
-    types::string<> pwd;
+    types::path pwd;
     kernel::signal_list signals;
 
     pid_t pid {};

+ 11 - 8
include/kernel/vfs.hpp

@@ -15,6 +15,7 @@
 #include <types/buffer.hpp>
 #include <types/cplusplus.hpp>
 #include <types/hash_map.hpp>
+#include <types/path.hpp>
 #include <types/lock.hpp>
 #include <types/types.h>
 
@@ -159,7 +160,7 @@ public:
         dentry* replace(dentry* val);
 
         // out_dst SHOULD be empty
-        void path(const dentry& root, name_type& out_dst) const;
+        void path(const dentry& root, types::path& out_dst) const;
 
         void invalidate(void);
     };
@@ -294,13 +295,15 @@ int vfs_rmfile(fs::vfs::dentry* dir, const char* filename);
 int vfs_mkdir(fs::vfs::dentry* dir, const char* dirname);
 int vfs_stat(fs::vfs::dentry* dent, statx* stat, unsigned int mask);
 
-// @param: pwd: current working directory
-//              if nullptr, use root directory
-//              if present, must be a valid absolute path
-//
-// @return pointer to the dentry if found, nullptr if not
-fs::vfs::dentry* vfs_open(fs::vfs::dentry& root,
-    const char* pwd, const char* path);
+/**
+ * @brief Opens a file or directory specified by the given path.
+ * 
+ * @param root The root directory of the file system.
+ * @param path The absolute path to the file or directory to be opened.
+ * @return A pointer to the opened file or directory entry if found.
+ *         Otherwise, nullptr is returned.
+ */
+fs::vfs::dentry* vfs_open(fs::vfs::dentry& root, const types::path& path);
 
 } // namespace fs
 

+ 111 - 2
include/types/path.hpp

@@ -1,5 +1,114 @@
 #pragma once
 
-namespace std {
+#include <types/string.hpp>
+#include <vector>
+#include <cstddef>
 
-} // namespace std
+namespace types {
+
+class path {
+public:
+    using item_string = types::string<>;
+    using item_vector = std::vector<item_string>;
+    using string_type = types::string<>;
+    using size_type = std::size_t;
+    using iterator = item_vector::const_iterator;
+
+private:
+    item_vector m_vec;
+
+public:
+    constexpr path() = default;
+    constexpr path(const path& val) = default;
+    constexpr path(path&& val) = default;
+    constexpr path(const char* str, size_type len = -1U)
+    { append(str, len); }
+
+    constexpr path& operator=(const path& val) = default;
+    constexpr path& operator=(path&& val) = default;
+    constexpr path& operator=(const char* str)
+    {
+        m_vec.clear();
+        append(str);
+        return *this;
+    }
+
+    constexpr string_type full_path() const
+    {
+        string_type str;
+        for (auto iter = m_vec.begin(); iter != m_vec.end(); ++iter) {
+            if (iter != m_vec.begin()
+                || (m_vec.front().empty() && m_vec.size() == 1))
+                str += '/';
+            str += *iter;
+        }
+        return str;
+    }
+    constexpr item_string last_name() const
+    { return m_vec.empty() ? item_string {} : m_vec.back(); }
+    constexpr bool empty() const
+    { return m_vec.empty(); }
+
+    constexpr bool is_absolute() const { return !empty() && !m_vec[0][0]; }
+    constexpr bool is_relative() const { return !empty() && !is_absolute(); }
+
+    constexpr path& append(const char* str, size_type len = -1U)
+    {
+        const char* start = str;
+        while (len-- && *str) {
+            if (*str == '/') {
+                if (m_vec.empty() || str != start)
+                    m_vec.emplace_back(start, str - start);
+                start = str + 1;
+            }
+            ++str;
+        }
+        if (str != start || m_vec.size() != 1 || !m_vec.front().empty())
+            m_vec.emplace_back(start, str - start);
+
+        return *this;
+    }
+    constexpr path& append(const path& val)
+    {
+        m_vec.insert(m_vec.end(), val.m_vec.begin(), val.m_vec.end());
+        return *this;
+    }
+
+    constexpr void clear() { m_vec.clear(); }
+    constexpr void remove_last()
+    {
+        if (m_vec.size() > 1)
+            m_vec.pop_back();
+    }
+
+    constexpr path& operator+=(const char* str)
+    { return append(str); }
+    constexpr path& operator+=(const path& val)
+    { return append(val); }
+
+    constexpr bool operator==(const char* str) const
+    {
+        return full_path() == str;
+    }
+
+    constexpr iterator begin() const { return m_vec.cbegin(); }
+    constexpr iterator end() const { return m_vec.cend(); }
+};
+
+constexpr path make_path(const char* pathstr, const char* pwd)
+{
+    if (*pathstr && pathstr[0] == '/')
+        return pathstr;
+    else
+        return path { pwd }.append(pathstr);
+}
+
+constexpr path make_path(const char* pathstr, const path& pwd)
+{
+    if (*pathstr && pathstr[0] == '/')
+        return pathstr;
+    else
+        return path{pwd}.append(pathstr);
+}
+
+} // namespace types

+ 23 - 21
include/types/string.hpp

@@ -7,20 +7,20 @@
 #include <types/types.h>
 
 namespace types {
-template <typename Allocator =
-    types::allocator_adapter<char, types::kernel_allocator>>
+
+template <typename Allocator = std::allocator<char>>
 class string : public std::vector<char, Allocator> {
 public:
-    using inner_vector_type = std::vector<char, Allocator>;
-    using size_type = typename inner_vector_type::size_type;
-    using iterator = typename inner_vector_type::iterator;
-    using const_iterator = typename inner_vector_type::const_iterator;
+    using _vector = std::vector<char, Allocator>;
+    using size_type = typename _vector::size_type;
+    using iterator = typename _vector::iterator;
+    using const_iterator = typename _vector::const_iterator;
 
-    static inline constexpr size_type npos = (-1U);
+    static constexpr size_type npos = -1U;
 
 public:
     constexpr string()
-        : inner_vector_type()
+        : _vector()
     {
         this->reserve(8);
         this->push_back(0x00);
@@ -32,14 +32,9 @@ public:
     }
     constexpr string& append(const char* str, size_type n = npos)
     {
-        this->pop_back();
-
-        while (n-- && *str != 0x00) {
-            this->push_back(*str);
-            ++str;
-        }
-
-        this->push_back(0x00);
+        size_type len = strlen(str);
+        const char* last = str + (len < n ? len : n);
+        this->insert(end(), str, last);
         return *this;
     }
     constexpr string& append(const string& str)
@@ -78,22 +73,29 @@ public:
     }
     constexpr void clear()
     {
-        inner_vector_type::clear();
+        _vector::clear();
         this->push_back(0x00);
     }
     constexpr char pop(void)
     {
         this->pop_back();
-        auto& ref = inner_vector_type::back();
+        auto& ref = _vector::back();
         char c = ref;
         ref = 0x00;
         return c;
     }
     constexpr iterator end() noexcept
-    { return --inner_vector_type::end(); }
+    { return --_vector::end(); }
     constexpr const_iterator end() const noexcept
-    { return --inner_vector_type::cend(); }
+    { return --_vector::cend(); }
     constexpr const_iterator cend() const noexcept
-    { return --inner_vector_type::cend(); }
+    { return --_vector::cend(); }
+    constexpr char back() const noexcept
+    { return *--cend(); }
+    constexpr size_type size() const noexcept
+    { return _vector::size() - 1; }
+    constexpr bool empty() const noexcept
+    { return _vector::size() == 1; }
 };
+
 } // namespace types

+ 2 - 2
src/kernel/hw/ata.cpp

@@ -182,7 +182,7 @@ static inline void mbr_part_probe(fs::inode* drive, uint16_t major, uint16_t min
     struct mbr hda_mbr {
     };
     // TODO: devtmpfs
-    auto* dev = fs::vfs_open(*fs::fs_root, nullptr, "/dev");
+    auto* dev = fs::vfs_open(*fs::fs_root, "/dev");
     assert(dev);
 
     fs::vfs_read(drive, (char*)&hda_mbr, 512, 0, 512);
@@ -229,7 +229,7 @@ void hw::init_ata(void)
         0,
         0xffffffff);
 
-    auto* hda = fs::vfs_open(*fs::fs_root, nullptr, "/dev/hda");
+    auto* hda = fs::vfs_open(*fs::fs_root, "/dev/hda");
     assert(hda);
     mbr_part_probe(hda->ind, 2, 1);
 }

+ 5 - 5
src/kernel/process.cpp

@@ -92,9 +92,9 @@ void kernel::tasks::thread::free_kstack(uint32_t p)
 }
 
 // TODO: file opening permissions check
-int filearr::open(const process &current, const char *filename, uint32_t flags)
+int filearr::open(const process &current, const types::path& filepath, uint32_t flags)
 {
-    auto* dentry = fs::vfs_open(*current.root, current.pwd.c_str(), filename);
+    auto* dentry = fs::vfs_open(*current.root, filepath);
 
     if (!dentry) {
         errno = ENOTFOUND;
@@ -268,10 +268,10 @@ void NORETURN _kernel_init(void)
     hw::init_ata();
 
     // TODO: parse kernel parameters
-    auto* drive = fs::vfs_open(*fs::fs_root, nullptr, "/dev/hda1");
+    auto* drive = fs::vfs_open(*fs::fs_root, "/dev/hda1");
     assert(drive);
     auto* _new_fs = fs::register_fs(new fs::fat::fat32(drive->ind));
-    auto* mnt = fs::vfs_open(*fs::fs_root, nullptr, "/mnt");
+    auto* mnt = fs::vfs_open(*fs::fs_root, "/mnt");
     assert(mnt);
     int ret = fs::fs_root->ind->fs->mount(mnt, _new_fs);
     assert(ret == GB_OK);
@@ -287,7 +287,7 @@ void NORETURN _kernel_init(void)
     d.envp = envp;
     d.system = false;
 
-    d.exec_dent = fs::vfs_open(*fs::fs_root, nullptr, "/mnt/init");
+    d.exec_dent = fs::vfs_open(*fs::fs_root, "/mnt/init");
     if (!d.exec_dent) {
         console->print("kernel panic: init not found!\n");
         freeze();

+ 8 - 6
src/kernel/syscall.cpp

@@ -22,6 +22,7 @@
 #include <string.h>
 #include <types/allocator.hpp>
 #include <types/elf.hpp>
+#include <types/path.hpp>
 #include <types/lock.hpp>
 #include <types/status.h>
 
@@ -165,7 +166,7 @@ int _syscall_chdir(interrupt_stack* data)
     SYSCALL_ARG1(const char*, path);
 
     auto* dir = fs::vfs_open(*current_process->root,
-        current_process->pwd.c_str(), path);
+        types::make_path(path, current_process->pwd));
     if (!dir)
         return -ENOENT;
 
@@ -194,7 +195,7 @@ int _syscall_execve(interrupt_stack* data)
     d.system = false;
 
     d.exec_dent = fs::vfs_open(*current_process->root,
-        current_process->pwd.c_str(), exec);
+        types::make_path(exec, current_process->pwd));
     
     if (!d.exec_dent)
         return -ENOENT;
@@ -318,8 +319,8 @@ int _syscall_open(interrupt_stack* data)
     SYSCALL_ARG1(const char*, path);
     SYSCALL_ARG2(uint32_t, flags);
 
-    return current_process->files.open(
-        *current_process, path, flags);
+    return current_process->files.open(*current_process,
+        types::make_path(path, current_process->pwd), flags);
 }
 
 int _syscall_getcwd(interrupt_stack* data)
@@ -328,7 +329,8 @@ int _syscall_getcwd(interrupt_stack* data)
     SYSCALL_ARG2(size_t, bufsize);
 
     // TODO: use copy_to_user
-    strncpy(buf, current_process->pwd.c_str(), bufsize);
+    auto path = current_process->pwd.full_path();
+    strncpy(buf, path.c_str(), bufsize);
     buf[bufsize - 1] = 0;
 
     return (uint32_t)buf;
@@ -700,7 +702,7 @@ int _syscall_statx(interrupt_stack* data)
         not_implemented();
 
     auto* dent = fs::vfs_open(*current_process->root,
-        current_process->pwd.c_str(), path);
+        types::make_path(path, current_process->pwd));
 
     if (!dent)
         return -ENOENT;

+ 17 - 58
src/kernel/vfs.cpp

@@ -15,11 +15,11 @@
 #include <stdio.h>
 #include <types/allocator.hpp>
 #include <types/status.h>
+#include <types/path.hpp>
 #include <types/string.hpp>
 
 using types::allocator_traits;
 using types::kernel_allocator;
-using types::string;
 
 struct tmpfs_file_entry {
     size_t ino;
@@ -94,7 +94,7 @@ fs::vfs::vfs(void)
 }
 
 void fs::vfs::dentry::path(
-    const dentry& root, name_type &out_dst) const
+    const dentry& root, types::path &out_dst) const
 {
     const dentry* dents[32];
     int cnt = 0;
@@ -106,15 +106,9 @@ void fs::vfs::dentry::path(
         cur = cur->parent;
     }
 
-    if (cnt == 0) {
-        out_dst += '/';
-        return;
-    }
-
-    for (int i = cnt - 1; i >= 0; --i) {
-        out_dst += '/';
-        out_dst += dents[i]->name;
-    }
+    out_dst.append("/");
+    for (int i = cnt - 1; i >= 0; --i)
+        out_dst.append(dents[i]->name.c_str());
 }
 
 fs::inode* fs::vfs::cache_inode(size_t size, ino_t ino,
@@ -510,54 +504,19 @@ int fs::vfs_mkdir(fs::vfs::dentry* dir, const char* dirname)
     return dir->ind->fs->inode_mkdir(dir, dirname);
 }
 
-fs::vfs::dentry* fs::vfs_open(
-    fs::vfs::dentry& root,
-    const char* pwd, const char* path)
+fs::vfs::dentry* fs::vfs_open(fs::vfs::dentry& root, const types::path& path)
 {
-    fs::vfs::dentry* cur = nullptr;
-    if (!*path)
-        return nullptr;
-
-    // absolute path
-    if (*path == '/' || !pwd)
-        cur = &root;
-    else
-        cur = vfs_open(root, nullptr, pwd);
-
-    size_t n = 0;
-    string curpath;
-    while (true) {
-        switch (path[n]) {
-        case '\0':
-            if (n != 0) {
-                curpath.clear();
-                curpath.append(path, n);
-                cur = cur->find(curpath);
-            }
-            return cur;
+    fs::vfs::dentry* cur = &root;
 
-        case '/':
-            if (n == 0) {
-                ++path;
-                continue;
-            }
-
-            curpath.clear();
-            curpath.append(path, n);
-            cur = cur->find(curpath);
-
-            if (!cur)
-                return cur;
-
-            path += (n + 1);
-            n = 0;
-            break;
-
-        default:
-            ++n;
-            break;
-        }
+    for (const auto& item : path) {
+        if (item.empty())
+            continue;
+        cur = cur->find(item);
+        if (!cur)
+            return nullptr;
     }
+
+    return cur;
 }
 
 int fs::vfs_stat(fs::vfs::dentry* ent, statx* stat, unsigned int mask)
@@ -724,12 +683,12 @@ void init_vfs(void)
     vfs_mkdir(fs_root, "mnt");
     vfs_mkfile(fs_root, "init");
 
-    auto* init = vfs_open(*fs_root, nullptr, "/init");
+    auto* init = vfs_open(*fs_root, "/init");
     assert(init);
     const char* str = "#/bin/sh\nexec /bin/sh\n";
     vfs_write(init->ind, str, 0, strlen(str));
 
-    auto* dev = vfs_open(*fs_root, nullptr, "/dev");
+    auto* dev = vfs_open(*fs_root, "/dev");
     assert(dev);
     vfs_mknode(dev, "null", { .in { .major = 0, .minor = 0 } });
     vfs_mknode(dev, "console", { .in { .major = 1, .minor = 0 } });

+ 1 - 1
src/types/elf.cpp

@@ -91,7 +91,7 @@ int types::elf::elf32_load(types::elf::elf32_load_data* d)
     // TODO: remove this
     fs::inode* null_ind = nullptr;
     {
-        auto* dent = fs::vfs_open(*fs::fs_root, nullptr, "/dev/null");
+        auto* dent = fs::vfs_open(*fs::fs_root, "/dev/null");
         if (!dent)
             kill_current(-1);
         null_ind = dent->ind;