From: Eric Biggers Date: Sat, 1 Sep 2012 01:31:02 +0000 (-0500) Subject: Split WIM mount and split WIM documentation X-Git-Tag: v1.0.0~23 X-Git-Url: https://wimlib.net/git/?p=wimlib;a=commitdiff_plain;h=512d3f87a1e7b59ca19ae6d6965dbcf7f4a17c15 Split WIM mount and split WIM documentation --- diff --git a/README b/README index c0dadaad..91deb1c0 100644 --- a/README +++ b/README @@ -25,6 +25,8 @@ format, and LZX compression format. The XPRESS documentation is acceptable, but the LZX documentation is not entirely correct, and the WIM documentation itself is very incomplete and is of unacceptable quality. +A WIM file may be either stand-alone or split into multiple parts. + WINDOWS PE A major use for this library is to create customized images of Windows PE, the diff --git a/doc/imagex-apply.1.in b/doc/imagex-apply.1.in index 06caf05e..e9dd4684 100644 --- a/doc/imagex-apply.1.in +++ b/doc/imagex-apply.1.in @@ -23,6 +23,9 @@ location and the WIM image(s) are extracted to that directory. If \fITARGET\fR specifies a regular file or block device, it is interpreted as a NTFS volume to which the WIM image is to be extracted. +\fBimagex apply\fR supports applying images from stand-alone WIMs as well as +split WIM. See \fBSPLIT WIMS\fR. + .SH NORMAL MODE The normal extraction mode is entered when \fITARGET\fR is a directory or @@ -155,6 +158,38 @@ Besides setting up the files on the "System" partition, don't forget to set the bootable flag on it, and have a master boot record that loads the bootable partition (Windows' MBR does, and SYSLINUX provides an equivalent MBR). +.SH SPLIT WIMS + +You may use \fBimagex apply\fR to apply images from a split WIM. The +\fIWIMFILE\fR argument is used to specify the first part of the split WIM, and +the \fB--refs\fR="\fIGLOB\fR" option is used to provide a shell-style file glob +that specifies the additional parts of the split WIM. \fIGLOB\fR is expected to +be a single string on the command line, so \fIGLOB\fR must be quoted so that it +is protected against shell expansion. \fIGLOB\fR must expand to all parts of +the split WIM, except optionally the first part which may either omitted or +included in the glob (but the first part MUST be specified as \fIWIMFILE\fR as +well). + +Here's an example. The names for the split WIMs usually go something like: + +.RS +.PP +.nf +mywim.swm +mywim2.swm +mywim3.swm +mywim4.swm +mywim5.swm +\. ... etc. +.RE + +To apply the first image of this split WIM to the directory "dir", we would do: +.PP +.RS +imagex apply mywim.swm 1 dir --ref="mywim*.swm" +.RE +.PP + .SH OPTIONS .TP 6 \fB--check\fR @@ -177,11 +212,13 @@ instead. This option is not available in the NTFS extraction mode. \fB--verbose\fR Print the path to of each file or directory within the WIM image as it is extracted, and some additional informational messages. +.TP +\fB--ref\fR="\fIGLOB\fR" +File glob of additional split WIM parts that are part of the split WIM being +applied. See \fBSPLIT_WIMS\fR. .SH NOTES -\fBimagex apply\fR does not yet support split WIMs. - \fBimagex apply\fR calculates the SHA1 message digest of every file stream it extracts and verifies that it is the same as the SHA1 message digest provided in the WIM file. It is an error if the message digests don't match. It's also diff --git a/doc/imagex-mount.1.in b/doc/imagex-mount.1.in index 3f5eb4a6..2518f350 100644 --- a/doc/imagex-mount.1.in +++ b/doc/imagex-mount.1.in @@ -4,7 +4,7 @@ imagex mount, mountrw, unmount \- Mount and unmount an image from a WIM archive .SH SYNOPSIS \fBimagex mount\fR \fIWIMFILE\fR \fIIMAGE\fR \fIDIRECTORY\fR [--check] -[--streams-interface=\fIINTERFACE\fR] +[--streams-interface=\fIINTERFACE\fR] [--ref="\fIGLOB\fR"] .br \fBimagex mountrw\fR \fIWIMFILE\fR \fIIMAGE\fR \fIDIRECTORY\fR [--check] [--streams-interface=\fIINTERFACE\fR] @@ -28,6 +28,40 @@ The WIM image can be unmounted using the \fBimagex unmount\fR command. Changes made to a WIM mounted read-write will be discarded unless the \fB--commit\fR flag is provided to \fBimagex unmount\fR. +.SH SPLIT WIMS + +You may use \fBimagex mount\fR to mount an image from a split WIM read-only. +However, you may not mount an image from a split WIM read-write. + +The \fIWIMFILE\fR argument is used to specify the first part of the split WIM, and +the \fB--refs\fR="\fIGLOB\fR" option is used to provide a shell-style file glob +that specifies the additional parts of the split WIM. \fIGLOB\fR is expected to +be a single string on the command line, so \fIGLOB\fR must be quoted so that it +is protected against shell expansion. \fIGLOB\fR must expand to all parts of +the split WIM, except optionally the first part which may either omitted or +included in the glob (but the first part MUST be specified as \fIWIMFILE\fR as +well). + +Here's an example. The names for the split WIMs usually go something like: + +.RS +.PP +.nf +mywim.swm +mywim2.swm +mywim3.swm +mywim4.swm +mywim5.swm +\. ... etc. +.RE + +To mount the first image of this split WIM to the directory "dir", we would do: +.PP +.RS +imagex mount mywim.swm 1 dir --ref="mywim*.swm" +.RE +.PP + .SH NOTES If wimlib was configured using the --without-fuse flag, then the \fBimagex @@ -36,9 +70,10 @@ mount\fR, \fBimagex mountrw\fR, and \fBimagex unmount\fR commands will not work. 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 -descriptor. - -Mounting split WIMs is not yet supported. +descriptor. Although there is support for accessing named data streams (see the +\fB--streams-interface\fR option), it is currently not possible +to set or get DOS names, file attributes, or security +descriptors in a mounted WIM. .SH MOUNT OPTIONS .TP @@ -73,6 +108,12 @@ stream. 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. + .SH UNMOUNT OPTIONS .TP \fB--commit\fR diff --git a/doc/imagex.1.in b/doc/imagex.1.in index 1352ce77..263b2c96 100644 --- a/doc/imagex.1.in +++ b/doc/imagex.1.in @@ -44,46 +44,52 @@ There is a separate manual page for each \fBimagex\fR command. The following features are currently supported: -.IP \[bu] 2 -Mount an image in a WIM read-only (\fBimagex mount\fR) -.IP \[bu] 2 -Mount an image in a WIM read-write (\fBimagex mountrw\fR) -.IP \[bu] 2 -Create a WIM from a directory or NTFS volume (\fBimagex capture\fR) -.IP \[bu] 2 -Append a directory or NTFS volume onto a WIM as a new image (\fBimagex +.IP \[bu] 3 +Create a stand-alone WIM from a directory or NTFS volume (\fBimagex capture\fR) +.IP \[bu] +Append a directory or NTFS volume onto a stand-alone WIM as a new image (\fBimagex append\fR) -.IP \[bu] 2 -Delete image(s) from a WIM (\fBimagex delete\fR) -.IP \[bu] 2 -Export image(s) from a WIM (\fBimagex export\fR) -.IP \[bu] 2 +.IP \[bu] +Apply an image from a stand-alone or split WIM to a directory or NTFS volume +(\fBimagex apply\fR) +.IP \[bu] +Mount an image from a stand-alone or split WIM read-only (\fBimagex mount\fR) +.IP \[bu] +Mount an image from a stand-alone WIM read-write (\fBimagex mountrw\fR) +.IP \[bu] +Delete image(s) from a stand-alone WIM (\fBimagex delete\fR) +.IP \[bu] +Export image(s) from a stand-alone WIM (\fBimagex export\fR) +.IP \[bu] Display information about a WIM file (\fBimagex info\fR, \fBimagex dir\fR) -.IP \[bu] 2 +.IP \[bu] Change the name or description of an image in the WIM (\fBimagex info\fR) -.IP \[bu] 2 +.IP \[bu] Change which image in a WIM is bootable (\fBimagex info\fR) -.IP \[bu] 2 -Combine split WIMs into one WIM (\fBimage join\fR) -.IP \[bu] 2 -Split a WIM into multiple parts (\fBimage split\fR) -.IP \[bu] 2 +.IP \[bu] +Combine split WIMs into one stand-alone WIM (\fBimage join\fR) +.IP \[bu] +Split a stand-alone WIM into multiple parts (\fBimage split\fR) +.IP \[bu] Support for all WIM compression types, both compression and decompression (LZX, XPRESS, and none) -.IP \[bu] 2 -Integrity table -.IP \[bu] 2 -XML data (parsed and written using \fBlibxml\fR(3)) +.IP \[bu] +WIM integrity table is supported (\fB--check\fR option to many commands) +.IP \[bu] +WIM XML data (parsed and written using \fBlibxml\fR(3)) .SH UNSUPPORTED FEATURES As of version 1.0.0, wimlib supports capturing and applying WIMs directly from -NTFS and has much improved support for hard links and symbolic links. I don't -think there are many other features that would be worth it to implement; the -only significant thing missing (in my opinion) is that split WIMs need to be -handled better (e.g. it should be possible to apply a split WIM using \fBimagex -apply\fR). And if Microsoft updates the WIM format, I'd need to support it, but -it looks like the format for Windows 8 is the same as that of Windows 7. +NTFS and has much improved support for hard links and symbolic links. In +addition, you may now apply split WIMs and mount them read-only. I don't think +there are many other features that would be worth it to implement. Besides +porting the library to Windows (which I'm not really interested in), the main +thing that could use improvement (in my opinion) is that the LZX compression +ratio still isn't quite as good as Microsoft's version. Also, exporting an +image from a split WIM could be supported. Furthermore, if Microsoft updates +the WIM format, I'd need to support it, but it looks like the format for Windows +8 is the same as that of Windows 7. .SH DIFFERENCES FROM MICROSOFT IMAGEX @@ -101,7 +107,9 @@ Some features, such as the ability to keep files hard-linked across WIM images when they are extracted from a WIM, are not available in Microsoft's version of imagex. Also, doesn't seem to be an equivalent of \fBimagex join\fR in Microsoft's version; you would have to use \fBimagex.exe /export\fR, but that -doesn't let you export all images at once. +doesn't let you export all images at once. Furthermore, this version of +\fBimagex\fR lets you mount an image from a split WIM read-only, while +Microsoft's version does not. Microsoft's version has some weird limitations, like it won't let you extract a WIM on a shared folder, and it requires some commands to be run only from diff --git a/programs/imagex.c b/programs/imagex.c index 12bfbc62..07381a9b 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -56,23 +56,8 @@ enum imagex_op_type { UNMOUNT, }; -static const char *path_basename(const char *path) -{ - const char *p = path; - while (*p) - p++; - p--; - - /* Trailing slashes. */ - while ((p != path - 1) && *p == '/') - p--; - - while ((p != path - 1) && *p != '/') - p--; - - return p + 1; -} - +static void usage(int cmd_type); +static void usage_all(); static const char *usage_strings[] = { [APPEND] = @@ -82,7 +67,7 @@ static const char *usage_strings[] = { [APPLY] = " imagex apply WIMFILE [IMAGE_NUM | IMAGE_NAME | all]\n" " (DIRECTORY | NTFS_VOLUME) [--check] [--hardlink]\n" -" [--symlink] [--verbose]\n", +" [--symlink] [--verbose] [--ref=\"GLOB\"]\n", [CAPTURE] = " imagex capture (DIRECTORY | NTFS_VOLUME) WIMFILE [IMAGE_NAME]\n" " [DESCRIPTION] [--boot] [--check] [--compress=TYPE]\n" @@ -105,7 +90,8 @@ static const char *usage_strings[] = { " imagex join [--check] WIMFILE SPLIT_WIM...\n", [MOUNT] = " imagex mount WIMFILE (IMAGE_NUM | IMAGE_NAME) DIRECTORY\n" -" [--check] [--debug] [--streams-interface=INTERFACE]\n", +" [--check] [--debug] [--streams-interface=INTERFACE]\n" +" [--ref=\"GLOB\"]\n", [MOUNTRW] = " imagex mountrw WIMFILE [IMAGE_NUM | IMAGE_NAME] DIRECTORY\n" " [--check] [--debug] [--streams-interface=INTERFACE]\n", @@ -180,6 +166,7 @@ static const struct option mount_options[] = { {"check", no_argument, NULL, 'c'}, {"debug", no_argument, NULL, 'd'}, {"streams-interface", required_argument, NULL, 's'}, + {"ref", required_argument, NULL, 'r'}, {NULL, 0, NULL, 0}, }; @@ -195,6 +182,7 @@ static const struct option unmount_options[] = { }; + /* Print formatted error message to stderr. */ static void imagex_error(const char *format, ...) { @@ -218,40 +206,24 @@ static void imagex_error_with_errno(const char *format, ...) va_end(va); } - -static inline void version() +static const char *path_basename(const char *path) { - static const char *s = - "imagex (" PACKAGE ") " PACKAGE_VERSION "\n" - "Copyright (C) 2012 Eric Biggers\n" - "License GPLv3+; GNU GPL version 3 or later .\n" - "This is free software: you are free to change and redistribute it.\n" - "There is NO WARRANTY, to the extent permitted by law.\n" - "\n" - "Report bugs to "PACKAGE_BUGREPORT".\n"; - fputs(s, stdout); -} + const char *p = path; + while (*p) + p++; + p--; -static inline void usage(int cmd) -{ - puts("IMAGEX: Usage:"); - fputs(usage_strings[cmd], stdout); -} + /* Trailing slashes. */ + while ((p != path - 1) && *p == '/') + p--; -static void usage_all() -{ - puts("IMAGEX: Usage:"); - for (int i = 0; i < ARRAY_LEN(usage_strings); i++) - fputs(usage_strings[i], stdout); - static const char *extra = -" imagex --help\n" -" imagex --version\n" -"\n" -" The compression TYPE may be \"maximum\", \"fast\", or \"none\".\n" - ; - fputs(extra, stdout); + while ((p != path - 1) && *p != '/') + p--; + + return p + 1; } + static int verify_image_exists(int image) { if (image == WIM_NO_IMAGE) { @@ -333,6 +305,62 @@ out_fclose: return NULL; } +static int open_swms_from_glob(const char *swm_glob, + const char *first_part, + int open_flags, + WIMStruct ***additional_swms_ret, + unsigned *num_additional_swms_ret) +{ + unsigned num_additional_swms = 0; + WIMStruct **additional_swms = NULL; + glob_t globbuf; + int ret; + + ret = glob(swm_glob, GLOB_ERR | GLOB_NOSORT, NULL, &globbuf); + if (ret != 0) { + if (ret == GLOB_NOMATCH) { + imagex_error("Found no files for glob \"%s\"", + swm_glob); + } else { + imagex_error_with_errno("Failed to process glob " + "\"%s\"", swm_glob); + } + ret = -1; + goto out; + } + num_additional_swms = globbuf.gl_pathc; + additional_swms = calloc(num_additional_swms, sizeof(additional_swms[0])); + if (!additional_swms) { + imagex_error("Out of memory"); + ret = -1; + goto out_globfree; + } + size_t offset = 0; + for (size_t i = 0; i < num_additional_swms; i++) { + if (strcmp(globbuf.gl_pathv[i], first_part) == 0) { + offset++; + continue; + } + ret = wimlib_open_wim(globbuf.gl_pathv[i], + open_flags | WIMLIB_OPEN_FLAG_SPLIT_OK, + &additional_swms[i - offset]); + if (ret != 0) + goto out_close_swms; + } + *additional_swms_ret = additional_swms; + *num_additional_swms_ret = num_additional_swms - offset; + ret = 0; + goto out_globfree; +out_close_swms: + for (unsigned i = 0; i < num_additional_swms; i++) + wimlib_free(additional_swms[i]); + free(additional_swms); +out_globfree: + globfree(&globbuf); +out: + return ret; +} + static int imagex_append(int argc, const char **argv) { int c; @@ -459,8 +487,7 @@ static int imagex_apply(int argc, const char **argv) const char *swm_glob = NULL; WIMStruct **additional_swms = NULL; - size_t num_additional_swms = 0; - glob_t globbuf; + unsigned num_additional_swms = 0; for_opt(c, apply_options) { switch (c) { @@ -519,33 +546,11 @@ static int imagex_apply(int argc, const char **argv) } if (swm_glob) { - ret = glob(swm_glob, GLOB_ERR | GLOB_NOSORT, NULL, &globbuf); - if (ret != 0) { - imagex_error_with_errno("Failed to process glob " - "\"%s\"", swm_glob); - ret = -1; - goto out; - } - num_additional_swms = globbuf.gl_pathc; - additional_swms = calloc(num_additional_swms, sizeof(additional_swms[0])); - if (!additional_swms) { - imagex_error("Out of memory"); - ret = -1; + ret = open_swms_from_glob(swm_glob, wimfile, open_flags, + &additional_swms, + &num_additional_swms); + if (ret != 0) goto out; - } - size_t offset = 0; - for (size_t i = 0; i < num_additional_swms; i++) { - if (strcmp(globbuf.gl_pathv[i], wimfile) == 0) { - offset++; - continue; - } - ret = wimlib_open_wim(globbuf.gl_pathv[i], - open_flags | WIMLIB_OPEN_FLAG_SPLIT_OK, - &additional_swms[i - offset]); - if (ret != 0) - goto out; - } - num_additional_swms -= offset; } #ifdef WITH_NTFS_3G @@ -1242,13 +1247,17 @@ static int imagex_mount_rw_or_ro(int argc, const char **argv) { int c; int mount_flags = 0; - int open_flags = WIMLIB_OPEN_FLAG_SHOW_PROGRESS; + int open_flags = WIMLIB_OPEN_FLAG_SHOW_PROGRESS | + WIMLIB_OPEN_FLAG_SPLIT_OK; const char *wimfile; const char *dir; WIMStruct *w; int image; int num_images; int ret; + const char *swm_glob = NULL; + WIMStruct **additional_swms = NULL; + unsigned num_additional_swms = 0; if (strcmp(argv[0], "mountrw") == 0) mount_flags |= WIMLIB_MOUNT_FLAG_READWRITE; @@ -1272,6 +1281,9 @@ static int imagex_mount_rw_or_ro(int argc, const char **argv) goto mount_usage; } break; + case 'r': + swm_glob = optarg; + break; default: goto mount_usage; } @@ -1287,6 +1299,14 @@ static int imagex_mount_rw_or_ro(int argc, const char **argv) if (ret != 0) return ret; + if (swm_glob) { + ret = open_swms_from_glob(swm_glob, wimfile, open_flags, + &additional_swms, + &num_additional_swms); + if (ret != 0) + goto out; + } + if (argc == 2) { image = 1; num_images = wimlib_get_num_images(w); @@ -1296,7 +1316,7 @@ static int imagex_mount_rw_or_ro(int argc, const char **argv) usage((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) ? MOUNTRW : MOUNT); ret = WIMLIB_ERR_INVALID_IMAGE; - goto done; + goto out; } dir = argv[1]; } else { @@ -1306,16 +1326,20 @@ static int imagex_mount_rw_or_ro(int argc, const char **argv) ret = verify_image_exists_and_is_single(image); if (ret != 0) - goto done; + goto out; - ret = wimlib_mount(w, image, dir, mount_flags); + ret = wimlib_mount(w, image, dir, mount_flags, additional_swms, + num_additional_swms); if (ret != 0) { imagex_error("Failed to mount image %d from `%s' on `%s'", image, wimfile, dir); } -done: +out: wimlib_free(w); + if (additional_swms) + for (unsigned i = 0; i < num_additional_swms; i++) + wimlib_free(additional_swms[i]); return ret; mount_usage: usage((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) @@ -1390,6 +1414,10 @@ struct imagex_command { int cmd; }; + +#define for_imagex_command(p) for (p = &imagex_commands[0]; \ + p != &imagex_commands[ARRAY_LEN(imagex_commands)]; p++) + static struct imagex_command imagex_commands[] = { {"append", imagex_append, APPEND}, {"apply", imagex_apply, APPLY}, @@ -1405,8 +1433,19 @@ static struct imagex_command imagex_commands[] = { {"unmount", imagex_unmount, UNMOUNT}, }; -#define for_imagex_command(p) for (p = &imagex_commands[0]; \ - p != &imagex_commands[ARRAY_LEN(imagex_commands)]; p++) +static void version() +{ + static const char *s = + "imagex (" PACKAGE ") " PACKAGE_VERSION "\n" + "Copyright (C) 2012 Eric Biggers\n" + "License GPLv3+; GNU GPL version 3 or later .\n" + "This is free software: you are free to change and redistribute it.\n" + "There is NO WARRANTY, to the extent permitted by law.\n" + "\n" + "Report bugs to "PACKAGE_BUGREPORT".\n"; + fputs(s, stdout); +} + static void help_or_version(int argc, const char **argv) { @@ -1440,6 +1479,34 @@ static void help_or_version(int argc, const char **argv) } +static void usage(int cmd_type) +{ + struct imagex_command *cmd; + puts("IMAGEX: Usage:"); + fputs(usage_strings[cmd_type], stdout); + for_imagex_command(cmd) + if (cmd->cmd == cmd_type) + printf("\nTry `man imagex-%s' for more details.\n", + cmd->name); +} + +static void usage_all() +{ + puts("IMAGEX: Usage:"); + for (int i = 0; i < ARRAY_LEN(usage_strings); i++) + fputs(usage_strings[i], stdout); + static const char *extra = +" imagex --help\n" +" imagex --version\n" +"\n" +" The compression TYPE may be \"maximum\", \"fast\", or \"none\".\n" +"\n" +" Try `man imagex' for more information.\n" + ; + fputs(extra, stdout); +} + + int main(int argc, const char **argv) { struct imagex_command *cmd; diff --git a/src/join.c b/src/join.c index 3710eec8..07cbfa97 100644 --- a/src/join.c +++ b/src/join.c @@ -31,10 +31,11 @@ static int copy_lte_to_table(struct lookup_table_entry *lte, void *table) { struct lookup_table_entry *copy; - copy = new_lookup_table_entry(); + copy = MALLOC(sizeof(struct lookup_table_entry)); if (!copy) return WIMLIB_ERR_NOMEM; memcpy(copy, lte, sizeof(struct lookup_table_entry)); + INIT_LIST_HEAD(©->lte_group_list); lookup_table_insert(table, copy); return 0; } diff --git a/src/mount.c b/src/mount.c index 7d1ba199..6f50a4e5 100644 --- a/src/mount.c +++ b/src/mount.c @@ -1822,35 +1822,54 @@ static int check_lte_refcnt(struct lookup_table_entry *lte, void *ignore) /* Mounts a WIM file. */ WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir, - int flags) + int flags, WIMStruct **additional_swms, + unsigned num_additional_swms) { int argc = 0; char *argv[16]; int ret; char *p; + struct lookup_table *joined_tab, *wim_tab_save; DEBUG("Mount: wim = %p, image = %d, dir = %s, flags = %d, ", wim, image, dir, flags); - if (!dir) + if (!wim || !dir) return WIMLIB_ERR_INVALID_PARAM; + ret = verify_swm_set(wim, additional_swms, num_additional_swms); + if (ret != 0) + return ret; + + if (num_additional_swms) { + ret = new_joined_lookup_table(wim, additional_swms, + num_additional_swms, + &joined_tab); + if (ret != 0) + return ret; + wim_tab_save = wim->lookup_table; + wim->lookup_table = joined_tab; + } + ret = wimlib_select_image(wim, image); if (ret != 0) - return ret; + goto out; DEBUG("Selected image %d", image); next_link_group_id = assign_link_group_ids(wim->image_metadata[image - 1].lgt); + DEBUG("Resolving lookup table entries"); /* Resolve all the lookup table entries of the dentry tree */ for_dentry_in_tree(wim_root_dentry(wim), dentry_resolve_ltes, wim->lookup_table); + DEBUG("Checking lookup table entry reference counts"); + ret = for_lookup_table_entry(wim->lookup_table, check_lte_refcnt, NULL); if (ret != 0) - return ret; + goto out; if (flags & WIMLIB_MOUNT_FLAG_READWRITE) wim_get_current_image_metadata(wim)->modified = true; @@ -1860,16 +1879,33 @@ WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir, WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS))) flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR; + DEBUG("Getting current directory"); + mount_dir = dir; working_directory = getcwd(NULL, 0); if (!working_directory) { ERROR_WITH_ERRNO("Could not determine current directory"); - return WIMLIB_ERR_NOTDIR; + ret = WIMLIB_ERR_NOTDIR; + goto out; } + DEBUG("Closing POSIX message queues"); + /* XXX hack to get rid of the message queues if they already exist for + * some reason (maybe left over from a previous mount that wasn't + * unmounted correctly) */ + ret = open_message_queues(true); + if (ret != 0) + goto out; + close_message_queues(); + + DEBUG("Preparing arguments to fuse_main()"); + + p = STRDUP(dir); - if (!p) - return WIMLIB_ERR_NOMEM; + if (!p) { + ret = WIMLIB_ERR_NOMEM; + goto out; + } argv[argc++] = "imagex"; argv[argc++] = p; @@ -1893,7 +1929,8 @@ WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir, make_staging_dir(); if (!staging_dir_name) { FREE(p); - return WIMLIB_ERR_MKDIR; + ret = WIMLIB_ERR_MKDIR; + goto out; } } else { /* Read-only mount */ @@ -1919,8 +1956,14 @@ WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir, mount_flags = flags; ret = fuse_main(argc, argv, &wimfs_operations, NULL); - - return (ret == 0) ? 0 : WIMLIB_ERR_FUSE; + if (ret) + ret = WIMLIB_ERR_FUSE; +out: + if (num_additional_swms) { + free_lookup_table(wim->lookup_table); + wim->lookup_table = wim_tab_save; + } + return ret; } @@ -2060,7 +2103,8 @@ WIMLIBAPI int wimlib_unmount(const char *dir, int flags) } WIMLIBAPI int wimlib_mount(WIMStruct *wim_p, int image, const char *dir, - int flags) + int flags, WIMStruct **additional_swms, + unsigned num_additional_swms) { return mount_unsupported_error(); } diff --git a/src/wimlib.h b/src/wimlib.h index 0debc5c2..94a0f9d9 100644 --- a/src/wimlib.h +++ b/src/wimlib.h @@ -54,6 +54,8 @@ * but the LZX documentation is not entirely correct, and the WIM documentation * itself is very incomplete and is of unacceptable quality. * + * A WIM file may be either stand-alone or split into multiple parts. + * * \section winpe Windows PE * * A major use for this library is to create customized images of Windows PE, the @@ -612,7 +614,7 @@ extern int wimlib_export_image(WIMStruct *src_wim, int src_image, * @param num_additional_swms * Number of additional WIM parts provided in the @a additional_swms array. * This number should be one less than the total number of parts in the - * split WIM. + * split WIM. Set to 0 if the WIM is a standalone WIM. * * @return 0 on success; nonzero on error. * @retval ::WIMLIB_ERR_DECOMPRESSION @@ -869,6 +871,16 @@ extern int wimlib_join(const char **swms, unsigned num_swms, * ::WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR, or * ::WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS. The default interface is * the XATTR interface. + * @param additional_swms + * Array of pointers to the ::WIMStruct for each additional part in the + * split WIM. Ignored if @a num_additional_swms is 0. The pointers do not + * need to be in any particular order, but they must include all parts of + * the split WIM other than the first part, which must be provided in the + * @a wim parameter. + * @param num_additional_swms + * Number of additional WIM parts provided in the @a additional_swms array. + * This number should be one less than the total number of parts in the + * split WIM. Set to 0 if the WIM is a standalone WIM. * * @return 0 on success; nonzero on error. * @retval ::WIMLIB_ERR_DECOMPRESSION @@ -894,8 +906,18 @@ extern int wimlib_join(const char **swms, unsigned num_swms, * @retval ::WIMLIB_ERR_READ * An unexpected end-of-file or read error occurred when trying to read * data from the WIM file associated with @a wim. + * @retval ::WIMLIB_ERR_SPLIT_INVALID + * The WIM is a split WIM, but the parts specified do not form a complete + * split WIM because they do not include all the parts of the original WIM, + * there are duplicate parts, or not all the parts have the same GUID and + * compression type. + * @retval ::WIMLIB_ERR_SPLIT_UNSUPPORTED + * The WIM is a split WIM and a read-write mount was requested. We only + * support mounting a split WIM read-only. */ -extern int wimlib_mount(WIMStruct *wim, int image, const char *dir, int flags); +extern int wimlib_mount(WIMStruct *wim, int image, const char *dir, int flags, + WIMStruct **additional_swms, + unsigned num_additional_swms); /** * Opens a WIM file and creates a ::WIMStruct for it.