summaryrefslogtreecommitdiffstats
path: root/sys/syscall_initrd_file.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/syscall_initrd_file.c')
-rw-r--r--sys/syscall_initrd_file.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/sys/syscall_initrd_file.c b/sys/syscall_initrd_file.c
new file mode 100644
index 0000000..8e34488
--- /dev/null
+++ b/sys/syscall_initrd_file.c
@@ -0,0 +1,98 @@
+#include "api/error.h"
+#include "boot/initrd.h"
+#include "lib/printf.h"
+#include "sys/message.h"
+#include "sys/syscall.h"
+#include "lib/string.h"
+
+int
+s_syscall_initrd_file_name(
+ jove_owned_obj_t *initrd_file,
+ jove_owned_obj_t *message)
+{
+ const char *filename = initrd_file_name(initrd_file);
+ size_t filename_len = strlen(filename);
+
+ size_t bytes_left = message_len(message);
+ size_t bytes_needed = filename_len + sizeof(struct syscall_initrd_file_name_ret);
+
+ CHECK_TOOSMALL(bytes_needed, bytes_left, "Message is too small for file name.");
+ struct syscall_initrd_file_name_ret *payload = message_data(message);
+
+ payload->len = filename_len;
+ memcpy(payload->c_str, filename, filename_len);
+ return 0;
+}
+
+int
+s_syscall_initrd_file_size(jove_owned_obj_t *initrd_file)
+{
+ return initrd_file_size(initrd_file);
+}
+
+int
+s_syscall_initrd_file_read(
+ jove_owned_obj_t *initrd_file,
+ jove_owned_obj_t *message,
+ size_t bytes_left,
+ void *payload_data)
+{
+ //Ensure that the message payload could hold the required read payload.
+ size_t bytes_needed = sizeof(struct syscall_initrd_file_read);
+ CHECK_TOOSMALL(bytes_needed, bytes_left,
+ "Message is too small to hold read payload.");
+
+ struct syscall_initrd_file_read *payload = payload_data;
+ bytes_needed = payload->read_size;
+ bytes_left = message_len(message);
+
+ //Ensure that the message is big enough to hold the read file data.
+ CHECK_TOOSMALL(bytes_needed, bytes_left,
+ "Message is too small to hold read bytes.");
+
+ size_t file_size = initrd_file_size(initrd_file);
+ char *file_data = initrd_file_data(initrd_file);
+
+ //Ensure that the start index is within the file.
+ if(payload->start_index >= file_size) {
+ klogf("Start index exceeds file length! (%i > %i)\n",
+ payload->start_index, file_size);
+ return -EOOB;
+ }
+
+ //Ensure that the read bounds is within the file.
+ if(payload->start_index + payload->read_size > file_size) {
+ klogf("Read bounds exceed file length! (%i+%i > %i)\n",
+ payload->start_index, payload->read_size, file_size);
+ return -ETOOBIG;
+ }
+
+ void *read_data = message_data(message);
+ memcpy(read_data, file_data + payload->start_index, payload->read_size);
+ return 0;
+}
+
+int
+_syscall_handle_initrd_file(syscall_context_t *ctx)
+{
+ switch(ctx->header->callid) {
+ case SYSCALL_INITRD_FILE_NAME:
+ if(ctx->target.permissions & SYSCALL_PERM_INITRD_FILE_NAME)
+ return s_syscall_initrd_file_name(
+ ctx->target.obj, ctx->message.obj);
+ return -EPERM;
+
+ case SYSCALL_INITRD_FILE_SIZE:
+ if(ctx->target.permissions & SYSCALL_PERM_INITRD_FILE_SIZE)
+ return s_syscall_initrd_file_size(ctx->target.obj);
+ return -EPERM;
+
+ case SYSCALL_INITRD_FILE_READ:
+ if(ctx->target.permissions & SYSCALL_PERM_INITRD_FILE_READ)
+ return s_syscall_initrd_file_read(
+ ctx->target.obj, ctx->message.obj, ctx->bytes_left, ctx->payload);
+ return -EPERM;
+ default:
+ return -EBADCALL;
+ }
+}