TarFs: janky tarfs for initramfs

This commit is contained in:
2024-05-03 23:11:08 +02:00
parent 3016120ba5
commit ed3599ce95
7 changed files with 258 additions and 25 deletions

View File

@@ -60,6 +60,9 @@ void PS2Keyboard::this_pooler() {
case 0x34:
r = 'g';
break;
case 0x4A:
r = '/';
break;
case 0x3C:
r = 'u';
break;

View File

@@ -32,6 +32,7 @@
#include <FbTty.hpp>
#include <LimineFramebuffer.hpp>
#include <TarFs.hpp>
void templates_tester() {
// GlobalTtyManager.all_tty_putstr("Testing templates\n");
@@ -53,31 +54,33 @@ void ktask_main() {
(new Task(Task::TaskMode::TASKMODE_KERN, templates_tester, "templates_tester"))->start();
(new Task(Task::TaskMode::TASKMODE_KERN, templates_tester, "templates_tester2"))->start();
VFSGlobals::mounts.add_mount(new MemFs(&VFSGlobals::root));
(new Task(Task::TaskMode::TASKMODE_KERN, vfs_tester, "vfs_tester"))->start();
Task *init;
// (new Task(Task::TaskMode::TASKMODE_KERN, vfs_tester, "vfs_tester"))->start();
for (int i = 0; i < saved_modules_size; i++) {
auto &mod = saved_modules[i];
VFSApi::touch(StrToPath(saved_modules_names[i]));
FDT::FD fd = VFSApi::open(StrToPath(saved_modules_names[i]));
File *f = VFSApi::get(fd);
f->write(static_cast<const char *>(mod.address), mod.size);
if (strcmp(saved_modules_names[i], "/init") == 0) {
Vector<char> read_data(mod.size);
memcpy(read_data.begin(), mod.address, mod.size);
ElfParser elfParser(std::move(read_data));
init = new Task(Task::TaskMode::TASKMODE_USER, (void (*)()) elfParser.get_entrypoint(), saved_modules_names[i]);
if (!elfParser.copy_to(init))
assert2(false, "Init couldn't be loaded!");
if (strcmp(saved_modules_names[i], "/sysroot.tar") == 0) {
VFSGlobals::mounts.add_mount(new TarFs((char *) mod.address, mod.size, &VFSGlobals::root));
}
VFSApi::close(fd);
}
GlobalTtyManager.all_tty_putstr("Setup finished \n");
GlobalTtyManager.all_tty_putstr("Starting init \n");
Task *init;
FDT::FD fd = VFSApi::open(StrToPath("/init"));
File *f = VFSApi::get(fd);
{
Vector<char> read_data(f->size());
f->read(read_data.data(), f->size());
ElfParser elfParser(std::move(read_data));
init = new Task(Task::TaskMode::TASKMODE_USER, (void (*)()) elfParser.get_entrypoint(), "/init");
if (!elfParser.copy_to(init))
assert2(false, "Init couldn't be loaded!");
}
VFSApi::close(fd);
init->start();
}

View File

@@ -2,10 +2,13 @@ add_custom_target(iso_limine)
add_custom_target(iso
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/isodir/
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/initramfs/
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/limine.cfg ${CMAKE_CURRENT_BINARY_DIR}/isodir/
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:kernel.elf> ${CMAKE_CURRENT_BINARY_DIR}/isodir/ficus.elf
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:init> ${CMAKE_CURRENT_BINARY_DIR}/isodir/init
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:hello2> ${CMAKE_CURRENT_BINARY_DIR}/isodir/hello2
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:init> ${CMAKE_CURRENT_BINARY_DIR}/initramfs/init
COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:hello2> ${CMAKE_CURRENT_BINARY_DIR}/initramfs/hello2
# TODO: this might not work when there are special symbols in path...
COMMAND pax -wvf ${CMAKE_CURRENT_BINARY_DIR}/isodir/sysroot.tar -s ":^${CMAKE_CURRENT_BINARY_DIR}/initramfs/::" ${CMAKE_CURRENT_BINARY_DIR}/initramfs
COMMAND xorriso -as mkisofs -b limine-bios-cd.bin -no-emul-boot -boot-load-size 4 -boot-info-table --efi-boot limine-uefi-cd.bin -efi-boot-part --efi-boot-image --protective-msdos-label ${CMAKE_CURRENT_BINARY_DIR}/isodir -o ${CMAKE_CURRENT_BINARY_DIR}/ficus.iso
COMMAND ${tools}/limine/prefix/bin/limine bios-install ${CMAKE_CURRENT_BINARY_DIR}/ficus.iso
VERBATIM

View File

@@ -8,9 +8,7 @@ TIMEOUT=1
# Path to the kernel to boot. boot:/// represents the partition on which limine.cfg is located.
KERNEL_PATH=boot:///ficus.elf
MODULE_PATH=boot:///init
MODULE_PATH=boot:///hello2
MODULE_PATH=boot:///sysroot.tar
# Same thing, but without KASLR.
:ficus (KASLR off)
@@ -20,5 +18,4 @@ TIMEOUT=1
KASLR=no
KERNEL_PATH=boot:///ficus.elf
MODULE_PATH=boot:///init
MODULE_PATH=boot:///hello2
MODULE_PATH=boot:///sysroot.tar

View File

@@ -13,4 +13,5 @@ target_sources(kernel.elf PRIVATE
File.cpp
PipeFs.cpp
TtyPipe.cpp
TarFs.cpp
)

147
src/kernel/vfs/TarFs.cpp Normal file
View File

@@ -0,0 +1,147 @@
//
// Created by Stepan Usatiuk on 01.05.2024.
//
#include "TarFs.hpp"
#include <TtyManager.hpp>
TarFs::TarFs(char *backing, size_t backing_size, NodeDir *mounted_on) : Filesystem(mounted_on), _backing((tar_header *) backing), _backing_size(backing_size) {
int i = 2;
const tar_header *header = _backing;
SkipListMap<String, ino_t> dir_map;
dir_map.emplace("", 1);
_dir_map.emplace(1, Vector<DirEntry>());
// FIXME: all this is extremely inefficient
// Also recheck that directories are handled correctly
while (true) {
if (header->filename[0] == '\0')
break;
unsigned int size = header_size(header);
int new_ino = i++;
_off_map.emplace(new_ino, header);
String pref = "";
String name = "";
{
Path p = StrToPath(header->filename);
if (p.size() > 1) {
pref += p[0];
for (int i = 1; i < p.size() - 1; i++) {
pref += "/";
pref += p[i];
}
}
name = p.back();
}
if (header->typeflag[0] == '5') {
String fullname;
if (pref.length() > 0) {
fullname += pref;
fullname += "/";
}
fullname += name;
if (dir_map.find(fullname) == dir_map.end()) {
dir_map.emplace(fullname, new_ino);
_dir_map.emplace(new_ino, Vector<DirEntry>());
}
if (dir_map.find(pref) == dir_map.end()) {
int dir_ino = i++;
dir_map.emplace(pref, dir_ino);
_dir_map.emplace(dir_ino, Vector<DirEntry>());
}
auto p = dir_map.find(pref);
auto d = _dir_map.find(p->second);
d->second.emplace_back(name, new_ino);
} else if (header->typeflag[0] == '\0' || header->typeflag[0] == '0') {
if (dir_map.find(pref) == dir_map.end()) {
int dir_ino = i++;
dir_map.emplace(pref, dir_ino);
_dir_map.emplace(dir_ino, Vector<DirEntry>());
}
auto p = dir_map.find(pref);
auto d = _dir_map.find(p->second);
d->second.emplace_back(name, new_ino);
} else {
GlobalTtyManager.all_tty_putstr("Skipping tar: ");
GlobalTtyManager.all_tty_putstr(pref.c_str());
GlobalTtyManager.all_tty_putstr("/");
GlobalTtyManager.all_tty_putstr(name.c_str());
GlobalTtyManager.all_tty_putstr("\n");
}
header = (const tar_header *) (((char *) (header)) + ((size / 512) + 1) * 512);
if (size % 512)
header = (const tar_header *) (((char *) (header)) + 512);
}
}
SharedPtr<NodeDir> TarFs::root() {
return static_ptr_cast<NodeDir>(get_node(1));
}
SharedPtr<Node> TarFs::get_node(ino_t inode) {
if (_dir_map.find(inode) != _dir_map.end()) {
return static_ptr_cast<Node>(TarFsNodeDir::create(this, inode));
} else {
return static_ptr_cast<Node>(TarFsNodeFile::create(this, inode));
}
assert(false);
}
Vector<DirEntry> TarFs::TarFsNodeDir::children() {
return static_cast<TarFs *>(_fs)->_dir_map.find(_ino)->second;
}
ino_t TarFs::TarFsNodeDir::mkdir(const String &name) {
return -1;
}
ino_t TarFs::TarFsNodeDir::mkfile(const String &name) {
return -1;
}
int64_t TarFs::TarFsNodeFile::read(char *buf, size_t start, size_t num) {
TarFs *tar_fs = static_cast<TarFs *>(_fs);
if (auto entry = tar_fs->_off_map.find(_ino); entry != tar_fs->_off_map.end()) {
num = std::min(num, size() - start);
for (size_t i = 0; i < num; i++) {
buf[i] = (((char *) entry->second) + 512)[start + i];
}
return num;
}
assert(false);
}
int64_t TarFs::TarFsNodeFile::write(const char *buf, size_t start, size_t num) {
return -1;
}
size_t TarFs::TarFsNodeFile::size() {
TarFs *tar_fs = static_cast<TarFs *>(_fs);
if (auto entry = tar_fs->_off_map.find(_ino); entry != tar_fs->_off_map.end()) {
return header_size(entry->second);
}
assert(false);
}
size_t TarFs::header_size(const tar_header *hdr) {
int size = 0;
size_t count = 1;
for (int j = 11; j > 0; j--, count *= 8)
size += ((hdr->size[j - 1] - '0') * count);
return size;
}

79
src/kernel/vfs/TarFs.hpp Normal file
View File

@@ -0,0 +1,79 @@
//
// Created by Stepan Usatiuk on 01.05.2024.
//
#ifndef TARFS_HPP
#define TARFS_HPP
#include <Filesystem.hpp>
class TarFs : public Filesystem {
public:
TarFs(char *backing, size_t backing_size, NodeDir *mounted_on);
~TarFs() override = default;
SharedPtr<NodeDir> root() override;
SharedPtr<Node> get_node(ino_t inode) override;
struct TarFsNodeDir : public ::NodeDir {
public:
~TarFsNodeDir() override = default;
Vector<DirEntry> children() override;
ino_t mkdir(const String &name) override;
ino_t mkfile(const String &name) override;
static SharedPtr<TarFsNodeDir> create(Filesystem *fs, ino_t id) {
auto shared = SharedPtr(new TarFsNodeDir(fs, id));
shared->_self_weak = static_ptr_cast<Node>(shared);
return shared;
}
private:
TarFsNodeDir(Filesystem *fs, ino_t id) : ::NodeDir(fs, id) {}
};
struct TarFsNodeFile : public ::NodeFile {
public:
~TarFsNodeFile() override = default;
int64_t read(char *buf, size_t start, size_t num) override;
int64_t write(const char *buf, size_t start, size_t num) override;
size_t size() override;
bool is_tty() override { return false; }
static SharedPtr<TarFsNodeFile> create(Filesystem *fs, ino_t id) {
auto shared = SharedPtr(new TarFsNodeFile(fs, id));
shared->_self_weak = static_ptr_cast<Node>(shared);
return shared;
}
private:
TarFsNodeFile(Filesystem *fs, ino_t id) : ::NodeFile(fs, id) {}
};
private:
struct tar_header {
char filename[100];
char mode[8];
char uid[8];
char gid[8];
char size[12];
char mtime[12];
char chksum[8];
char typeflag[1];
} __attribute__((packed));
const tar_header *_backing;
size_t _backing_size;
SkipListMap<ino_t, const tar_header *> _off_map;
SkipListMap<ino_t, Vector<DirEntry>> _dir_map;
// SkipListMap<ino_t, SharedPtr<Node>> _vnode_map;
static size_t header_size(const tar_header *hdr);
};
#endif //TARFS_HPP