]> wimlib.net Git - wimlib/commitdiff
Export from split WIM
authorEric Biggers <ebiggers3@gmail.com>
Sat, 1 Sep 2012 03:04:46 +0000 (22:04 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Sat, 1 Sep 2012 03:04:46 +0000 (22:04 -0500)
doc/imagex-export.1.in
programs/imagex.c
src/join.c
src/lookup_table.h
src/modify.c
src/wimlib.h

index d455e9d140a32194ab4effb295de50e15e0d6804..e80a5d13b67529058f886d2c0f0dbc37ea88523d 100644 (file)
@@ -29,6 +29,10 @@ If given, \fIDEST_IMAGE_DESCRIPTION\fR specifies the description to give the
 image being exported to \fIDEST_WIMFILE\fR.  The default is its description in
 \fISRC_WIMFILE\fR.
 
 image being exported to \fIDEST_WIMFILE\fR.  The default is its description in
 \fISRC_WIMFILE\fR.
 
+\fBimagex export\fR supports exporting images from stand-alone WIMs as well as
+from split WIMs.  However, you cannot export an image to a split WIM.  See
+\fBSPLIT WIMS\fR.
+
 .SH OPTIONS
 .TP 6
 \fB--boot\fR
 .SH OPTIONS
 .TP 6
 \fB--boot\fR
@@ -56,16 +60,50 @@ compression type must be the same as that of \fIDEST_WIMFILE\fR.
 You may also specify the actual names of the compression algorithms, "XPRESS"
 and "LZX", instead of "fast" and "maximum", respectively.
 
 You may also specify the actual names of the compression algorithms, "XPRESS"
 and "LZX", instead of "fast" and "maximum", respectively.
 
-.SH NOTES
+.TP
+\fB--ref\fR="\fIGLOB\fR"
+File glob of additional split WIM parts that are part of the split WIM being
+exported.  See \fBSPLIT_WIMS\fR.
+
+.SH SPLIT WIMS
+
+You may use \fBimagex export\fR to export images from a split WIM.  The
+\fISRC_WIMFILE\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 \fISRC_WIMFILE\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
 
 
-\fBimagex export\fR does not yet support split WIMs.
+To export the first image of this split WIM to a new or existing WIM file
+"other.wim", run:
+.PP
+.RS
+imagex export mywim.swm 1 other.wim --ref="mywim*.swm"
+.RE
+.PP
 
 .SH EXAMPLES
 
 .SH EXAMPLES
-Export the second image of 'boot.wim' to the new WIM file 'image2.wim', and
+Export the second image of 'boot.wim' to the new WIM file 'new.wim', and
 change the compression type to maximum, if it wasn't maximum already:
 .RS
 .PP
 change the compression type to maximum, if it wasn't maximum already:
 .RS
 .PP
-image export boot.wim 2 image2.wim --compress=maximum
+image export boot.wim 2 new.wim --compress=maximum
 .RE
 .PP
 
 .RE
 .PP
 
index 07381a9bf5752bf2f2642ceeb1e31e2b05920cee..fac692f054028fd8f32e0e70fd89249fcf311f82 100644 (file)
@@ -81,7 +81,7 @@ static const char *usage_strings[] = {
 "    imagex export SRC_WIMFILE (SRC_IMAGE_NUM | SRC_IMAGE_NAME | all ) \n"
 "                  DEST_WIMFILE [DEST_IMAGE_NAME]\n"
 "                  [DEST_IMAGE_DESCRIPTION] [--boot] [--check]\n"
 "    imagex export SRC_WIMFILE (SRC_IMAGE_NUM | SRC_IMAGE_NAME | all ) \n"
 "                  DEST_WIMFILE [DEST_IMAGE_NAME]\n"
 "                  [DEST_IMAGE_DESCRIPTION] [--boot] [--check]\n"
-"                  [--compress=TYPE]\n",
+"                  [--compress=TYPE] [--ref=\"GLOB\"]\n",
 [INFO] = 
 "    imagex info WIMFILE [IMAGE_NUM | IMAGE_NAME] [NEW_NAME]\n"
 "                [NEW_DESC] [--boot] [--check] [--header] [--lookup-table]\n"
 [INFO] = 
 "    imagex info WIMFILE [IMAGE_NUM | IMAGE_NAME] [NEW_NAME]\n"
 "                [NEW_DESC] [--boot] [--check] [--header] [--lookup-table]\n"
@@ -143,6 +143,7 @@ static const struct option export_options[] = {
        {"boot",       no_argument,       NULL, 'b'},
        {"check",      no_argument,       NULL, 'c'},
        {"compress",   required_argument, NULL, 'x'},
        {"boot",       no_argument,       NULL, 'b'},
        {"check",      no_argument,       NULL, 'c'},
        {"compress",   required_argument, NULL, 'x'},
+       {"ref",        required_argument, NULL, 'r'},
        {NULL, 0, NULL, 0},
 };
 
        {NULL, 0, NULL, 0},
 };
 
@@ -851,6 +852,9 @@ static int imagex_export(int argc, const char **argv)
        int image;
        struct stat stbuf;
        bool wim_is_new;
        int image;
        struct stat stbuf;
        bool wim_is_new;
+       const char *swm_glob = NULL;
+       WIMStruct **additional_swms = NULL;
+       unsigned num_additional_swms = 0;
 
        for_opt(c, export_options) {
                switch (c) {
 
        for_opt(c, export_options) {
                switch (c) {
@@ -867,6 +871,9 @@ static int imagex_export(int argc, const char **argv)
                                return -1;
                        compression_type_specified = true;
                        break;
                                return -1;
                        compression_type_specified = true;
                        break;
+               case 'r':
+                       swm_glob = optarg;
+                       break;
                default:
                        usage(EXPORT);
                        return -1;
                default:
                        usage(EXPORT);
                        return -1;
@@ -883,7 +890,8 @@ static int imagex_export(int argc, const char **argv)
        dest_wimfile          = argv[2];
        dest_name             = (argc >= 4) ? argv[3] : NULL;
        dest_desc             = (argc >= 5) ? argv[4] : NULL;
        dest_wimfile          = argv[2];
        dest_name             = (argc >= 4) ? argv[3] : NULL;
        dest_desc             = (argc >= 5) ? argv[4] : NULL;
-       ret = wimlib_open_wim(src_wimfile, open_flags, &src_w);
+       ret = wimlib_open_wim(src_wimfile,
+                             open_flags | WIMLIB_OPEN_FLAG_SPLIT_OK, &src_w);
        if (ret != 0)
                return ret;
 
        if (ret != 0)
                return ret;
 
@@ -896,11 +904,11 @@ static int imagex_export(int argc, const char **argv)
                if (!S_ISREG(stbuf.st_mode) && !S_ISLNK(stbuf.st_mode)) {
                        imagex_error("`%s' is not a regular file",
                                        dest_wimfile);
                if (!S_ISREG(stbuf.st_mode) && !S_ISLNK(stbuf.st_mode)) {
                        imagex_error("`%s' is not a regular file",
                                        dest_wimfile);
-                       goto done;
+                       goto out;
                }
                ret = wimlib_open_wim(dest_wimfile, open_flags, &dest_w);
                if (ret != 0)
                }
                ret = wimlib_open_wim(dest_wimfile, open_flags, &dest_w);
                if (ret != 0)
-                       goto done;
+                       goto out;
 
                if (compression_type_specified && compression_type != 
                                wimlib_get_compression_type(dest_w)) {
 
                if (compression_type_specified && compression_type != 
                                wimlib_get_compression_type(dest_w)) {
@@ -908,7 +916,7 @@ static int imagex_export(int argc, const char **argv)
                                     "not the same as that used in the "
                                     "destination WIM");
                        ret = -1;
                                     "not the same as that used in the "
                                     "destination WIM");
                        ret = -1;
-                       goto done;
+                       goto out;
                }
                compression_type = wimlib_get_compression_type(dest_w);
        } else {
                }
                compression_type = wimlib_get_compression_type(dest_w);
        } else {
@@ -917,23 +925,32 @@ static int imagex_export(int argc, const char **argv)
                if (errno == ENOENT) {
                        ret = wimlib_create_new_wim(compression_type, &dest_w);
                        if (ret != 0)
                if (errno == ENOENT) {
                        ret = wimlib_create_new_wim(compression_type, &dest_w);
                        if (ret != 0)
-                               goto done;
+                               goto out;
                } else {
                        imagex_error_with_errno("Cannot stat file `%s'",
                                                dest_wimfile);
                } else {
                        imagex_error_with_errno("Cannot stat file `%s'",
                                                dest_wimfile);
-                       goto done;
+                       goto out;
                }
        }
 
        image = wimlib_resolve_image(src_w, src_image_num_or_name);
        ret = verify_image_exists(image);
        if (ret != 0)
                }
        }
 
        image = wimlib_resolve_image(src_w, src_image_num_or_name);
        ret = verify_image_exists(image);
        if (ret != 0)
-               goto done;
+               goto out;
+
+       if (swm_glob) {
+               ret = open_swms_from_glob(swm_glob, src_wimfile, open_flags,
+                                         &additional_swms,
+                                         &num_additional_swms);
+               if (ret != 0)
+                       goto out;
+       }
 
        ret = wimlib_export_image(src_w, image, dest_w, dest_name, dest_desc, 
 
        ret = wimlib_export_image(src_w, image, dest_w, dest_name, dest_desc, 
-                                 export_flags);
+                                 export_flags, additional_swms,
+                                 num_additional_swms);
        if (ret != 0)
        if (ret != 0)
-               goto done;
+               goto out;
 
 
        if (wim_is_new)
 
 
        if (wim_is_new)
@@ -941,9 +958,12 @@ static int imagex_export(int argc, const char **argv)
                                   write_flags);
        else
                ret = wimlib_overwrite(dest_w, write_flags);
                                   write_flags);
        else
                ret = wimlib_overwrite(dest_w, write_flags);
-done:
+out:
        wimlib_free(src_w);
        wimlib_free(dest_w);
        wimlib_free(src_w);
        wimlib_free(dest_w);
+       if (additional_swms)
+               for (unsigned i = 0; i < num_additional_swms; i++)
+                       wimlib_free(additional_swms[i]);
        return ret;
 }
 
        return ret;
 }
 
index 07cbfa971c92622b08eb72df6b39e9d26e18524a..a1639e3627bb8641b9a87394b8c1bf13f3e8afe7 100644 (file)
@@ -138,6 +138,21 @@ int verify_swm_set(WIMStruct *w, WIMStruct **additional_swms,
        return 0;
 }
 
        return 0;
 }
 
+/* 
+ * Joins lookup tables from the parts of a split WIM.
+ *
+ * @w specifies the first part, while @additional_swms and @num_additional_swms
+ * specify an array of points to the WIMStruct's for additional split WIM parts.
+ *
+ * On success, 0 is returned on a pointer to the joined lookup table is returned
+ * in @table_ret.
+ *
+ * The reason we join the lookup tables is so:
+ *     - We only have to search one lookup table to find the location of a
+ *     resource in the entire split WIM.
+ *     - Each lookup table entry will have a pointer to its split WIM part (and
+ *     a part number field, although we don't really use it).
+ */
 int new_joined_lookup_table(WIMStruct *w,
                            WIMStruct **additional_swms,
                            unsigned num_additional_swms,
 int new_joined_lookup_table(WIMStruct *w,
                            WIMStruct **additional_swms,
                            unsigned num_additional_swms,
index f0ee25b78f2d89761352afaa4860a39e1f783312..6fc5ae50c3f5f37439ca191f01d4fc3ef3ba0105 100644 (file)
@@ -41,55 +41,97 @@ struct ntfs_location {
  *
  * It is used to find data streams for files in the WIM. 
  *
  *
  * It is used to find data streams for files in the WIM. 
  *
- * The lookup_table_entry for a given dentry in the WIM is found using the SHA1
- * message digest field. 
+ * Metadata resources and reparse point data buffers will also have lookup table
+ * entries associated with the data.
+ *
+ * The lookup_table_entry for a given dentry or alternate stream entry in the
+ * WIM is found using the SHA1 message digest field. 
  */
 struct lookup_table_entry {
 
        /* List of lookup table entries in this hash bucket */
        struct hlist_node hash_list;
 
  */
 struct lookup_table_entry {
 
        /* List of lookup table entries in this hash bucket */
        struct hlist_node hash_list;
 
-       /* @resource_entry is read from the lookup table in the WIM
-        * file; it says where to find the file resource in the WIM
-        * file, and whether it is compressed or not. */
+       /* Location and size of the stream in the WIM, whether it is compressed
+        * or not, and whether it's a metadata resource or not.  This is an
+        * on-disk field. */
        struct resource_entry resource_entry;
 
        struct resource_entry resource_entry;
 
-       /* Currently ignored; set to 1 in new lookup table entries. */
+       /* Specifies which part of the split WIM the resource is located in.
+        * This is on on-disk field.
+        *
+        * In stand-alone WIMs, this must be 1.
+        *
+        * In split WIMs, every split WIM part has its own lookup table, and in
+        * read_lookup_table() it's currently expected that the part number of
+        * each lookup table entry in a split WIM part's lookup table is the
+        * same as the part number of that split WIM part.  So this makes this
+        * field redundant since we store a pointer to the corresponding
+        * WIMStruct in the lookup table entry anyway.
+        */
        u16 part_number;
 
        u16 part_number;
 
-       /* If %true, this lookup table entry corresponds to a symbolic link
-        * reparse buffer.  @symlink_reparse_data_buf will give the target of
-        * the symbolic link. */
+       /* An enumerated type that identifies where the stream corresponding to
+        * this lookup table entry is actually located.
+        *
+        * Obviously if we open a WIM and read its lookup table, the location is
+        * set to RESOURCE_IN_WIM since all the streams will initially be
+        * located in the WIM.  However, to deal with problems such as image
+        * capture and image mount, we allow the actual location of the stream
+        * to be somewhere else, such as an external file.
+        */
        enum {
        enum {
+               /* The lookup table entry does not correspond to a stream (this
+                * state should exist only temporarily) */
                RESOURCE_NONEXISTENT = 0,
                RESOURCE_NONEXISTENT = 0,
+
+               /* The stream resource is located in a WIM file.  The WIMStruct
+                * for the WIM file will be pointed to by the @wim member. */
                RESOURCE_IN_WIM,
                RESOURCE_IN_WIM,
+
+               /* The stream resource is located in an external file.  The
+                * name of the file will be provided by @file_on_disk member.
+                * In addition, if @file_on_disk_fp is not NULL, it will be an
+                * open FILE * to the file. */
                RESOURCE_IN_FILE_ON_DISK,
                RESOURCE_IN_FILE_ON_DISK,
+
+               /* The stream resource is located in an external file in the
+                * staging directory for a read-write mount.  */
                RESOURCE_IN_STAGING_FILE,
                RESOURCE_IN_STAGING_FILE,
+
+               /* The stream resource is directly attached in an in-memory
+                * buffer pointed to by @attached_buffer. */
                RESOURCE_IN_ATTACHED_BUFFER,
                RESOURCE_IN_ATTACHED_BUFFER,
+
+               /* The stream resource is located in an NTFS volume.  It is
+                * identified by volume, filename, data stream name, and by
+                * whether it is a reparse point or not. @ntfs_loc points to a
+                * structure containing this information. */
                RESOURCE_IN_NTFS_VOLUME,
        } resource_location;
 
                RESOURCE_IN_NTFS_VOLUME,
        } resource_location;
 
-       /* Number of times this lookup table entry is referenced by dentries. */
+       /* (On-disk field)
+        * Number of times this lookup table entry is referenced by dentries.
+        * Unfortunately, this field is not always set correctly in Microsoft's
+        * WIMs, so we have no choice but to fix it if more references to the
+        * lookup table entry are found than stated here. */
        u32 refcnt;
 
        union {
        u32 refcnt;
 
        union {
-               /* SHA1 hash of the file resource pointed to by this lookup
-                * table entry */
+               /* (On-disk field) SHA1 message digest of the stream referenced
+                * by this lookup table entry */
                u8  hash[SHA1_HASH_SIZE];
 
                u8  hash[SHA1_HASH_SIZE];
 
-               /* First 4 or 8 bytes of the SHA1 hash, used for inserting the
-                * entry into the hash table.  Since the SHA1 hashes can be
-                * considered random, we don't really need the full 20 byte hash
-                * just to insert the entry in a hash table. */
+               /* First 4 or 8 bytes of the SHA1 message digest, used for
+                * inserting the entry into the hash table.  Since the SHA1
+                * message digest can be considered random, we don't really need
+                * the full 20 byte hash just to insert the entry in a hash
+                * table. */
                size_t hash_short;
        };
 
                size_t hash_short;
        };
 
-       /* If @file_on_disk != NULL, the file resource indicated by this lookup
-        * table entry is not in the WIM file, but rather a file on disk; this
-        * occurs for files that are added to the WIM.  In that case,
-        * file_on_disk is the name of the file in the outside filesystem.  
-        * It will not be compressed, and its size will be given by
-        * resource_entry.size and resource_entry.original_size. */
+       /* Pointers to somewhere where the stream is actually located.  See the
+        * comments for the @resource_location field above. */
        union {
                WIMStruct *wim;
                char *file_on_disk;
        union {
                WIMStruct *wim;
                char *file_on_disk;
@@ -100,14 +142,25 @@ struct lookup_table_entry {
        #endif
        };
        union {
        #endif
        };
        union {
+               /* Temporary field for creating a singly linked list.  Shouldn't
+                * really be here */
                struct lookup_table_entry *next_lte_in_swm;
                struct lookup_table_entry *next_lte_in_swm;
+
+               /* @file_on_disk_fp and @attr are both used to cache file/stream
+                * handles so we don't have re-open them on every read */
                FILE *file_on_disk_fp;
        #ifdef WITH_NTFS_3G
                struct _ntfs_attr *attr;
        #endif
        };
 #ifdef WITH_FUSE
                FILE *file_on_disk_fp;
        #ifdef WITH_NTFS_3G
                struct _ntfs_attr *attr;
        #endif
        };
 #ifdef WITH_FUSE
-       /* File descriptors table for this data stream */
+       /* File descriptors table for this data stream.  This is used if the WIM
+        * is mounted.  Basically, each time a file is open()ed, a new file
+        * descriptor is added here, and each time a file is close()ed, the file
+        * descriptor is gotten rid of.  If the stream is opened for writing, it
+        * will be extracted to the staging directory and there will be an
+        * actual native file descriptor associated with each "wimlib file
+        * descriptor". */
        u16 num_opened_fds;
        u16 num_allocated_fds;
        struct wimlib_fd **fds;
        u16 num_opened_fds;
        u16 num_allocated_fds;
        struct wimlib_fd **fds;
@@ -115,22 +168,31 @@ struct lookup_table_entry {
 
        /* When a WIM file is written, out_refcnt starts at 0 and is incremented
         * whenever the file resource pointed to by this lookup table entry
 
        /* When a WIM file is written, out_refcnt starts at 0 and is incremented
         * whenever the file resource pointed to by this lookup table entry
-        * needs to be written.  Naturally, the file resource only need to be
-        * written when out_refcnt is 0.  Incrementing it further is needed to
-        * find the correct reference count to write to the lookup table in the
-        * output file, which may be less than the regular refcnt if not all
-        * images in the WIM file are written. 
-        *
-        * output_resource_entry is the struct resource_entry for the position of the
-        * file resource when written to the output file. */
+        * needs to be written.  The file resource only need to be written when
+        * out_refcnt is nonzero, since otherwise it is not referenced by any
+        * dentries. */
        u32 out_refcnt;
        u32 out_refcnt;
+
        union {
        union {
+               /* When a WIM file is written, @output_resource_entry is filled
+                * in with the resource entry for the output WIM.  This will not
+                * necessarily be the same as the @resource_entry since:
+                *      - The stream may have a different offset in the new WIM
+                *      - The stream may have a different compressed size in the
+                *      new WIM if the compression type changed
+                */
                struct resource_entry output_resource_entry;
                struct resource_entry output_resource_entry;
+
+               /* This field is used for the special hardlink or symlink image
+                * application mode.   In these mode, all identical files are
+                * linked together, and @extracted_file will be set to the
+                * filename of the first extracted file containing this stream.
+                * */
                char *extracted_file;
        };
 
        /* Circular linked list of streams that share the same lookup table
                char *extracted_file;
        };
 
        /* Circular linked list of streams that share the same lookup table
-        * entry
+        * entry.
         * 
         * This list of streams may include streams from different hard link
         * sets that happen to be the same.  */
         * 
         * This list of streams may include streams from different hard link
         * sets that happen to be the same.  */
index 5223b81912c5abde8943a9d2c85023ca814029cd..8519881d2b95f613ae2f06a71bd6e35d79ffbc22 100644 (file)
@@ -267,16 +267,12 @@ static int add_lte_to_dest_wim(struct dentry *dentry, void *arg)
                if (dest_lte) {
                        dest_lte->refcnt++;
                } else {
                if (dest_lte) {
                        dest_lte->refcnt++;
                } else {
-                       dest_lte = new_lookup_table_entry();
+                       dest_lte = MALLOC(sizeof(struct lookup_table_entry));
                        if (!dest_lte)
                                return WIMLIB_ERR_NOMEM;
                        if (!dest_lte)
                                return WIMLIB_ERR_NOMEM;
-                       dest_lte->resource_location = RESOURCE_IN_WIM;
-                       dest_lte->wim = src_wim;
-                       memcpy(&dest_lte->resource_entry, 
-                              &src_lte->resource_entry, 
-                              sizeof(struct resource_entry));
-                       copy_hash(dest_lte->hash,
-                                 dentry_stream_hash_unresolved(dentry, i));
+                       memcpy(dest_lte, src_lte, sizeof(struct lookup_table_entry));
+                       dest_lte->part_number = 1;
+                       dest_lte->refcnt = 1;
                        lookup_table_insert(dest_wim->lookup_table, dest_lte);
                }
        }
                        lookup_table_insert(dest_wim->lookup_table, dest_lte);
                }
        }
@@ -356,19 +352,22 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
                                  WIMStruct *dest_wim, 
                                  const char *dest_name, 
                                  const char *dest_description, 
                                  WIMStruct *dest_wim, 
                                  const char *dest_name, 
                                  const char *dest_description, 
-                                 int flags)
+                                 int flags,
+                                 WIMStruct **additional_swms,
+                                 unsigned num_additional_swms)
 {
        int i;
        int ret;
        struct dentry *root;
        struct wim_pair wims;
        struct wim_security_data *sd;
 {
        int i;
        int ret;
        struct dentry *root;
        struct wim_pair wims;
        struct wim_security_data *sd;
+       struct lookup_table *joined_tab, *src_wim_tab_save;
 
        if (!src_wim || !dest_wim)
                return WIMLIB_ERR_INVALID_PARAM;
 
 
        if (!src_wim || !dest_wim)
                return WIMLIB_ERR_INVALID_PARAM;
 
-       if (src_wim->hdr.total_parts != 1 || src_wim->hdr.total_parts != 1) {
-               ERROR("Exporting an image to or from a split WIM is "
+       if (dest_wim->hdr.total_parts != 1) {
+               ERROR("Exporting an image to a split WIM is "
                      "unsupported");
                return WIMLIB_ERR_SPLIT_UNSUPPORTED;
        }
                      "unsupported");
                return WIMLIB_ERR_SPLIT_UNSUPPORTED;
        }
@@ -406,7 +405,9 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
                                ret = wimlib_export_image(src_wim, i, dest_wim, 
                                                          NULL,
                                                          dest_description,
                                ret = wimlib_export_image(src_wim, i, dest_wim, 
                                                          NULL,
                                                          dest_description,
-                                                         export_flags);
+                                                         export_flags,
+                                                         additional_swms,
+                                                         num_additional_swms);
                                if (ret != 0)
                                        return ret;
                        }
                                if (ret != 0)
                                        return ret;
                        }
@@ -416,13 +417,6 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
                }
        }
 
                }
        }
 
-       ret = wimlib_select_image(src_wim, src_image);
-       if (ret != 0) {
-               ERROR("Could not select image %d from the WIM `%s' "
-                     "to export it", src_image, src_wim->filename);
-               return ret;
-       }
-
        if (!dest_name) {
                dest_name = wimlib_get_image_name(src_wim, src_image);
                DEBUG("Using name `%s' for source image %d",
        if (!dest_name) {
                dest_name = wimlib_get_image_name(src_wim, src_image);
                DEBUG("Using name `%s' for source image %d",
@@ -437,12 +431,32 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
                return WIMLIB_ERR_IMAGE_NAME_COLLISION;
        }
 
                return WIMLIB_ERR_IMAGE_NAME_COLLISION;
        }
 
+       ret = verify_swm_set(src_wim, additional_swms, num_additional_swms);
+       if (ret != 0)
+               return ret;
+
+       if (num_additional_swms) {
+               ret = new_joined_lookup_table(src_wim, additional_swms,
+                                             num_additional_swms,
+                                             &joined_tab);
+               if (ret != 0)
+                       return ret;
+               src_wim_tab_save = src_wim->lookup_table;
+               src_wim->lookup_table = joined_tab;
+       }
+
+       ret = wimlib_select_image(src_wim, src_image);
+       if (ret != 0) {
+               ERROR("Could not select image %d from the WIM `%s' "
+                     "to export it", src_image, src_wim->filename);
+               goto out;
+       }
 
        /* Cleaning up here on failure would be hard.  For example, we could
         * fail to allocate memory in add_lte_to_dest_wim(),
         * leaving the lookup table entries in the destination WIM in an
         * inconsistent state.  Until these issues can be resolved,
 
        /* Cleaning up here on failure would be hard.  For example, we could
         * fail to allocate memory in add_lte_to_dest_wim(),
         * leaving the lookup table entries in the destination WIM in an
         * inconsistent state.  Until these issues can be resolved,
-        * wimlib_export_image() is documented as leaving dest_wim is an
+        * wimlib_export_image() is documented as leaving dest_wim in an
         * indeterminate state.  */
        root = wim_root_dentry(src_wim);
        sd = wim_security_data(src_wim);
         * indeterminate state.  */
        root = wim_root_dentry(src_wim);
        sd = wim_security_data(src_wim);
@@ -451,10 +465,10 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
        wims.dest_wim = dest_wim;
        ret = for_dentry_in_tree(root, add_lte_to_dest_wim, &wims);
        if (ret != 0)
        wims.dest_wim = dest_wim;
        ret = for_dentry_in_tree(root, add_lte_to_dest_wim, &wims);
        if (ret != 0)
-               return ret;
+               goto out;
        ret = add_new_dentry_tree(dest_wim, root, sd);
        if (ret != 0)
        ret = add_new_dentry_tree(dest_wim, root, sd);
        if (ret != 0)
-               return ret;
+               goto out;
        sd->refcnt++;
 
        if (flags & WIMLIB_EXPORT_FLAG_BOOT) {
        sd->refcnt++;
 
        if (flags & WIMLIB_EXPORT_FLAG_BOOT) {
@@ -462,8 +476,14 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
                dest_wim->hdr.boot_idx = dest_wim->hdr.image_count;
        }
 
                dest_wim->hdr.boot_idx = dest_wim->hdr.image_count;
        }
 
-       return xml_export_image(src_wim->wim_info, src_image, &dest_wim->wim_info,
-                               dest_name, dest_description);
+       ret = xml_export_image(src_wim->wim_info, src_image, &dest_wim->wim_info,
+                              dest_name, dest_description);
+out:
+       if (num_additional_swms) {
+               free_lookup_table(src_wim->lookup_table);
+               src_wim->lookup_table = src_wim_tab_save;
+       }
+       return ret;
 }
 
 /* 
 }
 
 /* 
index 94a0f9d994595956fc428b4691f615d0d579e002..05681b3a5c7b8420463174d7f1a27d24296679bb 100644 (file)
@@ -514,8 +514,8 @@ extern int wimlib_delete_image(WIMStruct *wim, int image);
  * Copies an image, or all the images, from a WIM file, into another WIM file.
  *
  * @param src_wim
  * Copies an image, or all the images, from a WIM file, into another WIM file.
  *
  * @param src_wim
- *     Pointer to the ::WIMStruct for a WIM file that contains the image(s)
- *     being exported.
+ *     Pointer to the ::WIMStruct for a stand-alone WIM or part 1 of a split
+ *     WIM that contains the image(s) being exported.
  * @param src_image
  *     The image to export from @a src_wim.  Can be the number of an image, or
  *     ::WIM_ALL_IMAGES to export all images.
  * @param src_image
  *     The image to export from @a src_wim.  Can be the number of an image, or
  *     ::WIM_ALL_IMAGES to export all images.
@@ -541,6 +541,16 @@ extern int wimlib_delete_image(WIMStruct *wim, int image);
  *     ::WIMLIB_EXPORT_FLAG_BOOT is valid only if one of the exported images is
  *     currently marked as bootable in @a src_wim; if that is the case, then
  *     that image is marked as bootable in the destination WIM.
  *     ::WIMLIB_EXPORT_FLAG_BOOT is valid only if one of the exported images is
  *     currently marked as bootable in @a src_wim; if that is the case, then
  *     that image is marked as bootable in the destination WIM.
+ * @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.  On error, @dest_wim is left in an
  * indeterminate state and should be freed with wimlib_free().
  *
  * @return 0 on success; nonzero on error.  On error, @dest_wim is left in an
  * indeterminate state and should be freed with wimlib_free().
@@ -570,13 +580,20 @@ extern int wimlib_delete_image(WIMStruct *wim, int image);
  *     Failed to allocate needed memory.
  * @retval ::WIMLIB_ERR_READ
  *     Could not read the metadata resource for @a src_image from @a src_wim.
  *     Failed to allocate needed memory.
  * @retval ::WIMLIB_ERR_READ
  *     Could not read the metadata resource for @a src_image from @a src_wim.
+ * @retval ::WIMLIB_ERR_SPLIT_INVALID
+ *     The source 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
  * @retval ::WIMLIB_ERR_SPLIT_UNSUPPORTED
- *     @a src_wim or @a dest_wim is part of a split WIM.  Exporting an image
- *     from or to a split WIM is unsupported.
+ *     @a dest_wim is part of a split WIM.  Exporting an image to a split WIM
+ *     is unsupported.
  */
 extern int wimlib_export_image(WIMStruct *src_wim, int src_image, 
                               WIMStruct *dest_wim, const char *dest_name, 
  */
 extern int wimlib_export_image(WIMStruct *src_wim, int src_image, 
                               WIMStruct *dest_wim, const char *dest_name, 
-                              const char *dest_description, int flags);
+                              const char *dest_description, int flags,
+                              WIMStruct **additional_swms,
+                              unsigned num_additional_swms);
 
 /**
  * Extracts an image, or all images, from a standalone or split WIM file.
 
 /**
  * Extracts an image, or all images, from a standalone or split WIM file.