[--streams-interface=\fIINTERFACE\fR] [--ref="\fIGLOB\fR"]
.br
\fBimagex mountrw\fR \fIWIMFILE\fR \fIIMAGE\fR \fIDIRECTORY\fR [--check]
-[--streams-interface=\fIINTERFACE\fR]
+[--streams-interface=\fIINTERFACE\fR] [--staging-dir=\fIDIR\fR]
.br
\fBimagex unmount\fR \fIDIRECTORY\fR [--commit] [--check]
If wimlib was configured using the --without-fuse flag, then the \fBimagex
mount\fR, \fBimagex mountrw\fR, and \fBimagex unmount\fR commands will not work.
+You can mount multiple images from a WIM file read-only at the same time, but
+you can only mount one image at a time from a WIM read-write.
+
All files in the mounted WIM will be accessible regardless of whether there is a
security descriptor in the WIM associated with the file or not. New files or
directories created in a read-write mounted WIM will be created with no security
descriptors in a mounted WIM.
.SH MOUNT OPTIONS
+
.TP
\fB--check\fR
When reading the WIM, verify its integrity if it contains an integrity table.
.TP
\fB--streams-interface\fR=\fIINTERFACE\fR
-
This option is inspired by the ntfs-3g filesystem driver (see \fBntfs-3g\fR
(8)). It controls how alternate data streams, or named data streams, in WIM
files are made available.
aren't actually used much, even though they complicate the WIM file format
considerably. Normally, all you care about is the default or "unnamed" data
stream.
-
.TP
\fB--debug\fR
Turn on debugging information printed by the FUSE library, and do not fork into
the background.
-
.TP
\fB--ref\fR="\fIGLOB\fR"
File glob of additional split WIM parts that are part of the split WIM being
mounted. This option is valid for \fBimagex mount\fR but not \fBimagex
mountrw\fR. See \fBSPLIT_WIMS\fR.
+.TP
+\fB--staging-dir\fR=\fIDIR\fR
+Store temporary staging files in the directory \fIDIR\fR. Only valid for
+\fBimagex mountrw\fR.
.SH UNMOUNT OPTIONS
+
.TP
\fB--commit\fR
Recreate the WIM file with the changes that have been made. Has no effect if
.SH IMPLEMENTATION DETAILS
Since a WIM is an archive and not a filesystem, \fBimagex mountrw\fR creates a
-temporary staging directory to contain files that are created or modified. When
-the filesystem is unmounted with \fB--commit\fR, the WIM is rebuilt, merging in
-the staging files as needed. Then, the temporary staging directory is deleted.
+temporary staging directory to contain files that are created or modified. This
+directory is located in the same directory as \fIWIMFILE\fR by default, but the
+location can be set using the \fB--staging-dir\fR option. When the filesystem
+is unmounted with \fB--commit\fR, the WIM is rebuilt, merging in the staging
+files as needed. Then, the temporary staging directory is deleted.
\fBimagex unmount\fR executes the \fBfusermount\fR (1) program, which should be
installed as part of libfuse, to unmount the filesystem. It then uses a POSIX
" [--ref=\"GLOB\"]\n",
[MOUNTRW] =
"imagex mountrw WIMFILE [IMAGE_NUM | IMAGE_NAME] DIRECTORY\n"
-" [--check] [--debug] [--streams-interface=INTERFACE]\n",
+" [--check] [--debug] [--streams-interface=INTERFACE]\n"
+" [--staging-dir=DIR]\n",
[OPTIMIZE] =
"imagex optimize WIMFILE [--check] [--recompress]\n",
[SPLIT] =
};
static const struct option mount_options[] = {
- {"check", no_argument, NULL, 'c'},
- {"debug", no_argument, NULL, 'd'},
+ {"check", no_argument, NULL, 'c'},
+ {"debug", no_argument, NULL, 'd'},
{"streams-interface", required_argument, NULL, 's'},
- {"ref", required_argument, NULL, 'r'},
+ {"ref", required_argument, NULL, 'r'},
+ {"staging-dir", required_argument, NULL, 'D'},
{NULL, 0, NULL, 0},
};
const char *swm_glob = NULL;
WIMStruct **additional_swms = NULL;
unsigned num_additional_swms = 0;
+ const char *staging_dir = NULL;
if (strcmp(argv[0], "mountrw") == 0)
mount_flags |= WIMLIB_MOUNT_FLAG_READWRITE;
case 'r':
swm_glob = optarg;
break;
+ case 'D':
+ staging_dir = optarg;
+ break;
default:
goto mount_usage;
}
}
ret = wimlib_mount_image(w, image, dir, mount_flags, additional_swms,
- num_additional_swms, NULL);
+ num_additional_swms, staging_dir);
if (ret != 0) {
imagex_error("Failed to mount image %d from `%s' on `%s'",
image, wimfile, dir);
/* The WIMStruct for the mounted WIM. */
WIMStruct *wim;
- /* Working directory when `imagex mount' is run. */
- char *working_directory;
-
/* Name of the staging directory for a read-write mount. Whenever a new file is
* created, it is done so in the staging directory. Furthermore, whenever a
* file in the WIM is modified, it is extracted to the staging directory. If
* Creates a randomly named staging directory and saves its name in the
* filesystem context structure.
*/
-static int make_staging_dir(struct wimfs_context *ctx)
+static int make_staging_dir(struct wimfs_context *ctx,
+ const char *user_prefix)
{
- /* XXX Give the user an option of where to stage files */
-
- static const char prefix[] = "wimlib-staging-";
- static const size_t prefix_len = sizeof(prefix) - 1;
static const size_t random_suffix_len = 10;
+ static const char *common_suffix = ".staging";
+ static const size_t common_suffix_len = 8;
- size_t pwd_len = strlen(ctx->working_directory);
+ char *staging_dir_name = NULL;
+ size_t staging_dir_name_len;
+ size_t prefix_len;
+ const char *wim_basename;
+ char *real_user_prefix = NULL;
+ int ret;
- ctx->staging_dir_name_len = pwd_len + 1 + prefix_len + random_suffix_len;
+ if (user_prefix) {
+ real_user_prefix = realpath(user_prefix, NULL);
+ if (!real_user_prefix) {
+ ERROR_WITH_ERRNO("Could not resolve `%s'",
+ real_user_prefix);
+ ret = WIMLIB_ERR_NOTDIR;
+ goto out;
+ }
+ wim_basename = path_basename(ctx->wim->filename);
+ prefix_len = strlen(real_user_prefix) + 1 + strlen(wim_basename);
+ } else {
+ prefix_len = strlen(ctx->wim->filename);
+ }
- ctx->staging_dir_name = MALLOC(ctx->staging_dir_name_len + 1);
- if (!ctx->staging_dir_name)
- return WIMLIB_ERR_NOMEM;
+ staging_dir_name_len = prefix_len + common_suffix_len + random_suffix_len;
+
+ staging_dir_name = MALLOC(staging_dir_name_len + 1);
+ if (!staging_dir_name) {
+ ret = WIMLIB_ERR_NOMEM;
+ goto out;
+ }
+
+ if (real_user_prefix)
+ sprintf(staging_dir_name, "%s/%s", real_user_prefix, wim_basename);
+ else
+ strcpy(staging_dir_name, ctx->wim->filename);
+
+ strcat(staging_dir_name, common_suffix);
+
+ randomize_char_array_with_alnum(staging_dir_name + prefix_len + common_suffix_len,
+ random_suffix_len);
- memcpy(ctx->staging_dir_name, ctx->working_directory, pwd_len);
- ctx->staging_dir_name[pwd_len] = '/';
- memcpy(ctx->staging_dir_name + pwd_len + 1, prefix, prefix_len);
- randomize_char_array_with_alnum(ctx->staging_dir_name + pwd_len +
- 1 + prefix_len, random_suffix_len);
- ctx->staging_dir_name[ctx->staging_dir_name_len] = '\0';
+ staging_dir_name[staging_dir_name_len] = '\0';
- if (mkdir(ctx->staging_dir_name, 0700) != 0) {
+ if (mkdir(staging_dir_name, 0700) != 0) {
ERROR_WITH_ERRNO("Failed to create temporary directory `%s'",
- ctx->staging_dir_name);
- FREE(ctx->staging_dir_name);
- ctx->staging_dir_name = NULL;
- return WIMLIB_ERR_MKDIR;
+ staging_dir_name);
+ ret = WIMLIB_ERR_MKDIR;
+ } else {
+ ret = 0;
}
- return 0;
+out:
+ FREE(real_user_prefix);
+ if (ret == 0) {
+ ctx->staging_dir_name = staging_dir_name;
+ ctx->staging_dir_name_len = staging_dir_name_len;
+ } else {
+ FREE(staging_dir_name);
+ }
+ return ret;
}
static int remove_file_or_directory(const char *fpath, const struct stat *sb,
}
/* Overwrites the WIM file, with changes saved. */
-static int rebuild_wim(struct wimfs_context *ctx, bool check_integrity)
+static int rebuild_wim(struct wimfs_context *ctx, int write_flags)
{
int ret;
struct lookup_table_entry *lte, *tmp;
xml_update_image_info(w, w->current_image);
- ret = wimlib_overwrite(w, check_integrity, 0, NULL);
+ ret = wimlib_overwrite(w, write_flags, 0, NULL);
if (ret != 0) {
ERROR("Failed to commit changes");
return ret;
char status;
char *mailbox;
struct wimfs_context *ctx = wimfs_get_context();
+ int write_flags;
if (open_message_queues(ctx, true))
return;
status = 0;
if (ctx->mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
if (commit) {
- ret = chdir(ctx->working_directory);
- if (ret == 0) {
- status = rebuild_wim(ctx, (check_integrity != 0));
- } else {
- ERROR_WITH_ERRNO("chdir()");
- status = WIMLIB_ERR_NOTDIR;
- }
+ if (check_integrity)
+ write_flags = WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
+ else
+ write_flags = 0;
+ status = rebuild_wim(ctx, write_flags);
}
ret = delete_staging_dir(ctx);
if (ret != 0) {
DEBUG("Initializing struct wimfs_context");
init_wimfs_context(&ctx);
-
- DEBUG("Getting current directory");
- ctx.working_directory = getcwd(NULL, 0);
- if (!ctx.working_directory) {
- ERROR_WITH_ERRNO("Could not determine current directory");
- ret = WIMLIB_ERR_NOTDIR;
- goto out;
- }
+ ctx.wim = wim;
+ ctx.mount_flags = mount_flags;
DEBUG("Unlinking message queues in case they already exist");
ret = set_message_queue_names(&ctx, dir);
if (ret != 0)
- goto out_free_working_directory;
+ goto out;
unlink_message_queues(&ctx);
DEBUG("Preparing arguments to fuse_main()");
argv[argc++] = optstring;
if ((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)) {
/* Read-write mount. Make the staging directory */
- ret = make_staging_dir(&ctx);
+ ret = make_staging_dir(&ctx, staging_dir);
if (ret != 0)
goto out_free_dir_copy;
} else {
ctx.next_ino = assign_inode_numbers(&imd->inode_list);
DEBUG("(next_ino = %"PRIu64")", ctx.next_ino);
- /* Finish initializing the filesystem context. */
- ctx.wim = wim;
- ctx.mount_flags = mount_flags;
DEBUG("Calling fuse_main()");
FREE(dir_copy);
out_free_message_queue_names:
free_message_queue_names(&ctx);
-out_free_working_directory:
- FREE(ctx.working_directory);
- ctx.working_directory = NULL;
out:
if (num_additional_swms) {
free_lookup_table(wim->lookup_table);