/** * @file initrd_fs.c * @brief CPIO initial ramdisk VFS driver implementation. * * Provides a read-only VFS interface to the CPIO archive loaded at boot. * Files are accessed directly from the archive memory (zero-copy reads). */ #include "initrd_fs.h" #include "vfs.h" #include "cpio.h" #include /* Debug print helpers defined in kernel.c */ extern void offset_print(const char *str); extern void print_hex(uint32_t val); /** * Read from a file in the initrd. * Data is read directly from the CPIO archive (memory-mapped). */ static int32_t initrd_read(vfs_node_t *node, uint32_t offset, uint32_t size, void *buf) { if (!node || !node->fs_data || !buf) return -1; /* fs_data points to the file's data within the CPIO archive */ const uint8_t *data = (const uint8_t *)node->fs_data; uint32_t file_size = node->size; if (offset >= file_size) return 0; uint32_t remaining = file_size - offset; if (size > remaining) size = remaining; memcpy(buf, data + offset, size); return (int32_t)size; } /** * Read a directory entry from the initrd root. * The initrd is a flat archive — all files are at the root level. */ static int initrd_readdir(vfs_node_t *dir, uint32_t idx, vfs_dirent_t *out) { (void)dir; uint32_t off = 0; uint32_t current = 0; cpio_entry_t entry; while (cpio_next(&off, &entry) == 0) { /* Skip the "." directory entry if present */ if (entry.name[0] == '.' && entry.name[1] == '\0') continue; /* Strip "./" prefix */ const char *name = entry.name; if (name[0] == '.' && name[1] == '/') name += 2; /* Skip empty names */ if (*name == '\0') continue; if (current == idx) { memset(out, 0, sizeof(vfs_dirent_t)); strncpy(out->name, name, VFS_MAX_NAME - 1); out->inode = current; out->type = VFS_FILE; return 0; } current++; } return -1; /* No more entries */ } /** * Find a file by name within the initrd. */ static int initrd_finddir(vfs_node_t *dir, const char *name, vfs_node_t *out) { (void)dir; cpio_entry_t entry; if (cpio_find(name, &entry) != 0) { return -1; } memset(out, 0, sizeof(vfs_node_t)); /* Strip "./" prefix for the node name */ const char *display_name = entry.name; if (display_name[0] == '.' && display_name[1] == '/') { display_name += 2; } strncpy(out->name, display_name, VFS_MAX_NAME - 1); out->type = VFS_FILE; out->size = entry.datasize; out->mode = entry.mode; out->fs_data = (void *)entry.data; /* Direct pointer into CPIO archive */ return 0; } /** Filesystem operations for the initrd. */ static vfs_fs_ops_t initrd_ops = { .open = NULL, /* No special open needed */ .close = NULL, /* No special close needed */ .read = initrd_read, .write = NULL, /* Read-only */ .readdir = initrd_readdir, .finddir = initrd_finddir, }; int init_initrd_fs(void) { if (cpio_count() == 0) { offset_print(" INITRD_FS: no files in ramdisk\n"); } int ret = vfs_mount("/initrd", &initrd_ops, NULL); if (ret != 0) { offset_print(" INITRD_FS: failed to mount\n"); return -1; } offset_print(" INITRD_FS: mounted at /initrd\n"); return 0; }