summaryrefslogtreecommitdiffstats
path: root/sys/syscall_initrd_file.c
blob: 904039da971a1740e39ed8cd7c2e22af915b023e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#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,
        void *message_data)
{
    const char *filename = initrd_file_name(initrd_file);
    size_t filename_len = strlen(filename);

    size_t bytes_left = 0x1000;
    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;

    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,
        void *message_data,
        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 = 0x1000;

    //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;
    }
    
    memcpy(message_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, (void*)ctx->header);
            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, (void*)ctx->header, ctx->bytes_left, ctx->payload);
            return -EPERM;
        default:
            return -EBADCALL;
    }
}