Split WIM mount and split WIM documentation
authorEric Biggers <ebiggers3@gmail.com>
Sat, 1 Sep 2012 01:31:02 +0000 (20:31 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Sat, 1 Sep 2012 01:31:02 +0000 (20:31 -0500)
README
doc/imagex-apply.1.in
doc/imagex-mount.1.in
doc/imagex.1.in
programs/imagex.c
src/join.c
src/mount.c
src/wimlib.h

diff --git a/README b/README
index c0dadaad14a2d6e847db1fae164d534c35768a98..91deb1c064ff4ad895e2647b0512c6231d523b31 100644 (file)
--- 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
index 06caf05e9bf5deb86b3f03dfc997e8094d1d1c72..e9dd4684fd6a663daae20fb0ba6ba3e5d5387b25 100644 (file)
@@ -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
index 3f5eb4a6b6fe69994cea0ed296920d2bd09f5120..2518f3502c0a3cc7ee3e0c11812a6f5baf7bf1c7 100644 (file)
@@ -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
index 1352ce77a489e9ad83c8394930e37cd8c44b2aa6..263b2c964849a37076674d30f721d09bd201d088 100644 (file)
@@ -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
index 12bfbc6201e888c839073c2611adc0266e7674af..07381a9bf5752bf2f2642ceeb1e31e2b05920cee 100644 (file)
@@ -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 <http://gnu.org/licenses/gpl.html>.\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 <http://gnu.org/licenses/gpl.html>.\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;
index 3710eec85ec72ec02fee1bae2d857cf328fd79b2..07cbfa971c92622b08eb72df6b39e9d26e18524a 100644 (file)
 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(&copy->lte_group_list);
        lookup_table_insert(table, copy);
        return 0;
 }
index 7d1ba19970eac069684f6c9018b8d72add308da4..6f50a4e5931d5d2b59a8dace45422edb7fb92b23 100644 (file)
@@ -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();
 }
index 0debc5c249e03feea012b3747aab3564dd17ad30..94a0f9d994595956fc428b4691f615d0d579e002 100644 (file)
@@ -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.