summaryrefslogtreecommitdiff
path: root/src/init/driver/tmpfs.c
blob: 4b639dab935ea93fb939e8a15109e315a90c1596 (plain)
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
#include <init/malloc.h>
#include <shared/mem.h>
#include <shared/syscalls.h>
#include <stddef.h>

struct node {
	const char *name;
	size_t len;
	struct node *next;
};

struct node *root = NULL;

static struct node *lookup(const char *path, size_t len) {
	for (struct node *iter = root; iter; iter = iter->next) {
		if (iter->len == len && !memcmp(path, iter->name, len))
			return iter;
	}
	return NULL;
}

static int tmpfs_open(const char *path, struct fs_wait_response *res) {
	if (res->len == 0) return -1;
	path++;
	res->len--;

	if (res->len == 0) return 0; /* root */

	// no directory support (yet)
	if (memchr(path, '/', res->len)) return -1;

	if (res->flags & OPEN_CREATE) {
		if (lookup(path, res->len)) return -1; /* already exists */
		struct node *new = malloc(sizeof *new);
		char *namebuf = malloc(res->len);
		memcpy(namebuf, path, res->len);
		new->name = namebuf;
		new->len = res->len;
		new->next = root;
		root = new;
		return 1;
	}

	return lookup(path, res->len) != 0 ? 1 : -1;
}

void tmpfs_drv(void) {
	// TODO replace all the static allocations in drivers with mallocs
	static char buf[512];
	struct fs_wait_response res;
	while (!_syscall_fs_wait(buf, sizeof buf, &res)) {
		switch (res.op) {
			case VFSOP_OPEN:
				_syscall_fs_respond(NULL, tmpfs_open(buf, &res), 0);
				break;

			case VFSOP_READ:
				if (res.id != 0) {
					// rw unimplemented
					_syscall_fs_respond(NULL, -1, 0);
					break;
				}
				size_t buf_pos = 0;
				size_t to_skip = res.offset;

				for (struct node *iter = root; iter; iter = iter->next) {
					if (iter->len <= to_skip) {
						to_skip -= iter->len;
						continue;
					}

					if (iter->len + buf_pos - to_skip >= sizeof(buf)) {
						memcpy(buf + buf_pos, iter->name + to_skip, sizeof(buf) - buf_pos - to_skip);
						buf_pos = sizeof(buf);
						break;
					}
					memcpy(buf + buf_pos, iter->name + to_skip, iter->len - to_skip);
					buf_pos += iter->len - to_skip;
					buf[buf_pos++] = '\0';
					to_skip = 0;
				}
				_syscall_fs_respond(buf, buf_pos, 0);
				break;

			default:
				_syscall_fs_respond(NULL, -1, 0);
				break;
		}
	}

	_syscall_exit(1);
}