Added VFS and Ext2 support. Optimized attributes of methods to improve code highlighting. Printf attribute, malloc attribute, etc.
187 lines
5.8 KiB
C
187 lines
5.8 KiB
C
//
|
|
// 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,
|
|
};
|