diff options
| author | Carlos Maiolino <[email protected]> | 2026-03-08 13:37:37 +0100 |
|---|---|---|
| committer | Carlos Maiolino <[email protected]> | 2026-03-08 13:47:28 +0100 |
| commit | 84b464a185d20d8e329b7aad0b482687a9705b58 (patch) | |
| tree | 273954db9a38ca577a1bb8171f2f31a9ddbce54b | |
| parent | 5ba10e3ee774602e20553091568551e210731fbb (diff) | |
Add a path parsing mechanism
Now the system can parse paths to files/directories.
It follows the same Unix standard namespace.
For now, only absolute paths are allowed.
The parse mechanism relies on the struct path_part. Which represents
each component on a single path.
All the components are chain-linked through path_part->next, where the
last path component will have ->next == NULL.
This also introduces path_root struct, which represents the root of
the path.
The first component, linked to path_root->head, is always the "/" component.
The disk_id represents the disk the root directory is found into. This
should actually (and likely will) be a mountpoint not a disk id.
Signed-off-by: Carlos Maiolino <[email protected]>
| -rw-r--r-- | Makefile | 7 | ||||
| -rw-r--r-- | src/fs/path.c | 194 | ||||
| -rw-r--r-- | src/include/fs/path.h | 25 | ||||
| -rw-r--r-- | src/include/toxic/config.h | 4 |
4 files changed, 229 insertions, 1 deletions
@@ -20,7 +20,8 @@ KOBJ_FILES = $(KERNEL_ASM_OBJ) \ ./build/mm/paging.asm.o \ ./build/mm/paging.o \ ./build/drivers/ata.o \ - ./build/block/block.o + ./build/block/block.o \ + ./build/fs/path.o BOOT_TGT =./bin/boot.bin @@ -88,6 +89,9 @@ $(BUILD_DIR)/drivers/ata.o: ./src/drivers/ata.c $(BUILD_DIR)/block/block.o: ./src/block/block.c i686-elf-gcc $(INCLUDES) $(FLAGS) -std=gnu99 -c ./src/block/block.c -o $(BUILD_DIR)/block/block.o +$(BUILD_DIR)/fs/path.o: ./src/fs/path.c + i686-elf-gcc $(INCLUDES) $(FLAGS) -std=gnu99 -c ./src/fs/path.c -o $(BUILD_DIR)/fs/path.o + clean: rm -f $(BOOT_TGT) rm -f bin/kernel.bin @@ -102,4 +106,5 @@ clean: rm -f build/mm/*.o rm -f build/drivers/*.o rm -f build/block/*.o + rm -f build/fs/*.o rm -f bin/os.bin diff --git a/src/fs/path.c b/src/fs/path.c new file mode 100644 index 0000000..d0e31af --- /dev/null +++ b/src/fs/path.c @@ -0,0 +1,194 @@ +#include <fs/path.h> +#include <toxic/string.h> +#include <toxic/config.h> +#include <mm/kernel_heap.h> +#include <toxic/errno.h> + +static int +is_valid(const char *path) +{ + int len = strnlen(path, PATH_MAX); + + /* Only allow for absolute paths for now */ + if (len < PATH_MAX && path[len] == '\0' && + strncmp(path, "/", 1) == 0) + return true; + + return false; +} + +/* + * Name must be dynamically allocated and not NULL + */ +static struct path_part * +path_alloc(const char *name) +{ + struct path_part *p = kzalloc(sizeof(struct path_part)); + p->name = name; + + return p; +} + +/* + * This is the main parser routine. + * It is designed to be called in a loop until it returns NULL, + * indicating the end of the path. + * + * It will return a copy of the current part of the path. + * + * So for a path like: /home/foo/bar, each call to this routine + * will return: "home", "foo", "bar" and NULL (signaling the end + * of the path). It uses the double pointer argument as its own + * cursor. + * + * - This makes no distinction if what it receives is an absolute + * or relative path. It just extracts the components. + * - The caller is responsible for checking if the path is + * absolute or relative. + * + * - It makes no distinction between files or directories, this only + * parses a path. + * + * - Double slashes like /home//foo are ignored and the entries returned + * will be "home" and "foo". + */ +static char * +get_path_part(char **path) +{ + char *name; + char *cur = *path; + int i = 0; + size_t pathlen = strlen(cur); + + /* We reached the end of the full path */ + if (!pathlen) + return NULL; + + /* Ignore any leading slashes */ + while (cur[i] == '/' && i < pathlen) + i++; + + /* There are no more components, just leading slash(es) */ + if (i >= pathlen) + return NULL; + + + /* Advance cursor to the first non-slash character */ + *path = cur += i; + + /* + * Reset the index and advance it accordingly to the + * new cursor position. + */ + for (i = 0; cur[i] != '/' && cur[i] != '\0'; i++); + + name = kzalloc(i + 1); /* Size of the current component + null */ + strncpy(name, cur, i); + + /* kzalloc'ed, null terminator already there, but just in case...*/ + name[i] = '\0'; + + /* + * Advance path to the next component + * + * The last for loop incremented 'i' to either the next '/' in the path + * or to the null terminator of the full path. + * + * Just point the caller's cursor to that location. Next call here will + * either return NULL or begin with a '/' + */ + *path += (i + 1); /* Move the path cursor to the next component */ + + return name; +} + +/* + * If last is not NULL, we are parsing a relative path + * so we should just extend the current path. + * + * Relative paths not implemented yet... last should ALWAYS + * be NULL + */ +static struct path_part * +construct_path( + struct path_part *last, + char *p) +{ + char *cur = p; /* Used to walk through the path */ + char *name = kzalloc(2); /* Alloc space for '/' */ + + name[0] = '/'; + name[1] = '\0'; + + /* Root path component has NULL as its name */ + struct path_part *root = path_alloc(name); + struct path_part *ptr_next = root; + + + /* Reset the name pointer before starting to parse the path */ + name = NULL; + + /* check (last == NULL); */ + + while ((name = get_path_part(&cur))) { + ptr_next->next = path_alloc(name); + + /* Gotta check if path_aloc() failed*/ + + ptr_next = ptr_next->next; + } + + /* Ensure we null terminate the component's linked list */ + ptr_next->next = NULL; + return root; + +err_out: + return NULL; +} + +static struct path_root * +root_init(void) +{ + struct path_root *r = kzalloc(sizeof(struct path_root)); + + /* + * We just have support for one disk by now, and the root + * shouldn't be tied to a specific disk. I want a Unix-like + * namespace + */ + r->disk_id = 0; + r->head = NULL; + return r; +} + +void +free_root(struct path_root *r) +{ + if (r) + kfree(r); +} + +/* + * This should account for a relative path. + * By now it only deals with absolute paths (see is_valid()) + */ + +struct path_root * +parse_path(char *path) +{ + struct path_root *root; + + if (!is_valid(path)) + return NULL; + + root = root_init(); + root->head = construct_path(NULL, path); + + if (!root->head) { + free_root(root); + return NULL; + } + + return root; +} + diff --git a/src/include/fs/path.h b/src/include/fs/path.h new file mode 100644 index 0000000..369e8b0 --- /dev/null +++ b/src/include/fs/path.h @@ -0,0 +1,25 @@ +#ifndef PATH_H +#define PATH_H + +/* + * Path structure follows unix format: + * + * /foo/bar/file + * + */ + +struct path_part { + const char *name; + struct path_part *next; +}; + +/* head is a linked list of all path components. + * the '/' is a component itself with name == NULL + */ +struct path_root { + int disk_id; + struct path_part *head; +}; + +struct path_root * parse_path(char *path); +#endif /* PATH_H */ diff --git a/src/include/toxic/config.h b/src/include/toxic/config.h index c1c1e7f..593eb2a 100644 --- a/src/include/toxic/config.h +++ b/src/include/toxic/config.h @@ -9,4 +9,8 @@ #define PAGE_SIZE (4096) #define SECTOR_SIZE (512) + +/* Path parsing */ +#define PATH_MAX (128) + #endif /* CONFIG_H */ |
