Add write_file () syscall, CE implement redirections, libarena arena_realloc ()
All checks were successful
Build documentation / build-and-deploy (push) Successful in 2m14s

This commit is contained in:
2026-03-01 12:04:21 +01:00
parent abd85744cc
commit a5d5e7d6a4
9 changed files with 220 additions and 44 deletions

187
ce/ce.c
View File

@@ -16,6 +16,46 @@
static struct arena arena; static struct arena arena;
struct strbuf {
char* items;
size_t count, capacity;
};
void strbuf_append (struct strbuf* strbuf, char c) {
if (strbuf->items == NULL) {
strbuf->capacity = 256;
strbuf->count = 0;
strbuf->items = arena_malloc (&arena, strbuf->capacity);
} else {
if (strbuf->count == strbuf->capacity) {
size_t prev_capacity = strbuf->capacity;
strbuf->capacity *= 2;
strbuf->items = arena_realloc (&arena, strbuf->items, prev_capacity, strbuf->capacity);
}
}
strbuf->items[strbuf->count++] = c;
}
void strbuf_append_str (struct strbuf* strbuf, const char* s) {
while (*s)
strbuf_append (strbuf, *s++);
}
struct context {
struct strbuf strbuf;
};
#define CPRINTF_BUF_MAX 4096
#define cprintf(context, fmt, ...) \
do { \
char* __cprintf_buf = malloc (CPRINTF_BUF_MAX); \
memset (__cprintf_buf, 0, CPRINTF_BUF_MAX); \
snprintf (__cprintf_buf, CPRINTF_BUF_MAX, (fmt), ##__VA_ARGS__); \
strbuf_append_str (&(context)->strbuf, __cprintf_buf); \
free (__cprintf_buf); \
} while (0)
#define LINE_BUFFER_MAX 1024 #define LINE_BUFFER_MAX 1024
#define TOKEN_MAX 64 #define TOKEN_MAX 64
#define CMD_ARGS_MAX 64 #define CMD_ARGS_MAX 64
@@ -25,6 +65,7 @@ static struct arena arena;
#define TOKEN_CLASS_CPAREN 1 #define TOKEN_CLASS_CPAREN 1
#define TOKEN_CLASS_WORD 2 #define TOKEN_CLASS_WORD 2
#define TOKEN_CLASS_SEMICOLON 3 #define TOKEN_CLASS_SEMICOLON 3
#define TOKEN_CLASS_REDIR 4
struct token { struct token {
struct list_node_link tokens_link; struct list_node_link tokens_link;
@@ -33,12 +74,14 @@ struct token {
}; };
#define PREC_NONE 0 #define PREC_NONE 0
#define PREC_SEQ 1 #define PREC_LOWEST 1
#define PREC_LOWEST 2 #define PREC_SEQ 2
#define PREC_REDIR 3
#define AST_NODE_CLASS_CMD 0 #define AST_NODE_CLASS_CMD 0
#define AST_NODE_CLASS_SUBSHELL 1 #define AST_NODE_CLASS_SUBSHELL 1
#define AST_NODE_CLASS_SEQ 2 #define AST_NODE_CLASS_SEQ 2
#define AST_NODE_CLASS_REDIR 3
struct ast_node; struct ast_node;
@@ -57,12 +100,18 @@ struct ast_seq {
struct ast_node* right; struct ast_node* right;
}; };
struct ast_redir {
struct ast_node* source;
char* file_path;
};
struct ast_node { struct ast_node {
int class; int class;
union { union {
struct ast_cmd cmd; struct ast_cmd cmd;
struct ast_subshell subshell; struct ast_subshell subshell;
struct ast_seq seq; struct ast_seq seq;
struct ast_redir redir;
} u; } u;
}; };
@@ -90,11 +139,15 @@ static struct ast_node* oparen_nud (struct parser* parser, struct token* token);
static struct ast_node* semicolon_led (struct parser* parser, struct token* token, static struct ast_node* semicolon_led (struct parser* parser, struct token* token,
struct ast_node* left); struct ast_node* left);
static struct ast_node* redir_led (struct parser* parser, struct token* token,
struct ast_node* left);
static struct parse_rule parse_rules[] = { static struct parse_rule parse_rules[] = {
[TOKEN_CLASS_WORD] = {&word_nud, NULL, PREC_NONE}, [TOKEN_CLASS_WORD] = {&word_nud, NULL, PREC_NONE},
[TOKEN_CLASS_OPAREN] = {&oparen_nud, NULL, PREC_NONE}, [TOKEN_CLASS_OPAREN] = {&oparen_nud, NULL, PREC_NONE},
[TOKEN_CLASS_CPAREN] = {NULL, NULL, PREC_NONE}, [TOKEN_CLASS_CPAREN] = {NULL, NULL, PREC_NONE},
[TOKEN_CLASS_SEMICOLON] = {NULL, &semicolon_led, PREC_SEQ}, [TOKEN_CLASS_SEMICOLON] = {NULL, &semicolon_led, PREC_SEQ},
[TOKEN_CLASS_REDIR] = {NULL, &redir_led, PREC_REDIR},
}; };
static struct token* get_token (struct list_node_link* link) { static struct token* get_token (struct list_node_link* link) {
@@ -179,6 +232,19 @@ static struct ast_node* semicolon_led (struct parser* parser, struct token* toke
return node; return node;
} }
static struct ast_node* redir_led (struct parser* parser, struct token* token,
struct ast_node* left) {
struct ast_node* node = arena_malloc (&arena, sizeof (*node));
node->class = AST_NODE_CLASS_REDIR;
node->u.redir.source = left;
struct token* next_token = advance (parser);
if (next_token != NULL && next_token->class == TOKEN_CLASS_WORD)
node->u.redir.file_path = next_token->buffer;
return node;
}
static int e_pid; static int e_pid;
static int e_pgid; static int e_pgid;
@@ -211,13 +277,15 @@ static void classify_tokens (struct list_node_link* tokens) {
token->class = TOKEN_CLASS_CPAREN; token->class = TOKEN_CLASS_CPAREN;
} else if (strcmp (token->buffer, ";") == 0) { } else if (strcmp (token->buffer, ";") == 0) {
token->class = TOKEN_CLASS_SEMICOLON; token->class = TOKEN_CLASS_SEMICOLON;
} else if (strcmp (token->buffer, ">") == 0) {
token->class = TOKEN_CLASS_REDIR;
} else { } else {
token->class = TOKEN_CLASS_WORD; token->class = TOKEN_CLASS_WORD;
} }
} }
} }
static void execute (struct ast_node* root); static void execute (struct ast_node* root, struct context* context);
static void parse_tokens (struct list_node_link* tokens) { static void parse_tokens (struct list_node_link* tokens) {
struct parser parser; struct parser parser;
@@ -225,20 +293,24 @@ static void parse_tokens (struct list_node_link* tokens) {
parser.next = get_token (tokens); parser.next = get_token (tokens);
while (parser.next != NULL) { while (parser.next != NULL) {
struct ast_node* root = parse_precedence (&parser, PREC_LOWEST); struct ast_node* root = parse_precedence (&parser, PREC_NONE);
if (root != NULL) { if (root != NULL) {
execute (root); struct context context = {0};
execute (root, &context);
if (context.strbuf.items != NULL)
printf ("%.*s", (int)context.strbuf.count, context.strbuf.items);
} }
} }
} }
static void echo (char** strings, size_t strings_count) { static void echo (struct context* context, char** strings, size_t strings_count) {
for (size_t i = 0; i < strings_count; i++) for (size_t i = 0; i < strings_count; i++)
printf ("%s ", strings[i]); cprintf (context, "%s ", strings[i]);
} }
static void mkfile (char** file_paths, size_t files_count) { static void mkfile (struct context* context, char** file_paths, size_t files_count) {
char volume[VOLUME_MAX]; char volume[VOLUME_MAX];
const char* path; const char* path;
int ret; int ret;
@@ -247,12 +319,12 @@ static void mkfile (char** file_paths, size_t files_count) {
const char* file_path = file_paths[i]; const char* file_path = file_paths[i];
if (!path_parse (file_path, volume, &path)) { if (!path_parse (file_path, volume, &path)) {
printf ("ERROR bad path '%s'\n", file_path); cprintf (context, "ERROR bad path '%s'\n", file_path);
continue; continue;
} }
if ((ret = volume_open (volume)) < 0) { if ((ret = volume_open (volume)) < 0) {
printf ("ERROR could not open volume '%s': %s\n", volume, str_status[-ret]); cprintf (context, "ERROR could not open volume '%s': %s\n", volume, str_status[-ret]);
continue; continue;
} }
@@ -262,7 +334,7 @@ static void mkfile (char** file_paths, size_t files_count) {
} }
} }
static void cat (char** file_paths, size_t files_count) { static void cat (struct context* context, char** file_paths, size_t files_count) {
struct desc desc; struct desc desc;
char volume[VOLUME_MAX]; char volume[VOLUME_MAX];
const char* path; const char* path;
@@ -272,12 +344,12 @@ static void cat (char** file_paths, size_t files_count) {
const char* file_path = file_paths[i]; const char* file_path = file_paths[i];
if (!path_parse (file_path, volume, &path)) { if (!path_parse (file_path, volume, &path)) {
printf ("ERROR bad path '%s'\n", file_path); cprintf (context, "ERROR bad path '%s'\n", file_path);
continue; continue;
} }
if ((ret = volume_open (volume)) < 0) { if ((ret = volume_open (volume)) < 0) {
printf ("ERROR could not open volume '%s': %s\n", volume, str_status[-ret]); cprintf (context, "ERROR could not open volume '%s': %s\n", volume, str_status[-ret]);
continue; continue;
} }
@@ -293,7 +365,7 @@ static void cat (char** file_paths, size_t files_count) {
memset (buffer, 0, desc.size + 1); memset (buffer, 0, desc.size + 1);
read_file (path, 0, (uint8_t*)buffer, desc.size); read_file (path, 0, (uint8_t*)buffer, desc.size);
printf ("%s\n", buffer); cprintf (context, "%s\n", buffer);
close: close:
if (buffer != NULL) if (buffer != NULL)
@@ -302,7 +374,7 @@ static void cat (char** file_paths, size_t files_count) {
} }
} }
static void ls (const char* path_string) { static void ls (struct context* context, const char* path_string) {
struct desc desc; struct desc desc;
char volume[VOLUME_MAX]; char volume[VOLUME_MAX];
const char* path; const char* path;
@@ -310,81 +382,108 @@ static void ls (const char* path_string) {
struct dir_entry entry; struct dir_entry entry;
if (!path_parse (path_string, volume, &path)) { if (!path_parse (path_string, volume, &path)) {
printf ("ERROR bad path '%s'\n", path_string); cprintf (context, "ERROR bad path '%s'\n", path_string);
return; return;
} }
if ((ret = volume_open (volume)) < 0) { if ((ret = volume_open (volume)) < 0) {
printf ("ERROR could not open volume '%s': %s\n", volume, str_status[-ret]); cprintf (context, "ERROR could not open volume '%s': %s\n", volume, str_status[-ret]);
return; return;
} }
describe (path, &desc); describe (path, &desc);
if (desc.type != FS_DIR) { if (desc.type != FS_DIR) {
printf ("ERROR '%s' is not a directory\n", path_string); cprintf (context, "ERROR '%s' is not a directory\n", path_string);
volume_close (); volume_close ();
return; return;
} }
size_t entries = desc.size; size_t entries = desc.size;
printf ("total entries: %zu\n", entries); cprintf (context, "total entries: %zu\n", entries);
printf ("\n"); cprintf (context, "\n");
for (size_t entry_num = 0; entry_num < entries; entry_num++) { for (size_t entry_num = 0; entry_num < entries; entry_num++) {
read_dir_entry (path, &entry, entry_num); read_dir_entry (path, &entry, entry_num);
describe (entry.path, &desc); describe (entry.path, &desc);
printf ("%-40s%c %-40zu\n", entry.path, (desc.type == FS_DIR ? '*' : ' '), desc.size); cprintf (context, "%-40s%c %-40zu\n", entry.path, (desc.type == FS_DIR ? '*' : ' '), desc.size);
} }
volume_close (); volume_close ();
} }
static void quit1 (void) { static void quit1 (struct context* context) {
run = false; run = false;
printf ("Goodbye!\n"); cprintf (context, "Goodbye!\n");
} }
static void help (void) { static void help (struct context* context) {
printf ("Available commands:\n"); cprintf (context, "Available commands:\n");
printf ("echo <word1> <word2> <word3> ...\n"); cprintf (context, "echo <word1> <word2> <word3> ...\n");
printf ("help\n"); cprintf (context, "help\n");
printf ("cat <file path>\n"); cprintf (context, "cat <file path>\n");
printf ("ls <directory path>\n"); cprintf (context, "ls <directory path>\n");
printf ("mkfile <file path>\n"); cprintf (context, "mkfile <file path>\n");
printf ("quit\n"); cprintf (context, "quit\n");
} }
static void execute_cmd (struct ast_cmd* cmd) { static void execute_cmd (struct ast_cmd* cmd, struct context* context) {
if (strcmp (cmd->name, "echo") == 0) { if (strcmp (cmd->name, "echo") == 0) {
echo (cmd->args, cmd->arg_count); echo (context, cmd->args, cmd->arg_count);
} else if (strcmp (cmd->name, "help") == 0) { } else if (strcmp (cmd->name, "help") == 0) {
help (); help (context);
} else if (strcmp (cmd->name, "cat") == 0) { } else if (strcmp (cmd->name, "cat") == 0) {
cat (cmd->args, cmd->arg_count); cat (context, cmd->args, cmd->arg_count);
} else if (strcmp (cmd->name, "ls") == 0) { } else if (strcmp (cmd->name, "ls") == 0) {
ls (cmd->args[0]); ls (context, cmd->args[0]);
} else if (strcmp (cmd->name, "quit") == 0) { } else if (strcmp (cmd->name, "quit") == 0) {
quit1 (); quit1 (context);
} else if (strcmp (cmd->name, "mkfile") == 0) { } else if (strcmp (cmd->name, "mkfile") == 0) {
mkfile (cmd->args, cmd->arg_count); mkfile (context, cmd->args, cmd->arg_count);
} else { } else {
printf ("ERROR unknown command '%s'\n", cmd->name); cprintf (context, "ERROR unknown command '%s'\n", cmd->name);
} }
} }
static void execute (struct ast_node* root) { static void execute_redir (struct ast_redir* redir, struct context* context) {
char volume[VOLUME_MAX];
const char* path;
int ret;
if (!(path_parse (redir->file_path, volume, &path))) {
cprintf (context, "ERROR bad path '%s'\n", redir->file_path);
return;
}
if ((ret = volume_open (volume)) < 0) {
cprintf (context, "ERROR could not open volume '%s': %s\n", volume, str_status[-ret]);
return;
}
create_file (path);
write_file (path, 0, (uint8_t*)context->strbuf.items, context->strbuf.count);
volume_close ();
}
static void execute (struct ast_node* root, struct context* context) {
struct context subcontext = {0};
switch (root->class) { switch (root->class) {
case AST_NODE_CLASS_CMD: case AST_NODE_CLASS_CMD:
execute_cmd (&root->u.cmd); execute_cmd (&root->u.cmd, context);
break; break;
case AST_NODE_CLASS_SUBSHELL: case AST_NODE_CLASS_SUBSHELL:
execute (root->u.subshell.inner); execute (root->u.subshell.inner, &subcontext);
break; break;
case AST_NODE_CLASS_SEQ: case AST_NODE_CLASS_SEQ:
execute (root->u.seq.left); execute (root->u.seq.left, context);
execute (root->u.seq.right); execute (root->u.seq.right, context);
break;
case AST_NODE_CLASS_REDIR:
execute (root->u.redir.source, &subcontext);
execute_redir (&root->u.redir, &subcontext);
break; break;
} }
} }

View File

@@ -24,5 +24,6 @@
#define SYS_GET_EXEC_PID 21 #define SYS_GET_EXEC_PID 21
#define SYS_READ_DIR_ENTRY 22 #define SYS_READ_DIR_ENTRY 22
#define SYS_CREATE_FILE 23 #define SYS_CREATE_FILE 23
#define SYS_WRITE_FILE 24
#endif // _M_SYSCALL_DEFS_H #endif // _M_SYSCALL_DEFS_H

View File

@@ -205,6 +205,25 @@ int vfs_read_file (struct proc* proc, const char* volume_name, const char* path,
return volume->driver_ops.read_file (volume, path, buffer, off, size); return volume->driver_ops.read_file (volume, path, buffer, off, size);
} }
int vfs_write_file (struct proc* proc, const char* volume_name, const char* path, uint8_t* buffer,
size_t off, size_t size) {
struct vfs_volume* volume = vfs_find_volume (volume_name);
if (volume == NULL)
return -ST_NOT_FOUND;
spin_lock (&volume->lock);
if (volume->locked && volume->owner != proc) {
spin_unlock (&volume->lock);
return -ST_PERMISSION_ERROR;
}
spin_unlock (&volume->lock);
return volume->driver_ops.write_file (volume, path, buffer, off, size);
}
int vfs_create_file (struct proc* proc, const char* volume_name, const char* path) { int vfs_create_file (struct proc* proc, const char* volume_name, const char* path) {
struct vfs_volume* volume = vfs_find_volume (volume_name); struct vfs_volume* volume = vfs_find_volume (volume_name);

View File

@@ -69,6 +69,9 @@ int vfs_format (struct proc* proc, const char* volume_name);
int vfs_read_file (struct proc* proc, const char* volume, const char* path, uint8_t* buffer, int vfs_read_file (struct proc* proc, const char* volume, const char* path, uint8_t* buffer,
size_t off, size_t size); size_t off, size_t size);
int vfs_write_file (struct proc* proc, const char* volume, const char* path, uint8_t* buffer,
size_t off, size_t size);
int vfs_describe (struct proc* proc, const char* volume, const char* path, struct desc* desc); int vfs_describe (struct proc* proc, const char* volume, const char* path, struct desc* desc);
int vfs_read_dir_entry (struct proc* proc, const char* volume, const char* path, int vfs_read_dir_entry (struct proc* proc, const char* volume, const char* path,

View File

@@ -483,6 +483,38 @@ DEFINE_SYSCALL (sys_create_file) {
return SYSRESULT (ret); return SYSRESULT (ret);
} }
/* int write_file (char* path, size_t off, uint8_t* buffer, size_t size) */
DEFINE_SYSCALL (sys_write_file) {
uintptr_t uvaddr_path = a1;
size_t off = (size_t)a2;
uintptr_t uvaddr_buffer = a3;
size_t size = (size_t)a4;
struct limine_hhdm_response* hhdm = limine_hhdm_request.response;
uintptr_t out_paddr;
spin_lock (&proc->procgroup->lock);
out_paddr = mm_v2p (&proc->procgroup->pd, uvaddr_path);
spin_unlock (&proc->procgroup->lock);
if (out_paddr == 0)
return SYSRESULT (-ST_BAD_ADDRESS_SPACE);
const char* path = (const char*)((uintptr_t)hhdm->offset + out_paddr);
uint8_t* buffer = sys_get_user_buffer (proc, uvaddr_buffer, size);
if (buffer == NULL)
return SYSRESULT (-ST_BAD_ADDRESS_SPACE);
spin_lock (&proc->lock);
int ret = vfs_write_file (proc, proc->cwv, path, buffer, off, size);
spin_unlock (&proc->lock);
return SYSRESULT (ret);
}
/* int get_exec_pid (void) */ /* int get_exec_pid (void) */
DEFINE_SYSCALL (sys_get_exec_pid) { return SYSRESULT (proc->exec_pid); } DEFINE_SYSCALL (sys_get_exec_pid) { return SYSRESULT (proc->exec_pid); }
@@ -510,6 +542,7 @@ static syscall_handler_func_t handler_table[] = {
[SYS_GET_EXEC_PID] = &sys_get_exec_pid, [SYS_GET_EXEC_PID] = &sys_get_exec_pid,
[SYS_READ_DIR_ENTRY] = &sys_read_dir_entry, [SYS_READ_DIR_ENTRY] = &sys_read_dir_entry,
[SYS_CREATE_FILE] = &sys_create_file, [SYS_CREATE_FILE] = &sys_create_file,
[SYS_WRITE_FILE] = &sys_write_file,
}; };
syscall_handler_func_t syscall_find_handler (int syscall_num) { syscall_handler_func_t syscall_find_handler (int syscall_num) {

View File

@@ -76,3 +76,15 @@ void* arena_malloc (struct arena* arena, size_t size) {
arena->end->size += size1; arena->end->size += size1;
return result; return result;
} }
void* arena_realloc (struct arena* arena, void* memory, size_t prev_size, size_t new_size) {
if (new_size <= prev_size)
return memory;
void* new_memory = arena_malloc (arena, new_size);
for (size_t i = 0; i < prev_size; i++)
((uint8_t*)new_memory)[i] = ((uint8_t*)memory)[i];
return new_memory;
}

View File

@@ -23,4 +23,6 @@ void arena_destroy (struct arena* arena);
void* arena_malloc (struct arena* arena, size_t size); void* arena_malloc (struct arena* arena, size_t size);
void* arena_realloc (struct arena* arena, void* memory, size_t prev_size, size_t new_size);
#endif // _LIBARENA_ARENA_H #endif // _LIBARENA_ARENA_H

View File

@@ -70,3 +70,7 @@ int read_dir_entry (const char* path, struct dir_entry* entry, size_t entry_num)
} }
int create_file (const char* path) { return (int)do_syscall (SYS_CREATE_FILE, path); } int create_file (const char* path) { return (int)do_syscall (SYS_CREATE_FILE, path); }
int write_file (const char* path, size_t off, uint8_t* buffer, size_t size) {
return (int)do_syscall (SYS_WRITE_FILE, path, off, buffer, size);
}

View File

@@ -84,4 +84,7 @@ int read_dir_entry (const char* path, struct dir_entry* entry, size_t entry_num)
/* create a file */ /* create a file */
int create_file (const char* path); int create_file (const char* path);
/* write to a file */
int write_file (const char* path, size_t off, uint8_t* buffer, size_t size);
#endif // _LIBMSL_M_SYSTEM_H #endif // _LIBMSL_M_SYSTEM_H