feat: Vfs and Ext2 support. Code style/attribute improvements
Added VFS and Ext2 support. Optimized attributes of methods to improve code highlighting. Printf attribute, malloc attribute, etc.
This commit is contained in:
186
kernel/vfs/vfs.c
Normal file
186
kernel/vfs/vfs.c
Normal file
@@ -0,0 +1,186 @@
|
||||
//
|
||||
// Created by rick on 12-08-21.
|
||||
//
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <myke/tasks/locking.h>
|
||||
#include <myke/vfs/vfs.h>
|
||||
#include <myke/vfs/vfs-driver.h>
|
||||
#include <myke/util/init.h>
|
||||
#include <myke/libk/libk.h>
|
||||
|
||||
vfs_mount_t *first_mount = NULL;
|
||||
mutex_t *mount_lock = NULL;
|
||||
|
||||
extern vfs_driver_t __start_vfs_driver[];
|
||||
extern vfs_driver_t __stop_vfs_driver[];
|
||||
#define NUM_DRIVERS ((size_t)(__stop_vfs_driver - __start_vfs_driver))
|
||||
#define DRIVER(i) ((__start_vfs_driver) + (i))
|
||||
|
||||
vfs_driver_t *vfs_get_driver_by_name(const char *name) {
|
||||
for (size_t i = 0; i < NUM_DRIVERS; ++i) {
|
||||
if (strcmp(DRIVER(i)->name, name) == 0) {
|
||||
return DRIVER(i);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void vfs_register_mount(vfs_mount_t *mount) {
|
||||
mutex_acquire(mount_lock);
|
||||
if (first_mount == NULL) {
|
||||
first_mount = mount;
|
||||
} else {
|
||||
vfs_mount_t *last_mount = first_mount;
|
||||
while (last_mount->next != NULL) last_mount = last_mount->next;
|
||||
last_mount->next = mount;
|
||||
}
|
||||
mutex_release(mount_lock);
|
||||
}
|
||||
|
||||
vfs_mount_t *vfs_get_mount_for_path(const char *path) {
|
||||
if (first_mount == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
mutex_acquire(mount_lock);
|
||||
size_t max_length = strlen(path);
|
||||
vfs_mount_t *longest_match = NULL;
|
||||
size_t match_length = 0;
|
||||
vfs_mount_t *last_mount = NULL;
|
||||
do {
|
||||
if (last_mount == NULL) {
|
||||
last_mount = first_mount;
|
||||
} else if ((last_mount = last_mount->next) == NULL) {
|
||||
break;
|
||||
}
|
||||
size_t mount_length = strlen(last_mount->prefix);
|
||||
if (mount_length > max_length || mount_length < match_length) {
|
||||
continue;
|
||||
}
|
||||
if (strncmp(last_mount->prefix, path, strlen(last_mount->prefix)) == 0) {
|
||||
longest_match = last_mount;
|
||||
match_length = mount_length;
|
||||
}
|
||||
} while (true);
|
||||
mutex_release(mount_lock);
|
||||
return longest_match;
|
||||
}
|
||||
|
||||
int vfs_mount(const char *path, const char *device, const char *driver) {
|
||||
vfs_driver_t *driver_impl = vfs_get_driver_by_name(driver);
|
||||
if (driver_impl == NULL) {
|
||||
return VFS_MOUNT_ERROR;
|
||||
}
|
||||
vfs_mount_t *mount = malloc(sizeof(vfs_mount_t));
|
||||
mount->driver = driver_impl;
|
||||
mount->device = device;
|
||||
mount->prefix = path;
|
||||
int result = driver_impl->vfs_mount(mount);
|
||||
if (result != VFS_MOUNT_OK) {
|
||||
free(mount);
|
||||
return result;
|
||||
}
|
||||
vfs_register_mount(mount);
|
||||
return VFS_MOUNT_OK;
|
||||
}
|
||||
|
||||
vfs_fd_t *vfs_open_intermediate(vfs_mount_t *mount, const char *path, int flags, int mode) {
|
||||
vfs_fd_t *intermediate_dir = malloc(sizeof(vfs_fd_t));
|
||||
vfs_fd_t *out = malloc(sizeof(vfs_fd_t));
|
||||
out->mount = mount;
|
||||
intermediate_dir->mount = mount;
|
||||
char *full_path = strdup(path);
|
||||
char *current_path = full_path;
|
||||
while (strlen(current_path) > 0) {
|
||||
if (current_path[0] == '/') {
|
||||
// root
|
||||
if (((vfs_driver_t *) mount->driver)->open(mount, NULL, NULL, flags, out) != VFS_OPEN_OK) {
|
||||
free(out);
|
||||
free(intermediate_dir);
|
||||
free(full_path);
|
||||
return NULL;
|
||||
}
|
||||
current_path = ¤t_path[1];
|
||||
} else {
|
||||
char *next_dir = strchr(current_path, '/');
|
||||
if (next_dir != NULL) {
|
||||
next_dir[0] = 0;
|
||||
}
|
||||
if (((vfs_driver_t *) mount->driver)->open(mount, intermediate_dir, current_path, flags, out) !=
|
||||
VFS_OPEN_OK) {
|
||||
((vfs_driver_t *) mount->driver)->close(mount, intermediate_dir);
|
||||
free(out);
|
||||
free(intermediate_dir);
|
||||
free(full_path);
|
||||
return NULL;
|
||||
}
|
||||
if (next_dir == NULL) {
|
||||
current_path = ¤t_path[strlen(current_path)];
|
||||
} else {
|
||||
current_path = &next_dir[1];
|
||||
}
|
||||
if (((vfs_driver_t *) mount->driver)->close(mount, intermediate_dir) != VFS_CLOSE_OK) {
|
||||
free(out);
|
||||
free(intermediate_dir);
|
||||
free(full_path);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
memcpy(intermediate_dir, out, sizeof(vfs_fd_t));
|
||||
}
|
||||
free(full_path);
|
||||
free(intermediate_dir);
|
||||
return out;
|
||||
}
|
||||
|
||||
// https://man7.org/linux/man-pages/man2/open.2.html
|
||||
vfs_fd_t *vfs_open(const char *path, int flags, int mode) {
|
||||
vfs_mount_t *mount = vfs_get_mount_for_path(path);
|
||||
if (mount == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return vfs_open_intermediate(mount, &path[strlen(mount->prefix) - 1], flags, mode);
|
||||
}
|
||||
|
||||
void vfs_close(vfs_fd_t *fd) {
|
||||
((vfs_driver_t *) (fd->mount->driver))->close(fd->mount, fd);
|
||||
free(fd);
|
||||
}
|
||||
|
||||
// https://man7.org/linux/man-pages/man2/stat.2.html
|
||||
int vfs_fstat(vfs_fd_t *dirfd, stat_t *target, int flags) {
|
||||
return ((vfs_driver_t *) (dirfd->mount->driver))->fstat(dirfd->mount, dirfd, target, flags);
|
||||
}
|
||||
|
||||
// https://man7.org/linux/man-pages/man2/read.2.html
|
||||
int vfs_read(vfs_fd_t *fd, void *target, size_t size) {
|
||||
return ((vfs_driver_t *) (fd->mount->driver))->fread(fd->mount, fd, target, size);
|
||||
}
|
||||
|
||||
// inspiration https://man7.org/linux/man-pages/man2/getdents.2.html
|
||||
int vfs_getdents(vfs_fd_t *fd, void *target, int count) {
|
||||
return ((vfs_driver_t *) fd->mount->driver)->dgetent(fd->mount, fd, target, count);
|
||||
}
|
||||
|
||||
void vfs_mk_dirent_record(vfs_dirent_t *ent, uint32_t inode, uint32_t cur_offset, uint8_t type, char *name,
|
||||
size_t name_length) {
|
||||
ent->inode = inode;
|
||||
strncpy(ent->name, name, name_length);
|
||||
ent->name[name_length] = 0;
|
||||
ent->type = type;
|
||||
ent->reclen = VFS_DIRENT_SIZE(name_length);
|
||||
ent->offset_next = cur_offset + ent->reclen;
|
||||
}
|
||||
|
||||
void vfs_init() {
|
||||
mount_lock = mutex_create();
|
||||
}
|
||||
|
||||
INIT_FUNCTION(100) = {
|
||||
.name = "vfs-task",
|
||||
.stage = INIT_STAGE_PRE_TASKING,
|
||||
.init = vfs_init,
|
||||
};
|
||||
Reference in New Issue
Block a user