#include #include #include #include #include #include #define TAR_BLOCKSIZE 512 #define TAR_FILE 0 #define TAR_HARDLINK 1 #define TAR_SYMLINK 2 #define TAR_CHARDEV 3 #define TAR_BLOCK 4 #define TAR_DIR 5 #define TAR_FIFO 6 static volatile struct limine_module_request modreq = { .id = LIMINE_MODULE_REQUEST, .revision = 0 }; typedef struct{ char name[100]; char mode[8]; char uid[8]; char gid[8]; char size[12]; char modtime[12]; char checksum[8]; char type[1]; char link[100]; char indicator[6]; char version[2]; char uname[32]; char gname[32]; char devmajor[8]; char devminor[8]; char prefix[155]; } tar_block; typedef struct{ char name[256]; short mode; short gid; short uid; size_t size; size_t modtime; short checksum; short type; char link[101]; char indicator[6]; char version[2]; short devminor; short devmajor; } tar_entry; static volatile size_t convert(char* buff, size_t len){ size_t result = 0; while(len--){ result *= 8; result += *buff - '0'; buff++; } return result; } static volatile void buildentry(tar_entry* entry, void* addr){ tar_block* block = (tar_block*)addr; if(block->name[99]){ if(block->prefix[154]){ memcpy(entry->name, block->prefix, 154); } else{ strcpy(entry->name, block->prefix); } memcpy(entry->name + strlen(entry->name), block->name, 99); } else{ strcpy(entry->name, block->name); } entry->mode = convert(block->mode, 7); entry->uid = convert(block->uid, 7); entry->gid = convert(block->gid, 7); entry->size = convert(block->size, 11); entry->modtime = convert(block->modtime, 11); entry->checksum = convert(block->checksum, 7); entry->type = convert(block->type, 1); if(block->link[99]){ memcpy(entry->link, block->link, 100); } else{ strcpy(entry->link, block->link); } memcpy(entry->indicator, block->indicator, 6); memcpy(entry->version, block->version, 2); entry->devmajor = convert(block->devmajor, 7); entry->devminor = convert(block->devminor, 7); } void initrd_parse(){ if(!modreq.response) _panic("No modules passed to limine!", 0); size_t modcount = modreq.response->module_count; struct limine_file** modules = modreq.response->modules; struct limine_file* initrd = NULL; for(size_t i = 0; i < modcount; ++i){ if(!strcmp(modules[i]->path, "/initrd")){ initrd = modules[i]; break; } } if(!initrd) _panic("No initrd found!", 0); printf("Found initrd at %p with size %lu\n", initrd->address, initrd->size); void* addr = initrd->address; tar_entry entry; memset(entry.name, 0, 256); memset(entry.link, 0, 101); for(;;){ buildentry(&entry, addr); if(strncmp("ustar", entry.indicator, 5)) break; void* datastart = addr + TAR_BLOCKSIZE; addr += TAR_BLOCKSIZE + TAR_BLOCKSIZE * (entry.size / TAR_BLOCKSIZE) + (entry.size % TAR_BLOCKSIZE > 0 ? TAR_BLOCKSIZE : 0); switch(entry.type){ case TAR_FILE: int err = vfs_create(vfs_root(), entry.name, entry.mode); if(err){ printf("Failed creating %s: ERROR %lu\n", entry.name, err); } break; case TAR_DIR: err = vfs_mkdir(vfs_root(), entry.name, entry.mode); if(err) printf("Failed creating %s: ERROR %lu\n", entry.name, err); break; } if(entry.type != TAR_FILE) continue; vnode_t *node; int error; vfs_open(&node, vfs_root(), entry.name); if(vfs_write(&error, node, datastart, entry.size, 0) == -1){ printf("WRITE ERROR %lu\n", error); _panic("Failed to write from initrd", 0); } vfs_close(node); } }