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

View File

@@ -4,6 +4,12 @@
#include <fs/allocator.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_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;
}
kern_status_t fs_context_dispatch_msg(
struct fs_context *ctx,
kern_handle_t channel,
struct msg_endpoint *sender,
struct msg_header *hdr)
{
return fs_dispatch(
channel,
&ctx->ctx_vtable,
sender,
hdr,
NULL,
0,
ctx);
out[i] = in[i];
i++;
}
out[i] = '\0';
return i;
}
extern enum fs_status fs_context_resolve_path(
struct fs_context *ctx,
const char *path,
struct fs_dentry **out)
{
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);
}

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 <fs/dentry.h>
#include <fs/file.h>
#include <fs/inode.h>
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

View File

@@ -2,30 +2,54 @@
#define FS_CONTEXT_H_
#include <rosetta/fs.h>
#include <xpc/msg.h>
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

View File

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

View File

@@ -5,11 +5,31 @@
#include <stddef.h>
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

View File

@@ -1,17 +1,37 @@
#ifndef FS_INODE_H_
#define FS_INODE_H_
#include <fs/status.h>
#include <stddef.h>
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

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_
#include <mango/types.h>
#include <xpc/buffer.h>
#include <xpc/context.h>
#include <xpc/endpoint.h>
#include <xpc/string.h>
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

View File

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

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