diff --git a/lib/libfs/CMakeLists.txt b/lib/libfs/CMakeLists.txt index 8753962..f6459b8 100644 --- a/lib/libfs/CMakeLists.txt +++ b/lib/libfs/CMakeLists.txt @@ -23,7 +23,7 @@ sysroot_add_library( HEADER_DIR /usr/include LIB_DIR /usr/lib) -target_link_libraries(libfs libmango interface::fs libc) -target_link_libraries(libfs-static libmango interface::fs libc-core) +target_link_libraries(libfs libmango interface::fs libc libxpc) +target_link_libraries(libfs-static libmango interface::fs libc-core libxpc-static) set_target_properties(libfs-static PROPERTIES POSITION_INDEPENDENT_CODE FALSE) diff --git a/lib/libfs/context.c b/lib/libfs/context.c index fc96338..6fb9a0c 100644 --- a/lib/libfs/context.c +++ b/lib/libfs/context.c @@ -4,6 +4,12 @@ #include #include +#include +#include +#include +#include +#include +#include BTREE_DEFINE_SIMPLE_GET(struct fs_file, unsigned long, f_node, f_id, get_file); BTREE_DEFINE_SIMPLE_INSERT(struct fs_file, f_node, f_id, put_file); @@ -16,9 +22,7 @@ struct fs_context { struct fs_vtable ctx_vtable; }; -struct fs_context *fs_context_create( - struct fs_allocator *alloc, - struct fs_superblock *sb) +struct fs_context *fs_context_create(struct fs_allocator *alloc) { struct fs_context *ctx = fs_alloc(alloc, sizeof *ctx); if (!ctx) { @@ -27,10 +31,10 @@ struct fs_context *fs_context_create( memset(ctx, 0x0, sizeof *ctx); - ctx->ctx_sb = sb; ctx->ctx_alloc = alloc; ctx->ctx_vtable.open = fs_msg_open; + ctx->ctx_vtable.read = fs_msg_read; return ctx; } @@ -40,6 +44,35 @@ void fs_context_destroy(struct fs_context *ctx) fs_free(ctx->ctx_alloc, ctx); } +enum fs_status fs_context_mount_filesystem( + struct fs_context *ctx, + fs_mount_function_t func, + void *arg, + enum fs_mount_flags flags) +{ + if (!func) { + return FS_ERR_INVALID_ARGUMENT; + } + + struct fs_superblock *sb = NULL; + enum fs_status status = func(ctx, arg, flags, &sb); + if (status != FS_SUCCESS) { + return status; + } + + if (!sb) { + return FS_ERR_INTERNAL_FAILURE; + } + + ctx->ctx_sb = sb; + return FS_SUCCESS; +} + +enum fs_status fs_context_unmount_filesystem(struct fs_context *ctx) +{ + return FS_ERR_NOT_IMPLEMENTED; +} + struct fs_file *fs_context_open_file(struct fs_context *ctx, unsigned long id) { struct fs_file *f = get_file(&ctx->ctx_filelist, id); @@ -58,29 +91,104 @@ struct fs_file *fs_context_open_file(struct fs_context *ctx, unsigned long id) return f; } +struct fs_file *fs_context_get_file(struct fs_context *ctx, unsigned long id) +{ + return get_file(&ctx->ctx_filelist, id); +} + void fs_context_close_file(struct fs_context *ctx, struct fs_file *f) { } -struct fs_dentry *fs_context_resolve_path( - struct fs_context *ctx, - const char *path) +static size_t get_first_path_component(const char *in, char *out, size_t max) { - return NULL; + size_t i = 0; + while (i < max - 1) { + if (in[i] == '\0' || in[i] == '/') { + break; + } + + out[i] = in[i]; + i++; + } + + out[i] = '\0'; + return i; } -kern_status_t fs_context_dispatch_msg( +extern enum fs_status fs_context_resolve_path( struct fs_context *ctx, - kern_handle_t channel, - struct msg_endpoint *sender, - struct msg_header *hdr) + const char *path, + struct fs_dentry **out) { - return fs_dispatch( - channel, - &ctx->ctx_vtable, - sender, - hdr, - NULL, - 0, - ctx); + if (!ctx->ctx_sb || !ctx->ctx_sb->s_root) { + return FS_ERR_NO_ENTRY; + } + + struct fs_dentry *cur = ctx->ctx_sb->s_root; + + char tok[256]; + + while (*path != '\0') { + while (*path == '/') { + path++; + } + + size_t tok_len + = get_first_path_component(path, tok, sizeof tok); + + if (!tok_len) { + break; + } + + bool is_dir = *(path + tok_len) != '\0'; + + if (cur->d_inode->i_mode != FS_INODE_DIR) { + return FS_ERR_NOT_DIRECTORY; + } + + struct fs_dentry *next = NULL; + enum fs_status status + = fs_inode_lookup(cur->d_inode, tok, &next); + + if (status != FS_SUCCESS) { + return status; + } + + if (!next) { + return FS_ERR_INTERNAL_FAILURE; + } + + cur = next; + + path += tok_len; + } + + *out = cur; + return FS_SUCCESS; +} + +kern_status_t fs_context_dispatch_msg(struct fs_context *ctx, xpc_msg_t *msg) +{ + return fs_dispatch(NULL, msg, &ctx->ctx_vtable, ctx); +} + +void *fs_context_alloc(struct fs_context *ctx, size_t count) +{ + return fs_alloc(ctx->ctx_alloc, count); +} + +void *fs_context_calloc(struct fs_context *ctx, size_t count, size_t sz) +{ + return fs_calloc(ctx->ctx_alloc, count, sz); +} + +void *fs_context_realloc(struct fs_context *ctx, void *p, size_t count) +{ + return fs_realloc(ctx->ctx_alloc, p, count); +} + +void fs_context_free(struct fs_context *ctx, void *p) +{ + fs_free(ctx->ctx_alloc, p); } diff --git a/lib/libfs/file.c b/lib/libfs/file.c new file mode 100644 index 0000000..f8018fc --- /dev/null +++ b/lib/libfs/file.c @@ -0,0 +1,41 @@ +#include "file.h" + +struct fs_inode *fs_file_get_inode(const struct fs_file *f) +{ + return f->f_inode; +} + +size_t fs_file_get_cursor(const struct fs_file *f) +{ + return f->f_seek; +} + +enum fs_status fs_file_read( + struct fs_file *f, + struct xpc_buffer *buf, + size_t count) +{ + if (!f->f_ops || !f->f_ops->f_read) { + return FS_ERR_NOT_IMPLEMENTED; + } + + off_t seek = f->f_seek; + enum fs_status status = f->f_ops->f_read(f, buf, count, &seek); + f->f_seek = seek; + return status; +} + +enum fs_status fs_file_write( + struct fs_file *f, + struct xpc_buffer *buf, + size_t count) +{ + if (!f->f_ops || !f->f_ops->f_write) { + return FS_ERR_NOT_IMPLEMENTED; + } + + off_t seek = f->f_seek; + enum fs_status status = f->f_ops->f_write(f, buf, count, &seek); + f->f_seek = seek; + return status; +} diff --git a/lib/libfs/file.h b/lib/libfs/file.h index 99611bb..d566aff 100644 --- a/lib/libfs/file.h +++ b/lib/libfs/file.h @@ -3,7 +3,9 @@ #include "btree.h" +#include #include +#include struct fs_file { /* id of the open file, equal to the koid of the port being used to @@ -12,6 +14,10 @@ struct fs_file { struct btree_node f_node; const struct fs_file_ops *f_ops; + + off_t f_seek; + struct fs_inode *f_inode; + struct fs_dentry *f_dent; }; #endif diff --git a/lib/libfs/include/fs/context.h b/lib/libfs/include/fs/context.h index fc40f19..498b220 100644 --- a/lib/libfs/include/fs/context.h +++ b/lib/libfs/include/fs/context.h @@ -2,30 +2,54 @@ #define FS_CONTEXT_H_ #include +#include struct fs_file; +struct fs_dentry; struct fs_context; struct fs_allocator; struct fs_superblock; -extern struct fs_context *fs_context_create( - struct fs_allocator *alloc, - struct fs_superblock *sb); +enum fs_mount_flags { + FS_MOUNT_READONLY = 0x01u, +}; + +typedef enum fs_status (*fs_mount_function_t)( + struct fs_context *, + void *arg, + enum fs_mount_flags, + struct fs_superblock **); + +extern struct fs_context *fs_context_create(struct fs_allocator *alloc); extern void fs_context_destroy(struct fs_context *ctx); +extern enum fs_status fs_context_mount_filesystem( + struct fs_context *ctx, + fs_mount_function_t func, + void *arg, + enum fs_mount_flags flags); +extern enum fs_status fs_context_unmount_filesystem(struct fs_context *ctx); + extern struct fs_file *fs_context_open_file( struct fs_context *ctx, unsigned long id); +extern struct fs_file *fs_context_get_file( + struct fs_context *ctx, + unsigned long id); extern void fs_context_close_file(struct fs_context *ctx, struct fs_file *f); -extern struct fs_dentry *fs_context_resolve_path( +extern enum fs_status fs_context_resolve_path( struct fs_context *ctx, - const char *path); + const char *path, + struct fs_dentry **out); extern kern_status_t fs_context_dispatch_msg( struct fs_context *ctx, - kern_handle_t channel, - struct msg_endpoint *sender, - struct msg_header *hdr); + xpc_msg_t *msg); + +extern void *fs_context_alloc(struct fs_context *ctx, size_t count); +extern void *fs_context_calloc(struct fs_context *ctx, size_t count, size_t sz); +extern void *fs_context_realloc(struct fs_context *ctx, void *p, size_t count); +extern void fs_context_free(struct fs_context *ctx, void *p); #endif diff --git a/lib/libfs/include/fs/dentry.h b/lib/libfs/include/fs/dentry.h index f751f85..6e52aa0 100644 --- a/lib/libfs/include/fs/dentry.h +++ b/lib/libfs/include/fs/dentry.h @@ -13,6 +13,7 @@ struct fs_dentry { struct fs_superblock *d_sb; const struct fs_dentry_ops *d_ops; void *d_fsdata; + char *d_name; }; #endif diff --git a/lib/libfs/include/fs/file.h b/lib/libfs/include/fs/file.h index 129da9f..af36791 100644 --- a/lib/libfs/include/fs/file.h +++ b/lib/libfs/include/fs/file.h @@ -5,11 +5,31 @@ #include struct fs_file; +struct xpc_buffer; struct fs_file_ops { - ssize_t (*f_read)(struct fs_file *, void *, size_t); - ssize_t (*f_write)(struct fs_file *, const void *, size_t); - off_t (*f_seek)(struct fs_file *, off_t, int); + enum fs_status (*f_read)( + struct fs_file *, + struct xpc_buffer *, + size_t, + off_t *); + enum fs_status (*f_write)( + struct fs_file *, + const struct xpc_buffer *, + size_t, + off_t *); + enum fs_status (*f_seek)(struct fs_file *, off_t, int); }; +extern struct fs_inode *fs_file_get_inode(const struct fs_file *f); +extern size_t fs_file_get_cursor(const struct fs_file *f); +extern enum fs_status fs_file_read( + struct fs_file *f, + struct xpc_buffer *buf, + size_t count); +extern enum fs_status fs_file_write( + struct fs_file *f, + struct xpc_buffer *buf, + size_t count); + #endif diff --git a/lib/libfs/include/fs/inode.h b/lib/libfs/include/fs/inode.h index 8a853db..da0d2b3 100644 --- a/lib/libfs/include/fs/inode.h +++ b/lib/libfs/include/fs/inode.h @@ -1,17 +1,37 @@ #ifndef FS_INODE_H_ #define FS_INODE_H_ +#include +#include + struct fs_inode; struct fs_dentry; struct fs_superblock; +struct fs_file_ops; + +enum fs_inode_mode { + FS_INODE_REG = 0x01u, + FS_INODE_DIR = 0x02u, +}; struct fs_inode_ops { - int (*i_lookup)(struct fs_inode *, struct fs_dentry *); + enum fs_status (*i_lookup)( + struct fs_inode *, + const char *, + struct fs_dentry **); }; struct fs_inode { + enum fs_inode_mode i_mode; struct fs_superblock *i_sb; const struct fs_inode_ops *i_ops; + const struct fs_file_ops *i_fops; + size_t i_size; }; +extern enum fs_status fs_inode_lookup( + struct fs_inode *inode, + const char *name, + struct fs_dentry **out); + #endif diff --git a/lib/libfs/include/fs/status.h b/lib/libfs/include/fs/status.h new file mode 100644 index 0000000..1486994 --- /dev/null +++ b/lib/libfs/include/fs/status.h @@ -0,0 +1,18 @@ +#ifndef FS_STATUS_H_ +#define FS_STATUS_H_ + +enum fs_status { + FS_SUCCESS = 0, + FS_ERR_NO_ENTRY, + FS_ERR_NO_MEMORY, + FS_ERR_INVALID_ARGUMENT, + FS_ERR_NOT_IMPLEMENTED, + FS_ERR_IS_DIRECTORY, + FS_ERR_NOT_DIRECTORY, + FS_ERR_BAD_STATE, + FS_ERR_INTERNAL_FAILURE, +}; + +extern int fs_status_to_errno(enum fs_status status); + +#endif diff --git a/lib/libfs/inode.c b/lib/libfs/inode.c new file mode 100644 index 0000000..2f2667e --- /dev/null +++ b/lib/libfs/inode.c @@ -0,0 +1,13 @@ +#include + +enum fs_status fs_inode_lookup( + struct fs_inode *inode, + const char *name, + struct fs_dentry **out) +{ + if (!inode->i_ops || !inode->i_ops->i_lookup) { + return FS_ERR_NOT_IMPLEMENTED; + } + + return inode->i_ops->i_lookup(inode, name, out); +} diff --git a/lib/libfs/interface.h b/lib/libfs/interface.h index d6d4b0c..f57e9ee 100644 --- a/lib/libfs/interface.h +++ b/lib/libfs/interface.h @@ -2,12 +2,17 @@ #define _FS_INTERFACE_H_ #include +#include +#include +#include +#include struct msg_endpoint; extern kern_status_t fs_msg_open( - const struct msg_endpoint *sender, - const char *path, + xpc_context_t *ctx, + const xpc_endpoint_t *sender, + const xpc_string_t *path, int flags, int *out_err, void *arg); @@ -18,4 +23,13 @@ extern kern_status_t fs_msg_close( int *out_err, void *arg); +extern kern_status_t fs_msg_read( + xpc_context_t *ctx, + const xpc_endpoint_t *sender, + size_t count, + int *out_err, + size_t *out_nr_read, + xpc_buffer_t *out_data, + void *arg); + #endif diff --git a/lib/libfs/interface/open.c b/lib/libfs/interface/open.c index ee3eeff..68cb3f2 100644 --- a/lib/libfs/interface/open.c +++ b/lib/libfs/interface/open.c @@ -1,21 +1,53 @@ +#include "../file.h" + #include #include +#include +#include extern kern_status_t fs_msg_open( - const struct msg_endpoint *sender, - const char *path, + xpc_context_t *xpc, + xpc_endpoint_t *sender, + const xpc_string_t *path, int flags, int *out_err, void *arg) { + char path_buf[4096]; + size_t path_len = 0; + kern_status_t status + = xpc_string_read(path, path_buf, sizeof path_buf, &path_len); + if (status != KERN_OK) { + return status; + } + struct fs_context *ctx = arg; - struct fs_dentry *dent = fs_context_resolve_path(ctx, path); - if (!dent) { - *out_err = ENOENT; + struct fs_file *f = fs_context_open_file(ctx, sender->e_port); + if (!f) { + *out_err = ENOMEM; return KERN_OK; } + if (f->f_inode) { + *out_err = EBUSY; + return KERN_OK; + } + + struct fs_dentry *dent = NULL; + enum fs_status fs_status + = fs_context_resolve_path(ctx, path_buf, &dent); + if (fs_status != FS_SUCCESS) { + fs_context_close_file(ctx, f); + *out_err = fs_status_to_errno(status); + return KERN_OK; + } + + f->f_seek = 0; + f->f_dent = dent; + f->f_inode = dent->d_inode; + f->f_ops = dent->d_inode->i_fops; + *out_err = SUCCESS; return KERN_OK; } diff --git a/lib/libfs/interface/read.c b/lib/libfs/interface/read.c new file mode 100644 index 0000000..4e6aa7f --- /dev/null +++ b/lib/libfs/interface/read.c @@ -0,0 +1,30 @@ +#include +#include +#include +#include + +extern kern_status_t fs_msg_read( + xpc_context_t *xpc, + xpc_endpoint_t *sender, + size_t count, + int *out_err, + size_t *out_nr_read, + xpc_buffer_t *out_data, + void *arg) +{ + struct fs_context *ctx = arg; + struct fs_file *f = fs_context_get_file(ctx, sender->e_port); + if (!f) { + *out_err = EBADF; + return KERN_OK; + } + + size_t start = fs_file_get_cursor(f); + enum fs_status status = fs_file_read(f, out_data, count); + size_t end = fs_file_get_cursor(f); + + *out_err = fs_status_to_errno(status); + *out_nr_read = end - start; + + return KERN_OK; +} diff --git a/lib/libfs/status.c b/lib/libfs/status.c new file mode 100644 index 0000000..f691fcc --- /dev/null +++ b/lib/libfs/status.c @@ -0,0 +1,25 @@ +#include +#include + +int fs_status_to_errno(enum fs_status status) +{ + switch (status) { + case FS_SUCCESS: + return SUCCESS; + case FS_ERR_NO_ENTRY: + return ENOENT; + case FS_ERR_NO_MEMORY: + return ENOMEM; + case FS_ERR_INVALID_ARGUMENT: + return EINVAL; + case FS_ERR_NOT_IMPLEMENTED: + return ENOSYS; + case FS_ERR_IS_DIRECTORY: + return EISDIR; + case FS_ERR_NOT_DIRECTORY: + return ENOTDIR; + + default: + return EINVAL; + } +}