lib: fs: implement mounting filesystems; reading, writing from files

This commit is contained in:
2026-03-10 19:15:26 +00:00
parent aef0163017
commit 6d88cf4bf3
14 changed files with 393 additions and 41 deletions

View File

@@ -23,7 +23,7 @@ sysroot_add_library(
HEADER_DIR /usr/include HEADER_DIR /usr/include
LIB_DIR /usr/lib) LIB_DIR /usr/lib)
target_link_libraries(libfs libmango interface::fs libc) target_link_libraries(libfs libmango interface::fs libc libxpc)
target_link_libraries(libfs-static libmango interface::fs libc-core) target_link_libraries(libfs-static libmango interface::fs libc-core libxpc-static)
set_target_properties(libfs-static PROPERTIES POSITION_INDEPENDENT_CODE FALSE) set_target_properties(libfs-static PROPERTIES POSITION_INDEPENDENT_CODE FALSE)

View File

@@ -4,6 +4,12 @@
#include <fs/allocator.h> #include <fs/allocator.h>
#include <fs/context.h> #include <fs/context.h>
#include <fs/dentry.h>
#include <fs/inode.h>
#include <fs/status.h>
#include <fs/superblock.h>
#include <mango/log.h>
#include <stdio.h>
BTREE_DEFINE_SIMPLE_GET(struct fs_file, unsigned long, f_node, f_id, get_file); 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); 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_vtable ctx_vtable;
}; };
struct fs_context *fs_context_create( struct fs_context *fs_context_create(struct fs_allocator *alloc)
struct fs_allocator *alloc,
struct fs_superblock *sb)
{ {
struct fs_context *ctx = fs_alloc(alloc, sizeof *ctx); struct fs_context *ctx = fs_alloc(alloc, sizeof *ctx);
if (!ctx) { if (!ctx) {
@@ -27,10 +31,10 @@ struct fs_context *fs_context_create(
memset(ctx, 0x0, sizeof *ctx); memset(ctx, 0x0, sizeof *ctx);
ctx->ctx_sb = sb;
ctx->ctx_alloc = alloc; ctx->ctx_alloc = alloc;
ctx->ctx_vtable.open = fs_msg_open; ctx->ctx_vtable.open = fs_msg_open;
ctx->ctx_vtable.read = fs_msg_read;
return ctx; return ctx;
} }
@@ -40,6 +44,35 @@ void fs_context_destroy(struct fs_context *ctx)
fs_free(ctx->ctx_alloc, 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 *fs_context_open_file(struct fs_context *ctx, unsigned long id)
{ {
struct fs_file *f = get_file(&ctx->ctx_filelist, 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; 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) void fs_context_close_file(struct fs_context *ctx, struct fs_file *f)
{ {
} }
struct fs_dentry *fs_context_resolve_path( static size_t get_first_path_component(const char *in, char *out, size_t max)
struct fs_context *ctx,
const char *path)
{ {
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, struct fs_context *ctx,
kern_handle_t channel, const char *path,
struct msg_endpoint *sender, struct fs_dentry **out)
struct msg_header *hdr)
{ {
return fs_dispatch( if (!ctx->ctx_sb || !ctx->ctx_sb->s_root) {
channel, return FS_ERR_NO_ENTRY;
&ctx->ctx_vtable, }
sender,
hdr, struct fs_dentry *cur = ctx->ctx_sb->s_root;
NULL,
0, char tok[256];
ctx);
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);
} }

41
lib/libfs/file.c Normal file
View File

@@ -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;
}

View File

@@ -3,7 +3,9 @@
#include "btree.h" #include "btree.h"
#include <fs/dentry.h>
#include <fs/file.h> #include <fs/file.h>
#include <fs/inode.h>
struct fs_file { struct fs_file {
/* id of the open file, equal to the koid of the port being used to /* 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; struct btree_node f_node;
const struct fs_file_ops *f_ops; const struct fs_file_ops *f_ops;
off_t f_seek;
struct fs_inode *f_inode;
struct fs_dentry *f_dent;
}; };
#endif #endif

View File

@@ -2,30 +2,54 @@
#define FS_CONTEXT_H_ #define FS_CONTEXT_H_
#include <rosetta/fs.h> #include <rosetta/fs.h>
#include <xpc/msg.h>
struct fs_file; struct fs_file;
struct fs_dentry;
struct fs_context; struct fs_context;
struct fs_allocator; struct fs_allocator;
struct fs_superblock; struct fs_superblock;
extern struct fs_context *fs_context_create( enum fs_mount_flags {
struct fs_allocator *alloc, FS_MOUNT_READONLY = 0x01u,
struct fs_superblock *sb); };
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 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( extern struct fs_file *fs_context_open_file(
struct fs_context *ctx, struct fs_context *ctx,
unsigned long id); 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 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, struct fs_context *ctx,
const char *path); const char *path,
struct fs_dentry **out);
extern kern_status_t fs_context_dispatch_msg( extern kern_status_t fs_context_dispatch_msg(
struct fs_context *ctx, struct fs_context *ctx,
kern_handle_t channel, xpc_msg_t *msg);
struct msg_endpoint *sender,
struct msg_header *hdr); 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 #endif

View File

@@ -13,6 +13,7 @@ struct fs_dentry {
struct fs_superblock *d_sb; struct fs_superblock *d_sb;
const struct fs_dentry_ops *d_ops; const struct fs_dentry_ops *d_ops;
void *d_fsdata; void *d_fsdata;
char *d_name;
}; };
#endif #endif

View File

@@ -5,11 +5,31 @@
#include <stddef.h> #include <stddef.h>
struct fs_file; struct fs_file;
struct xpc_buffer;
struct fs_file_ops { struct fs_file_ops {
ssize_t (*f_read)(struct fs_file *, void *, size_t); enum fs_status (*f_read)(
ssize_t (*f_write)(struct fs_file *, const void *, size_t); struct fs_file *,
off_t (*f_seek)(struct fs_file *, off_t, int); 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 #endif

View File

@@ -1,17 +1,37 @@
#ifndef FS_INODE_H_ #ifndef FS_INODE_H_
#define FS_INODE_H_ #define FS_INODE_H_
#include <fs/status.h>
#include <stddef.h>
struct fs_inode; struct fs_inode;
struct fs_dentry; struct fs_dentry;
struct fs_superblock; struct fs_superblock;
struct fs_file_ops;
enum fs_inode_mode {
FS_INODE_REG = 0x01u,
FS_INODE_DIR = 0x02u,
};
struct fs_inode_ops { 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 { struct fs_inode {
enum fs_inode_mode i_mode;
struct fs_superblock *i_sb; struct fs_superblock *i_sb;
const struct fs_inode_ops *i_ops; 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 #endif

View File

@@ -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

13
lib/libfs/inode.c Normal file
View File

@@ -0,0 +1,13 @@
#include <fs/inode.h>
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);
}

View File

@@ -2,12 +2,17 @@
#define _FS_INTERFACE_H_ #define _FS_INTERFACE_H_
#include <mango/types.h> #include <mango/types.h>
#include <xpc/buffer.h>
#include <xpc/context.h>
#include <xpc/endpoint.h>
#include <xpc/string.h>
struct msg_endpoint; struct msg_endpoint;
extern kern_status_t fs_msg_open( extern kern_status_t fs_msg_open(
const struct msg_endpoint *sender, xpc_context_t *ctx,
const char *path, const xpc_endpoint_t *sender,
const xpc_string_t *path,
int flags, int flags,
int *out_err, int *out_err,
void *arg); void *arg);
@@ -18,4 +23,13 @@ extern kern_status_t fs_msg_close(
int *out_err, int *out_err,
void *arg); 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 #endif

View File

@@ -1,21 +1,53 @@
#include "../file.h"
#include <errno.h> #include <errno.h>
#include <fs/context.h> #include <fs/context.h>
#include <fs/file.h>
#include <fs/status.h>
extern kern_status_t fs_msg_open( extern kern_status_t fs_msg_open(
const struct msg_endpoint *sender, xpc_context_t *xpc,
const char *path, xpc_endpoint_t *sender,
const xpc_string_t *path,
int flags, int flags,
int *out_err, int *out_err,
void *arg) 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_context *ctx = arg;
struct fs_dentry *dent = fs_context_resolve_path(ctx, path); struct fs_file *f = fs_context_open_file(ctx, sender->e_port);
if (!dent) { if (!f) {
*out_err = ENOENT; *out_err = ENOMEM;
return KERN_OK; 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; *out_err = SUCCESS;
return KERN_OK; return KERN_OK;
} }

View File

@@ -0,0 +1,30 @@
#include <errno.h>
#include <fs/context.h>
#include <fs/file.h>
#include <fs/status.h>
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;
}

25
lib/libfs/status.c Normal file
View File

@@ -0,0 +1,25 @@
#include <errno.h>
#include <fs/status.h>
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;
}
}