diff --git a/kernel/src/fs/VFS.cpp b/kernel/src/fs/VFS.cpp index adaf43a3..5852b9d1 100644 --- a/kernel/src/fs/VFS.cpp +++ b/kernel/src/fs/VFS.cpp @@ -17,14 +17,9 @@ namespace VFS kdbgln("vfs: trying to resolve path %s", path); - SharedPtr current_inode; + SharedPtr current_inode = root_fs->root_inode(); - if (parser.is_absolute()) { current_inode = root_fs->root_inode(); } - else - { - kwarnln("vfs: cannot resolve path '%s', as relative paths are not supported yet", path); - return err(ENOTSUP); - } + // FIXME: Properly handle relative paths. const char* section; while (parser.next().try_set_value(section)) @@ -35,4 +30,18 @@ namespace VFS return current_inode; } + + Result> create_directory(const char* path) + { + auto parser = TRY(PathParser::create(path)); + auto parent_path = TRY(parser.dirname()); + + auto parent_inode = TRY(resolve_path(parent_path.chars())); + + auto child_name = TRY(parser.basename()); + + kdbgln("vfs: creating directory '%s' in parent '%s'", child_name.chars(), parent_path.chars()); + + return parent_inode->create_subdirectory(child_name.chars()); + } } diff --git a/kernel/src/fs/VFS.h b/kernel/src/fs/VFS.h index d3179af1..c699d99a 100644 --- a/kernel/src/fs/VFS.h +++ b/kernel/src/fs/VFS.h @@ -78,5 +78,7 @@ namespace VFS Result> resolve_path(const char* path); + Result> create_directory(const char* path); + Inode& root_inode(); } diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index b403cdeb..6d636928 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -58,7 +58,7 @@ static Result try_init_vfs() kinfoln("root inode's '.' entry inode number: %zu", TRY(root_inode.find("."))->inode_number()); kinfoln("root inode's '..' entry inode number: %zu", TRY(root_inode.find(".."))->inode_number()); - TRY(root_inode.create_subdirectory("etc")); + TRY(VFS::create_directory("/etc/")); kinfoln("root inode's 'etc' entry inode number: %zu", TRY(root_inode.find("etc"))->inode_number()); diff --git a/libluna/CMakeLists.txt b/libluna/CMakeLists.txt index 067e2a83..9ff201e9 100644 --- a/libluna/CMakeLists.txt +++ b/libluna/CMakeLists.txt @@ -7,6 +7,7 @@ set(FREESTANDING_SOURCES src/Format.cpp src/NumberParsing.cpp src/CString.cpp + src/CPath.cpp src/Units.cpp src/SystemError.cpp src/Bitmap.cpp diff --git a/libluna/include/luna/CPath.h b/libluna/include/luna/CPath.h new file mode 100644 index 00000000..5bbd38c0 --- /dev/null +++ b/libluna/include/luna/CPath.h @@ -0,0 +1,4 @@ +#pragma once + +char* basename(char*); +char* dirname(char*); diff --git a/libluna/include/luna/CString.h b/libluna/include/luna/CString.h index 7b607e71..6d17c6e7 100644 --- a/libluna/include/luna/CString.h +++ b/libluna/include/luna/CString.h @@ -33,4 +33,5 @@ extern "C" [[deprecated]] char* strcat(char* dst, const char* src); char* strchr(const char* str, int c); + char* strrchr(const char* str, int c); } diff --git a/libluna/include/luna/PathParser.h b/libluna/include/luna/PathParser.h index a1da5ee5..33588ed7 100644 --- a/libluna/include/luna/PathParser.h +++ b/libluna/include/luna/PathParser.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include class PathParser { @@ -17,6 +18,9 @@ class PathParser return *m_original == '/'; } + Result basename(); + Result dirname(); + Option next(); private: diff --git a/libluna/src/CPath.cpp b/libluna/src/CPath.cpp new file mode 100644 index 00000000..cbe31799 --- /dev/null +++ b/libluna/src/CPath.cpp @@ -0,0 +1,47 @@ +#include +#include + +static char dot[] = "."; + +char* basename(char* path) +{ + // If path is NULL, or the string's length is 0, return . + if (!path) return dot; + size_t len = strlen(path); + if (!len) return dot; + + // Strip trailing slashes. + char* it = path + len - 1; + while (*it == '/' && it != path) { it--; } + *(it + 1) = 0; + if (it == path) return path; + + // Return path from the first character if there are no more slashes, or from the first character after the last + // slash. + char* beg = strrchr(path, '/'); + if (!beg) return path; + return beg + 1; +} + +char* dirname(char* path) +{ + // If path is NULL, or the string's length is 0, return . + if (!path) return dot; + size_t len = strlen(path); + if (!len) return dot; + + // Strip trailing slashes. + char* it = path + len - 1; + while (*it == '/' && it != path) { it--; } + *(char*)(it + 1) = 0; + if (it == path) return path; + + // Search for the last slash. If there is none, return . + // Otherwise, we end the string there and return. + char* end = strrchr(path, '/'); + if (!end) return dot; + if (end != path) *end = 0; + else + *(end + 1) = 0; + return path; +} diff --git a/libluna/src/CString.cpp b/libluna/src/CString.cpp index d3fef924..38160120 100644 --- a/libluna/src/CString.cpp +++ b/libluna/src/CString.cpp @@ -126,6 +126,15 @@ extern "C" return NULL; } + char* strrchr(const char* str, int c) + { + const char* s = str + strlen(str); + while (s != str && *s != (char)c) s--; + if (s != str) return const_cast(s); + if (*s == (char)c) return const_cast(s); + return NULL; + } + usize strlcpy(char* dest, const char* src, usize len) { usize src_len = strlen(src); diff --git a/libluna/src/PathParser.cpp b/libluna/src/PathParser.cpp index 9d47c5f0..47cdb94e 100644 --- a/libluna/src/PathParser.cpp +++ b/libluna/src/PathParser.cpp @@ -1,4 +1,6 @@ +#include #include +#include Result PathParser::create(const char* path) { @@ -31,3 +33,29 @@ Option PathParser::next() return result; } + +Result PathParser::basename() +{ + char* copy = strdup(m_original); + if (!copy) return err(ENOMEM); + + auto guard = make_scope_guard([copy] { free_impl(copy); }); + + char* result = ::basename(copy); + + // We must copy this as we cannot rely on the original string. + return OwnedStringView::from_string_literal(result); +} + +Result PathParser::dirname() +{ + char* copy = strdup(m_original); + if (!copy) return err(ENOMEM); + + auto guard = make_scope_guard([copy] { free_impl(copy); }); + + char* result = ::dirname(copy); + + // We must copy this as we cannot rely on the original string. + return OwnedStringView::from_string_literal(result); +} diff --git a/libluna/src/TarStream.cpp b/libluna/src/TarStream.cpp index 5b91307e..73bb60bd 100644 --- a/libluna/src/TarStream.cpp +++ b/libluna/src/TarStream.cpp @@ -46,7 +46,7 @@ Result TarStream::parse_header(const TarStream::TarHeader* hdr entry.mode = (mode_t)parse_unsigned_integer(hdr->mode, nullptr, 8); entry.m_pos = m_offset; - entry.m_data = (u8*)(m_base + m_offset); + entry.m_data = (u8*)m_base + m_offset; switch (hdr->typeflag) {