Compare commits

..

6 Commits

22 changed files with 261 additions and 66 deletions

View File

@ -26,13 +26,14 @@ static bool can_write_segment(u32 flags)
namespace ELFLoader namespace ELFLoader
{ {
// FIXME: Check that all calls to read_contents() read the proper amount of bytes. // FIXME: Check that all calls to read_contents() read the proper amount of bytes.
Result<ELFData> load(const TarStream::Entry& elf_entry, const TarStream& stream) Result<ELFData> load(SharedPtr<VFS::Inode> inode)
{ {
Elf64_Ehdr elf_header; Elf64_Ehdr elf_header;
usize nread = stream.read_contents(elf_entry, &elf_header, 0, sizeof elf_header); usize nread = TRY(inode->read((u8*)&elf_header, 0, sizeof elf_header));
if (nread < sizeof elf_header) if (nread < sizeof elf_header)
{ {
kdbgln("Error while loading ELF: ELF header does not fit in entry"); kdbgln("Error while loading ELF: ELF header does not fit in file");
return err(ENOEXEC); return err(ENOEXEC);
} }
@ -78,10 +79,10 @@ namespace ELFLoader
usize i; usize i;
Elf64_Phdr program_header; Elf64_Phdr program_header;
for (stream.read_contents(elf_entry, &program_header, elf_header.e_phoff, sizeof program_header), i = 0; for (TRY(inode->read((u8*)&program_header, elf_header.e_phoff, sizeof program_header)), i = 0;
i < elf_header.e_phnum; i < elf_header.e_phnum;
i++, stream.read_contents(elf_entry, &program_header, elf_header.e_phoff + (i * elf_header.e_phentsize), i++, TRY(inode->read((u8*)&program_header, elf_header.e_phoff + (i * elf_header.e_phentsize),
sizeof program_header)) sizeof program_header)))
{ {
if (program_header.p_type == PT_LOAD) if (program_header.p_type == PT_LOAD)
{ {
@ -103,8 +104,7 @@ namespace ELFLoader
base_vaddr, get_blocks_from_size(program_header.p_memsz + vaddr_diff, ARCH_PAGE_SIZE), flags)); base_vaddr, get_blocks_from_size(program_header.p_memsz + vaddr_diff, ARCH_PAGE_SIZE), flags));
// Load the file section of the segment // Load the file section of the segment
stream.read_contents(elf_entry, (void*)program_header.p_vaddr, program_header.p_offset, inode->read((u8*)program_header.p_vaddr, program_header.p_offset, program_header.p_filesz);
program_header.p_filesz);
// Fill out the rest of the segment with 0s // Fill out the rest of the segment with 0s
memset((void*)(program_header.p_vaddr + program_header.p_filesz), 0, memset((void*)(program_header.p_vaddr + program_header.p_filesz), 0,

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "fs/VFS.h"
#include <luna/LinkedList.h> #include <luna/LinkedList.h>
#include <luna/TarStream.h>
#include <luna/Types.h> #include <luna/Types.h>
#define ELFMAG "\177ELF" #define ELFMAG "\177ELF"
@ -54,5 +54,5 @@ struct ELFData
namespace ELFLoader namespace ELFLoader
{ {
Result<ELFData> load(const TarStream::Entry& elf_entry, const TarStream& stream); Result<ELFData> load(SharedPtr<VFS::Inode> inode);
}; };

View File

@ -1,6 +1,7 @@
#include "InitRD.h" #include "InitRD.h"
#include "arch/MMU.h" #include "arch/MMU.h"
#include "boot/bootboot.h" #include "boot/bootboot.h"
#include "fs/VFS.h"
TarStream g_initrd; TarStream g_initrd;
extern const BOOTBOOT bootboot; extern const BOOTBOOT bootboot;
@ -11,3 +12,29 @@ void InitRD::initialize()
g_initrd.initialize((void*)virtual_initrd_address, bootboot.initrd_size); g_initrd.initialize((void*)virtual_initrd_address, bootboot.initrd_size);
} }
static Result<void> vfs_create_dir_if_not_exists(const char* path)
{
auto rc = VFS::create_directory(path);
if (rc.has_error())
{
if (rc.error() == EEXIST) return {};
return rc.release_error();
}
return {};
}
Result<void> InitRD::populate_vfs()
{
TarStream::Entry entry;
while (TRY(g_initrd.read_next_entry(entry)))
{
if (entry.type == TarStream::EntryType::RegularFile)
{
auto file = TRY(VFS::create_file(entry.name));
file->write(entry.data(), 0, entry.size);
}
else if (entry.type == TarStream::EntryType::Directory) { TRY(vfs_create_dir_if_not_exists(entry.name)); }
}
return {};
}

View File

@ -6,4 +6,5 @@ extern TarStream g_initrd;
namespace InitRD namespace InitRD
{ {
void initialize(); void initialize();
Result<void> populate_vfs();
} }

View File

@ -15,24 +15,41 @@ namespace VFS
{ {
auto parser = TRY(PathParser::create(path)); auto parser = TRY(PathParser::create(path));
kdbgln("vfs: trying to resolve path %s", path); SharedPtr<Inode> current_inode = root_fs->root_inode();
SharedPtr<Inode> current_inode; // FIXME: Properly handle relative paths.
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);
}
const char* section; const char* section;
while (parser.next().try_set_value(section)) while (parser.next().try_set_value(section)) { current_inode = TRY(current_inode->find(section)); }
{
kdbgln("vfs: searching for entry '%s' in inode %zu", section, current_inode->inode_number());
current_inode = TRY(current_inode->find(section));
}
return current_inode; return current_inode;
} }
Result<SharedPtr<Inode>> 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());
}
Result<SharedPtr<Inode>> create_file(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 file '%s' in parent '%s'", child_name.chars(), parent_path.chars());
return parent_inode->create_file(child_name.chars());
}
} }

View File

@ -21,6 +21,11 @@ namespace VFS
virtual Result<SharedPtr<Inode>> create_subdirectory(const char* name) = 0; virtual Result<SharedPtr<Inode>> create_subdirectory(const char* name) = 0;
// File-specific methods
virtual Result<usize> read(u8* buf, usize offset, usize length) const = 0;
virtual Result<usize> write(const u8* buf, usize offset, usize length) = 0;
// Generic methods // Generic methods
virtual FileSystem& fs() const = 0; virtual FileSystem& fs() const = 0;
@ -73,5 +78,8 @@ namespace VFS
Result<SharedPtr<Inode>> resolve_path(const char* path); Result<SharedPtr<Inode>> resolve_path(const char* path);
Result<SharedPtr<Inode>> create_directory(const char* path);
Result<SharedPtr<Inode>> create_file(const char* path);
Inode& root_inode(); Inode& root_inode();
} }

View File

@ -66,6 +66,8 @@ namespace TmpFS
Result<SharedPtr<VFS::Inode>> DirInode::create_file(const char* name) Result<SharedPtr<VFS::Inode>> DirInode::create_file(const char* name)
{ {
if (find(name).has_value()) return err(EEXIST);
auto inode = TRY(m_fs->create_file_inode()); auto inode = TRY(m_fs->create_file_inode());
TRY(add_entry(inode, name)); TRY(add_entry(inode, name));
@ -75,10 +77,45 @@ namespace TmpFS
Result<SharedPtr<VFS::Inode>> DirInode::create_subdirectory(const char* name) Result<SharedPtr<VFS::Inode>> DirInode::create_subdirectory(const char* name)
{ {
if (find(name).has_value()) return err(EEXIST);
auto inode = TRY(m_fs->create_dir_inode(m_self)); auto inode = TRY(m_fs->create_dir_inode(m_self));
TRY(add_entry(inode, name)); TRY(add_entry(inode, name));
return inode; return inode;
} }
Result<usize> FileInode::read(u8* buf, usize offset, usize length) const
{
if (length == 0) return 0;
if (offset > m_data_buffer.size()) return 0;
if (offset + length > m_data_buffer.size()) length = m_data_buffer.size() - offset;
memcpy(buf, m_data_buffer.data() + offset, length);
return length;
}
Result<usize> FileInode::write(const u8* buf, usize offset, usize length)
{
if (length == 0) return 0;
if (offset > m_data_buffer.size())
{
// Fill the in-between space with zeroes.
usize old_size = m_data_buffer.size();
usize zeroes = offset - old_size;
TRY(m_data_buffer.try_resize(offset));
memset(m_data_buffer.data() + old_size, 0, zeroes);
}
u8* slice = TRY(m_data_buffer.slice(offset, length));
memcpy(slice, buf, length);
return length;
}
} }

View File

@ -2,6 +2,7 @@
#include "fs/VFS.h" #include "fs/VFS.h"
#include <luna/Atomic.h> #include <luna/Atomic.h>
#include <luna/Badge.h> #include <luna/Badge.h>
#include <luna/Buffer.h>
#include <luna/StaticString.h> #include <luna/StaticString.h>
#include <luna/Vector.h> #include <luna/Vector.h>
@ -58,10 +59,15 @@ namespace TmpFS
return m_inode_number; return m_inode_number;
} }
Result<usize> read(u8*, usize, usize) const override;
Result<usize> write(const u8*, usize, usize) override;
virtual ~FileInode() = default; virtual ~FileInode() = default;
private: private:
VFS::FileSystem* m_fs; VFS::FileSystem* m_fs;
Buffer m_data_buffer;
usize m_inode_number; usize m_inode_number;
}; };
@ -87,6 +93,16 @@ namespace TmpFS
Result<SharedPtr<VFS::Inode>> find(const char* name) const override; Result<SharedPtr<VFS::Inode>> find(const char* name) const override;
Result<usize> read(u8*, usize, usize) const override
{
return err(EISDIR);
}
Result<usize> write(const u8*, usize, usize) override
{
return err(EISDIR);
}
VFS::FileSystem& fs() const override VFS::FileSystem& fs() const override
{ {
return *m_fs; return *m_fs;

View File

@ -51,29 +51,7 @@ static Result<void> try_init_vfs()
{ {
VFS::root_fs = TRY(TmpFS::FileSystem::create()); VFS::root_fs = TRY(TmpFS::FileSystem::create());
VFS::Inode& root_inode = VFS::root_inode(); InitRD::populate_vfs();
kinfoln("root inode number: %zu", root_inode.inode_number());
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"));
kinfoln("root inode's 'etc' entry inode number: %zu", TRY(root_inode.find("etc"))->inode_number());
auto& etc = *TRY(root_inode.find("etc"));
kinfoln("etc inode's '.' entry inode number: %zu", TRY(etc.find("."))->inode_number());
kinfoln("etc inode's '..' entry inode number: %zu", TRY(etc.find(".."))->inode_number());
TRY(etc.create_file("passwd"));
kinfoln("etc inode's 'passwd' entry inode number: %zu", TRY(etc.find("passwd"))->inode_number());
auto& passwd = *TRY(VFS::resolve_path("/etc/passwd"));
kinfoln("/etc/passwd's inode number: %zu", passwd.inode_number());
return {}; return {};
} }
@ -85,17 +63,9 @@ static void init_vfs()
static Result<void> try_init_userspace() static Result<void> try_init_userspace()
{ {
TarStream::Entry entry; auto app = TRY(VFS::resolve_path("/bin/app"));
while (TRY(g_initrd.read_next_entry(entry)))
{
if (entry.type == TarStream::EntryType::RegularFile)
{
kinfoln("Found file %s in initial ramdisk, of size %s and mode %#ho", entry.name,
to_dynamic_unit(entry.size).release_value().chars(), entry.mode);
if (!strcmp(entry.name, "bin/app")) { TRY(Scheduler::new_userspace_thread(entry, g_initrd)); } TRY(Scheduler::new_userspace_thread(app));
}
}
return {}; return {};
} }

View File

@ -118,7 +118,7 @@ namespace Scheduler
return {}; return {};
} }
Result<void> new_userspace_thread(const TarStream::Entry& entry, const TarStream& stream) Result<void> new_userspace_thread(SharedPtr<VFS::Inode> inode)
{ {
Thread* const thread = TRY(new_thread()); Thread* const thread = TRY(new_thread());
@ -139,7 +139,7 @@ namespace Scheduler
thread->init_regs_user(); thread->init_regs_user();
const ELFData data = TRY(ELFLoader::load(entry, stream)); const ELFData data = TRY(ELFLoader::load(inode));
thread->set_ip(data.entry); thread->set_ip(data.entry);

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "fs/VFS.h"
#include "thread/Thread.h" #include "thread/Thread.h"
#include <luna/TarStream.h>
namespace Scheduler namespace Scheduler
{ {
@ -13,7 +13,7 @@ namespace Scheduler
Result<void> new_kernel_thread(void (*func)(void)); Result<void> new_kernel_thread(void (*func)(void));
Result<void> new_kernel_thread(void (*func)(void*), void* arg); Result<void> new_kernel_thread(void (*func)(void*), void* arg);
Result<void> new_userspace_thread(const TarStream::Entry& entry, const TarStream& stream); Result<void> new_userspace_thread(SharedPtr<VFS::Inode> inode);
Thread* pick_task(); Thread* pick_task();

View File

@ -7,6 +7,7 @@ set(FREESTANDING_SOURCES
src/Format.cpp src/Format.cpp
src/NumberParsing.cpp src/NumberParsing.cpp
src/CString.cpp src/CString.cpp
src/CPath.cpp
src/Units.cpp src/Units.cpp
src/SystemError.cpp src/SystemError.cpp
src/Bitmap.cpp src/Bitmap.cpp

View File

@ -15,7 +15,9 @@ class Buffer
Result<void> try_resize(usize new_size); Result<void> try_resize(usize new_size);
Result<u8*> create_slice_at_end(usize size); Result<u8*> slice_at_end(usize size);
Result<u8*> slice(usize offset, usize size);
u8* data() u8* data()
{ {
@ -27,6 +29,16 @@ class Buffer
return m_data; return m_data;
} }
u8* end()
{
return m_data + m_size;
}
const u8* end() const
{
return m_data + m_size;
}
usize size() const usize size() const
{ {
return m_size; return m_size;

View File

@ -0,0 +1,4 @@
#pragma once
char* basename(char*);
char* dirname(char*);

View File

@ -33,4 +33,5 @@ extern "C"
[[deprecated]] char* strcat(char* dst, const char* src); [[deprecated]] char* strcat(char* dst, const char* src);
char* strchr(const char* str, int c); char* strchr(const char* str, int c);
char* strrchr(const char* str, int c);
} }

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include <luna/CString.h> #include <luna/CString.h>
#include <luna/Heap.h> #include <luna/Heap.h>
#include <luna/OwnedStringView.h>
class PathParser class PathParser
{ {
@ -17,6 +18,9 @@ class PathParser
return *m_original == '/'; return *m_original == '/';
} }
Result<OwnedStringView> basename();
Result<OwnedStringView> dirname();
Option<const char*> next(); Option<const char*> next();
private: private:

View File

@ -20,8 +20,14 @@ class TarStream
mode_t mode; mode_t mode;
EntryType type; EntryType type;
const u8* data() const
{
return m_data;
}
private: private:
usize pos; usize m_pos;
u8* m_data;
friend class TarStream; friend class TarStream;
}; };

View File

@ -32,9 +32,15 @@ Result<void> Buffer::try_resize(usize new_size)
return {}; return {};
} }
Result<u8*> Buffer::create_slice_at_end(usize size) Result<u8*> Buffer::slice_at_end(usize size)
{ {
usize old_size = m_size; usize old_size = m_size;
TRY(try_resize(m_size + size)); TRY(try_resize(m_size + size));
return m_data + old_size; return m_data + old_size;
} }
Result<u8*> Buffer::slice(usize offset, usize size)
{
if (offset + size > m_size) { TRY(try_resize(offset + size)); }
return m_data + offset;
}

47
libluna/src/CPath.cpp Normal file
View File

@ -0,0 +1,47 @@
#include <luna/CPath.h>
#include <luna/CString.h>
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;
}

View File

@ -126,6 +126,15 @@ extern "C"
return NULL; 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<char*>(s);
if (*s == (char)c) return const_cast<char*>(s);
return NULL;
}
usize strlcpy(char* dest, const char* src, usize len) usize strlcpy(char* dest, const char* src, usize len)
{ {
usize src_len = strlen(src); usize src_len = strlen(src);

View File

@ -1,4 +1,6 @@
#include <luna/CPath.h>
#include <luna/PathParser.h> #include <luna/PathParser.h>
#include <luna/ScopeGuard.h>
Result<PathParser> PathParser::create(const char* path) Result<PathParser> PathParser::create(const char* path)
{ {
@ -31,3 +33,29 @@ Option<const char*> PathParser::next()
return result; return result;
} }
Result<OwnedStringView> 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<OwnedStringView> 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);
}

View File

@ -45,7 +45,8 @@ Result<TarStream::Entry> TarStream::parse_header(const TarStream::TarHeader* hdr
entry.mode = (mode_t)parse_unsigned_integer(hdr->mode, nullptr, 8); entry.mode = (mode_t)parse_unsigned_integer(hdr->mode, nullptr, 8);
entry.pos = m_offset; entry.m_pos = m_offset;
entry.m_data = (u8*)m_base + m_offset;
switch (hdr->typeflag) switch (hdr->typeflag)
{ {
@ -99,7 +100,7 @@ usize TarStream::read_contents(const Entry& entry, void* buf, usize offset, usiz
if (offset >= entry.size) return 0; if (offset >= entry.size) return 0;
if ((length + offset) > entry.size) length = entry.size - offset; if ((length + offset) > entry.size) length = entry.size - offset;
memcpy(buf, offset_ptr(m_base, entry.pos + offset), length); memcpy(buf, offset_ptr(m_base, entry.m_pos + offset), length);
return length; return length;
} }