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
{
// 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;
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)
{
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);
}
@ -78,10 +79,10 @@ namespace ELFLoader
usize i;
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++, stream.read_contents(elf_entry, &program_header, elf_header.e_phoff + (i * elf_header.e_phentsize),
sizeof program_header))
i++, TRY(inode->read((u8*)&program_header, elf_header.e_phoff + (i * elf_header.e_phentsize),
sizeof program_header)))
{
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));
// Load the file section of the segment
stream.read_contents(elf_entry, (void*)program_header.p_vaddr, program_header.p_offset,
program_header.p_filesz);
inode->read((u8*)program_header.p_vaddr, program_header.p_offset, program_header.p_filesz);
// Fill out the rest of the segment with 0s
memset((void*)(program_header.p_vaddr + program_header.p_filesz), 0,

View File

@ -1,6 +1,6 @@
#pragma once
#include "fs/VFS.h"
#include <luna/LinkedList.h>
#include <luna/TarStream.h>
#include <luna/Types.h>
#define ELFMAG "\177ELF"
@ -54,5 +54,5 @@ struct ELFData
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 "arch/MMU.h"
#include "boot/bootboot.h"
#include "fs/VFS.h"
TarStream g_initrd;
extern const BOOTBOOT bootboot;
@ -11,3 +12,29 @@ void InitRD::initialize()
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
{
void initialize();
Result<void> populate_vfs();
}

View File

@ -15,24 +15,41 @@ namespace VFS
{
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;
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))
{
kdbgln("vfs: searching for entry '%s' in inode %zu", section, current_inode->inode_number());
current_inode = TRY(current_inode->find(section));
}
while (parser.next().try_set_value(section)) { current_inode = TRY(current_inode->find(section)); }
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;
// 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
virtual FileSystem& fs() const = 0;
@ -73,5 +78,8 @@ namespace VFS
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();
}

View File

@ -66,6 +66,8 @@ namespace TmpFS
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());
TRY(add_entry(inode, name));
@ -75,10 +77,45 @@ namespace TmpFS
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));
TRY(add_entry(inode, name));
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 <luna/Atomic.h>
#include <luna/Badge.h>
#include <luna/Buffer.h>
#include <luna/StaticString.h>
#include <luna/Vector.h>
@ -58,10 +59,15 @@ namespace TmpFS
return m_inode_number;
}
Result<usize> read(u8*, usize, usize) const override;
Result<usize> write(const u8*, usize, usize) override;
virtual ~FileInode() = default;
private:
VFS::FileSystem* m_fs;
Buffer m_data_buffer;
usize m_inode_number;
};
@ -87,6 +93,16 @@ namespace TmpFS
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
{
return *m_fs;

View File

@ -51,29 +51,7 @@ static Result<void> try_init_vfs()
{
VFS::root_fs = TRY(TmpFS::FileSystem::create());
VFS::Inode& root_inode = VFS::root_inode();
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());
InitRD::populate_vfs();
return {};
}
@ -85,17 +63,9 @@ static void init_vfs()
static Result<void> try_init_userspace()
{
TarStream::Entry entry;
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);
auto app = TRY(VFS::resolve_path("/bin/app"));
if (!strcmp(entry.name, "bin/app")) { TRY(Scheduler::new_userspace_thread(entry, g_initrd)); }
}
}
TRY(Scheduler::new_userspace_thread(app));
return {};
}

View File

@ -118,7 +118,7 @@ namespace Scheduler
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());
@ -139,7 +139,7 @@ namespace Scheduler
thread->init_regs_user();
const ELFData data = TRY(ELFLoader::load(entry, stream));
const ELFData data = TRY(ELFLoader::load(inode));
thread->set_ip(data.entry);

View File

@ -1,6 +1,6 @@
#pragma once
#include "fs/VFS.h"
#include "thread/Thread.h"
#include <luna/TarStream.h>
namespace Scheduler
{
@ -13,7 +13,7 @@ namespace Scheduler
Result<void> new_kernel_thread(void (*func)(void));
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();

View File

@ -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

View File

@ -15,7 +15,9 @@ class Buffer
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()
{
@ -27,6 +29,16 @@ class Buffer
return m_data;
}
u8* end()
{
return m_data + m_size;
}
const u8* end() const
{
return m_data + m_size;
}
usize size() const
{
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);
char* strchr(const char* str, int c);
char* strrchr(const char* str, int c);
}

View File

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

View File

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

View File

@ -32,9 +32,15 @@ Result<void> Buffer::try_resize(usize new_size)
return {};
}
Result<u8*> Buffer::create_slice_at_end(usize size)
Result<u8*> Buffer::slice_at_end(usize size)
{
usize old_size = m_size;
TRY(try_resize(m_size + 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;
}
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 src_len = strlen(src);

View File

@ -1,4 +1,6 @@
#include <luna/CPath.h>
#include <luna/PathParser.h>
#include <luna/ScopeGuard.h>
Result<PathParser> PathParser::create(const char* path)
{
@ -31,3 +33,29 @@ Option<const char*> PathParser::next()
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.pos = m_offset;
entry.m_pos = m_offset;
entry.m_data = (u8*)m_base + m_offset;
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 ((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;
}