Skip to content

Commit

Permalink
fs: refactor path resolution
Browse files Browse the repository at this point in the history
  • Loading branch information
mosmeh committed Jun 23, 2024
1 parent 341033a commit 60f1fc9
Show file tree
Hide file tree
Showing 13 changed files with 473 additions and 478 deletions.
1 change: 1 addition & 0 deletions kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ OBJS := \
fs/fifo.o \
fs/fs.o \
fs/initrd.o \
fs/path.o \
fs/procfs/pid.o \
fs/procfs/procfs.o \
fs/procfs/root.o \
Expand Down
82 changes: 40 additions & 42 deletions kernel/console/psf.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,24 @@
#include <common/extra.h>
#include <kernel/api/err.h>
#include <kernel/api/fcntl.h>
#include <kernel/api/stdio.h>
#include <kernel/fs/fs.h>
#include <kernel/fs/path.h>
#include <kernel/memory/memory.h>
#include <string.h>

static struct font* load_psf1(const char* filename) {
file_description* desc = vfs_open(filename, O_RDONLY, 0);
if (IS_ERR(desc))
return ERR_CAST(desc);

static struct font* load_psf1(file_description* desc) {
struct psf1_header header;
if (file_description_read(desc, &header, sizeof(struct psf1_header)) !=
sizeof(struct psf1_header)) {
file_description_close(desc);
return ERR_PTR(-EINVAL);
}
if (header.magic[0] != PSF1_MAGIC0 || header.magic[1] != PSF1_MAGIC1) {
file_description_close(desc);
if (header.magic[0] != PSF1_MAGIC0 || header.magic[1] != PSF1_MAGIC1)
return ERR_PTR(-EINVAL);
}

struct font* font = kmalloc(sizeof(struct font));
if (!font) {
file_description_close(desc);
if (!font)
return ERR_PTR(-ENOMEM);
}

font->glyph_width = 8;
font->glyph_height = font->bytes_per_glyph = header.charsize;
Expand All @@ -36,14 +29,12 @@ static struct font* load_psf1(const char* filename) {
font->glyphs = kmalloc(buf_size);
if (!font->glyphs) {
kfree(font);
file_description_close(desc);
return ERR_PTR(-ENOMEM);
}
if ((size_t)file_description_read(desc, font->glyphs, buf_size) !=
buf_size) {
kfree(font->glyphs);
kfree(font);
file_description_close(desc);
return ERR_PTR(-EINVAL);
}

Expand All @@ -56,7 +47,6 @@ static struct font* load_psf1(const char* filename) {
sizeof(uint16_t)) {
kfree(font->glyphs);
kfree(font);
file_description_close(desc);
return ERR_PTR(-EINVAL);
}
if (uc == PSF1_SEPARATOR)
Expand All @@ -70,55 +60,41 @@ static struct font* load_psf1(const char* filename) {
font->ascii_to_glyph[i] = i;
}

file_description_close(desc);
return font;
}

static struct font* load_psf2(const char* filename) {
file_description* desc = vfs_open(filename, O_RDONLY, 0);
if (IS_ERR(desc))
return ERR_CAST(desc);

static struct font* load_psf2(file_description* desc) {
struct psf2_header header;
if (file_description_read(desc, &header, sizeof(struct psf2_header)) !=
sizeof(struct psf2_header)) {
file_description_close(desc);
sizeof(struct psf2_header))
return ERR_PTR(-EINVAL);
}
if (header.magic != PSF2_MAGIC || header.version != 0 ||
header.headersize != sizeof(struct psf2_header)) {
file_description_close(desc);
header.headersize != sizeof(struct psf2_header))
return ERR_PTR(-EINVAL);
}

struct font* font = kmalloc(sizeof(struct font));
if (!font) {
file_description_close(desc);
if (!font)
return ERR_PTR(-ENOMEM);
}

font->glyph_width = header.width;
font->glyph_height = header.height;
font->bytes_per_glyph = header.bytesperglyph;
if (div_ceil(font->glyph_width, 8) * font->glyph_height !=
font->bytes_per_glyph) {
kfree(font);
file_description_close(desc);
return ERR_PTR(-EINVAL);
}

size_t buf_size = header.numglyph * font->bytes_per_glyph;
font->glyphs = kmalloc(buf_size);
if (!font->glyphs) {
kfree(font);
file_description_close(desc);
return ERR_PTR(-ENOMEM);
}
if ((size_t)file_description_read(desc, font->glyphs, buf_size) !=
buf_size) {
kfree(font->glyphs);
kfree(font);
file_description_close(desc);
return ERR_PTR(-EINVAL);
}

Expand All @@ -131,7 +107,6 @@ static struct font* load_psf2(const char* filename) {
sizeof(uint8_t)) {
kfree(font->glyphs);
kfree(font);
file_description_close(desc);
return ERR_PTR(-EINVAL);
}
if (uc == PSF2_SEPARATOR)
Expand All @@ -145,18 +120,41 @@ static struct font* load_psf2(const char* filename) {
font->ascii_to_glyph[i] = i;
}

file_description_close(desc);
return font;
}

struct font* load_psf(const char* filename) {
struct font* font = load_psf1(filename);
if (IS_OK(font))
return font;
struct path* root = vfs_get_root();
if (IS_ERR(root))
return ERR_CAST(root);

struct font* ret = NULL;

font = load_psf2(filename);
if (IS_OK(font))
return font;
file_description* desc = vfs_open_at(root, filename, O_RDONLY, 0);
if (IS_ERR(desc)) {
ret = ERR_CAST(desc);
goto done;
}

return ERR_PTR(-EINVAL);
ret = load_psf1(desc);
if (IS_OK(ret))
goto done;

int rc = file_description_seek(desc, 0, SEEK_SET);
if (IS_ERR(rc)) {
ret = ERR_PTR(rc);
goto done;
}

ret = load_psf2(desc);
if (IS_OK(ret))
goto done;

ret = ERR_PTR(-EINVAL);

done:
if (desc)
file_description_close(desc);
path_destroy_recursive(root);
return ret;
}
2 changes: 1 addition & 1 deletion kernel/exec.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ NODISCARD static int push_ptrs(uintptr_t* sp, uintptr_t stack_base,

static int execve(const char* pathname, string_vec* argv, string_vec* envp) {
struct stat stat;
int rc = vfs_stat(pathname, &stat);
int rc = vfs_stat_at(current->cwd, pathname, &stat, 0);
if (IS_ERR(rc))
return rc;
if (!S_ISREG(stat.st_mode))
Expand Down
25 changes: 19 additions & 6 deletions kernel/fs/fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,21 +107,34 @@ NODISCARD int file_description_block(file_description*,

void vfs_init(void);
void vfs_populate_root_fs(const multiboot_module_t* initrd_mod);
struct inode* vfs_get_root(void);
NODISCARD int vfs_mount(const char* path, struct inode* fs_root);
struct path* vfs_get_root(void);
NODISCARD int vfs_mount(const char* pathname, struct inode* fs_root);
NODISCARD int vfs_mount_at(const struct path* base, const char* pathname,
struct inode* fs_root);

NODISCARD int vfs_register_device(struct inode* device);
struct inode* vfs_get_device(dev_t);
dev_t vfs_generate_unnamed_device_number(void);

// Return a path even if the last component of the path does not exist.
// The last component will have NULL inode in this case.
#define O_ALLOW_NOENT 0x4000

NODISCARD file_description* vfs_open(const char* pathname, int flags,
mode_t mode);
NODISCARD int vfs_stat(const char* pathname, struct stat* buf);
NODISCARD file_description* vfs_open_at(const struct path* base,
const char* pathname, int flags,
mode_t mode);
NODISCARD int vfs_stat(const char* pathname, struct stat* buf, int flags);
NODISCARD int vfs_stat_at(const struct path* base, const char* pathname,
struct stat* buf, int flags);
NODISCARD struct inode* vfs_create(const char* pathname, mode_t mode);
NODISCARD struct inode* vfs_create_at(const struct path* base,
const char* pathname, mode_t mode);

char* vfs_canonicalize_path(const char* pathname);
struct inode* vfs_resolve_path(const char* pathname, struct inode** out_parent,
char** out_basename);
struct path* vfs_resolve_path(const char* pathname, int flags);
struct path* vfs_resolve_path_at(const struct path* base, const char* pathname,
int flags);

uint8_t mode_to_dirent_type(mode_t);

Expand Down
12 changes: 10 additions & 2 deletions kernel/fs/initrd.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <common/extra.h>
#include <kernel/api/fcntl.h>
#include <kernel/boot_defs.h>
#include <kernel/fs/path.h>
#include <kernel/memory/memory.h>
#include <kernel/panic.h>
#include <string.h>
Expand Down Expand Up @@ -43,6 +44,9 @@ void initrd_populate_root_fs(uintptr_t paddr, size_t size) {
ASSERT_OK(
paging_map_to_physical_range(vaddr, region_start, region_size, 0));

struct path* root = vfs_get_root();
ASSERT_OK(root);

uintptr_t cursor = vaddr + (paddr - region_start);
for (;;) {
const struct cpio_odc_header* header =
Expand All @@ -59,10 +63,12 @@ void initrd_populate_root_fs(uintptr_t paddr, size_t size) {
size_t file_size = PARSE(header->c_filesize);

if (S_ISDIR(mode)) {
ASSERT_OK(vfs_create(filename, mode));
struct inode* inode = vfs_create_at(root, filename, mode);
ASSERT_OK(inode);
inode_unref(inode);
} else {
file_description* desc =
vfs_open(filename, O_CREAT | O_EXCL | O_WRONLY, mode);
vfs_open_at(root, filename, O_CREAT | O_EXCL | O_WRONLY, mode);
ASSERT_OK(desc);

desc->inode->rdev = PARSE(header->c_rdev);
Expand All @@ -83,6 +89,8 @@ void initrd_populate_root_fs(uintptr_t paddr, size_t size) {
cursor += sizeof(struct cpio_odc_header) + name_size + file_size;
}

path_destroy_recursive(root);

paging_kernel_unmap(vaddr, region_size);
ASSERT_OK(
range_allocator_free(&kernel_vaddr_allocator, vaddr, region_size));
Expand Down
101 changes: 101 additions & 0 deletions kernel/fs/path.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#include "path.h"
#include "fs.h"
#include <common/string.h>
#include <kernel/memory/memory.h>
#include <kernel/panic.h>

char* path_to_string(const struct path* path) {
size_t len = 1; // For the null terminator
for (const struct path* it = path; it; it = it->parent) {
if (it->basename)
len += strlen(it->basename) + 1; // +1 for the '/'
else
ASSERT(it->parent == NULL); // Root directory
}
char* s = kmalloc(len);
if (!s)
return NULL;
char* p = s + len - 1;
*p = 0;
for (const struct path* it = path; it; it = it->parent) {
if (!it->basename) {
ASSERT(it->parent == NULL); // Root directory
break;
}
size_t basename_len = strlen(it->basename);
p -= basename_len;
memcpy(p, it->basename, basename_len);
--p;
*p = '/';
}
ASSERT(p == s);
return s;
}

struct path* path_dup(const struct path* path) {
if (!path)
return NULL;
struct path* new_path = kmalloc(sizeof(struct path));
if (!new_path)
return ERR_PTR(-ENOMEM);
*new_path = (struct path){0};
if (path->basename) {
new_path->basename = kstrdup(path->basename);
if (!new_path->basename) {
kfree(new_path);
return ERR_PTR(-ENOMEM);
}
}
new_path->parent = path_dup(path->parent);
if (IS_ERR(new_path->parent)) {
kfree(new_path->basename);
kfree(new_path);
return new_path->parent;
}
new_path->inode = path->inode;
inode_ref(new_path->inode);
return new_path;
}

struct path* path_join(struct path* parent, struct inode* inode,
const char* basename) {
struct path* path = kmalloc(sizeof(struct path));
if (!path) {
inode_unref(inode);
return ERR_PTR(-ENOMEM);
}
path->basename = kstrdup(basename);
if (!path->basename) {
kfree(path);
inode_unref(inode);
return ERR_PTR(-ENOMEM);
}
path->inode = inode;
path->parent = parent;
return path;
}

struct inode* path_into_inode(struct path* path) {
if (!path)
return NULL;
struct inode* inode = path->inode;
path->inode = NULL;
path_destroy_recursive(path);
return inode;
}

void path_destroy_last(struct path* path) {
if (!path)
return;
inode_unref(path->inode);
kfree(path->basename);
kfree(path);
}

void path_destroy_recursive(struct path* path) {
while (path) {
struct path* parent = path->parent;
path_destroy_last(path);
path = parent;
}
}
Loading

0 comments on commit 60f1fc9

Please sign in to comment.