summaryrefslogtreecommitdiff
path: root/src/kernel/vfs/initrd.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/vfs/initrd.cpp')
-rw-r--r--src/kernel/vfs/initrd.cpp67
1 files changed, 67 insertions, 0 deletions
diff --git a/src/kernel/vfs/initrd.cpp b/src/kernel/vfs/initrd.cpp
new file mode 100644
index 0000000..50aa95c
--- /dev/null
+++ b/src/kernel/vfs/initrd.cpp
@@ -0,0 +1,67 @@
+#include "initrd.h"
+#include "vfile.h"
+#include <ui/vt.h>
+
+int initrd_check(uint8_t *data) {
+ initrd_header *h = (initrd_header*)data;
+ if (h->magic == INITRD_MAGIC) return 0;
+ return -1;
+}
+
+int initrd_load(uint8_t *data, vdir *root) {
+ if (root == 0) return -1;
+
+ union {
+ uint8_t *c;
+ initrd_header *ih;
+ initrd_file_header *fh;
+ } curr;
+ curr.c = data;
+
+ if (curr.ih->magic != INITRD_MAGIC) return -2;
+
+ uint32_t files = curr.ih->files; curr.ih++;
+ for (unsigned i = 0; i < files; i++) {
+ initrd_file_header *h = curr.fh;
+ curr.fh++;
+ if (h->name_length == 0) continue;
+ char* path = (char*)curr.c;
+ curr.c += h->name_length + 1;
+ if (strlen(path) != (int)h->name_length) return -3;
+
+ node* parent = root;
+ // parse filename
+ char *member = path;
+ while (*path != 0 && parent != 0) {
+ if (*path == '/') {
+ if (member == path) {
+ member++;
+ path++;
+ } else {
+ *path = 0;
+ path++;
+ node* n = parent->get_child(member);
+ if (n == 0) {
+ n = new vdir(parent);
+ parent->add_child(member, n);
+ }
+ parent = n;
+ member = path;
+ }
+ } else {
+ path++;
+ }
+ }
+ if (parent == 0) return -5;
+ if (member == path) return -6; // filename ended by '/', bad.
+
+ // add file
+ if (h->file_length == 0) {
+ if (parent->add_child(member, new vdir(parent)) != 0) return -4;
+ } else {
+ if (parent->add_child(member, new vfile(parent, (char*)curr.c, h->file_length)) != 0) return -4;
+ curr.c += h->file_length;
+ }
+ }
+ return 0;
+}