#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static struct vfs_volume_table volume_table; size_t volume_populate_volume_infos(struct volume_info* infos, size_t count) { if (count >= lengthof(volume_table.volume_buckets)) count = lengthof(volume_table.volume_buckets); size_t j = 0; for (size_t i = 0; i < lengthof(volume_table.volume_buckets); i++) { struct hash_node_link* hash_link = volume_table.volume_buckets[i]; while (hash_link != NULL && j < count) { struct vfs_volume* volume = hash_entry(hash_link, struct vfs_volume, volume_table_link); struct volume_info* info = &infos[j]; memcpy(info->volume_name, volume->key, sizeof(info->volume_name)); memcpy(info->device_key, volume->back_device->key, sizeof(info->device_key)); hash_link = hash_link->next; j++; } } return j; } static struct vfs_volume* vfs_find_volume(const char* volume) { struct hash_node_link* found_link = NULL; size_t volume_len = strlen_null(volume); uint32_t hash = hash_fnv32(volume, volume_len); hash_find(&volume_table, volume, volume_len, hash, lengthof(volume_table.volume_buckets), volume_buckets, struct vfs_volume, volume_table_link, key, found_link); if (found_link == NULL) return NULL; return hash_entry(found_link, struct vfs_volume, volume_table_link); } int vfs_create_volume(struct proc* proc, struct reschedule_ctx* rctx, const char* key, int fs_type, struct device* back_device, bool format) { if (strlen_null(key) > VOLUME_MAX) return -ST_OOB_ERROR; struct vfs_volume* volume = malloc(sizeof(*volume)); if (volume == NULL) return -ST_OOM_ERROR; memset(volume, 0, sizeof(*volume)); memcpy(volume->key, key, strlen_null(key)); volume->fs_type = fs_type; volume->back_device = back_device; switch (volume->fs_type) { case FS_TARFS: volume->driver_ops.mount = &tarfs_mount; volume->driver_ops.unmount = &tarfs_unmount; volume->driver_ops.format = &tarfs_format; volume->driver_ops.describe = &tarfs_describe; volume->driver_ops.read_file = &tarfs_read_file; volume->driver_ops.write_file = &tarfs_write_file; volume->driver_ops.read_dir_entry = &tarfs_read_dir_entry; volume->driver_ops.create_file = &tarfs_create_file; volume->driver_ops.create_dir = &tarfs_create_dir; volume->driver_ops.remove = &tarfs_remove; break; case FS_FAT16: volume->driver_ops.mount = &fatfs_mount; volume->driver_ops.unmount = &fatfs_unmount; volume->driver_ops.format = &fatfs16_format; volume->driver_ops.describe = &fatfs_describe; volume->driver_ops.read_file = &fatfs_read_file; volume->driver_ops.write_file = &fatfs_write_file; volume->driver_ops.read_dir_entry = &fatfs_read_dir_entry; volume->driver_ops.create_file = &fatfs_create_file; volume->driver_ops.create_dir = &fatfs_create_dir; volume->driver_ops.remove = &fatfs_remove; break; case FS_FAT32: volume->driver_ops.mount = &fatfs_mount; volume->driver_ops.unmount = &fatfs_unmount; volume->driver_ops.format = &fatfs32_format; volume->driver_ops.describe = &fatfs_describe; volume->driver_ops.read_file = &fatfs_read_file; volume->driver_ops.write_file = &fatfs_write_file; volume->driver_ops.read_dir_entry = &fatfs_read_dir_entry; volume->driver_ops.create_file = &fatfs_create_file; volume->driver_ops.create_dir = &fatfs_create_dir; volume->driver_ops.remove = &fatfs_remove; break; case FS_ISO9660: volume->driver_ops.mount = &iso9660fs_mount; volume->driver_ops.unmount = &iso9660fs_unmount; volume->driver_ops.format = &iso9660fs_format; volume->driver_ops.describe = &iso9660fs_describe; volume->driver_ops.read_file = &iso9660fs_read_file; volume->driver_ops.write_file = &iso9660fs_write_file; volume->driver_ops.read_dir_entry = &iso9660fs_read_dir_entry; volume->driver_ops.create_file = &iso9660fs_create_file; volume->driver_ops.create_dir = &iso9660fs_create_dir; volume->driver_ops.remove = &iso9660fs_remove; break; default: free(volume); return -ST_MOUNT_ERROR; } int ret = volume->driver_ops.mount(volume, proc, rctx, format); if (ret < 0) { free(volume); return ret; } uint32_t mp_hash = hash_fnv32(volume->key, strlen_null(volume->key)); hash_insert(&volume_table, &volume->volume_table_link, mp_hash, lengthof(volume_table.volume_buckets), volume_buckets); return ST_OK; } int vfs_volume_delete(const char* key) { struct hash_node_link* found_link = NULL; size_t key_len = strlen_null(key); uint32_t hash = hash_fnv32(key, key_len); hash_find(&volume_table, key, key_len, hash, lengthof(volume_table.volume_buckets), volume_buckets, struct vfs_volume, volume_table_link, key, found_link); if (found_link == NULL) { return -ST_NOT_FOUND; } struct vfs_volume* volume = hash_entry(found_link, struct vfs_volume, volume_table_link); if (volume == NULL) { return -ST_NOT_FOUND; } hash_delete(&volume_table, key, strlen_null(key), hash, lengthof(volume_table.volume_buckets), volume_buckets, struct vfs_volume, volume_table_link, key, found_link); int ret = volume->driver_ops.unmount(volume); free(volume); return ret; } int vfs_format(struct proc* proc, struct reschedule_ctx* rctx, const char* volume_name) { struct vfs_volume* volume = vfs_find_volume(volume_name); if (volume == NULL) return -ST_NOT_FOUND; return volume->driver_ops.format(volume, proc, rctx); } int vfs_read_file(struct proc* proc, struct reschedule_ctx* rctx, const char* volume_name, const char* path, uint8_t* buffer, size_t off, size_t size) { struct vfs_volume* volume = vfs_find_volume(volume_name); if (volume == NULL) return -ST_NOT_FOUND; return volume->driver_ops.read_file(volume, proc, rctx, path, buffer, off, size); } int vfs_write_file(struct proc* proc, struct reschedule_ctx* rctx, const char* volume_name, const char* path, uint8_t* buffer, size_t off, size_t size, uint32_t flags) { struct vfs_volume* volume = vfs_find_volume(volume_name); if (volume == NULL) return -ST_NOT_FOUND; return volume->driver_ops.write_file(volume, proc, rctx, path, buffer, off, size, flags); } int vfs_create_file(struct proc* proc, struct reschedule_ctx* rctx, const char* volume_name, const char* path) { struct vfs_volume* volume = vfs_find_volume(volume_name); if (volume == NULL) return -ST_NOT_FOUND; return volume->driver_ops.create_file(volume, proc, rctx, path); } int vfs_describe(struct proc* proc, struct reschedule_ctx* rctx, const char* volume_name, const char* path, struct desc* desc) { struct vfs_volume* volume = vfs_find_volume(volume_name); if (volume == NULL) return -ST_NOT_FOUND; return volume->driver_ops.describe(volume, proc, rctx, path, desc); } int vfs_read_dir_entry(struct proc* proc, struct reschedule_ctx* rctx, const char* volume_name, const char* path, struct dir_entry* entry, size_t entry_num) { struct vfs_volume* volume = vfs_find_volume(volume_name); if (volume == NULL) return -ST_NOT_FOUND; return volume->driver_ops.read_dir_entry(volume, proc, rctx, path, entry, entry_num); } int vfs_create_dir(struct proc* proc, struct reschedule_ctx* rctx, const char* volume_name, const char* path) { struct vfs_volume* volume = vfs_find_volume(volume_name); if (volume == NULL) return -ST_NOT_FOUND; return volume->driver_ops.create_dir(volume, proc, rctx, path); } int vfs_remove(struct proc* proc, struct reschedule_ctx* rctx, const char* volume_name, const char* path) { struct vfs_volume* volume = vfs_find_volume(volume_name); if (volume == NULL) return -ST_NOT_FOUND; return volume->driver_ops.remove(volume, proc, rctx, path); } void vfs_init(void) { memset(&volume_table, 0, sizeof(volume_table)); } void vfs_translate(size_t fs_block, size_t fs_block_count, size_t fs_block_size, size_t device_sector_size, size_t* out_phys_sector, size_t* out_sector_count) { size_t ratio = fs_block_size / device_sector_size; if (out_phys_sector != NULL) *out_phys_sector = fs_block * ratio; if (out_sector_count != NULL) *out_sector_count = fs_block_count * ratio; }