lib: fs: implement mounting filesystems; reading, writing from files
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
41
lib/libfs/file.c
Normal 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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
18
lib/libfs/include/fs/status.h
Normal file
18
lib/libfs/include/fs/status.h
Normal 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
13
lib/libfs/inode.c
Normal 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);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
30
lib/libfs/interface/read.c
Normal file
30
lib/libfs/interface/read.c
Normal 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
25
lib/libfs/status.c
Normal 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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user