summaryrefslogblamecommitdiff
path: root/src/kernel/vfs/initrd.cpp
blob: 50aa95c641d78d11afda66d3850ff13d153c33af (plain) (tree)


































































                                                                                                                        
#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;
}