diff --git a/ce/ce.c b/ce/ce.c index 95e8d4c..a97075a 100644 --- a/ce/ce.c +++ b/ce/ce.c @@ -16,6 +16,46 @@ 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 TOKEN_MAX 64 #define CMD_ARGS_MAX 64 @@ -25,6 +65,7 @@ static struct arena arena; #define TOKEN_CLASS_CPAREN 1 #define TOKEN_CLASS_WORD 2 #define TOKEN_CLASS_SEMICOLON 3 +#define TOKEN_CLASS_REDIR 4 struct token { struct list_node_link tokens_link; @@ -33,12 +74,14 @@ struct token { }; #define PREC_NONE 0 -#define PREC_SEQ 1 -#define PREC_LOWEST 2 +#define PREC_LOWEST 1 +#define PREC_SEQ 2 +#define PREC_REDIR 3 #define AST_NODE_CLASS_CMD 0 #define AST_NODE_CLASS_SUBSHELL 1 #define AST_NODE_CLASS_SEQ 2 +#define AST_NODE_CLASS_REDIR 3 struct ast_node; @@ -57,12 +100,18 @@ struct ast_seq { struct ast_node* right; }; +struct ast_redir { + struct ast_node* source; + char* file_path; +}; + struct ast_node { int class; union { struct ast_cmd cmd; struct ast_subshell subshell; struct ast_seq seq; + struct ast_redir redir; } 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, 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[] = { [TOKEN_CLASS_WORD] = {&word_nud, NULL, PREC_NONE}, [TOKEN_CLASS_OPAREN] = {&oparen_nud, NULL, PREC_NONE}, [TOKEN_CLASS_CPAREN] = {NULL, NULL, PREC_NONE}, [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) { @@ -179,6 +232,19 @@ static struct ast_node* semicolon_led (struct parser* parser, struct token* toke 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_pgid; @@ -211,13 +277,15 @@ static void classify_tokens (struct list_node_link* tokens) { token->class = TOKEN_CLASS_CPAREN; } else if (strcmp (token->buffer, ";") == 0) { token->class = TOKEN_CLASS_SEMICOLON; + } else if (strcmp (token->buffer, ">") == 0) { + token->class = TOKEN_CLASS_REDIR; } else { 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) { struct parser parser; @@ -225,20 +293,24 @@ static void parse_tokens (struct list_node_link* tokens) { parser.next = get_token (tokens); 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) { - 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++) - 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]; const char* path; int ret; @@ -247,12 +319,12 @@ static void mkfile (char** file_paths, size_t files_count) { const char* file_path = file_paths[i]; 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; } 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; } @@ -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; char volume[VOLUME_MAX]; const char* path; @@ -272,12 +344,12 @@ static void cat (char** file_paths, size_t files_count) { const char* file_path = file_paths[i]; 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; } 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; } @@ -293,7 +365,7 @@ static void cat (char** file_paths, size_t files_count) { memset (buffer, 0, desc.size + 1); read_file (path, 0, (uint8_t*)buffer, desc.size); - printf ("%s\n", buffer); + cprintf (context, "%s\n", buffer); close: 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; char volume[VOLUME_MAX]; const char* path; @@ -310,81 +382,108 @@ static void ls (const char* path_string) { struct dir_entry entry; 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; } 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; } describe (path, &desc); 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 (); return; } size_t entries = desc.size; - printf ("total entries: %zu\n", entries); - printf ("\n"); + cprintf (context, "total entries: %zu\n", entries); + cprintf (context, "\n"); for (size_t entry_num = 0; entry_num < entries; entry_num++) { read_dir_entry (path, &entry, entry_num); 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 (); } -static void quit1 (void) { +static void quit1 (struct context* context) { run = false; - printf ("Goodbye!\n"); + cprintf (context, "Goodbye!\n"); } -static void help (void) { - printf ("Available commands:\n"); - printf ("echo ...\n"); - printf ("help\n"); - printf ("cat \n"); - printf ("ls \n"); - printf ("mkfile \n"); - printf ("quit\n"); +static void help (struct context* context) { + cprintf (context, "Available commands:\n"); + cprintf (context, "echo ...\n"); + cprintf (context, "help\n"); + cprintf (context, "cat \n"); + cprintf (context, "ls \n"); + cprintf (context, "mkfile \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) { - echo (cmd->args, cmd->arg_count); + echo (context, cmd->args, cmd->arg_count); } else if (strcmp (cmd->name, "help") == 0) { - help (); + help (context); } 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) { - ls (cmd->args[0]); + ls (context, cmd->args[0]); } else if (strcmp (cmd->name, "quit") == 0) { - quit1 (); + quit1 (context); } else if (strcmp (cmd->name, "mkfile") == 0) { - mkfile (cmd->args, cmd->arg_count); + mkfile (context, cmd->args, cmd->arg_count); } 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) { case AST_NODE_CLASS_CMD: - execute_cmd (&root->u.cmd); + execute_cmd (&root->u.cmd, context); break; case AST_NODE_CLASS_SUBSHELL: - execute (root->u.subshell.inner); + execute (root->u.subshell.inner, &subcontext); break; case AST_NODE_CLASS_SEQ: - execute (root->u.seq.left); - execute (root->u.seq.right); + execute (root->u.seq.left, context); + 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; } } diff --git a/include/syscall_defs.h b/include/syscall_defs.h index d2d0f71..dd41c28 100644 --- a/include/syscall_defs.h +++ b/include/syscall_defs.h @@ -24,5 +24,6 @@ #define SYS_GET_EXEC_PID 21 #define SYS_READ_DIR_ENTRY 22 #define SYS_CREATE_FILE 23 +#define SYS_WRITE_FILE 24 #endif // _M_SYSCALL_DEFS_H diff --git a/kernel/fs/vfs.c b/kernel/fs/vfs.c index 5b09029..08fe822 100644 --- a/kernel/fs/vfs.c +++ b/kernel/fs/vfs.c @@ -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); } +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) { struct vfs_volume* volume = vfs_find_volume (volume_name); diff --git a/kernel/fs/vfs.h b/kernel/fs/vfs.h index 1147897..092437b 100644 --- a/kernel/fs/vfs.h +++ b/kernel/fs/vfs.h @@ -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, 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_read_dir_entry (struct proc* proc, const char* volume, const char* path, diff --git a/kernel/syscall/syscall.c b/kernel/syscall/syscall.c index 701e7d9..ceeff65 100644 --- a/kernel/syscall/syscall.c +++ b/kernel/syscall/syscall.c @@ -483,6 +483,38 @@ DEFINE_SYSCALL (sys_create_file) { 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) */ 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_READ_DIR_ENTRY] = &sys_read_dir_entry, [SYS_CREATE_FILE] = &sys_create_file, + [SYS_WRITE_FILE] = &sys_write_file, }; syscall_handler_func_t syscall_find_handler (int syscall_num) { diff --git a/libarena/arena.c b/libarena/arena.c index a8c0246..0da0739 100644 --- a/libarena/arena.c +++ b/libarena/arena.c @@ -76,3 +76,15 @@ void* arena_malloc (struct arena* arena, size_t size) { arena->end->size += size1; 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; +} diff --git a/libarena/arena.h b/libarena/arena.h index d50de5f..74dad6a 100644 --- a/libarena/arena.h +++ b/libarena/arena.h @@ -23,4 +23,6 @@ void arena_destroy (struct arena* arena); 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 diff --git a/libsystem/system.c b/libsystem/system.c index 4a84478..5aaa829 100644 --- a/libsystem/system.c +++ b/libsystem/system.c @@ -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 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); +} diff --git a/libsystem/system.h b/libsystem/system.h index c93f676..abdbd59 100644 --- a/libsystem/system.h +++ b/libsystem/system.h @@ -84,4 +84,7 @@ int read_dir_entry (const char* path, struct dir_entry* entry, size_t entry_num) /* create a file */ 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