diff --git a/meson.build b/meson.build index 8bbec38..a5c2807 100644 --- a/meson.build +++ b/meson.build @@ -52,6 +52,7 @@ kernel_sources = files( 'src/keyboard.c', 'src/memory.c', 'src/panic.c', + 'src/path.c', 'src/pic.c', 'src/string.c', 'src/vga.c', diff --git a/src/app/cat.c b/src/app/cat.c index 8f1b8dc..35e293f 100644 --- a/src/app/cat.c +++ b/src/app/cat.c @@ -1,78 +1,31 @@ #include "src/app/cat.h" #include "src/fs.h" #include "src/memory.h" -#include "src/string.h" -#include "src/util.h" - +#include "src/path.h" #include -static stream_t *stream_in; -static stream_t *stream_out; - -#define WRITE_S(s) stream_out->write(stream_out, s, sizeof(s) - 1); -#define WRITE_D(s) stream_out->write(stream_out, s, string_length(s)); - -void cat(stream_t *stdin, stream_t *stdout, uint8_t argc, char **argv) { - stream_in = stdin; - stream_out = stdout; - +void cat(process_t *proc, uint8_t argc, char **argv) { if (argc != 2) { WRITE_S("cat: requires a single path\n"); return; } - char *path_components[16]; - uint64_t path_length = string_split(argv[1], '/', 16, path_components); - if (!string_empty(path_components[0])) { - WRITE_S("cat: relative paths not supported\n"); + path_t *path = path_open(proc->root, proc->cwd, argv[1]); + if (!path) { + WRITE_S("cat: invalid path\n"); return; } - fs_node_t *root = fs_mount(); - - fs_node_t *prev = NUL; - fs_node_t *curr = root; - uint8_t i = 1; - while (i < path_length) { - if (string_empty(path_components[i])) { - i++; - continue; - } - - if (!curr->is_dir) { - WRITE_S("cat: can not navigate into a file\n"); - fs_close(curr); - return; - } - - prev = curr; - curr = fs_open_by(curr, path_components[i]); - if (prev != root) { - fs_close(prev); - } - - if (!curr) { - WRITE_S("cat: invalid path\n"); - return; - } - i++; - } - + fs_node_t *curr = path->depth ? path->stack[path->depth - 1] : proc->root; if (curr->is_dir) { WRITE_S("cat: can not print a directory\n"); - if (curr != root) { - fs_close(curr); - } + path_close(path); return; } char *content = memory_allocate(curr->size + 1); fs_read(curr, 0, curr->size, content); - stream_out->write(stream_out, content, curr->size); + proc->stdout->write(proc->stdout, content, curr->size); memory_free(content); - fs_close(curr); - - fs_unmount(root); - - stream_in = stream_out = NUL; + path_close(path); } diff --git a/src/app/cat.h b/src/app/cat.h index 91891d5..be8a4ae 100644 --- a/src/app/cat.h +++ b/src/app/cat.h @@ -1,5 +1,5 @@ #pragma once -#include "src/stream.h" +#include "src/process.h" -void cat(stream_t *stdin, stream_t *stdout, uint8_t argc, char **argv); +void cat(process_t *proc, uint8_t argc, char **argv); diff --git a/src/app/ls.c b/src/app/ls.c index 6133daa..05a1990 100644 --- a/src/app/ls.c +++ b/src/app/ls.c @@ -1,65 +1,24 @@ #include "src/app/ls.h" #include "src/fs.h" -#include "src/string.h" -#include "src/util.h" - +#include "src/path.h" #include -static stream_t *stream_in; -static stream_t *stream_out; - -#define WRITE_S(s) stream_out->write(stream_out, s, sizeof(s) - 1); -#define WRITE_D(s) stream_out->write(stream_out, s, string_length(s)); - -void ls(stream_t *stdin, stream_t *stdout, uint8_t argc, char **argv) { - stream_in = stdin; - stream_out = stdout; - - if (argc != 2) { +void ls(process_t *proc, uint8_t argc, char **argv) { + if (argc > 2) { WRITE_S("ls: requires a single path\n"); return; } - char *path_components[16]; - uint64_t path_length = string_split(argv[1], '/', 16, path_components); - if (!string_empty(path_components[0])) { - WRITE_S("ls: relative paths not supported\n"); + path_t *path = path_open(proc->root, proc->cwd, argc == 1 ? "." : argv[1]); + if (!path) { + WRITE_S("ls: invalid path\n"); return; } - fs_node_t *root = fs_mount(); - - fs_node_t *prev = NUL; - fs_node_t *curr = root; - uint8_t i = 1; - while (i < path_length) { - if (string_empty(path_components[i])) { - i++; - continue; - } - - if (!curr->is_dir) { - WRITE_S("ls: can not navigate into a file\n"); - fs_close(curr); - return; - } - - prev = curr; - curr = fs_open_by(curr, path_components[i]); - if (prev != root) { - fs_close(prev); - } - - if (!curr) { - WRITE_S("ls: invalid path\n"); - return; - } - i++; - } - + fs_node_t *curr = path->depth ? path->stack[path->depth - 1] : proc->root; if (!curr->is_dir) { - WRITE_S("ls: can not list file\n"); - fs_close(curr); + WRITE_S("ls: can not list a file\n"); + path_close(path); return; } @@ -71,11 +30,5 @@ void ls(stream_t *stdin, stream_t *stdout, uint8_t argc, char **argv) { fs_close(item); item = fs_open_at(curr, j++); } - if (curr != root) { - fs_close(curr); - } - - fs_unmount(root); - - stream_in = stream_out = NUL; + path_close(path); } diff --git a/src/app/ls.h b/src/app/ls.h index b8c7a6a..3f4963e 100644 --- a/src/app/ls.h +++ b/src/app/ls.h @@ -1,5 +1,5 @@ #pragma once -#include "src/stream.h" +#include "src/process.h" -void ls(stream_t *stdin, stream_t *stdout, uint8_t argc, char **argv); +void ls(process_t *proc, uint8_t argc, char **argv); diff --git a/src/app/terminal.c b/src/app/terminal.c index d29f00c..f5f7c6e 100644 --- a/src/app/terminal.c +++ b/src/app/terminal.c @@ -3,14 +3,17 @@ #include "src/app/ls.h" #include "src/fs.h" #include "src/memory.h" +#include "src/path.h" +#include "src/process.h" #include "src/string.h" #include "src/util.h" #include -#define PROMPT_LENGTH 255 +static void help(process_t *proc, uint8_t argc, char **argv); +static void cd(process_t *proc, uint8_t argc, char **argv); -fs_node_t *root; +#define PROMPT_LENGTH 255 static const char bs[PROMPT_LENGTH + 1]; static const char ws[PROMPT_LENGTH + 1]; @@ -19,20 +22,63 @@ static char prompt[PROMPT_LENGTH + 1]; static uint8_t prompt_length = 0; static uint8_t prompt_offset = 0; -static stream_t *stream_in; -static stream_t *stream_out; +process_t *proc; static uint8_t active = 1; -#define WRITE_S(s) stream_out->write(stream_out, s, sizeof(s) - 1); -#define WRITE_D(s) stream_out->write(stream_out, s, string_length(s)); +typedef struct { + const char *name; + app_t app; +} app_entry_t; + +static app_entry_t apps[] = { + {"help", help}, + {"cd", cd}, + {"ls", ls}, + {"cat", cat}, +}; + +static void help(process_t *proc, uint8_t argc, __attribute__((unused)) char **argv) { + if (argc > 1) { + WRITE_S("help: accepts no arguments\n"); + } + + WRITE_S("Available commands:\n"); + for (uint64_t i = 0; i < sizeof(apps) / sizeof(app_entry_t); i++) { + WRITE_D(apps[i].name); + WRITE_S("\n"); + } +} + +static void cd(process_t *proc, uint8_t argc, char **argv) { + if (argc != 2) { + WRITE_S("cd: requires a single path\n"); + return; + } + + path_t *new = path_open(proc->root, proc->cwd, argv[1]); + if (!new) { + WRITE_S("cd: path does not exist\n"); + return; + } + + path_close(proc->cwd); + proc->cwd = new; +} + +static void print_prompt() { + WRITE_S("["); + fs_node_t *curr = proc->cwd->depth ? proc->cwd->stack[proc->cwd->depth - 1] : proc->root; + WRITE_D(curr->name); + WRITE_S("]$ "); +} static void on_home_pressed() { if (!prompt_offset) { return; } - stream_out->write(stream_out, bs, prompt_offset); + proc->stdout->write(proc->stdout, bs, prompt_offset); prompt_offset = 0; } @@ -41,7 +87,7 @@ static void on_left_pressed() { return; } - stream_out->write(stream_out, bs, 1); + proc->stdout->write(proc->stdout, bs, 1); prompt_offset--; } @@ -50,7 +96,7 @@ static void on_right_pressed() { return; } - stream_out->write(stream_out, prompt + prompt_offset, 1); + proc->stdout->write(proc->stdout, prompt + prompt_offset, 1); prompt_offset++; } @@ -59,21 +105,10 @@ static void on_end_pressed() { return; } - stream_out->write(stream_out, prompt + prompt_offset, prompt_length - prompt_offset); + proc->stdout->write(proc->stdout, prompt + prompt_offset, prompt_length - prompt_offset); prompt_offset = prompt_length; } -static void help(uint8_t argc, __attribute__((unused)) char **argv) { - if (argc > 1) { - WRITE_S("help: accepts no arguments\n"); - } - - WRITE_S("Available commands:\n" - "help\n" - "ls DIR\n" - "cat FILE\n") -} - static void on_enter_pressed() { prompt[prompt_length] = '\0'; @@ -82,23 +117,24 @@ static void on_enter_pressed() { WRITE_S("\n"); - if (string_equal(argv[0], "help")) { - help(argc, argv); - } else if (string_equal(argv[0], "ls")) { - ls(stream_in, stream_out, argc, argv); - } else if (string_equal(argv[0], "cat")) { - cat(stream_in, stream_out, argc, argv); - } else { + uint8_t i; + for (i = 0; i < sizeof(apps) / sizeof(app_entry_t); i++) { + if (string_equal(argv[0], apps[i].name)) { + apps[i].app(proc, argc, argv); + break; + } + } + if (i == sizeof(apps) / sizeof(app_entry_t)) { WRITE_S("Unknown command\n"); } - WRITE_S("$ "); prompt_length = prompt_offset = 0; + print_prompt(); } static void on_cancel_pressed() { WRITE_S("^C\n"); - WRITE_S("$ "); prompt_length = prompt_offset = 0; + print_prompt(); } static void on_disconnect_pressed() { @@ -116,9 +152,9 @@ static void on_ctrl_character_pressed(char c) { static void redraw_from_cursor() { uint64_t tail = prompt_length - prompt_offset; - stream_out->write(stream_out, prompt + prompt_offset, tail); - stream_out->write(stream_out, ws, 1); // erase the character past the end - stream_out->write(stream_out, bs, tail + 1); // move back to cursor position + proc->stdout->write(proc->stdout, prompt + prompt_offset, tail); + proc->stdout->write(proc->stdout, ws, 1); // erase the character past the end + proc->stdout->write(proc->stdout, bs, tail + 1); // move back to cursor position } static void on_character_pressed(char c) { @@ -132,7 +168,7 @@ static void on_character_pressed(char c) { prompt_length++; prompt_offset++; - stream_out->write(stream_out, &c, 1); // emit the character itself + proc->stdout->write(proc->stdout, &c, 1); // emit the character itself redraw_from_cursor(); } @@ -146,7 +182,7 @@ static void on_backspace_pressed() { prompt_offset--; prompt_length--; - stream_out->write(stream_out, bs, 1); + proc->stdout->write(proc->stdout, bs, 1); redraw_from_cursor(); } @@ -228,28 +264,24 @@ static void on_char_received(char c) { } } -void terminal(stream_t *stdin, stream_t *stdout, __attribute__((unused)) uint8_t argc, __attribute__((unused)) char **argv) { +void terminal(process_t *p, __attribute__((unused)) uint8_t argc, __attribute__((unused)) char **argv) { memory_set('\b', PROMPT_LENGTH, (char *)bs); memory_set(' ', PROMPT_LENGTH, (char *)ws); - stream_in = stdin; - stream_out = stdout; - - root = fs_mount(); + proc = p; char *greeting = string_format("Welcome to FreywarOS v%s!\n\n", VERSION); WRITE_D(greeting); memory_free(greeting); - WRITE_S("$ "); + print_prompt(); while (active) { char c; - if (stream_in->read(stream_in, 1, &c)) { + if (proc->stdin->read(proc->stdin, 1, &c)) { on_char_received(c); } } - // fs_unmount(root); - stream_in = stream_out = NUL; + proc = NUL; } diff --git a/src/app/terminal.h b/src/app/terminal.h index b1e8f11..1d4932e 100644 --- a/src/app/terminal.h +++ b/src/app/terminal.h @@ -1,5 +1,5 @@ #pragma once -#include "src/stream.h" +#include "src/process.h" -void terminal(stream_t *stdin, stream_t *stdout, uint8_t argc, char **argv); +void terminal(process_t *proc, uint8_t argc, char **argv); diff --git a/src/fat16.c b/src/fat16.c index a6be2c1..d659316 100644 --- a/src/fat16.c +++ b/src/fat16.c @@ -1,5 +1,6 @@ #include "src/fat16.h" #include "src/ata.h" +#include "src/fs.h" #include "src/memory.h" #include "src/string.h" #include "src/util.h" @@ -86,7 +87,7 @@ fs_node_t *fat16_mount() { // Assuming one partition. } static void ensure_fat() { - ASSERT(bpb.sectors_per_fat<256, "ensure_fat: big FAT not implemented") + ASSERT(bpb.sectors_per_fat < 256, "ensure_fat: big FAT not implemented") if (!fat) { fat = memory_allocate(bpb.sectors_per_fat * SECTOR_SIZE); ata_read_sectors(FIRST_PARTITION_SECTOR + bpb.reserved_sectors, (uint8_t)bpb.sectors_per_fat, fat); @@ -193,6 +194,12 @@ fs_node_t *fat16_open_at(const fs_node_t *directory, uint64_t index) { return result; } +fs_node_t *fat16_open_again(const fs_node_t *source) { + fs_node_t *result = memory_allocate(sizeof(fat16_node_t)); + memory_copy(source, sizeof(fat16_node_t), result); + return result; +} + void fat16_read(const fs_node_t *file, uint64_t offset, uint64_t size, void *to) { ASSERT(file->type == FAT16, "fat16_read: file is not FAT16"); ASSERT(!file->is_dir, "fat16_read: can not read directory"); diff --git a/src/fat16.h b/src/fat16.h index 4a79b78..e74abe6 100644 --- a/src/fat16.h +++ b/src/fat16.h @@ -10,6 +10,8 @@ fs_node_t *fat16_open_by(const fs_node_t *directory, const char *name); fs_node_t *fat16_open_at(const fs_node_t *directory, uint64_t index); +fs_node_t *fat16_open_again(const fs_node_t *source); + void fat16_read(const fs_node_t *file, uint64_t offset, uint64_t size, void *to); void fat16_close(fs_node_t *node); diff --git a/src/fs.c b/src/fs.c index 824f2b1..2c9fc13 100644 --- a/src/fs.c +++ b/src/fs.c @@ -13,6 +13,10 @@ fs_node_t *fs_open_at(const fs_node_t *directory, uint64_t index) { return fat16_open_at(directory, index); } +fs_node_t *fs_open_again(const fs_node_t *source) { + return fat16_open_again(source); +} + void fs_read(const fs_node_t *file, uint64_t offset, uint64_t size, void *to) { fat16_read(file, offset, size, to); } diff --git a/src/fs.h b/src/fs.h index acb9d48..cd1334a 100644 --- a/src/fs.h +++ b/src/fs.h @@ -18,6 +18,8 @@ fs_node_t *fs_open_by(const fs_node_t *directory, const char *name); fs_node_t *fs_open_at(const fs_node_t *directory, uint64_t index); +fs_node_t *fs_open_again(const fs_node_t *source); + void fs_read(const fs_node_t *file, uint64_t offset, uint64_t size, void *to); void fs_close(fs_node_t *node); diff --git a/src/kernel.c b/src/kernel.c index 3140efe..f5ff1f0 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -1,9 +1,11 @@ #include "src/app/terminal.h" +#include "src/fs.h" #include "src/idt.h" #include "src/keyboard.h" #include "src/memory.h" +#include "src/path.h" #include "src/pic.h" -#include "src/stream.h" +#include "src/process.h" #include "src/util.h" #include "src/vga.h" @@ -42,10 +44,13 @@ void kernel_main() { memory_init(); - stream_t *stdin = keyboard_init(); - stream_t *stdout = vga_init(); + process_t *proc = memory_allocate(sizeof(process_t)); + proc->cwd = memory_allocate(sizeof(path_t)); + proc->root = fs_mount(); + proc->stdin = keyboard_init(); + proc->stdout = vga_init(); - terminal(stdin, stdout, 0, NUL); + terminal(proc, 0, NUL); outw(0x604, 0x2000); // TODO: parse ACPI tables for real hardware __asm__ volatile("cli; hlt"); diff --git a/src/path.c b/src/path.c new file mode 100644 index 0000000..fb488ce --- /dev/null +++ b/src/path.c @@ -0,0 +1,46 @@ +#include "src/path.h" +#include "src/fs.h" +#include "src/memory.h" +#include "src/string.h" +#include "src/util.h" +#include + +path_t *path_open(const fs_node_t *root, const path_t *source, char *path) { + path_t *result = memory_allocate(sizeof(path_t)); + + char *path_components[PATH_DEPTH]; + uint8_t path_length = (uint8_t)string_split(path, '/', PATH_DEPTH, path_components); + if (!string_empty(path_components[0])) { + for (uint8_t i = 0; i < source->depth; i++) { + result->stack[result->depth++] = fs_open_again(source->stack[i]); + } + } + + for (uint8_t i = 0; i < path_length; i++) { + if (string_empty(path_components[i]) || string_equal(path_components[i], ".")) { + continue; + } else if (string_equal(path_components[i], "..")) { + if (result->depth) { + fs_close(result->stack[--result->depth]); + } + } else { + const fs_node_t *prev = result->depth ? result->stack[result->depth - 1] : root; + fs_node_t *next = prev->is_dir ? fs_open_by(prev, path_components[i]) : NUL; + if (!next || result->depth >= PATH_DEPTH) { + path_close(result); + return NUL; + } else { + result->stack[result->depth++] = next; + } + } + } + + return result; +} + +void path_close(path_t *path) { + for (uint64_t i = 0; i < path->depth; i++) { + fs_close(path->stack[i]); + } + memory_free(path); +} diff --git a/src/path.h b/src/path.h new file mode 100644 index 0000000..9ccd20a --- /dev/null +++ b/src/path.h @@ -0,0 +1,15 @@ +#pragma once + +#include "src/fs.h" +#include + +#define PATH_DEPTH 255 + +typedef struct { + fs_node_t *stack[PATH_DEPTH]; + uint8_t depth; +} path_t; + +path_t *path_open(const fs_node_t *root, const path_t *source, char *path); + +void path_close(path_t *path); diff --git a/src/process.h b/src/process.h new file mode 100644 index 0000000..fc2a4e1 --- /dev/null +++ b/src/process.h @@ -0,0 +1,18 @@ +#pragma once + +#include "src/fs.h" +#include "src/path.h" +#include "src/stream.h" +#include "src/string.h" + +typedef struct { + path_t *cwd; + fs_node_t *root; + stream_t *stdin; + stream_t *stdout; +} process_t; + +typedef void (*app_t)(process_t *proc, uint8_t argc, char **argv); + +#define WRITE_S(s) proc->stdout->write(proc->stdout, s, sizeof(s) - 1); +#define WRITE_D(s) proc->stdout->write(proc->stdout, s, string_length(s));