static int __fatfs_control_load_fat_cache(struct fatfs_control *ctrl, u32 sect_num) { int rc; u32 index; u64 fat_base, len; if (-1 < __fatfs_control_find_fat_cache(ctrl, sect_num)) { return VMM_OK; } index = ctrl->fat_cache_victim; ctrl->fat_cache_victim++; if (ctrl->fat_cache_victim == FAT_TABLE_CACHE_SIZE) { ctrl->fat_cache_victim = 0; } rc = __fatfs_control_flush_fat_cache(ctrl, index); if (rc) { return rc; } fat_base = (u64)ctrl->first_fat_sector * ctrl->bytes_per_sector; len = vmm_blockdev_read(ctrl->bdev, &ctrl->fat_cache_buf[index * ctrl->bytes_per_sector], fat_base + sect_num * ctrl->bytes_per_sector, ctrl->bytes_per_sector); if (len != ctrl->bytes_per_sector) { return VMM_EIO; } ctrl->fat_cache_num[index] = sect_num; return VMM_OK; }
static struct dir_entry *path_to_dentry(struct vmm_blockdev *mdev, const char *path, struct dir_entry *pdentry) { char dirname[VFS_MAX_NAME] = { 0 }; struct dir_entry *dentry, *d_root; int i = 0, rd; int len = 0; char rpath[VFS_MAX_NAME]; len = strlen(path); if (!len) return NULL; vmm_snprintf(rpath, len, "%s", path); if (rpath[len - 1] != '/') { rpath[len] = '/'; rpath[len+1] = 0; } path = rpath; if (*path == '/') { path++; if (!*path) return pdentry; } while (*path && *path != '/') { dirname[i] = *path; path++; i++; } dentry = lookup_dentry(dirname, pdentry); if (dentry) { d_root = vmm_zalloc(dentry->dlen.lsb); rd = vmm_blockdev_read(mdev, (u8 *)d_root, (dentry->start_lba.lsb * 2048), dentry->dlen.lsb); if (rd != dentry->dlen.lsb) { vmm_free(d_root); return NULL; } dentry = path_to_dentry(mdev, path, d_root); } return dentry; }
/* vnode operations */ static size_t iso9660fs_read(struct vnode *v, loff_t off, void *buf, size_t len) { u64 toff; size_t sz = 0; if (v->v_type != VREG) { return 0; } if (off >= v->v_size) { return 0; } sz = len; if ((v->v_size - off) < sz) { sz = v->v_size - off; } toff = (u64)(v->v_data); sz = vmm_blockdev_read(v->v_mount->m_dev, (u8 *)buf, (toff + off), sz); return sz; }
/* Mount operation */ static int iso9660fs_mount(struct mount *m, const char *dev, u32 flags) { u64 read_count; int retval = VMM_OK, rd; struct iso9660_mount_data *mdata; if (dev == NULL) { return VMM_EINVALID; } if (vmm_blockdev_total_size(m->m_dev) <= sizeof(struct primary_vol_desc)) { return VMM_EFAIL; } mdata = vmm_zalloc(sizeof(struct iso9660_mount_data)); if (!mdata) return VMM_ENOMEM; mdata->mdev = m->m_dev; read_count = vmm_blockdev_read(m->m_dev, (u8 *)(&mdata->vol_desc), VOL_DESC_START_OFFS, sizeof(struct primary_vol_desc)); if (read_count != sizeof(struct primary_vol_desc)) { retval = VMM_EIO; goto _fail; } if (mdata->vol_desc.type != VOL_DESC_PRIMARY) { retval = VMM_EINVALID; goto _fail; } if (strncmp((const char *)&mdata->vol_desc.ident[0], "CD001", 5) != 0) { retval = VMM_EINVALID; goto _fail; } mdata->root_dir_entry = (struct dir_entry *) (&mdata->vol_desc.root_dir_entry[0]); mdata->root_dir_offset = mdata->root_dir_entry->start_lba.lsb * 2048; mdata->root_dir_len = mdata->root_dir_entry->dlen.lsb; mdata->root_dir = vmm_zalloc(mdata->root_dir_len); if (!mdata->root_dir) { retval = VMM_ENOMEM; goto _fail; } rd = vmm_blockdev_read(m->m_dev, (u8 *)mdata->root_dir, mdata->root_dir_offset, mdata->root_dir_len); if (!rd || rd != mdata->root_dir_len) { retval = VMM_EIO; goto _fail; } /* We don't support writing to ISO9660 fs */ m->m_flags = MOUNT_RDONLY; m->m_root->v_data = NULL; m->m_data = mdata; return VMM_OK; _fail: if (mdata) { if (mdata->root_dir) vmm_free(mdata->root_dir); vmm_free(mdata); } return retval; }