static int cmd_vfs_umount(struct vmm_chardev *cdev, const char *path) { int rc; rc = vfs_unmount(path); if (rc) { vmm_cprintf(cdev, "Unmount failed\n"); } else { vmm_cprintf(cdev, "Unmount successful\n"); } return rc; }
static int cmd_unmount(int nargs, char **args) { char *device; if (nargs != 2) { kprintf("Usage: unmount device:\n"); return EINVAL; } device = args[1]; /* Allow (but do not require) colon after device name */ if (device[strlen(device) - 1] == ':') { device[strlen(device) - 1] = 0; } return vfs_unmount(device); }
/* Main entry point for unmount, accepts an array of arguments */ int cmd_unmount(char **argv) { unsigned int argc; int rc; argc = cli_count_args(argv); if (argc != 2) { printf("%s: invalid number of arguments.\n", cmdname); return CMD_FAILURE; } rc = vfs_unmount(argv[1]); if (rc != EOK) { printf("Unable to unmount %s (rc=%d)\n", argv[1], rc); return CMD_FAILURE; } return CMD_SUCCESS; }
static void vfs_connection(ipc_callid_t iid, ipc_call_t *icall, void *arg) { bool cont = true; /* * The connection was opened via the IPC_CONNECT_ME_TO call. * This call needs to be answered. */ async_answer_0(iid, EOK); while (cont) { ipc_call_t call; ipc_callid_t callid = async_get_call(&call); if (!IPC_GET_IMETHOD(call)) break; switch (IPC_GET_IMETHOD(call)) { case VFS_IN_REGISTER: vfs_register(callid, &call); cont = false; break; case VFS_IN_MOUNT: vfs_mount(callid, &call); break; case VFS_IN_UNMOUNT: vfs_unmount(callid, &call); break; case VFS_IN_OPEN: vfs_open(callid, &call); break; case VFS_IN_CLOSE: vfs_close(callid, &call); break; case VFS_IN_READ: vfs_read(callid, &call); break; case VFS_IN_WRITE: vfs_write(callid, &call); break; case VFS_IN_SEEK: vfs_seek(callid, &call); break; case VFS_IN_TRUNCATE: vfs_truncate(callid, &call); break; case VFS_IN_FSTAT: vfs_fstat(callid, &call); break; case VFS_IN_STAT: vfs_stat(callid, &call); break; case VFS_IN_MKDIR: vfs_mkdir(callid, &call); break; case VFS_IN_UNLINK: vfs_unlink(callid, &call); break; case VFS_IN_RENAME: vfs_rename(callid, &call); break; case VFS_IN_SYNC: vfs_sync(callid, &call); break; case VFS_IN_DUP: vfs_dup(callid, &call); break; case VFS_IN_WAIT_HANDLE: vfs_wait_handle(callid, &call); break; case VFS_IN_MTAB_GET: vfs_get_mtab(callid, &call); break; default: async_answer_0(callid, ENOTSUP); break; } } /* * Open files for this client will be cleaned up when its last * connection fibril terminates. */ }
void vfs_setup(CallChain next) { char *res_path, *storage_path, *cache_path; get_core_paths(&res_path, &storage_path, &cache_path); char *local_res_path = strfmt("%s%cresources", storage_path, vfs_get_syspath_separator()); vfs_syspath_normalize_inplace(local_res_path); log_info("Resource path: %s", res_path); log_info("Storage path: %s", storage_path); log_info("Local resource path: %s", local_res_path); log_info("Cache path: %s", cache_path); struct mpoint_t { const char *dest; const char *syspath; bool loadpaks; uint flags; } mpts[] = { // per-user directory, where configs, replays, screenshots, etc. get stored { "storage", storage_path, false, VFS_SYSPATH_MOUNT_MKDIR }, // system-wide directory, contains all of the game assets { "resdirs", res_path, true, VFS_SYSPATH_MOUNT_READONLY }, // subpath of storage, files here override the global assets { "resdirs", local_res_path, true, VFS_SYSPATH_MOUNT_MKDIR | VFS_SYSPATH_MOUNT_READONLY }, // per-user directory, to contain various cached resources to speed up loading times { "cache", cache_path, false, VFS_SYSPATH_MOUNT_MKDIR }, {NULL} }; vfs_init(); // temporary union of the "real" directories vfs_create_union_mountpoint("resdirs"); // temporary union of the packages (e.g. zip files) vfs_create_union_mountpoint("respkgs"); // permanent union of respkgs and resdirs // this way, files in any of the "real" directories always have priority over anything in packages vfs_create_union_mountpoint("res"); for(struct mpoint_t *mp = mpts; mp->dest; ++mp) { if(mp->loadpaks) { // mount it to a temporary mountpoint to get a list of packages from this directory if(!vfs_mount_syspath("tmp", mp->syspath, mp->flags)) { log_fatal("Failed to mount '%s': %s", mp->syspath, vfs_get_error()); } if(!vfs_query("tmp").is_dir) { log_error("'%s' is not a directory", mp->syspath); vfs_unmount("tmp"); continue; } // load all packages from this directory into the respkgs union load_packages("tmp", "respkgs"); // now mount it to the intended destination, and remove the temporary mountpoint vfs_mount_alias(mp->dest, "tmp"); vfs_unmount("tmp"); } else if(!vfs_mount_syspath(mp->dest, mp->syspath, mp->flags)) { log_fatal("Failed to mount '%s': %s", mp->syspath, vfs_get_error()); } } vfs_mkdir_required("storage/replays"); vfs_mkdir_required("storage/screenshots"); free(local_res_path); free(res_path); free(storage_path); free(cache_path); // set up the final "res" union and get rid of the temporaries vfs_mount_alias("res", "respkgs"); vfs_mount_alias("res", "resdirs"); // vfs_make_readonly("res"); vfs_unmount("resdirs"); vfs_unmount("respkgs"); run_call_chain(&next, NULL); }