]> wimlib.net Git - wimlib/commitdiff
Generalized support for referencing resources in external WIMs
authorEric Biggers <ebiggers3@gmail.com>
Tue, 20 Aug 2013 00:17:36 +0000 (19:17 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Tue, 20 Aug 2013 00:28:38 +0000 (19:28 -0500)
In preparation for supporting "delta" WIMs, this commit generalizes the library
interface for handling split WIMs.

Instead of cluttering up various functions with additional split WIM parameters,
there is now a function wimlib_reference_resource_files() available that can
load additional resources (e.g. from a split WIM part) into a WIMStruct that has
metadata available (e.g. the first part of a split WIM, or a standalone WIM).

wimlib_reference_resource_files() can handle file globbing by itself, so it
actually makes it easier for library users to process split WIMs.

Lower-level APIs wimlib_reference_resources() and wimlib_unreference_resources()
are also provided, but not yet used directly by `wimlib-imagex'.

Some instances of WIMLIB_ERR_SPLIT_UNSUPPORTED error returns were changed to
the new error code WIMLIB_ERR_METADATA_NOT_FOUND.

This commit also re-writes wimlib_export_image() to correctly roll back changes
on multi-image exports and better handle resources in the source WIM being
missing, as well as add a flag to make all destination image(s) unnamed.

31 files changed:
Makefile.am
NEWS
doc/imagex-apply.1.in
doc/imagex-export.1.in
doc/imagex-extract.1.in
doc/imagex-mount.1.in
include/wimlib.h
include/wimlib/glob.h [new file with mode: 0644]
include/wimlib/lookup_table.h
include/wimlib/swm.h [deleted file]
include/wimlib/wim.h
include/wimlib_tchar.h
programs/imagex-win32.c
programs/imagex-win32.h
programs/imagex.c
src/dentry.c
src/export_image.c
src/extract.c
src/integrity.c
src/join.c
src/lookup_table.c
src/mount_image.c
src/split.c
src/swm.c [deleted file]
src/util.c
src/wim.c
src/win32_apply.c
src/win32_capture.c
src/win32_replacements.c
src/write.c
src/xml.c

index 6d24bdf1126ad022a72c2e2ed9dd8eb95f8cf1d4..d2e80a2f4826c15db6e969d4599d7684b3dc54e2 100644 (file)
@@ -45,7 +45,6 @@ libwim_la_SOURCES =           \
        src/security.c          \
        src/sha1.c              \
        src/split.c             \
        src/security.c          \
        src/sha1.c              \
        src/split.c             \
-       src/swm.c               \
        src/reparse.c           \
        src/timestamp.c         \
        src/update_image.c      \
        src/reparse.c           \
        src/timestamp.c         \
        src/update_image.c      \
@@ -68,6 +67,7 @@ libwim_la_SOURCES =           \
        include/wimlib/endianness.h     \
        include/wimlib/error.h          \
        include/wimlib/file_io.h        \
        include/wimlib/endianness.h     \
        include/wimlib/error.h          \
        include/wimlib/file_io.h        \
+       include/wimlib/glob.h           \
        include/wimlib/header.h         \
        include/wimlib/integrity.h      \
        include/wimlib/list.h           \
        include/wimlib/header.h         \
        include/wimlib/integrity.h      \
        include/wimlib/list.h           \
@@ -80,7 +80,6 @@ libwim_la_SOURCES =           \
        include/wimlib/resource.h       \
        include/wimlib/security.h       \
        include/wimlib/sha1.h           \
        include/wimlib/resource.h       \
        include/wimlib/security.h       \
        include/wimlib/sha1.h           \
-       include/wimlib/swm.h            \
        include/wimlib/timestamp.h      \
        include/wimlib/types.h          \
        include/wimlib/util.h           \
        include/wimlib/timestamp.h      \
        include/wimlib/types.h          \
        include/wimlib/util.h           \
diff --git a/NEWS b/NEWS
index c31cea5cf68262711e633a71e7cbbc74eedb5221..783e0256ac3e5bc17af906f5b05543434d0a5f80 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,11 +5,18 @@ Version 1.5.0:
        to standard output and applying images from standard input, but they are
        not compatible with Microsoft's software and are not created by default.
        See the documentation for --pipable flag of `wimlib-imagex capture' for
        to standard output and applying images from standard input, but they are
        not compatible with Microsoft's software and are not created by default.
        See the documentation for --pipable flag of `wimlib-imagex capture' for
-       more information.  Two new functions have been added to the library to
-       fully support this: wimlib_write_to_fd() and
-       wimlib_extract_image_from_pipe().
+       more information.
 
 
-       wimlib now preserve WIM integrity tables by default, even if
+       To better support incremental backups, added support for declaring an
+       image as a modified form of a prior image.  See the documentation for
+       the '--delta-from' option of `wimlib-imagex append'.
+
+       The library support for managing split WIMs has been changed to support
+       other arrangements, such as delta WIMs, and be easier to use.  This
+       change is visible in `wimlib-imagex', which also can now accept the
+       '--ref' option multiple times.
+
+       wimlib now preserves WIM integrity tables by default, even if
        WIMLIB_WRITE_FLAG_CHECK_INTEGRITY is not specified.  This changes the
        behavior of `wimlib-imagex' whenever the WIM being operated on contains
        an integrity table and the '--check' option is not specified.
        WIMLIB_WRITE_FLAG_CHECK_INTEGRITY is not specified.  This changes the
        behavior of `wimlib-imagex' whenever the WIM being operated on contains
        an integrity table and the '--check' option is not specified.
@@ -19,52 +26,30 @@ Version 1.5.0:
        ratio by default, which is usually what is desired, at a cost of some
        speed.
 
        ratio by default, which is usually what is desired, at a cost of some
        speed.
 
-       For convenience, `wimlib-imagex' now supports being invoked as
-       wimCOMMAND, where COMMAND is the command as in `wimlib-imagex COMMAND';
-       for example, it can be invoked as `wimapply' as an alternative to
-       `wimlib-imagex apply'.  The appropriate hard links are created in UNIX
-       installations of `wimlib-imagex', while for the Windows distribution of
-       `wimlib-imagex', batch files that emulate this behavior are generated.
-
-       `wimlib-imagex' no longer recognizes the 'mount', 'mountrw', and
-       'unmount' commands on Windows, since they didn't work on Windows anyway.
+       `wimlib-imagex' now supports being invoked as wimCOMMAND, where COMMAND
+       is the command as in `wimlib-imagex COMMAND'; for example, it can be
+       invoked as `wimapply' as an alternative to `wimlib-imagex apply'.  The
+       appropriate hard links are created in UNIX installations of
+       `wimlib-imagex', while for the Windows distribution of `wimlib-imagex',
+       batch files that emulate this behavior are generated.
 
        Security descriptors are now extracted correctly on Windows.
 
 
        Security descriptors are now extracted correctly on Windows.
 
-       `mkwinpeimg' now supports grabbing files from the WAIK supplement rather
-       than the WAIK itself.
-
-       The test suite no longer fails when run in a locale where the decimal
-       separator is not a period.
-
-       From the library, WIMLIB_PROGRESS_MSG_EXTRACT_DENTRY has been removed
-       and WIMLIB_EXTRACT_FLAG_VERBOSE re-reserved for future use.  Also,
-       WIMLIB_PROGRESS_MSG_JOIN_STREAMS has been removed, but
-       WIMLIB_PROGRESS_MSG_WRITE_STREAMS will be received instead and now
-       provides WIM part numbers.
+       Fixed archiving DOS names in NTFS-3g capture mode.
 
        The extraction code has been rewritten and it will now be easier to
        support new features on all supported backends (currently Win32, UNIX,
        and NTFS-3g).  For example, hard-linked extraction mode (--hardlink) is
        now supported on all backends, not just UNIX.
 
 
        The extraction code has been rewritten and it will now be easier to
        support new features on all supported backends (currently Win32, UNIX,
        and NTFS-3g).  For example, hard-linked extraction mode (--hardlink) is
        now supported on all backends, not just UNIX.
 
-       The LZX compression and decompression code now compiles correctly on the
-       ARM architecture (where 'char' is unsigned).
-
-       wimlib_split() progress messages now report the total number of parts
-       being written.
-
-       Fixed storing DOS names in NTFS-3g capture mode.
-
-       A few changes were made to the error codes returned by library routines.
+       `mkwinpeimg' now supports grabbing files from the WAIK supplement rather
+       than the WAIK itself.
 
 
-       To make wimlib easier to use on Windows, wimlib_global_init() now
-       automatically attempts to acquire additional privileges on Windows, so
-       library clients need not do this (although they can provide a flag to
-       get the old behavior and manage privileges themselves).
+       wimlib_global_init() now, by default, attempts to acquire additional
+       privileges on Windows, so library clients need not do this.
 
 
-       This update bumps the shared library version number up to 9, since it
-       doesn't quite maintain binary compatibility with previous releases.
+       This update bumps the shared library version number up to 9, since it is
+       not binary compatibible with previous releases.
 
 Version 1.4.2:
        Fixed bug in `wimlib-imagex export' that made it impossible to export an
 
 Version 1.4.2:
        Fixed bug in `wimlib-imagex export' that made it impossible to export an
index 1166a6a6678d9153bad8a41705e87a8d06bf617a..0c536df2d51619135926815a126de879cccf5de8 100644 (file)
@@ -235,16 +235,11 @@ Files with full paths over 260 characters (MAX_PATH) are extracted by using the
 most Windows software and may not be able to be deleted easily.
 .SH SPLIT WIMS
 You may use \fB@IMAGEX_PROGNAME@ apply\fR to apply images from a split WIM.  The
 most Windows software and may not be able to be deleted easily.
 .SH SPLIT WIMS
 You may use \fB@IMAGEX_PROGNAME@ 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).
-.PP
-Here's an example.  The names for the split WIMs usually go something like:
+\fIWIMFILE\fR argument must specify the first part of the split WIM, while the
+additional parts of the split WIM must be specified in one or more
+\fB--ref\fR="\fIGLOB\fR" options.  Since globbing is built into the \fB--ref\fR
+option, typically only one \fB--ref\fR option is necessary.  For example, the
+names for the split WIM parts usually go something like:
 .RS
 .PP
 .nf
 .RS
 .PP
 .nf
@@ -294,8 +289,11 @@ When reading \fIWIMFILE\fR, verify its integrity if the integrity table is
 present.
 .TP
 \fB--ref\fR="\fIGLOB\fR"
 present.
 .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.
+File glob of additional WIMs or split WIM parts to reference resources from.
+See \fBSPLIT_WIMS\fR.  This option can be specified multiple times.  Note:
+\fIGLOB\fR is listed in quotes because it is interpreted by
+\fB@IMAGEX_PROGNAME@\fR and may need to be quoted to protect against shell
+expansion.
 .TP
 \fB--rpfix\fR, \fB--norpfix\fR
 Set whether to fix targets of absolute symbolic links (reparse points in Windows
 .TP
 \fB--rpfix\fR, \fB--norpfix\fR
 Set whether to fix targets of absolute symbolic links (reparse points in Windows
index 34b63eabb349f43571cd04b3fb9d52ada9005917..f1d7e3e89253d91d403055300d80a4b23b3c720f 100644 (file)
@@ -88,8 +88,11 @@ little bit of space that would otherwise be left as a hole in the WIM.  Also see
 \fB@IMAGEX_PROGNAME@ optimize\fR.
 .TP
 \fB--ref\fR="\fIGLOB\fR"
 \fB@IMAGEX_PROGNAME@ optimize\fR.
 .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.
+File glob of additional WIMs or split WIM parts to reference resources from.
+See \fBSPLIT_WIMS\fR.  This option can be specified multiple times.  Note:
+\fIGLOB\fR is listed in quotes because it is interpreted by
+\fB@IMAGEX_PROGNAME@\fR and may need to be quoted to protect against shell
+expansion.
 .TP
 \fB--pipable\fR
 Build, or rebuild, \fIDEST_WIMFILE\fR as a "pipable WIM" so that it can be
 .TP
 \fB--pipable\fR
 Build, or rebuild, \fIDEST_WIMFILE\fR as a "pipable WIM" so that it can be
@@ -103,17 +106,12 @@ Build, or rebuld, \fIDEST_WIMFILE\fR as a normal, non-pipable WIM.  This is the
 default behavior, unless \fIDEST_WIMFILE\fR already existed and was already
 pipable, or if \fIDEST_WIMFILE\fR was "-" (standard output).
 .SH SPLIT WIMS
 default behavior, unless \fIDEST_WIMFILE\fR already existed and was already
 pipable, or if \fIDEST_WIMFILE\fR was "-" (standard output).
 .SH SPLIT WIMS
-You may use \fB@IMAGEX_PROGNAME@ 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).
-.PP
-Here's an example.  The names for the split WIMs usually go something like:
+You may use \fB@IMAGEX_PROGNAME@ export\fR to export images from a split WIM.
+The \fISRC_WIMFILE\fR argument must specify the first part of the split WIM,
+while the additional parts of the split WIM must be specified in one or more
+\fB--ref\fR="\fIGLOB\fR" options.  Since globbing is built into the \fB--ref\fR
+option, typically only one \fB--ref\fR option is necessary.  For example, the
+names for the split WIM parts usually go something like:
 .PP
 .RS
 .nf
 .PP
 .RS
 .nf
index 40e29763f92132706cbff6eea2122cb2d18a82cc..55155a835218e1564715912bc897b9f0d675f353 100644 (file)
@@ -51,8 +51,10 @@ When reading \fIWIMFILE\fR, verify its integrity if an integrity table is
 present.
 .TP
 \fB--ref\fR="\fIGLOB\fR"
 present.
 .TP
 \fB--ref\fR="\fIGLOB\fR"
-File glob of additional split WIM parts that are part of the split WIM.  See
-\fBSPLIT_WIMS\fR.
+File glob of additional WIMs or split WIM parts to reference resources from.
+See \fBSPLIT_WIMS\fR.  Note: since \fIGLOB\fR is listed in quotes because it is
+interpreted by \fB@IMAGEX_PROGNAME@\fR and may need to be quoted to protect
+against shell expansion.
 .TP
 \fB--verbose\fR
 This option no longer does anything but is reserved for future use.
 .TP
 \fB--verbose\fR
 This option no longer does anything but is reserved for future use.
index 33102ff9e21049b2657bccc7819149dc0677ec9c..f2a50e63a5d8ffbe93095af3798c81ae9f6f2cdd 100644 (file)
@@ -25,21 +25,16 @@ The WIM image can be unmounted using the \fB@IMAGEX_PROGNAME@ unmount\fR command
 made to a WIM mounted read-write will be discarded unless the \fB--commit\fR
 flag is provided to \fB@IMAGEX_PROGNAME@ unmount\fR.
 .SH SPLIT WIMS
 made to a WIM mounted read-write will be discarded unless the \fB--commit\fR
 flag is provided to \fB@IMAGEX_PROGNAME@ unmount\fR.
 .SH SPLIT WIMS
-You may use \fB@IMAGEX_PROGNAME@ 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.
+You may use \fB@IMAGEX_PROGNAME@ 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.
 .PP
 .PP
-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).
+The \fIWIMFILE\fR argument must specify the first part of the split WIM, while
+the additional parts of the split WIM must be specified in one or more
+\fB--ref\fR="\fIGLOB\fR" options.  Since globbing is built into the \fB--ref\fR
+option, typically only one \fB--ref\fR option is necessary.  For example, the
+names for the split WIM parts usually go something like:
 .PP
 .PP
-Here's an example.  The names for the split WIMs usually go something like:
 .RS
 .RS
-.PP
 .nf
 mywim.swm
 mywim2.swm
 .nf
 mywim.swm
 mywim2.swm
@@ -48,7 +43,7 @@ mywim4.swm
 mywim5.swm
 .RE
 .PP
 mywim5.swm
 .RE
 .PP
-To mount the first image of this split WIM to the directory "dir", we would do:
+To mount the first image of this split WIM to the directory "dir", run:
 .PP
 .RS
 @IMAGEX_PROGNAME@ mount mywim.swm 1 dir --ref="mywim*.swm"
 .PP
 .RS
 @IMAGEX_PROGNAME@ mount mywim.swm 1 dir --ref="mywim*.swm"
@@ -58,7 +53,7 @@ To mount the first image of this split WIM to the directory "dir", we would do:
 If wimlib was configured using the \fB--without-fuse\fR flag, then the
 \fB@IMAGEX_PROGNAME@ mount\fR, \fB@IMAGEX_PROGNAME@ mountrw\fR, and
 \fB@IMAGEX_PROGNAME@ unmount\fR commands will not work.  Also, these commands
 If wimlib was configured using the \fB--without-fuse\fR flag, then the
 \fB@IMAGEX_PROGNAME@ mount\fR, \fB@IMAGEX_PROGNAME@ mountrw\fR, and
 \fB@IMAGEX_PROGNAME@ unmount\fR commands will not work.  Also, these commands
-are not available in the Windows builds of wimlib.
+are not available in the Windows builds of \fB@IMAGEX_PROGNAME@\fR.
 .PP
 You can mount multiple images from a WIM file read-only at the same time, but
 you can only mount one image at a time from a WIM read-write.
 .PP
 You can mount multiple images from a WIM file read-only at the same time, but
 you can only mount one image at a time from a WIM read-write.
@@ -93,7 +88,8 @@ If "xattr" (default), named data streams will be accessible through extended
 file attributes, unless this support was disabled when compiling wimlib.  The
 named data streams may be accessed through extended attributes named "user.*",
 where the * is the name of the named data stream.  See \fBsetfattr\fR (1) and
 file attributes, unless this support was disabled when compiling wimlib.  The
 named data streams may be accessed through extended attributes named "user.*",
 where the * is the name of the named data stream.  See \fBsetfattr\fR (1) and
-\fBgetfattr\fR (1).
+\fBgetfattr\fR (1).  Note that this is not an ideal interface, since named data
+streams may be larger than the maximum allowed extended attribute size.
 .IP ""
 If "windows", the named data streams will be accessible by specifying the
 filename, then a colon, then the name of the named data stream; for example,
 .IP ""
 If "windows", the named data streams will be accessible by specifying the
 filename, then a colon, then the name of the named data stream; for example,
@@ -109,9 +105,11 @@ Turn on debugging information printed by the FUSE library, and do not fork into
 the background.
 .TP
 \fB--ref\fR="\fIGLOB\fR"
 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 \fB@IMAGEX_PROGNAME@ mount\fR but not \fB@IMAGEX_PROGNAME@
-mountrw\fR.  See \fBSPLIT_WIMS\fR.
+File glob of additional WIMs or split WIM parts to reference resources from.
+See \fBSPLIT_WIMS\fR.  This option can be specified multiple times.  Note:
+\fIGLOB\fR is listed in quotes because it is interpreted by
+\fB@IMAGEX_PROGNAME@\fR and may need to be quoted to protect against shell
+expansion.
 .TP
 \fB--staging-dir\fR=\fIDIR\fR
 Store temporary staging files in a subdirectory of the directory \fIDIR\fR.
 .TP
 \fB--staging-dir\fR=\fIDIR\fR
 Store temporary staging files in a subdirectory of the directory \fIDIR\fR.
@@ -168,9 +166,6 @@ the temporary staging directory is deleted.
 .PP
 \fB@IMAGEX_PROGNAME@ unmount\fR runs in a separate process from the process that previously
 ran \fB@IMAGEX_PROGNAME@ mount\fR, and these two processes communicate using POSIX message
 .PP
 \fB@IMAGEX_PROGNAME@ unmount\fR runs in a separate process from the process that previously
 ran \fB@IMAGEX_PROGNAME@ mount\fR, and these two processes communicate using POSIX message
-queues.  See \fIsrc/mount_image.c\fR in the sources for details.  Note: As of
-wimlib v1.2.1, \fB@IMAGEX_PROGNAME@ unmount\fR correctly fails with an error within a
-reasonable amount of time (1 second) if the filesystem daemon is abnormally
-terminated.
+queues.  See \fIsrc/mount_image.c\fR in the sources for details.
 .SH SEE ALSO
 .BR @IMAGEX_PROGNAME@ (1)
 .SH SEE ALSO
 .BR @IMAGEX_PROGNAME@ (1)
index 40d062aab8a63ee5a635af17019db3aa91cefae2..197f9b65320dd8fe25da8832ac14fcaca8bd2e42 100644 (file)
@@ -900,6 +900,14 @@ typedef int (*wimlib_iterate_dir_tree_callback_t)(const struct wimlib_dir_entry
 typedef int (*wimlib_iterate_lookup_table_callback_t)(const struct wimlib_resource_entry *resource,
                                                      void *user_ctx);
 
 typedef int (*wimlib_iterate_lookup_table_callback_t)(const struct wimlib_resource_entry *resource,
                                                      void *user_ctx);
 
+/**
+ * @name Directory tree iteration flags
+ *
+ * The following flags can be passed to wimlib_iterate_dir_tree().
+ *
+ * @{
+ */
+
 /** For wimlib_iterate_dir_tree(): Iterate recursively on children rather than
  * just on the specified path. */
 #define WIMLIB_ITERATE_DIR_TREE_FLAG_RECURSIVE 0x00000001
 /** For wimlib_iterate_dir_tree(): Iterate recursively on children rather than
  * just on the specified path. */
 #define WIMLIB_ITERATE_DIR_TREE_FLAG_RECURSIVE 0x00000001
@@ -910,9 +918,15 @@ typedef int (*wimlib_iterate_lookup_table_callback_t)(const struct wimlib_resour
 
 
 
 
 
 
-/*****************************
- * WIMLIB_ADD_FLAG_*
- *****************************/
+/**
+ * @name Add flags
+ *
+ * The following flags can be passed to wimlib_add_image(),
+ * wimlib_add_image_multisource(), and add commands passed to
+ * wimlib_update_image().
+ *
+ * @{
+ */
 
 /** Directly capture a NTFS volume rather than a generic directory.  This flag
  * cannot be combined with ::WIMLIB_ADD_FLAG_DEREFERENCE or
 
 /** Directly capture a NTFS volume rather than a generic directory.  This flag
  * cannot be combined with ::WIMLIB_ADD_FLAG_DEREFERENCE or
@@ -1011,9 +1025,14 @@ typedef int (*wimlib_iterate_lookup_table_callback_t)(const struct wimlib_resour
                                                WIMLIB_ADD_FLAG_NO_UNSUPPORTED_EXCLUDE
 #define WIMLIB_ADD_IMAGE_FLAG_WINCONFIG                WIMLIB_ADD_FLAG_WINCONFIG
 
                                                WIMLIB_ADD_FLAG_NO_UNSUPPORTED_EXCLUDE
 #define WIMLIB_ADD_IMAGE_FLAG_WINCONFIG                WIMLIB_ADD_FLAG_WINCONFIG
 
-/******************************
- * WIMLIB_DELETE_FLAG_*
- ******************************/
+/**
+ * @name Delete flags
+ *
+ * The following flags can be specified in delete commands passed to
+ * wimlib_update_image().
+ *
+ * @{
+ */
 
 /** Do not issue an error if the path to delete does not exist. */
 #define WIMLIB_DELETE_FLAG_FORCE                       0x00000001
 
 /** Do not issue an error if the path to delete does not exist. */
 #define WIMLIB_DELETE_FLAG_FORCE                       0x00000001
@@ -1022,16 +1041,38 @@ typedef int (*wimlib_iterate_lookup_table_callback_t)(const struct wimlib_resour
  * issued if the path to delete is a directory. */
 #define WIMLIB_DELETE_FLAG_RECURSIVE                   0x00000002
 
  * issued if the path to delete is a directory. */
 #define WIMLIB_DELETE_FLAG_RECURSIVE                   0x00000002
 
-/******************************
- * WIMLIB_EXPORT_FLAG_*
- ******************************/
+/**
+ * @name Export flags
+ *
+ * The following flags can be passed to wimlib_export_image().
+ *
+ * @{
+ */
 
 
-/** See documentation for wimlib_export_image(). */
+/**
+ * If a single image is being exported, mark it bootable in the destination WIM.
+ * Alternatively, if ::WIMLIB_ALL_IMAGES is specified as the image to export,
+ * the image in the source WIM (if any) that is marked as bootable is also
+ * marked as bootable in the destination WIM.
+ */
 #define WIMLIB_EXPORT_FLAG_BOOT                                0x00000001
 
 #define WIMLIB_EXPORT_FLAG_BOOT                                0x00000001
 
-/******************************
- * WIMLIB_EXTRACT_FLAG_*
- ******************************/
+/** Give the exported image(s) no names.  Avoids problems with image name
+ * collisions.
+ */
+#define WIMLIB_EXPORT_FLAG_NO_NAMES                    0x00000002
+
+/** Give the exported image(s) no descriptions.  */
+#define WIMLIB_EXPORT_FLAG_NO_DESCRIPTIONS             0x00000004
+
+/**
+ * @name Extract flags
+ *
+ * The following flags can be passed to wimlib_extract_image(),
+ * wimlib_extract_files(), and wimlib_extract_image_from_pipe().
+ *
+ * @{
+ */
 
 /** Extract the image directly to a NTFS volume rather than a generic directory.
  * This mode is only available if wimlib was compiled with libntfs-3g support;
 
 /** Extract the image directly to a NTFS volume rather than a generic directory.
  * This mode is only available if wimlib was compiled with libntfs-3g support;
@@ -1117,9 +1158,13 @@ typedef int (*wimlib_iterate_lookup_table_callback_t)(const struct wimlib_resour
  * behavior is currently less than satisfactory.  Do not use (yet).  */
 #define WIMLIB_EXTRACT_FLAG_RESUME                     0x00010000
 
  * behavior is currently less than satisfactory.  Do not use (yet).  */
 #define WIMLIB_EXTRACT_FLAG_RESUME                     0x00010000
 
-/******************************
- * WIMLIB_MOUNT_FLAG_*
- ******************************/
+/**
+ * @name Mount flags
+ *
+ * The following flags can be passed to wimlib_mount_image().
+ *
+ * @{
+ */
 
 /** Mount the WIM image read-write rather than the default of read-only. */
 #define WIMLIB_MOUNT_FLAG_READWRITE                    0x00000001
 
 /** Mount the WIM image read-write rather than the default of read-only. */
 #define WIMLIB_MOUNT_FLAG_READWRITE                    0x00000001
@@ -1146,9 +1191,13 @@ typedef int (*wimlib_iterate_lookup_table_callback_t)(const struct wimlib_resour
  * allow_other option to FUSE mount) */
 #define WIMLIB_MOUNT_FLAG_ALLOW_OTHER                  0x00000040
 
  * allow_other option to FUSE mount) */
 #define WIMLIB_MOUNT_FLAG_ALLOW_OTHER                  0x00000040
 
-/******************************
- * WIMLIB_OPEN_FLAG_*
- ******************************/
+/**
+ * @name Open flags
+ *
+ * The following flags can be passed to wimlib_open_wim() and several other
+ * functions such as wimlib_join().
+ * @{
+ */
 
 /** Verify the WIM contents against the WIM's integrity table, if present.  This
  * causes the raw data of the WIM file, divided into 10 MB chunks, to be
 
 /** Verify the WIM contents against the WIM's integrity table, if present.  This
  * causes the raw data of the WIM file, divided into 10 MB chunks, to be
@@ -1171,9 +1220,12 @@ typedef int (*wimlib_iterate_lookup_table_callback_t)(const struct wimlib_resour
  * an error sooner rather than later. */
 #define WIMLIB_OPEN_FLAG_WRITE_ACCESS                  0x00000004
 
  * an error sooner rather than later. */
 #define WIMLIB_OPEN_FLAG_WRITE_ACCESS                  0x00000004
 
-/******************************
- * WIMLIB_UNMOUNT_FLAG_*
- ******************************/
+/**
+ * @name Unmount flags
+ *
+ * The following flags can be passed to wimlib_unmount_image().
+ * @{
+ */
 
 /** See ::WIMLIB_WRITE_FLAG_CHECK_INTEGRITY.  */
 #define WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY            0x00000001
 
 /** See ::WIMLIB_WRITE_FLAG_CHECK_INTEGRITY.  */
 #define WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY            0x00000001
@@ -1191,17 +1243,24 @@ typedef int (*wimlib_iterate_lookup_table_callback_t)(const struct wimlib_resour
 /** Do a "lazy" unmount (detach filesystem immediately, even if busy).  */
 #define WIMLIB_UNMOUNT_FLAG_LAZY                       0x00000010
 
 /** Do a "lazy" unmount (detach filesystem immediately, even if busy).  */
 #define WIMLIB_UNMOUNT_FLAG_LAZY                       0x00000010
 
-/******************************
- * WIMLIB_UPDATE_FLAG_*
- ******************************/
+/**
+ * @name Update flags
+ *
+ * The following flags can be passed to wimlib_update_image().
+ * @{
+ */
 
 /** Send ::WIMLIB_PROGRESS_MSG_UPDATE_BEGIN_COMMAND and
  * ::WIMLIB_PROGRESS_MSG_UPDATE_END_COMMAND messages.  */
 #define WIMLIB_UPDATE_FLAG_SEND_PROGRESS               0x00000001
 
 
 /** Send ::WIMLIB_PROGRESS_MSG_UPDATE_BEGIN_COMMAND and
  * ::WIMLIB_PROGRESS_MSG_UPDATE_END_COMMAND messages.  */
 #define WIMLIB_UPDATE_FLAG_SEND_PROGRESS               0x00000001
 
-/******************************
- * WIMLIB_WRITE_FLAG_*
- ******************************/
+/**
+ * @name Write flags
+ *
+ * The following flags can be passed to wimlib_write(), wimlib_overwrite(),
+ * wimlib_write_to_fd(), and several other functions such as wimlib_join().
+ * @{
+ */
 
 /** Include an integrity table in the WIM.
  *
 
 /** Include an integrity table in the WIM.
  *
@@ -1260,9 +1319,11 @@ typedef int (*wimlib_iterate_lookup_table_callback_t)(const struct wimlib_resour
  * set the readonly flag on the on-disk WIM file.  */
 #define WIMLIB_WRITE_FLAG_IGNORE_READONLY_FLAG         0x00000100
 
  * set the readonly flag on the on-disk WIM file.  */
 #define WIMLIB_WRITE_FLAG_IGNORE_READONLY_FLAG         0x00000100
 
-/******************************
- * WIMLIB_INIT_FLAG_*
- ******************************/
+/**
+ * @name Init flags
+ *
+ * The following flags can be passed to wimlib_global_init().
+ */
 
 /** Assume that strings are represented in UTF-8, even if this is not the
  * locale's character encoding.  This flag is ignored on Windows, where wimlib
 
 /** Assume that strings are represented in UTF-8, even if this is not the
  * locale's character encoding.  This flag is ignored on Windows, where wimlib
@@ -1292,6 +1353,29 @@ typedef int (*wimlib_iterate_lookup_table_callback_t)(const struct wimlib_resour
  */
 #define WIMLIB_INIT_FLAG_STRICT_APPLY_PRIVILEGES       0x00000008
 
  */
 #define WIMLIB_INIT_FLAG_STRICT_APPLY_PRIVILEGES       0x00000008
 
+/**
+ * @name Resource reference flags
+ *
+ * The following flags can be passed to wimlib_reference_resource_files() and
+ * wimlib_reference_resources().
+ */
+
+/** wimlib_reference_resource_files() only:  Enable shell-style filename
+ * globbing.  */
+#define WIMLIB_REF_FLAG_GLOB_ENABLE            0x00000001
+
+/** wimlib_reference_resource_files() only:  Issue an error
+ * (::WIMLIB_ERR_GLOB_HAD_NO_MATCHES) if a glob did not match any files.  The
+ * default behavior without this flag is to issue no error at that point, but
+ * then attempt to open the glob as a literal path, which of course will fail
+ * anyway if no file exists at that path.  No effect if
+ * ::WIMLIB_REF_FLAG_GLOB_ENABLE is not also specified.  */
+#define WIMLIB_REF_FLAG_GLOB_ERR_ON_NOMATCH    0x00000002
+
+/**
+ * @}
+ */
+
 /** Specification of an update to perform on a WIM image. */
 struct wimlib_update_command {
 
 /** Specification of an update to perform on a WIM image. */
 struct wimlib_update_command {
 
@@ -1381,6 +1465,7 @@ enum wimlib_error_code {
        WIMLIB_ERR_FORK,
        WIMLIB_ERR_FUSE,
        WIMLIB_ERR_FUSERMOUNT,
        WIMLIB_ERR_FORK,
        WIMLIB_ERR_FUSE,
        WIMLIB_ERR_FUSERMOUNT,
+       WIMLIB_ERR_GLOB_HAD_NO_MATCHES,
        WIMLIB_ERR_ICONV_NOT_AVAILABLE,
        WIMLIB_ERR_IMAGE_COUNT,
        WIMLIB_ERR_IMAGE_NAME_COLLISION,
        WIMLIB_ERR_ICONV_NOT_AVAILABLE,
        WIMLIB_ERR_IMAGE_COUNT,
        WIMLIB_ERR_IMAGE_NAME_COLLISION,
@@ -1401,13 +1486,13 @@ enum wimlib_error_code {
        WIMLIB_ERR_INVALID_PIPABLE_WIM,
        WIMLIB_ERR_INVALID_REPARSE_DATA,
        WIMLIB_ERR_INVALID_RESOURCE_HASH,
        WIMLIB_ERR_INVALID_PIPABLE_WIM,
        WIMLIB_ERR_INVALID_REPARSE_DATA,
        WIMLIB_ERR_INVALID_RESOURCE_HASH,
-       WIMLIB_ERR_INVALID_SECURITY_DATA,
        WIMLIB_ERR_INVALID_UNMOUNT_MESSAGE,
        WIMLIB_ERR_INVALID_UTF16_STRING,
        WIMLIB_ERR_INVALID_UTF8_STRING,
        WIMLIB_ERR_IS_DIRECTORY,
        WIMLIB_ERR_LIBXML_UTF16_HANDLER_NOT_AVAILABLE,
        WIMLIB_ERR_LINK,
        WIMLIB_ERR_INVALID_UNMOUNT_MESSAGE,
        WIMLIB_ERR_INVALID_UTF16_STRING,
        WIMLIB_ERR_INVALID_UTF8_STRING,
        WIMLIB_ERR_IS_DIRECTORY,
        WIMLIB_ERR_LIBXML_UTF16_HANDLER_NOT_AVAILABLE,
        WIMLIB_ERR_LINK,
+       WIMLIB_ERR_METADATA_NOT_FOUND,
        WIMLIB_ERR_MKDIR,
        WIMLIB_ERR_MQUEUE,
        WIMLIB_ERR_NOMEM,
        WIMLIB_ERR_MKDIR,
        WIMLIB_ERR_MQUEUE,
        WIMLIB_ERR_NOMEM,
@@ -1628,10 +1713,11 @@ wimlib_create_new_wim(int ctype, WIMStruct **wim_ret);
  *     flag.
  *
  * This function can additionally return ::WIMLIB_ERR_DECOMPRESSION,
  *     flag.
  *
  * This function can additionally return ::WIMLIB_ERR_DECOMPRESSION,
- * ::WIMLIB_ERR_INVALID_METADATA_RESOURCE, ::WIMLIB_ERR_NOMEM,
- * ::WIMLIB_ERR_READ, or ::WIMLIB_ERR_UNEXPECTED_END_OF_FILE, all of which
- * indicate failure (for different reasons) to read the metadata resource for an
- * image that needed to be deleted.
+ * ::WIMLIB_ERR_INVALID_METADATA_RESOURCE, ::WIMLIB_ERR_METADATA_NOT_FOUND,
+ * ::WIMLIB_ERR_NOMEM, ::WIMLIB_ERR_READ, or
+ * ::WIMLIB_ERR_UNEXPECTED_END_OF_FILE, all of which indicate failure (for
+ * different reasons) to read the metadata resource for an image that needed to
+ * be deleted.
  */
 extern int
 wimlib_delete_image(WIMStruct *wim, int image);
  */
 extern int
 wimlib_delete_image(WIMStruct *wim, int image);
@@ -1658,76 +1744,63 @@ wimlib_delete_image(WIMStruct *wim, int image);
  *     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
  *     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 @p src_wim.  Can be the number of an image, or
- *     ::WIMLIB_ALL_IMAGES to export all images.
+ *     The image to export from @p src_wim, as either a 1-based image index to
+ *     export a single image, or ::WIMLIB_ALL_IMAGES to export all images.
  * @param dest_wim
  * @param dest_wim
- *     Pointer to the ::WIMStruct for a WIM file that will receive the images
- *     being exported.
+ *     Pointer to the ::WIMStruct for a WIM that will receive the images being
+ *     exported.
  * @param dest_name
  * @param dest_name
- *     The name to give the exported image in the new WIM file.  If left @c
- *     NULL, the name from @p src_wim is used.  This parameter must be left @c
- *     NULL if @p src_image is ::WIMLIB_ALL_IMAGES and @p src_wim contains more
- *     than one image; in that case, the names are all taken from the @p
- *     src_wim.  (This is allowed even if one or more images being exported has
- *     no name.)
+ *     For single-image exports, the name to give the exported image in @p
+ *     dest_wim.  If left @c NULL, the name from @p src_wim is used.  For
+ *     ::WIMLIB_ALL_IMAGES exports, this parameter must be left @c NULL; in
+ *     that case, the names are all taken from @p src_wim.  This parameter is
+ *     overridden by ::WIMLIB_EXPORT_FLAG_NO_NAMES.
  * @param dest_description
  * @param dest_description
- *     The description to give the exported image in the new WIM file.  If left
- *     @c NULL, the description from the @p src_wim is used.  This parameter must
- *     be left @c NULL if @p src_image is ::WIMLIB_ALL_IMAGES and @p src_wim contains
- *     more than one image; in that case, the descriptions are all taken from
- *     @p src_wim.  (This is allowed even if one or more images being exported
- *     has no description.)
+ *     For single-image exports, the description to give the exported image in
+ *     the new WIM file.  If left @c NULL, the description from @p src_wim is
+ *     used.  For ::WIMLIB_ALL_IMAGES exports, this parameter must be left @c
+ *     NULL; in that case, the description are all taken from @p src_wim.  This
+ *     parameter is overridden by ::WIMLIB_EXPORT_FLAG_NO_DESCRIPTIONS.
  * @param export_flags
  * @param export_flags
- *     ::WIMLIB_EXPORT_FLAG_BOOT if the image being exported is to be made
- *     bootable, or 0 if which image is marked as bootable in the destination
- *     WIM is to be left unchanged.  If @p src_image is ::WIMLIB_ALL_IMAGES and
- *     there are multiple images in @p src_wim, specifying
- *     ::WIMLIB_EXPORT_FLAG_BOOT is valid only if one of the exported images is
- *     currently marked as bootable in @p 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 @p 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
- *     @p wim parameter.
- * @param num_additional_swms
- *     Number of additional WIM parts provided in the @p 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.
+ *     Bitwise OR of flags prefixed with WIMLIB_EXPORT_FLAG.
  * @param progress_func
  * @param progress_func
- *     If non-NULL, a function that will be called periodically with the
- *     progress of the current operation.
+ *     Currently ignored, but reserved for a function that will be called with
+ *     information about the operation.  Use NULL if no additional information
+ *     is desired.
  *
  * @return 0 on success; nonzero on error.
  * @retval ::WIMLIB_ERR_IMAGE_NAME_COLLISION
  *     One or more of the names being given to an exported image was already in
  *     use in the destination WIM.
  * @retval ::WIMLIB_ERR_INVALID_IMAGE
  *
  * @return 0 on success; nonzero on error.
  * @retval ::WIMLIB_ERR_IMAGE_NAME_COLLISION
  *     One or more of the names being given to an exported image was already in
  *     use in the destination WIM.
  * @retval ::WIMLIB_ERR_INVALID_IMAGE
- *     @p src_image does not exist in @p src_wim.
+ *     @p src_image does not exist in @p src_wim and was not
+ *     ::WIMLIB_ALL_IMAGES.
  * @retval ::WIMLIB_ERR_INVALID_PARAM
  * @retval ::WIMLIB_ERR_INVALID_PARAM
- *     ::WIMLIB_EXPORT_FLAG_BOOT was specified in @p flags, @p src_image was
- *     ::WIMLIB_ALL_IMAGES, @p src_wim contains multiple images, and no images in
- *     @p src_wim are marked as bootable; or @p dest_name and/or @p
- *     dest_description were non-<code>NULL</code>, @p src_image was
- *     ::WIMLIB_ALL_IMAGES, and @p src_wim contains multiple images.
+ *     @p src_wim and/or @p dest_wim were @c NULL; or @p src_image was
+ *     ::WIMLIB_ALL_IMAGES but @p dest_name and/or @p dest_description were not
+ *     @c NULL.
+ * @retval ::WIMLIB_ERR_METADATA_NOT_FOUND
+ *     Either @p src_wim or @p dest_wim did not contain metadata resources; for
+ *     example, one of them was a non-first part of a split WIM.
  * @retval ::WIMLIB_ERR_NOMEM
  *     Failed to allocate needed memory.
  * @retval ::WIMLIB_ERR_NOMEM
  *     Failed to allocate needed memory.
- * @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
- *     split WIM, there are duplicate parts, or not all the parts are in fact
- *     from the same split WIM.
+ * @retval ::WIMLIB_ERR_RESOURCE_NOT_FOUND
+ *     A resource that needed to be exported could not be found in either the
+ *     source or destination WIMs.  This error can occur if, for example, @p
+ *     src_wim is part of a split WIM but resources from the other split WIM
+ *     parts were not referenced with wimlib_reference_resources() or
+ *     wimlib_reference_resource_files().
  * @retval ::WIMLIB_ERR_WIM_IS_READONLY
  *     @p dest_wim is considered read-only because of any of the reasons
  *     mentioned in the documentation for the ::WIMLIB_OPEN_FLAG_WRITE_ACCESS
  *     flag.
  *
  * This function can additionally return ::WIMLIB_ERR_DECOMPRESSION,
  * @retval ::WIMLIB_ERR_WIM_IS_READONLY
  *     @p dest_wim is considered read-only because of any of the reasons
  *     mentioned in the documentation for the ::WIMLIB_OPEN_FLAG_WRITE_ACCESS
  *     flag.
  *
  * This function can additionally return ::WIMLIB_ERR_DECOMPRESSION,
- * ::WIMLIB_ERR_INVALID_METADATA_RESOURCE, ::WIMLIB_ERR_NOMEM,
- * ::WIMLIB_ERR_READ, or ::WIMLIB_ERR_UNEXPECTED_END_OF_FILE, all of which
- * indicate failure (for different reasons) to read the metadata resource for an
- * image in @p src_wim that needed to be exported.
+ * ::WIMLIB_ERR_INVALID_METADATA_RESOURCE, ::WIMLIB_ERR_METADATA_NOT_FOUND,
+ * ::WIMLIB_ERR_NOMEM, ::WIMLIB_ERR_READ, or
+ * ::WIMLIB_ERR_UNEXPECTED_END_OF_FILE, all of which indicate failure (for
+ * different reasons) to read the metadata resource for an image in @p src_wim
+ * that needed to be exported.
  */
 extern int
 wimlib_export_image(WIMStruct *src_wim, int src_image,
  */
 extern int
 wimlib_export_image(WIMStruct *src_wim, int src_image,
@@ -1735,8 +1808,6 @@ wimlib_export_image(WIMStruct *src_wim, int src_image,
                    const wimlib_tchar *dest_name,
                    const wimlib_tchar *dest_description,
                    int export_flags,
                    const wimlib_tchar *dest_name,
                    const wimlib_tchar *dest_description,
                    int export_flags,
-                   WIMStruct **additional_swms,
-                   unsigned num_additional_swms,
                    wimlib_progress_func_t progress_func);
 
 /**
                    wimlib_progress_func_t progress_func);
 
 /**
@@ -1766,18 +1837,6 @@ wimlib_export_image(WIMStruct *src_wim, int src_image,
  *     been specified in the ::wimlib_extract_command.extract_flags member in
  *     each extraction command, in combination with any flags already present.
  *
  *     been specified in the ::wimlib_extract_command.extract_flags member in
  *     each extraction command, in combination with any flags already present.
  *
- * @param additional_swms
- *     Array of pointers to the ::WIMStruct for each additional part in the
- *     split WIM.  Ignored if @p 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
- *     @p wim parameter.
- *
- * @param num_additional_swms
- *     Number of additional WIM parts provided in the @p 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.
- *
  * @param progress_func
  *     If non-NULL, a function that will be called periodically with the
  *     progress of the current operation.
  * @param progress_func
  *     If non-NULL, a function that will be called periodically with the
  *     progress of the current operation.
@@ -1810,8 +1869,6 @@ wimlib_extract_files(WIMStruct *wim,
                     const struct wimlib_extract_command *cmds,
                     size_t num_cmds,
                     int default_extract_flags,
                     const struct wimlib_extract_command *cmds,
                     size_t num_cmds,
                     int default_extract_flags,
-                    WIMStruct **additional_swms,
-                    unsigned num_additional_swms,
                     wimlib_progress_func_t progress_func);
 
 /**
                     wimlib_progress_func_t progress_func);
 
 /**
@@ -1844,25 +1901,13 @@ wimlib_extract_files(WIMStruct *wim,
  *     path to the unmounted NTFS volume to extract the image to.
  * @param extract_flags
  *     Bitwise OR of the flags prefixed with WIMLIB_EXTRACT_FLAG.
  *     path to the unmounted NTFS volume to extract the image to.
  * @param extract_flags
  *     Bitwise OR of the flags prefixed with WIMLIB_EXTRACT_FLAG.
- * @param additional_swms
- *     Array of pointers to the ::WIMStruct for each additional part in the
- *     split WIM.  Ignored if @p 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
- *     @p wim parameter.
- * @param num_additional_swms
- *     Number of additional WIM parts provided in the @p 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.
- *
  * @param progress_func
  *     If non-NULL, a function that will be called periodically with the
  *     progress of the current operation.
  *
  * @return 0 on success; nonzero on error.
  * @retval ::WIMLIB_ERR_DECOMPRESSION
  * @param progress_func
  *     If non-NULL, a function that will be called periodically with the
  *     progress of the current operation.
  *
  * @return 0 on success; nonzero on error.
  * @retval ::WIMLIB_ERR_DECOMPRESSION
- *     Failed to decompress a resource to be extracted, or failed to decompress
- *     a needed metadata resource.
+ *     Failed to decompress a resource to be extracted.
  * @retval ::WIMLIB_ERR_INVALID_PARAM
  *     Both ::WIMLIB_EXTRACT_FLAG_HARDLINK and ::WIMLIB_EXTRACT_FLAG_SYMLINK
  *     were specified in @p extract_flags; or both
  * @retval ::WIMLIB_ERR_INVALID_PARAM
  *     Both ::WIMLIB_EXTRACT_FLAG_HARDLINK and ::WIMLIB_EXTRACT_FLAG_SYMLINK
  *     were specified in @p extract_flags; or both
@@ -1872,8 +1917,6 @@ wimlib_extract_files(WIMStruct *wim,
  *     ::WIMLIB_EXTRACT_FLAG_RESUME was specified in @p extract_flags; or if
  *     ::WIMLIB_EXTRACT_FLAG_NTFS was specified in @p extract_flags and
  *     @p image was ::WIMLIB_ALL_IMAGES.
  *     ::WIMLIB_EXTRACT_FLAG_RESUME was specified in @p extract_flags; or if
  *     ::WIMLIB_EXTRACT_FLAG_NTFS was specified in @p extract_flags and
  *     @p image was ::WIMLIB_ALL_IMAGES.
- * @retval ::WIMLIB_ERR_INVALID_METADATA_RESOURCE
- *     The metadata resource for an image being extracted was invalid.
  * @retval ::WIMLIB_ERR_INVALID_RESOURCE_HASH
  *     The SHA1 message digest of an extracted stream did not match the SHA1
  *     message digest given in the WIM file.
  * @retval ::WIMLIB_ERR_INVALID_RESOURCE_HASH
  *     The SHA1 message digest of an extracted stream did not match the SHA1
  *     message digest given in the WIM file.
@@ -1913,11 +1956,6 @@ wimlib_extract_files(WIMStruct *wim,
  * @retval ::WIMLIB_ERR_SET_TIMESTAMPS
  *     Failed to set timestamps on a file (only if
  *     ::WIMLIB_EXTRACT_FLAG_STRICT_TIMESTAMPS was specified in @p extract_flags).
  * @retval ::WIMLIB_ERR_SET_TIMESTAMPS
  *     Failed to set timestamps on a file (only if
  *     ::WIMLIB_EXTRACT_FLAG_STRICT_TIMESTAMPS was specified in @p extract_flags).
- * @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_UNEXPECTED_END_OF_FILE
  *     Unexpected end-of-file occurred when reading data from the WIM file
  *     associated with @p wim.
  * @retval ::WIMLIB_ERR_UNEXPECTED_END_OF_FILE
  *     Unexpected end-of-file occurred when reading data from the WIM file
  *     associated with @p wim.
@@ -1940,13 +1978,18 @@ wimlib_extract_files(WIMStruct *wim,
  *     ::WIMLIB_EXTRACT_FLAG_NTFS was not specified in @p extract_flags.
  * @retval ::WIMLIB_ERR_WRITE
  *     Failed to write data to a file being extracted.
  *     ::WIMLIB_EXTRACT_FLAG_NTFS was not specified in @p extract_flags.
  * @retval ::WIMLIB_ERR_WRITE
  *     Failed to write data to a file being extracted.
+ *
+ * This function can additionally return ::WIMLIB_ERR_DECOMPRESSION,
+ * ::WIMLIB_ERR_INVALID_METADATA_RESOURCE, ::WIMLIB_ERR_METADATA_NOT_FOUND,
+ * ::WIMLIB_ERR_NOMEM, ::WIMLIB_ERR_READ, or
+ * ::WIMLIB_ERR_UNEXPECTED_END_OF_FILE, all of which indicate failure (for
+ * different reasons) to read the metadata resource for an image that needed to
+ * be extracted.
  */
 extern int
 wimlib_extract_image(WIMStruct *wim, int image,
                     const wimlib_tchar *target,
                     int extract_flags,
  */
 extern int
 wimlib_extract_image(WIMStruct *wim, int image,
                     const wimlib_tchar *target,
                     int extract_flags,
-                    WIMStruct **additional_swms,
-                    unsigned num_additional_swms,
                     wimlib_progress_func_t progress_func);
 
 /**
                     wimlib_progress_func_t progress_func);
 
 /**
@@ -2197,10 +2240,11 @@ wimlib_image_name_in_use(const WIMStruct *wim, const wimlib_tchar *name);
  *     Failed to allocate memory needed to create a ::wimlib_dir_entry.
  *
  * This function can additionally return ::WIMLIB_ERR_DECOMPRESSION,
  *     Failed to allocate memory needed to create a ::wimlib_dir_entry.
  *
  * This function can additionally return ::WIMLIB_ERR_DECOMPRESSION,
- * ::WIMLIB_ERR_INVALID_METADATA_RESOURCE, ::WIMLIB_ERR_NOMEM,
- * ::WIMLIB_ERR_READ, or ::WIMLIB_ERR_UNEXPECTED_END_OF_FILE, all of which
- * indicate failure (for different reasons) to read the metadata resource for an
- * image over which iteration needed to be done.
+ * ::WIMLIB_ERR_INVALID_METADATA_RESOURCE, ::WIMLIB_ERR_METADATA_NOT_FOUND,
+ * ::WIMLIB_ERR_NOMEM, ::WIMLIB_ERR_READ, or
+ * ::WIMLIB_ERR_UNEXPECTED_END_OF_FILE, all of which indicate failure (for
+ * different reasons) to read the metadata resource for an image over which
+ * iteration needed to be done.
  */
 extern int
 wimlib_iterate_dir_tree(WIMStruct *wim, int image, const wimlib_tchar *path,
  */
 extern int
 wimlib_iterate_dir_tree(WIMStruct *wim, int image, const wimlib_tchar *path,
@@ -2366,16 +2410,6 @@ wimlib_lzx_decompress(const void *compressed_data, unsigned compressed_len,
  *     The path to an existing empty directory to mount the image on.
  * @param mount_flags
  *     Bitwise OR of the flags prefixed with WIMLIB_MOUNT_FLAG.
  *     The path to an existing empty directory to mount the image on.
  * @param mount_flags
  *     Bitwise OR of the flags prefixed with WIMLIB_MOUNT_FLAG.
- * @param additional_swms
- *     Array of pointers to the ::WIMStruct for each additional part in the
- *     split WIM.  Ignored if @p 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
- *     @p wim parameter.
- * @param num_additional_swms
- *     Number of additional WIM parts provided in the @p 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.
  * @param staging_dir
  *     If non-NULL, the name of a directory in which the staging directory will
  *     be created.  Ignored if ::WIMLIB_MOUNT_FLAG_READWRITE is not specified
  * @param staging_dir
  *     If non-NULL, the name of a directory in which the staging directory will
  *     be created.  Ignored if ::WIMLIB_MOUNT_FLAG_READWRITE is not specified
@@ -2389,14 +2423,10 @@ wimlib_lzx_decompress(const void *compressed_data, unsigned compressed_len,
  *     the on-disk WIM file could not be acquired because another thread or
  *     process has mounted an image from the WIM read-write or is currently
  *     modifying the WIM in-place.
  *     the on-disk WIM file could not be acquired because another thread or
  *     process has mounted an image from the WIM read-write or is currently
  *     modifying the WIM in-place.
- * @retval ::WIMLIB_ERR_DECOMPRESSION
- *     Could not decompress the metadata resource for @p image in @p wim.
  * @retval ::WIMLIB_ERR_FUSE
  *     A non-zero status was returned by @c fuse_main().
  * @retval ::WIMLIB_ERR_INVALID_IMAGE
  *     @p image does not specify an existing, single image in @p wim.
  * @retval ::WIMLIB_ERR_FUSE
  *     A non-zero status was returned by @c fuse_main().
  * @retval ::WIMLIB_ERR_INVALID_IMAGE
  *     @p image does not specify an existing, single image in @p wim.
- * @retval ::WIMLIB_ERR_INVALID_METADATA_RESOURCE
- *     The metadata resource for @p image is invalid.
  * @retval ::WIMLIB_ERR_INVALID_PARAM
  *     @p image is shared among multiple ::WIMStruct's as a result of a call to
  *     wimlib_export_image(), or @p image has been added with
  * @retval ::WIMLIB_ERR_INVALID_PARAM
  *     @p image is shared among multiple ::WIMStruct's as a result of a call to
  *     wimlib_export_image(), or @p image has been added with
@@ -2404,40 +2434,32 @@ wimlib_lzx_decompress(const void *compressed_data, unsigned compressed_len,
  * @retval ::WIMLIB_ERR_MKDIR
  *     ::WIMLIB_MOUNT_FLAG_READWRITE was specified in @p mount_flags, but the
  *     staging directory could not be created.
  * @retval ::WIMLIB_ERR_MKDIR
  *     ::WIMLIB_MOUNT_FLAG_READWRITE was specified in @p mount_flags, but the
  *     staging directory could not be created.
- * @retval ::WIMLIB_ERR_NOMEM
- *     Failed to allocate needed memory.
  * @retval ::WIMLIB_ERR_NOTDIR
  *     Could not determine the current working directory.
  * @retval ::WIMLIB_ERR_NOTDIR
  *     Could not determine the current working directory.
- * @retval ::WIMLIB_ERR_READ
- *     Failed to read data from the WIM file associated with @p wim.
  * @retval ::WIMLIB_ERR_RESOURCE_NOT_FOUND
  *     One of the dentries in the image referenced a stream not present in the
  *     WIM's lookup table (or in any of the lookup tables of the split WIM
  *     parts).
  * @retval ::WIMLIB_ERR_RESOURCE_NOT_FOUND
  *     One of the dentries in the image referenced a stream not present in the
  *     WIM's lookup table (or in any of the lookup tables of the split WIM
  *     parts).
- * @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_WIM_IS_READONLY
  *     ::WIMLIB_MOUNT_FLAG_READWRITE was specified in @p mount_flags, but @p
  *     wim is considered read-only because of any of the reasons mentioned in
  *     the documentation for the ::WIMLIB_OPEN_FLAG_WRITE_ACCESS flag.
  * @retval ::WIMLIB_ERR_WIM_IS_READONLY
  *     ::WIMLIB_MOUNT_FLAG_READWRITE was specified in @p mount_flags, but @p
  *     wim is considered read-only because of any of the reasons mentioned in
  *     the documentation for the ::WIMLIB_OPEN_FLAG_WRITE_ACCESS flag.
- * @retval ::WIMLIB_ERR_UNEXPECTED_END_OF_FILE
- *     Unexpected end-of-file occurred while reading data from the WIM file
- *     associated with @p wim.
  * @retval ::WIMLIB_ERR_UNSUPPORTED
  *     Mounting is not supported, either because the platform is Windows, or
  *     because the platform is UNIX-like and wimlib was compiled with @c
  *     --without-fuse.
  * @retval ::WIMLIB_ERR_UNSUPPORTED
  *     Mounting is not supported, either because the platform is Windows, or
  *     because the platform is UNIX-like and wimlib was compiled with @c
  *     --without-fuse.
+ *
+ * This function can additionally return ::WIMLIB_ERR_DECOMPRESSION,
+ * ::WIMLIB_ERR_INVALID_METADATA_RESOURCE, ::WIMLIB_ERR_METADATA_NOT_FOUND,
+ * ::WIMLIB_ERR_NOMEM, ::WIMLIB_ERR_READ, or
+ * ::WIMLIB_ERR_UNEXPECTED_END_OF_FILE, all of which indicate failure (for
+ * different reasons) to read the metadata resource for the image to mount.
  */
 extern int
 wimlib_mount_image(WIMStruct *wim,
                   int image,
                   const wimlib_tchar *dir,
                   int mount_flags,
  */
 extern int
 wimlib_mount_image(WIMStruct *wim,
                   int image,
                   const wimlib_tchar *dir,
                   int mount_flags,
-                  WIMStruct **additional_swms,
-                  unsigned num_additional_swms,
                   const wimlib_tchar *staging_dir);
 
 /**
                   const wimlib_tchar *staging_dir);
 
 /**
@@ -2625,6 +2647,93 @@ wimlib_print_header(const WIMStruct *wim) _wimlib_deprecated;
 extern int
 wimlib_print_metadata(WIMStruct *wim, int image) _wimlib_deprecated;
 
 extern int
 wimlib_print_metadata(WIMStruct *wim, int image) _wimlib_deprecated;
 
+/**
+ * Reference resources from other WIM files or split WIM parts.  This function
+ * can be used on WIMs that are not standalone, such as split or "delta" WIMs,
+ * to load needed resources (that is, "streams" keyed by SHA1 message digest)
+ * from other files, before calling a function such as wimlib_extract_image()
+ * that requires the resources to be present.
+ *
+ * @param wim
+ *     The ::WIMStruct for a WIM that contains metadata resources, but is not
+ *     necessarily "standalone".  In the case of split WIMs, this should be the
+ *     first part, since only the first part contains the metadata resources.
+ *     In the case of delta WIMs, this should be the delta WIM rather than the
+ *     WIM on which it is based.
+ * @param resource_wimfiles_or_globs
+ *     Array of paths to WIM files and/or split WIM parts to reference.
+ *     Alternatively, when ::WIMLIB_REF_FLAG_GLOB_ENABLE is specified in @p
+ *     ref_flags, these are treated as globs rather than literal paths.  That
+ *     is, using this function you can specify zero or more globs, each of
+ *     which expands to one or more literal paths.
+ * @param count
+ *     Number of entries in @p resource_wimfiles_or_globs.
+ * @param ref_flags
+ *     Bitwise OR of ::WIMLIB_REF_FLAG_GLOB_ENABLE and/or
+ *     ::WIMLIB_REF_FLAG_GLOB_ERR_ON_NOMATCH.
+ * @param open_flags
+ *     Additional open flags, such as ::WIMLIB_OPEN_FLAG_CHECK_INTEGRITY, to
+ *     pass to internal calls to wimlib_open_wim() on the reference files.
+ *     Note: ::WIMLIB_OPEN_FLAG_SPLIT_OK will be supplied regardless of this
+ *     parameter.
+ * @param progress_func
+ *     Passed to internal calls to wimlib_open_wim() on the reference files.
+ *
+ * @return 0 on success; nonzero on error.
+ *
+ * @retval ::WIMLIB_ERR_GLOB_HAD_NO_MATCHES
+ *     One of the specified globs did not match any paths (only with both
+ *     ::WIMLIB_REF_FLAG_GLOB_ENABLE and ::WIMLIB_REF_FLAG_GLOB_ERR_ON_NOMATCH
+ *     specified in @p ref_flags).
+ * @retval ::WIMLIB_ERR_NOMEM
+ *     Failed to allocate memory.
+ * @retval ::WIMLIB_ERR_READ
+ *     I/O or permissions error while processing a file glob.
+ *
+ * This function can additionally return most values that can be returned by
+ * wimlib_open_wim().
+ */
+extern int
+wimlib_reference_resource_files(WIMStruct *wim,
+                               const wimlib_tchar * const *resource_wimfiles_or_globs,
+                               unsigned count,
+                               int ref_flags,
+                               int open_flags,
+                               wimlib_progress_func_t progress_func);
+
+/**
+ * Similar to wimlib_reference_resource_files(), but operates at a lower level
+ * where the caller must open the ::WIMStruct for each referenced file itself.
+ *
+ * @param wim
+ *     The ::WIMStruct for a WIM that contains metadata resources, but is not
+ *     necessarily "standalone".  In the case of split WIMs, this should be the
+ *     first part, since only the first part contains the metadata resources.
+ * @param resource_wims
+ *     Array of pointers to the ::WIMStruct's for additional resource WIMs or
+ *     split WIM parts to reference.
+ * @param num_resource_wims
+ *     Number of entries in @p resource_wims.
+ * @param ref_flags
+ *     Currently ignored (set to 0).
+ *
+ * @return 0 on success; nonzero on error.  On success, the ::WIMStruct's
+ * specified in @p resource_wims should be considered "don't touch" until either
+ * wimlib_free() is called on @p wim, or wimlib_unreference_resources() is
+ * called to unreference them.
+ *
+ * @retval ::WIMLIB_ERR_INVALID_PARAM
+ *     @p wim was @c NULL, or @p num_resource_wims was nonzero but @p
+ *     resource_wims was @c NULL, or @p wim did not contain metadata resources,
+ *     or an entry in @p resource_wims was @p NULL, or an entry in @p
+ *     resource_wims was already referenced by a call to this function without
+ *     a corresponding call to wimlib_free() on the metadata WIM, or
+ *     wimlib_unreference_resources().
+ */
+extern int
+wimlib_reference_resources(WIMStruct *wim, WIMStruct **resource_wims,
+                          unsigned num_resource_wims, int ref_flags);
+
 /**
  * Declares that a newly added image is mostly the same as a prior image, but
  * captured at a later point in time, possibly with some modifications in the
 /**
  * Declares that a newly added image is mostly the same as a prior image, but
  * captured at a later point in time, possibly with some modifications in the
@@ -2651,18 +2760,18 @@ wimlib_print_metadata(WIMStruct *wim, int image) _wimlib_deprecated;
  * wimlib_add_image()), but before writing the updated WIM file (e.g. with
  * wimlib_overwrite()).
  *
  * wimlib_add_image()), but before writing the updated WIM file (e.g. with
  * wimlib_overwrite()).
  *
- * @p wim
+ * @param wim
  *     Pointer to the ::WIMStruct for a WIM.
  *     Pointer to the ::WIMStruct for a WIM.
- * @p new_image
+ * @param new_image
  *     1-based index in the WIM of the newly added image.  This image can have
  *     been added with wimlib_add_image() or wimlib_add_image_multisource(), or
  *     wimlib_add_empty_image() followed by wimlib_update_image().
  *     1-based index in the WIM of the newly added image.  This image can have
  *     been added with wimlib_add_image() or wimlib_add_image_multisource(), or
  *     wimlib_add_empty_image() followed by wimlib_update_image().
- * @p template_image
+ * @param template_image
  *     1-based index in the WIM of a template image that reflects a prior state
  *     of the directory tree being captured.
  *     1-based index in the WIM of a template image that reflects a prior state
  *     of the directory tree being captured.
- * @p flags
+ * @param flags
  *     Reserved; must be 0.
  *     Reserved; must be 0.
- * @p progress_func
+ * @param progress_func
  *     Currently ignored, but reserved for a function that will be called with
  *     information about the operation.  Use NULL if no additional information
  *     is desired.
  *     Currently ignored, but reserved for a function that will be called with
  *     information about the operation.  Use NULL if no additional information
  *     is desired.
@@ -2672,6 +2781,10 @@ wimlib_print_metadata(WIMStruct *wim, int image) _wimlib_deprecated;
  * @retval ::WIMLIB_ERR_INVALID_IMAGE
  *     @p new_image and/or @p template_image were not a valid image indices in
  *     the WIM.
  * @retval ::WIMLIB_ERR_INVALID_IMAGE
  *     @p new_image and/or @p template_image were not a valid image indices in
  *     the WIM.
+ * @retval ::WIMLIB_ERR_METADATA_NOT_FOUND
+ *     The specified ::WIMStruct did not actually contain the metadata resource
+ *     for the new or template image; for example, it was a non-first part of a
+ *     split WIM.
  * @retval ::WIMLIB_ERR_NOMEM
  *     Failed to allocate needed memory.
  * @retval ::WIMLIB_ERR_INVALID_PARAM
  * @retval ::WIMLIB_ERR_NOMEM
  *     Failed to allocate needed memory.
  * @retval ::WIMLIB_ERR_INVALID_PARAM
@@ -2679,10 +2792,10 @@ wimlib_print_metadata(WIMStruct *wim, int image) _wimlib_deprecated;
  *     an image that had not been modified since opening the WIM.
  *
  * This function can additionally return ::WIMLIB_ERR_DECOMPRESSION,
  *     an image that had not been modified since opening the WIM.
  *
  * This function can additionally return ::WIMLIB_ERR_DECOMPRESSION,
- * ::WIMLIB_ERR_INVALID_METADATA_RESOURCE, ::WIMLIB_ERR_NOMEM,
- * ::WIMLIB_ERR_READ, or ::WIMLIB_ERR_UNEXPECTED_END_OF_FILE, all of which
- * indicate failure (for different reasons) to read the metadata resource for
- * the template image.
+ * ::WIMLIB_ERR_INVALID_METADATA_RESOURCE, ::WIMLIB_ERR_METADATA_NOT_FOUND,
+ * ::WIMLIB_ERR_NOMEM, ::WIMLIB_ERR_READ, or
+ * ::WIMLIB_ERR_UNEXPECTED_END_OF_FILE, all of which indicate failure (for
+ * different reasons) to read the metadata resource for the template image.
  */
 extern int
 wimlib_reference_template_image(WIMStruct *wim, int new_image,
  */
 extern int
 wimlib_reference_template_image(WIMStruct *wim, int new_image,
@@ -2827,8 +2940,8 @@ wimlib_set_image_flags(WIMStruct *wim, int image, const wimlib_tchar *flags);
  *     @p wim is considered read-only because of any of the reasons mentioned
  *     in the documentation for the ::WIMLIB_OPEN_FLAG_WRITE_ACCESS flag.
  */
  *     @p wim is considered read-only because of any of the reasons mentioned
  *     in the documentation for the ::WIMLIB_OPEN_FLAG_WRITE_ACCESS flag.
  */
-extern int wimlib_set_image_name(WIMStruct *wim, int image,
-                                const wimlib_tchar *name);
+extern int
+wimlib_set_image_name(WIMStruct *wim, int image, const wimlib_tchar *name);
 
 /**
  * Set the functions that wimlib uses to allocate and free memory.
 
 /**
  * Set the functions that wimlib uses to allocate and free memory.
@@ -2918,8 +3031,6 @@ wimlib_set_print_errors(bool show_messages);
  * codes that can be returned by wimlib_write() as well as the following error
  * codes:
  *
  * codes that can be returned by wimlib_write() as well as the following error
  * codes:
  *
- * @retval ::WIMLIB_ERR_SPLIT_UNSUPPORTED
- *     @p wim was not part 1 of a stand-alone WIM.
  * @retval ::WIMLIB_ERR_INVALID_PARAM
  *     @p swm_name was not a nonempty string, or @p part_size was 0.
  *
  * @retval ::WIMLIB_ERR_INVALID_PARAM
  *     @p swm_name was not a nonempty string, or @p part_size was 0.
  *
@@ -3002,6 +3113,30 @@ wimlib_unmount_image(const wimlib_tchar *dir,
                     int unmount_flags,
                     wimlib_progress_func_t progress_func);
 
                     int unmount_flags,
                     wimlib_progress_func_t progress_func);
 
+/**
+ * Unreferences resources previously referenced with
+ * wimlib_reference_resources().
+ *
+ * Calling this is not necessary (or even possible) if the higher-level function
+ * wimlib_reference_resource_files() is used.
+ *
+ * @param wim
+ *     See corresponding parameter to wimlib_reference_resources().
+ * @param resource_wims
+ *     See corresponding parameter to wimlib_reference_resources().
+ * @param num_resource_wims
+ *     See corresponding parameter to wimlib_reference_resources().
+ *
+ * @return 0 on success; nonzero on error.
+ *
+ * @retval ::WIMLIB_ERR_INVALID_PARAM
+ *     Not all entries in @p resource_wims specify valid ::WIMStruct's that are
+ *     referenced by @p wim.
+ */
+extern int
+wimlib_unreference_resources(WIMStruct *wim, WIMStruct **resource_wims,
+                            unsigned num_resource_wims);
+
 /**
  * Update a WIM image by adding, deleting, and/or renaming files or directories.
  *
 /**
  * Update a WIM image by adding, deleting, and/or renaming files or directories.
  *
@@ -3025,8 +3160,6 @@ wimlib_unmount_image(const wimlib_tchar *dir,
  * update commands may have been executed.  No individual update command will
  * have been partially executed.  Possible error codes include:
  *
  * update commands may have been executed.  No individual update command will
  * have been partially executed.  Possible error codes include:
  *
- * @retval ::WIMLIB_ERR_DECOMPRESSION
- *     Failed to decompress the metadata resource from @p image in @p wim.
  * @retval ::WIMLIB_ERR_INVALID_CAPTURE_CONFIG
  *     The capture configuration structure specified for an add command was
  *     invalid.
  * @retval ::WIMLIB_ERR_INVALID_CAPTURE_CONFIG
  *     The capture configuration structure specified for an add command was
  *     invalid.
@@ -3047,10 +3180,6 @@ wimlib_unmount_image(const wimlib_tchar *dir,
  * @retval ::WIMLIB_ERR_INVALID_REPARSE_DATA
  *     (Windows only):  While executing an add command, tried to capture a
  *     reparse point with invalid data.
  * @retval ::WIMLIB_ERR_INVALID_REPARSE_DATA
  *     (Windows only):  While executing an add command, tried to capture a
  *     reparse point with invalid data.
- * @retval ::WIMLIB_ERR_INVALID_RESOURCE_SIZE
- *     The metadata resource for @p image in @p wim is invalid.
- * @retval ::WIMLIB_ERR_INVALID_SECURITY_DATA
- *     The security data for image @p image in @p wim is invalid.
  * @retval ::WIMLIB_ERR_IS_DIRECTORY
  *     A delete command without ::WIMLIB_DELETE_FLAG_RECURSIVE specified was
  *     for a WIM path that corresponded to a directory; or, a rename command
  * @retval ::WIMLIB_ERR_IS_DIRECTORY
  *     A delete command without ::WIMLIB_DELETE_FLAG_RECURSIVE specified was
  *     for a WIM path that corresponded to a directory; or, a rename command
@@ -3077,20 +3206,14 @@ wimlib_unmount_image(const wimlib_tchar *dir,
  *     WIM path that did not exist; or, a rename command attempted to rename a
  *     file that does not exist.
  * @retval ::WIMLIB_ERR_READ
  *     WIM path that did not exist; or, a rename command attempted to rename a
  *     file that does not exist.
  * @retval ::WIMLIB_ERR_READ
- *     Failed to read the metadata resource for @p image in @p wim; or, while
- *     executing an add command, failed to read data from a file or directory
- *     to be captured.
+ *     While executing an add command, failed to read data from a file or
+ *     directory to be captured.
  * @retval ::WIMLIB_ERR_READLINK
  *     While executing an add command, failed to read the target of a symbolic
  *     link or junction point.
  * @retval ::WIMLIB_ERR_REPARSE_POINT_FIXUP_FAILED
  *     (Windows only) Failed to perform a reparse point fixup because of
  *     problems with the data of a reparse point.
  * @retval ::WIMLIB_ERR_READLINK
  *     While executing an add command, failed to read the target of a symbolic
  *     link or junction point.
  * @retval ::WIMLIB_ERR_REPARSE_POINT_FIXUP_FAILED
  *     (Windows only) Failed to perform a reparse point fixup because of
  *     problems with the data of a reparse point.
- * @retval ::WIMLIB_ERR_UNSUPPORTED_FILE
- *     While executing an add command, attempted to capture a file that was not
- *     a supported file type (e.g. a device file).  Only if
- *     ::WIMLIB_ADD_FLAG_NO_UNSUPPORTED_EXCLUDE specified in @p the add_flags
- *     for an update command.
  * @retval ::WIMLIB_ERR_STAT
  *     While executing an add command, failed to get attributes for a file or
  *     directory.
  * @retval ::WIMLIB_ERR_STAT
  *     While executing an add command, failed to get attributes for a file or
  *     directory.
@@ -3100,10 +3223,22 @@ wimlib_unmount_image(const wimlib_tchar *dir,
  *     or, the platform is Windows and either the ::WIMLIB_ADD_FLAG_UNIX_DATA
  *     or the ::WIMLIB_ADD_FLAG_DEREFERENCE flags were specified in the @p
  *     add_flags for an update command.
  *     or, the platform is Windows and either the ::WIMLIB_ADD_FLAG_UNIX_DATA
  *     or the ::WIMLIB_ADD_FLAG_DEREFERENCE flags were specified in the @p
  *     add_flags for an update command.
+ * @retval ::WIMLIB_ERR_UNSUPPORTED_FILE
+ *     While executing an add command, attempted to capture a file that was not
+ *     a supported file type (e.g. a device file).  Only if
+ *     ::WIMLIB_ADD_FLAG_NO_UNSUPPORTED_EXCLUDE specified in @p the add_flags
+ *     for an update command.
  * @retval ::WIMLIB_ERR_WIM_IS_READONLY
  *     The WIM file is considered read-only because of any of the reasons
  *     mentioned in the documentation for the ::WIMLIB_OPEN_FLAG_WRITE_ACCESS
  *     flag.
  * @retval ::WIMLIB_ERR_WIM_IS_READONLY
  *     The WIM file is considered read-only because of any of the reasons
  *     mentioned in the documentation for the ::WIMLIB_OPEN_FLAG_WRITE_ACCESS
  *     flag.
+ *
+ * This function can additionally return ::WIMLIB_ERR_DECOMPRESSION,
+ * ::WIMLIB_ERR_INVALID_METADATA_RESOURCE, ::WIMLIB_ERR_METADATA_NOT_FOUND,
+ * ::WIMLIB_ERR_NOMEM, ::WIMLIB_ERR_READ, or
+ * ::WIMLIB_ERR_UNEXPECTED_END_OF_FILE, all of which indicate failure (for
+ * different reasons) to read the metadata resource for an image that needed to
+ * be updated.
  */
 extern int
 wimlib_update_image(WIMStruct *wim,
  */
 extern int
 wimlib_update_image(WIMStruct *wim,
@@ -3147,8 +3282,6 @@ wimlib_update_image(WIMStruct *wim,
  *
  * @return 0 on success; nonzero on error.
  *
  *
  * @return 0 on success; nonzero on error.
  *
- * @retval ::WIMLIB_ERR_DECOMPRESSION
- *     Failed to decompress a metadata or file resource in @p wim.
  * @retval ::WIMLIB_ERR_INVALID_IMAGE
  *     @p image does not specify a single existing image in @p wim, and is not
  *     ::WIMLIB_ALL_IMAGES.
  * @retval ::WIMLIB_ERR_INVALID_IMAGE
  *     @p image does not specify a single existing image in @p wim, and is not
  *     ::WIMLIB_ALL_IMAGES.
@@ -3158,8 +3291,6 @@ wimlib_update_image(WIMStruct *wim,
  *     message digest check.
  * @retval ::WIMLIB_ERR_INVALID_PARAM
  *     @p path was @c NULL.
  *     message digest check.
  * @retval ::WIMLIB_ERR_INVALID_PARAM
  *     @p path was @c NULL.
- * @retval ::WIMLIB_ERR_INVALID_METADATA_RESOURCE
- *     The metadata resource for @p image in @p wim is invalid.
  * @retval ::WIMLIB_ERR_NOMEM
  *     Failed to allocate needed memory.
  * @retval ::WIMLIB_ERR_OPEN
  * @retval ::WIMLIB_ERR_NOMEM
  *     Failed to allocate needed memory.
  * @retval ::WIMLIB_ERR_OPEN
@@ -3173,6 +3304,13 @@ wimlib_update_image(WIMStruct *wim,
  *     files.
  * @retval ::WIMLIB_ERR_WRITE
  *     An error occurred when trying to write data to the new WIM file.
  *     files.
  * @retval ::WIMLIB_ERR_WRITE
  *     An error occurred when trying to write data to the new WIM file.
+ *
+ * This function can additionally return ::WIMLIB_ERR_DECOMPRESSION,
+ * ::WIMLIB_ERR_INVALID_METADATA_RESOURCE, ::WIMLIB_ERR_METADATA_NOT_FOUND,
+ * ::WIMLIB_ERR_NOMEM, ::WIMLIB_ERR_READ, or
+ * ::WIMLIB_ERR_UNEXPECTED_END_OF_FILE, all of which indicate failure (for
+ * different reasons) to read the metadata resource for an image that needed to
+ * be written.
  */
 extern int
 wimlib_write(WIMStruct *wim,
  */
 extern int
 wimlib_write(WIMStruct *wim,
diff --git a/include/wimlib/glob.h b/include/wimlib/glob.h
new file mode 100644 (file)
index 0000000..22ebfa9
--- /dev/null
@@ -0,0 +1,35 @@
+#ifndef _WIMLIB_GLOB_H
+#define _WIMLIB_GLOB_H
+
+#ifndef __WIN32__
+#  include <glob.h>
+#else
+
+#include <wchar.h>
+#include <stddef.h>
+
+typedef struct {
+       size_t    gl_pathc;
+       wchar_t **gl_pathv;
+       size_t    gl_offs;
+} glob_t;
+
+/* WARNING: this is a reduced functionality replacement */
+extern int
+win32_wglob(const wchar_t *pattern, int flags,
+           int (*errfunc)(const wchar_t *epath, int eerrno),
+           glob_t *pglob);
+
+extern void globfree(glob_t *pglob);
+
+#define        GLOB_ERR        0x1 /* Return on read errors.  */
+#define        GLOB_NOSORT     0x2 /* Don't sort the names.  */
+
+/* Error returns from `glob'.  */
+#define        GLOB_NOSPACE    1       /* Ran out of memory.  */
+#define        GLOB_ABORTED    2       /* Read error.  */
+#define        GLOB_NOMATCH    3       /* No matches found.  */
+
+#endif /* __WIN32__ */
+
+#endif /* _WIMLIB_GLOB_H */
index 481794daf74d20849612eb1c23132b9f27da6223..746d744965718a9dc5090374cb8e74769a5600a3 100644 (file)
@@ -416,6 +416,9 @@ extern int
 inode_resolve_ltes(struct wim_inode *inode, struct wim_lookup_table *table,
                   bool force);
 
 inode_resolve_ltes(struct wim_inode *inode, struct wim_lookup_table *table,
                   bool force);
 
+extern int
+resource_not_found_error(struct wim_inode *inode, const u8 *hash);
+
 extern void
 inode_unresolve_ltes(struct wim_inode *inode);
 
 extern void
 inode_unresolve_ltes(struct wim_inode *inode);
 
diff --git a/include/wimlib/swm.h b/include/wimlib/swm.h
deleted file mode 100644 (file)
index 08a51fc..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef _WIMLIB_SWM_H
-#define _WIMLIB_SWM_H
-
-#include "wimlib/types.h"
-
-extern int
-verify_swm_set(WIMStruct *wim,
-              WIMStruct **additional_swms, unsigned num_additional_swms);
-
-extern void
-merge_lookup_tables(WIMStruct *wim,
-                   WIMStruct **additional_swms, unsigned num_additional_swms);
-
-extern void
-unmerge_lookup_table(WIMStruct *wim);
-
-#endif
index dfd31fa3f9a758720762faa5d922335202169f45..fc36c51991a534f32a551aff1659c8aacc7dec19 100644 (file)
@@ -4,6 +4,7 @@
 #include "wimlib/header.h"
 #include "wimlib/types.h"
 #include "wimlib/file_io.h"
 #include "wimlib/header.h"
 #include "wimlib/types.h"
 #include "wimlib/file_io.h"
+#include "wimlib/list.h"
 
 struct wim_info;
 struct wim_lookup_table;
 
 struct wim_info;
 struct wim_lookup_table;
@@ -41,6 +42,12 @@ struct WIMStruct {
        /* Temporary field */
        void *private;
 
        /* Temporary field */
        void *private;
 
+       WIMStruct *master_wim;
+
+       struct list_head resource_wims;
+
+       struct list_head resource_wim_node;
+
        /* The currently selected image, indexed starting at 1.  If not 0,
         * subtract 1 from this to get the index of the current image in the
         * image_metadata array. */
        /* The currently selected image, indexed starting at 1.  If not 0,
         * subtract 1 from this to get the index of the current image in the
         * image_metadata array. */
@@ -58,6 +65,10 @@ struct WIMStruct {
 
        u8 wim_locked : 1;
 
 
        u8 wim_locked : 1;
 
+       u8 being_unmerged : 1;
+
+       u8 is_owned_by_master : 1;
+
        /* One of WIMLIB_COMPRESSION_TYPE_*, cached from the header flags. */
        u8 compression_type : 2;
 };
        /* One of WIMLIB_COMPRESSION_TYPE_*, cached from the header flags. */
        u8 compression_type : 2;
 };
@@ -72,6 +83,11 @@ static inline bool wim_has_integrity_table(const WIMStruct *wim)
        return (wim->hdr.integrity.offset != 0);
 }
 
        return (wim->hdr.integrity.offset != 0);
 }
 
+static inline bool wim_has_metadata(const WIMStruct *wim)
+{
+       return (wim->image_metadata != NULL || wim->hdr.image_count == 0);
+}
+
 extern void
 wim_recalculate_refcnts(WIMStruct *wim);
 
 extern void
 wim_recalculate_refcnts(WIMStruct *wim);
 
index fefaabc491158d345191aba11bfc68905c8b8fe2..4d33efef554fa2c804a5b79bbc59dd10b81b03c0 100644 (file)
@@ -24,7 +24,7 @@ typedef wchar_t tchar;
 #  define tmempcpy     wmempcpy
 #  define tstrcpy      wcscpy
 #  define tprintf      wprintf
 #  define tmempcpy     wmempcpy
 #  define tstrcpy      wcscpy
 #  define tprintf      wprintf
-#  define tsprintf     swprintf
+#  define tsprintf     _swprintf
 #  define tfprintf     fwprintf
 #  define tvfprintf    vfwprintf
 #  define istalpha     iswalpha
 #  define tfprintf     fwprintf
 #  define tvfprintf    vfwprintf
 #  define istalpha     iswalpha
@@ -61,6 +61,7 @@ typedef wchar_t tchar;
 #  define tstrerror_r   win32_strerror_r_replacement
 #  define trename      win32_rename_replacement
 #  define ttruncate    win32_truncate_replacement
 #  define tstrerror_r   win32_strerror_r_replacement
 #  define trename      win32_rename_replacement
 #  define ttruncate    win32_truncate_replacement
+#  define tglob                win32_wglob
 #else /* __WIN32__ */
 /* For non-Windows builds, the "tchar" type will be one byte and will specify a
  * string in the locale-dependent multibyte encoding.  However, only UTF-8 is
 #else /* __WIN32__ */
 /* For non-Windows builds, the "tchar" type will be one byte and will specify a
  * string in the locale-dependent multibyte encoding.  However, only UTF-8 is
@@ -118,6 +119,7 @@ typedef char tchar;
 #  define trename      rename
 #  define ttruncate    truncate
 #  define taccess      access
 #  define trename      rename
 #  define ttruncate    truncate
 #  define taccess      access
+#  define tglob                glob
 #endif /* !__WIN32__ */
 
 #endif /* _WIMLIB_TCHAR_H */
 #endif /* !__WIN32__ */
 
 #endif /* _WIMLIB_TCHAR_H */
index a0cbc33dec91fd5d3c648d2ccae3fd16ed3203fd..083c1453a9dc1d034721770e55ca28c7b8b38586 100644 (file)
 #endif
 
 #include "imagex-win32.h"
 #endif
 
 #include "imagex-win32.h"
-#include <assert.h>
-#include <errno.h>
 #include <fcntl.h>
 #include <io.h>
 #include <stdio.h>
 #include <fcntl.h>
 #include <io.h>
 #include <stdio.h>
-#include <string.h>
 #include <windows.h>
 
 #include <windows.h>
 
-/* Replacement for glob() in Windows native builds that operates on wide
- * characters.  */
-int
-win32_wglob(const wchar_t *pattern, int flags,
-           int (*errfunc)(const wchar_t *epath, int eerrno),
-           glob_t *pglob)
-{
-       WIN32_FIND_DATAW dat;
-       DWORD err;
-       HANDLE hFind;
-       int ret;
-       size_t nspaces;
-
-       const wchar_t *backslash, *end_slash;
-       size_t prefix_len;
-
-       backslash = wcsrchr(pattern, L'\\');
-       end_slash = wcsrchr(pattern, L'/');
-
-       if (backslash > end_slash)
-               end_slash = backslash;
-
-       if (end_slash)
-               prefix_len = end_slash - pattern + 1;
-       else
-               prefix_len = 0;
-
-       /* This function does not support all functionality of the POSIX glob(),
-        * so make sure the parameters are consistent with supported
-        * functionality. */
-       assert(errfunc == NULL);
-       assert((flags & GLOB_ERR) == GLOB_ERR);
-       assert((flags & ~(GLOB_NOSORT | GLOB_ERR)) == 0);
-
-       hFind = FindFirstFileW(pattern, &dat);
-       if (hFind == INVALID_HANDLE_VALUE) {
-               err = GetLastError();
-               if (err == ERROR_FILE_NOT_FOUND) {
-                       errno = 0;
-                       return GLOB_NOMATCH;
-               } else {
-                       /* The other possible error codes for FindFirstFile()
-                        * are undocumented. */
-                       errno = EIO;
-                       return GLOB_ABORTED;
-               }
-       }
-       pglob->gl_pathc = 0;
-       pglob->gl_pathv = NULL;
-       nspaces = 0;
-       do {
-               wchar_t *path;
-               if (pglob->gl_pathc == nspaces) {
-                       size_t new_nspaces;
-                       wchar_t **pathv;
-
-                       new_nspaces = nspaces * 2 + 1;  
-                       pathv = realloc(pglob->gl_pathv,
-                                       new_nspaces * sizeof(pglob->gl_pathv[0]));
-                       if (!pathv)
-                               goto oom;
-                       pglob->gl_pathv = pathv;
-                       nspaces = new_nspaces;
-               }
-               size_t filename_len = wcslen(dat.cFileName);
-               size_t len_needed = prefix_len + filename_len;
-
-               path = malloc((len_needed + 1) * sizeof(wchar_t));
-               if (!path)
-                       goto oom;
-
-               wmemcpy(path, pattern, prefix_len);
-               wmemcpy(path + prefix_len, dat.cFileName, filename_len + 1);
-               pglob->gl_pathv[pglob->gl_pathc++] = path;
-       } while (FindNextFileW(hFind, &dat));
-       err = GetLastError();
-       CloseHandle(hFind);
-       if (err == ERROR_NO_MORE_FILES) {
-               errno = 0;
-               return 0;
-       } else {
-               /* Other possible error codes for FindNextFile() are
-                * undocumented */
-               errno = EIO;
-               ret = GLOB_ABORTED;
-               goto fail_globfree;
-       }
-oom:
-       CloseHandle(hFind);
-       errno = ENOMEM;
-       ret = GLOB_NOSPACE;
-fail_globfree:
-       globfree(pglob);
-       return ret;
-}
-
-void
-globfree(glob_t *pglob)
-{
-       size_t i;
-       for (i = 0; i < pglob->gl_pathc; i++)
-               free(pglob->gl_pathv[i]);
-       free(pglob->gl_pathv);
-}
-
 /* Convert a string from the "current Windows codepage" to UTF-16LE.  */
 wchar_t *
 win32_mbs_to_wcs(const char *mbs, size_t mbs_nbytes, size_t *num_wchars_ret)
 /* Convert a string from the "current Windows codepage" to UTF-16LE.  */
 wchar_t *
 win32_mbs_to_wcs(const char *mbs, size_t mbs_nbytes, size_t *num_wchars_ret)
index 0d5f5ad2a4a446e56ffa4f98193c6b8e5b5fb47b..bf1d2a7f0979df29d9abd7851c6d96234914a917 100644 (file)
@@ -5,40 +5,6 @@
 #include <stdbool.h>
 #include <wchar.h>
 
 #include <stdbool.h>
 #include <wchar.h>
 
-typedef struct {
-       size_t    gl_pathc;
-       wchar_t **gl_pathv;
-       size_t    gl_offs;
-} glob_t;
-
-/* WARNING: this is a reduced functionality replacement */
-extern int
-win32_wglob(const wchar_t *pattern, int flags,
-           int (*errfunc)(const wchar_t *epath, int eerrno),
-           glob_t *pglob);
-
-extern void globfree(glob_t *pglob);
-
-#define        GLOB_ERR        0x1 /* Return on read errors.  */
-#define        GLOB_NOSORT     0x2 /* Don't sort the names.  */
-
-/* Error returns from `glob'.  */
-#define        GLOB_NOSPACE    1       /* Ran out of memory.  */
-#define        GLOB_ABORTED    2       /* Read error.  */
-#define        GLOB_NOMATCH    3       /* No matches found.  */
-
-extern void
-win32_acquire_capture_privileges(void);
-
-extern void
-win32_release_capture_privileges(void);
-
-extern void
-win32_acquire_restore_privileges(void);
-
-extern void
-win32_release_restore_privileges(void);
-
 extern wchar_t *
 win32_mbs_to_wcs(const char *mbs, size_t mbs_nbytes, size_t *num_wchars_ret);
 
 extern wchar_t *
 win32_mbs_to_wcs(const char *mbs, size_t mbs_nbytes, size_t *num_wchars_ret);
 
index f7a3620bd049fe43d31ad20af2bb3b322b7aa29e..e3800ca3a13382168eeec1ff537d257d977adf40 100644 (file)
@@ -49,7 +49,6 @@
 #ifdef __WIN32__
 #  include "imagex-win32.h"
 #  define tbasename    win32_wbasename
 #ifdef __WIN32__
 #  include "imagex-win32.h"
 #  define tbasename    win32_wbasename
-#  define tglob                win32_wglob
 #  define OS_PREFERRED_PATH_SEPARATOR L'\\'
 #  define OS_PREFERRED_PATH_SEPARATOR_STRING L"\\"
 #else /* __WIN32__ */
 #  define OS_PREFERRED_PATH_SEPARATOR L'\\'
 #  define OS_PREFERRED_PATH_SEPARATOR_STRING L"\\"
 #else /* __WIN32__ */
@@ -57,7 +56,6 @@
 #  include <getopt.h>
 #  include <langinfo.h>
 #  define tbasename    basename
 #  include <getopt.h>
 #  include <langinfo.h>
 #  define tbasename    basename
-#  define tglob                glob
 #  define OS_PREFERRED_PATH_SEPARATOR '/'
 #  define OS_PREFERRED_PATH_SEPARATOR_STRING "/"
 static inline void set_fd_to_binary_mode(int fd)
 #  define OS_PREFERRED_PATH_SEPARATOR '/'
 #  define OS_PREFERRED_PATH_SEPARATOR_STRING "/"
 static inline void set_fd_to_binary_mode(int fd)
@@ -80,7 +78,6 @@ static inline void set_fd_to_binary_mode(int fd)
 #define for_opt(c, opts) while ((c = getopt_long_only(argc, (tchar**)argv, T(""), \
                                opts, NULL)) != -1)
 
 #define for_opt(c, opts) while ((c = getopt_long_only(argc, (tchar**)argv, T(""), \
                                opts, NULL)) != -1)
 
-
 enum {
        CMD_NONE = -1,
        CMD_APPEND = 0,
 enum {
        CMD_NONE = -1,
        CMD_APPEND = 0,
@@ -110,6 +107,9 @@ static void usage_all(FILE *fp);
 static void recommend_man_page(int cmd, FILE *fp);
 static const tchar *get_cmd_string(int cmd, bool nospace);
 
 static void recommend_man_page(int cmd, FILE *fp);
 static const tchar *get_cmd_string(int cmd, bool nospace);
 
+static int imagex_progress_func(enum wimlib_progress_msg msg,
+                               const union wimlib_progress_info *info);
+
 static bool imagex_be_quiet = false;
 static FILE *imagex_info_file;
 
 static bool imagex_be_quiet = false;
 static FILE *imagex_info_file;
 
@@ -411,6 +411,75 @@ get_compression_type(const tchar *optarg)
        }
 }
 
        }
 }
 
+struct refglob_set {
+       const tchar **globs;
+       unsigned num_globs;
+       unsigned num_alloc_globs;
+};
+
+#define REFGLOB_SET_INITIALIZER \
+       { .globs = NULL, .num_globs = 0, .num_alloc_globs = 0, }
+
+#define REFGLOB_SET(_refglobs) \
+       struct refglob_set _refglobs = REFGLOB_SET_INITIALIZER
+
+static int
+refglob_set_append(struct refglob_set *set, const tchar *glob)
+{
+       unsigned num_alloc_globs = set->num_alloc_globs;
+
+       if (set->num_globs == num_alloc_globs) {
+               const tchar **new_globs;
+
+               num_alloc_globs += 4;
+               new_globs = realloc(set->globs, sizeof(set->globs[0]) * num_alloc_globs);
+               if (!new_globs) {
+                       imagex_error(T("Out of memory!"));
+                       return -1;
+               }
+               set->globs = new_globs;
+               set->num_alloc_globs = num_alloc_globs;
+       }
+       set->globs[set->num_globs++] = glob;
+       return 0;
+}
+
+static int
+wim_reference_globs(WIMStruct *wim, struct refglob_set *set, int open_flags)
+{
+       return wimlib_reference_resource_files(wim, set->globs, set->num_globs,
+                                              WIMLIB_REF_FLAG_GLOB_ENABLE,
+                                              open_flags,
+                                              imagex_progress_func);
+}
+
+static void
+refglob_set_destroy(struct refglob_set *set)
+{
+       free(set->globs);
+}
+
+static void
+do_resource_not_found_warning(const tchar *wimfile,
+                             const struct wimlib_wim_info *info,
+                             const struct refglob_set *refglobs)
+{
+       if (info->total_parts > 1) {
+               if (refglobs->num_globs == 0) {
+                       imagex_error(T("\"%"TS"\" is part of a split WIM. "
+                                      "Use --ref to specify the other parts."),
+                                    wimfile);
+               } else {
+                       imagex_error(T("Perhaps the '--ref' argument did not "
+                                      "specify all other parts of the split "
+                                      "WIM?"));
+               }
+       } else {
+               imagex_error(T("If this is a delta WIM, use the --ref argument "
+                              "to specify the WIM on which it is based."));
+       }
+}
+
 /* Returns the size of a file given its name, or -1 if the file does not exist
  * or its size cannot be determined.  */
 static off_t
 /* Returns the size of a file given its name, or -1 if the file does not exist
  * or its size cannot be determined.  */
 static off_t
@@ -1154,70 +1223,6 @@ imagex_progress_func(enum wimlib_progress_msg msg,
        return 0;
 }
 
        return 0;
 }
 
-/* Open all the split WIM parts that correspond to a file glob.
- *
- * @first_part specifies the first part of the split WIM and it may be either
- * included or omitted from the glob. */
-static int
-open_swms_from_glob(const tchar *swm_glob,
-                   const tchar *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;
-
-       /* Warning: glob() is replaced in Windows native builds */
-       ret = tglob(swm_glob, GLOB_ERR | GLOB_NOSORT, NULL, &globbuf);
-       if (ret) {
-               if (ret == GLOB_NOMATCH) {
-                       imagex_error(T("Found no files for glob \"%"TS"\""),
-                                    swm_glob);
-               } else {
-                       imagex_error_with_errno(T("Failed to process glob \"%"TS"\""),
-                                               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(T("Out of memory"));
-               ret = -1;
-               goto out_globfree;
-       }
-       unsigned offset = 0;
-       for (unsigned i = 0; i < num_additional_swms; i++) {
-               if (tstrcmp(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],
-                                     imagex_progress_func);
-               if (ret)
-                       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 unsigned
 parse_num_threads(const tchar *optarg)
 {
 static unsigned
 parse_num_threads(const tchar *optarg)
 {
@@ -1448,15 +1453,14 @@ imagex_apply(int argc, tchar **argv, int cmd)
        int open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK;
        int image;
        WIMStruct *wim;
        int open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK;
        int image;
        WIMStruct *wim;
+       struct wimlib_wim_info info;
        int ret;
        const tchar *wimfile;
        const tchar *target;
        const tchar *image_num_or_name;
        int extract_flags = WIMLIB_EXTRACT_FLAG_SEQUENTIAL;
 
        int ret;
        const tchar *wimfile;
        const tchar *target;
        const tchar *image_num_or_name;
        int extract_flags = WIMLIB_EXTRACT_FLAG_SEQUENTIAL;
 
-       const tchar *swm_glob = NULL;
-       WIMStruct **additional_swms;
-       unsigned num_additional_swms;
+       REFGLOB_SET(refglobs);
 
        for_opt(c, apply_options) {
                switch (c) {
 
        for_opt(c, apply_options) {
                switch (c) {
@@ -1473,7 +1477,9 @@ imagex_apply(int argc, tchar **argv, int cmd)
                        extract_flags |= WIMLIB_EXTRACT_FLAG_VERBOSE;
                        break;
                case IMAGEX_REF_OPTION:
                        extract_flags |= WIMLIB_EXTRACT_FLAG_VERBOSE;
                        break;
                case IMAGEX_REF_OPTION:
-                       swm_glob = optarg;
+                       ret = refglob_set_append(&refglobs, optarg);
+                       if (ret)
+                               goto out_free_refglobs;
                        break;
                case IMAGEX_UNIX_DATA_OPTION:
                        extract_flags |= WIMLIB_EXTRACT_FLAG_UNIX_DATA;
                        break;
                case IMAGEX_UNIX_DATA_OPTION:
                        extract_flags |= WIMLIB_EXTRACT_FLAG_UNIX_DATA;
@@ -1518,13 +1524,13 @@ imagex_apply(int argc, tchar **argv, int cmd)
                        target = argv[2];
                }
                wim = NULL;
                        target = argv[2];
                }
                wim = NULL;
-               num_additional_swms = 0;
-               additional_swms = NULL;
        } else {
                ret = wimlib_open_wim(wimfile, open_flags, &wim,
                                      imagex_progress_func);
                if (ret)
        } else {
                ret = wimlib_open_wim(wimfile, open_flags, &wim,
                                      imagex_progress_func);
                if (ret)
-                       goto out;
+                       goto out_free_refglobs;
+
+               wimlib_get_wim_info(wim, &info);
 
                if (argc >= 3) {
                        /* Image explicitly specified.  */
 
                if (argc >= 3) {
                        /* Image explicitly specified.  */
@@ -1537,9 +1543,7 @@ imagex_apply(int argc, tchar **argv, int cmd)
                } else {
                        /* No image specified; default to image 1, but only if the WIM
                         * contains exactly one image.  */
                } else {
                        /* No image specified; default to image 1, but only if the WIM
                         * contains exactly one image.  */
-                       struct wimlib_wim_info info;
 
 
-                       wimlib_get_wim_info(wim, &info);
                        if (info.image_count != 1) {
                                imagex_error(T("\"%"TS"\" contains %d images; "
                                               "Please select one (or all)."),
                        if (info.image_count != 1) {
                                imagex_error(T("\"%"TS"\" contains %d images; "
                                               "Please select one (or all)."),
@@ -1550,17 +1554,17 @@ imagex_apply(int argc, tchar **argv, int cmd)
                        image = 1;
                        target = argv[1];
                }
                        image = 1;
                        target = argv[1];
                }
+       }
 
 
-               if (swm_glob) {
-                       ret = open_swms_from_glob(swm_glob, wimfile, open_flags,
-                                                 &additional_swms,
-                                                 &num_additional_swms);
-                       if (ret)
-                               goto out_wimlib_free;
-               } else {
-                       additional_swms = NULL;
-                       num_additional_swms = 0;
+       if (refglobs.num_globs) {
+               if (wim == NULL) {
+                       imagex_error(T("Can't specify --ref when applying from stdin!"));
+                       ret = -1;
+                       goto out_wimlib_free;
                }
                }
+               ret = wim_reference_globs(wim, &refglobs, open_flags);
+               if (ret)
+                       goto out_wimlib_free;
        }
 
 #ifndef __WIN32__
        }
 
 #ifndef __WIN32__
@@ -1574,7 +1578,7 @@ imagex_apply(int argc, tchar **argv, int cmd)
                                imagex_error_with_errno(T("Failed to stat \"%"TS"\""),
                                                        target);
                                ret = -1;
                                imagex_error_with_errno(T("Failed to stat \"%"TS"\""),
                                                        target);
                                ret = -1;
-                               goto out_free_swms;
+                               goto out_wimlib_free;
                        }
                } else {
                        if (S_ISBLK(stbuf.st_mode) || S_ISREG(stbuf.st_mode))
                        }
                } else {
                        if (S_ISBLK(stbuf.st_mode) || S_ISREG(stbuf.st_mode))
@@ -1585,7 +1589,6 @@ imagex_apply(int argc, tchar **argv, int cmd)
 
        if (wim) {
                ret = wimlib_extract_image(wim, image, target, extract_flags,
 
        if (wim) {
                ret = wimlib_extract_image(wim, image, target, extract_flags,
-                                          additional_swms, num_additional_swms,
                                           imagex_progress_func);
        } else {
                set_fd_to_binary_mode(STDIN_FILENO);
                                           imagex_progress_func);
        } else {
                set_fd_to_binary_mode(STDIN_FILENO);
@@ -1594,21 +1597,28 @@ imagex_apply(int argc, tchar **argv, int cmd)
                                                     target, extract_flags,
                                                     imagex_progress_func);
        }
                                                     target, extract_flags,
                                                     imagex_progress_func);
        }
-       if (ret == 0)
+       if (ret == 0) {
                imagex_printf(T("Done applying WIM image.\n"));
                imagex_printf(T("Done applying WIM image.\n"));
-out_free_swms:
-       for (unsigned i = 0; i < num_additional_swms; i++)
-               wimlib_free(additional_swms[i]);
-       free(additional_swms);
+       } else if (ret == WIMLIB_ERR_RESOURCE_NOT_FOUND) {
+               if (wim) {
+                       do_resource_not_found_warning(wimfile, &info, &refglobs);
+               } else {
+                       imagex_error(T(        "If you are applying an image "
+                                              "from a split pipable WIM,\n"
+                                      "       make sure you have "
+                                      "concatenated together all parts."));
+               }
+       }
 out_wimlib_free:
        wimlib_free(wim);
 out_wimlib_free:
        wimlib_free(wim);
-out:
+out_free_refglobs:
+       refglob_set_destroy(&refglobs);
        return ret;
 
 out_usage:
        usage(CMD_APPLY, stderr);
        ret = -1;
        return ret;
 
 out_usage:
        usage(CMD_APPLY, stderr);
        ret = -1;
-       goto out;
+       goto out_free_refglobs;
 }
 
 /* Create a WIM image from a directory tree, NTFS volume, or multiple files or
 }
 
 /* Create a WIM image from a directory tree, NTFS volume, or multiple files or
@@ -2144,14 +2154,13 @@ imagex_export(int argc, tchar **argv, int cmd)
        const tchar *dest_name;
        const tchar *dest_desc;
        WIMStruct *src_wim;
        const tchar *dest_name;
        const tchar *dest_desc;
        WIMStruct *src_wim;
+       struct wimlib_wim_info src_info;
        WIMStruct *dest_wim;
        int ret;
        int image;
        struct stat stbuf;
        bool wim_is_new;
        WIMStruct *dest_wim;
        int ret;
        int image;
        struct stat stbuf;
        bool wim_is_new;
-       const tchar *swm_glob = NULL;
-       WIMStruct **additional_swms;
-       unsigned num_additional_swms;
+       REFGLOB_SET(refglobs);
        unsigned num_threads = 0;
 
        for_opt(c, export_options) {
        unsigned num_threads = 0;
 
        for_opt(c, export_options) {
@@ -2172,7 +2181,9 @@ imagex_export(int argc, tchar **argv, int cmd)
                                goto out_err;
                        break;
                case IMAGEX_REF_OPTION:
                                goto out_err;
                        break;
                case IMAGEX_REF_OPTION:
-                       swm_glob = optarg;
+                       ret = refglob_set_append(&refglobs, optarg);
+                       if (ret)
+                               goto out_free_refglobs;
                        break;
                case IMAGEX_THREADS_OPTION:
                        num_threads = parse_num_threads(optarg);
                        break;
                case IMAGEX_THREADS_OPTION:
                        num_threads = parse_num_threads(optarg);
@@ -2205,7 +2216,9 @@ imagex_export(int argc, tchar **argv, int cmd)
                              open_flags | WIMLIB_OPEN_FLAG_SPLIT_OK, &src_wim,
                              imagex_progress_func);
        if (ret)
                              open_flags | WIMLIB_OPEN_FLAG_SPLIT_OK, &src_wim,
                              imagex_progress_func);
        if (ret)
-               goto out;
+               goto out_free_refglobs;
+
+       wimlib_get_wim_info(src_wim, &src_info);
 
        /* Determine if the destination is an existing file or not.  If so, we
         * try to append the exported image(s) to it; otherwise, we create a new
 
        /* Determine if the destination is an existing file or not.  If so, we
         * try to append the exported image(s) to it; otherwise, we create a new
@@ -2278,9 +2291,6 @@ imagex_export(int argc, tchar **argv, int cmd)
                        /* The user did not specify a compression type; default
                         * to that of the source WIM.  */
 
                        /* The user did not specify a compression type; default
                         * to that of the source WIM.  */
 
-                       struct wimlib_wim_info src_info;
-
-                       wimlib_get_wim_info(src_wim, &src_info);
                        compression_type = src_info.compression_type;
                }
                ret = wimlib_create_new_wim(compression_type, &dest_wim);
                        compression_type = src_info.compression_type;
                }
                ret = wimlib_create_new_wim(compression_type, &dest_wim);
@@ -2293,22 +2303,30 @@ imagex_export(int argc, tchar **argv, int cmd)
        if (ret)
                goto out_free_dest_wim;
 
        if (ret)
                goto out_free_dest_wim;
 
-       if (swm_glob) {
-               ret = open_swms_from_glob(swm_glob, src_wimfile, open_flags,
-                                         &additional_swms,
-                                         &num_additional_swms);
+       if (refglobs.num_globs) {
+               ret = wim_reference_globs(src_wim, &refglobs, open_flags);
                if (ret)
                        goto out_free_dest_wim;
                if (ret)
                        goto out_free_dest_wim;
-       } else {
-               additional_swms = NULL;
-               num_additional_swms = 0;
+       }
+
+       if ((export_flags & WIMLIB_EXPORT_FLAG_BOOT) &&
+           image == WIMLIB_ALL_IMAGES && src_info.boot_index == 0)
+       {
+               imagex_error(T("--boot specified for all-images export, but source WIM "
+                              "has no bootable image."));
+               ret = -1;
+               goto out_free_dest_wim;
        }
 
        ret = wimlib_export_image(src_wim, image, dest_wim, dest_name,
        }
 
        ret = wimlib_export_image(src_wim, image, dest_wim, dest_name,
-                                 dest_desc, export_flags, additional_swms,
-                                 num_additional_swms, imagex_progress_func);
-       if (ret)
-               goto out_free_swms;
+                                 dest_desc, export_flags, imagex_progress_func);
+       if (ret) {
+               if (ret == WIMLIB_ERR_RESOURCE_NOT_FOUND) {
+                       do_resource_not_found_warning(src_wimfile,
+                                                     &src_info, &refglobs);
+               }
+               goto out_free_dest_wim;
+       }
 
        if (!wim_is_new)
                ret = wimlib_overwrite(dest_wim, write_flags, num_threads,
 
        if (!wim_is_new)
                ret = wimlib_overwrite(dest_wim, write_flags, num_threads,
@@ -2321,24 +2339,19 @@ imagex_export(int argc, tchar **argv, int cmd)
                ret = wimlib_write_to_fd(dest_wim, dest_wim_fd,
                                         WIMLIB_ALL_IMAGES, write_flags,
                                         num_threads, imagex_progress_func);
                ret = wimlib_write_to_fd(dest_wim, dest_wim_fd,
                                         WIMLIB_ALL_IMAGES, write_flags,
                                         num_threads, imagex_progress_func);
-       if (ret)
-               imagex_error(T("Export failed."));
-out_free_swms:
-       for (unsigned i = 0; i < num_additional_swms; i++)
-               wimlib_free(additional_swms[i]);
-       free(additional_swms);
 out_free_dest_wim:
        wimlib_free(dest_wim);
 out_free_src_wim:
        wimlib_free(src_wim);
 out_free_dest_wim:
        wimlib_free(dest_wim);
 out_free_src_wim:
        wimlib_free(src_wim);
-out:
+out_free_refglobs:
+       refglob_set_destroy(&refglobs);
        return ret;
 
 out_usage:
        usage(CMD_EXPORT, stderr);
 out_err:
        ret = -1;
        return ret;
 
 out_usage:
        usage(CMD_EXPORT, stderr);
 out_err:
        ret = -1;
-       goto out;
+       goto out_free_refglobs;
 }
 
 static bool
 }
 
 static bool
@@ -2416,9 +2429,7 @@ imagex_extract(int argc, tchar **argv, int cmd)
        tchar *dest_dir = T(".");
        int extract_flags = WIMLIB_EXTRACT_FLAG_SEQUENTIAL | WIMLIB_EXTRACT_FLAG_NORPFIX;
 
        tchar *dest_dir = T(".");
        int extract_flags = WIMLIB_EXTRACT_FLAG_SEQUENTIAL | WIMLIB_EXTRACT_FLAG_NORPFIX;
 
-       const tchar *swm_glob = NULL;
-       WIMStruct **additional_swms;
-       unsigned num_additional_swms;
+       REFGLOB_SET(refglobs);
 
        struct wimlib_extract_command *cmds;
        size_t num_cmds;
 
        struct wimlib_extract_command *cmds;
        size_t num_cmds;
@@ -2432,7 +2443,9 @@ imagex_extract(int argc, tchar **argv, int cmd)
                        extract_flags |= WIMLIB_EXTRACT_FLAG_VERBOSE;
                        break;
                case IMAGEX_REF_OPTION:
                        extract_flags |= WIMLIB_EXTRACT_FLAG_VERBOSE;
                        break;
                case IMAGEX_REF_OPTION:
-                       swm_glob = optarg;
+                       ret = refglob_set_append(&refglobs, optarg);
+                       if (ret)
+                               goto out_free_refglobs;
                        break;
                case IMAGEX_UNIX_DATA_OPTION:
                        extract_flags |= WIMLIB_EXTRACT_FLAG_UNIX_DATA;
                        break;
                case IMAGEX_UNIX_DATA_OPTION:
                        extract_flags |= WIMLIB_EXTRACT_FLAG_UNIX_DATA;
@@ -2487,19 +2500,13 @@ imagex_extract(int argc, tchar **argv, int cmd)
        if (ret)
                goto out_wimlib_free;
 
        if (ret)
                goto out_wimlib_free;
 
-       if (swm_glob) {
-               ret = open_swms_from_glob(swm_glob, wimfile, open_flags,
-                                         &additional_swms,
-                                         &num_additional_swms);
+       if (refglobs.num_globs) {
+               ret = wim_reference_globs(wim, &refglobs, open_flags);
                if (ret)
                        goto out_wimlib_free;
                if (ret)
                        goto out_wimlib_free;
-       } else {
-               additional_swms = NULL;
-               num_additional_swms = 0;
        }
 
        ret = wimlib_extract_files(wim, image, cmds, num_cmds, 0,
        }
 
        ret = wimlib_extract_files(wim, image, cmds, num_cmds, 0,
-                                  additional_swms, num_additional_swms,
                                   imagex_progress_func);
        if (ret == 0) {
                if (!imagex_be_quiet)
                                   imagex_progress_func);
        if (ret == 0) {
                if (!imagex_be_quiet)
@@ -2509,22 +2516,25 @@ imagex_extract(int argc, tchar **argv, int cmd)
                                   "files and directories\n"
                                   "      are in the WIM image.\n"),
                                get_cmd_string(CMD_INFO, false));
                                   "files and directories\n"
                                   "      are in the WIM image.\n"),
                                get_cmd_string(CMD_INFO, false));
+       } else if (ret == WIMLIB_ERR_RESOURCE_NOT_FOUND) {
+               struct wimlib_wim_info info;
+
+               wimlib_get_wim_info(wim, &info);
+               do_resource_not_found_warning(wimfile, &info, &refglobs);
        }
        }
-       for (unsigned i = 0; i < num_additional_swms; i++)
-               wimlib_free(additional_swms[i]);
-       free(additional_swms);
 out_wimlib_free:
        wimlib_free(wim);
 out_free_cmds:
        free_extract_commands(cmds, num_cmds, dest_dir);
 out_wimlib_free:
        wimlib_free(wim);
 out_free_cmds:
        free_extract_commands(cmds, num_cmds, dest_dir);
-out:
+out_free_refglobs:
+       refglob_set_destroy(&refglobs);
        return ret;
 
 out_usage:
        usage(CMD_EXTRACT, stderr);
 out_err:
        ret = -1;
        return ret;
 
 out_usage:
        usage(CMD_EXTRACT, stderr);
 out_err:
        ret = -1;
-       goto out;
+       goto out_free_refglobs;
 }
 
 static void print_byte_field(const uint8_t field[], size_t len)
 }
 
 static void print_byte_field(const uint8_t field[], size_t len)
@@ -2928,15 +2938,15 @@ imagex_mount_rw_or_ro(int argc, tchar **argv, int cmd)
        int c;
        int mount_flags = 0;
        int open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK;
        int c;
        int mount_flags = 0;
        int open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK;
-       const tchar *swm_glob = NULL;
        const tchar *staging_dir = NULL;
        const tchar *wimfile;
        const tchar *dir;
        WIMStruct *wim;
        const tchar *staging_dir = NULL;
        const tchar *wimfile;
        const tchar *dir;
        WIMStruct *wim;
+       struct wimlib_wim_info info;
        int image;
        int ret;
        int image;
        int ret;
-       WIMStruct **additional_swms;
-       unsigned num_additional_swms;
+
+       REFGLOB_SET(refglobs);
 
        if (cmd == CMD_MOUNTRW) {
                mount_flags |= WIMLIB_MOUNT_FLAG_READWRITE;
 
        if (cmd == CMD_MOUNTRW) {
                mount_flags |= WIMLIB_MOUNT_FLAG_READWRITE;
@@ -2968,7 +2978,9 @@ imagex_mount_rw_or_ro(int argc, tchar **argv, int cmd)
                        }
                        break;
                case IMAGEX_REF_OPTION:
                        }
                        break;
                case IMAGEX_REF_OPTION:
-                       swm_glob = optarg;
+                       ret = refglob_set_append(&refglobs, optarg);
+                       if (ret)
+                               goto out_free_refglobs;
                        break;
                case IMAGEX_STAGING_DIR_OPTION:
                        staging_dir = optarg;
                        break;
                case IMAGEX_STAGING_DIR_OPTION:
                        staging_dir = optarg;
@@ -2989,7 +3001,9 @@ imagex_mount_rw_or_ro(int argc, tchar **argv, int cmd)
 
        ret = wimlib_open_wim(wimfile, open_flags, &wim, imagex_progress_func);
        if (ret)
 
        ret = wimlib_open_wim(wimfile, open_flags, &wim, imagex_progress_func);
        if (ret)
-               goto out;
+               goto out_free_refglobs;
+
+       wimlib_get_wim_info(wim, &info);
 
        if (argc >= 3) {
                /* Image explicitly specified.  */
 
        if (argc >= 3) {
                /* Image explicitly specified.  */
@@ -3001,9 +3015,7 @@ imagex_mount_rw_or_ro(int argc, tchar **argv, int cmd)
        } else {
                /* No image specified; default to image 1, but only if the WIM
                 * contains exactly one image.  */
        } else {
                /* No image specified; default to image 1, but only if the WIM
                 * contains exactly one image.  */
-               struct wimlib_wim_info info;
 
 
-               wimlib_get_wim_info(wim, &info);
                if (info.image_count != 1) {
                        imagex_error(T("\"%"TS"\" contains %d images; Please "
                                       "select one."), wimfile, info.image_count);
                if (info.image_count != 1) {
                        imagex_error(T("\"%"TS"\" contains %d images; Please "
                                       "select one."), wimfile, info.image_count);
@@ -3014,36 +3026,28 @@ imagex_mount_rw_or_ro(int argc, tchar **argv, int cmd)
                dir = argv[1];
        }
 
                dir = argv[1];
        }
 
-       if (swm_glob) {
-               ret = open_swms_from_glob(swm_glob, wimfile, open_flags,
-                                         &additional_swms,
-                                         &num_additional_swms);
+       if (refglobs.num_globs) {
+               ret = wim_reference_globs(wim, &refglobs, open_flags);
                if (ret)
                        goto out_free_wim;
                if (ret)
                        goto out_free_wim;
-       } else {
-               additional_swms = NULL;
-               num_additional_swms = 0;
        }
 
        }
 
-       ret = wimlib_mount_image(wim, image, dir, mount_flags, additional_swms,
-                                num_additional_swms, staging_dir);
+       ret = wimlib_mount_image(wim, image, dir, mount_flags, staging_dir);
        if (ret) {
                imagex_error(T("Failed to mount image %d from \"%"TS"\" "
                               "on \"%"TS"\""),
                             image, wimfile, dir);
        }
        if (ret) {
                imagex_error(T("Failed to mount image %d from \"%"TS"\" "
                               "on \"%"TS"\""),
                             image, wimfile, dir);
        }
-       for (unsigned i = 0; i < num_additional_swms; i++)
-               wimlib_free(additional_swms[i]);
-       free(additional_swms);
 out_free_wim:
        wimlib_free(wim);
 out_free_wim:
        wimlib_free(wim);
-out:
+out_free_refglobs:
+       refglob_set_destroy(&refglobs);
        return ret;
 
 out_usage:
        usage(cmd, stderr);
        ret = -1;
        return ret;
 
 out_usage:
        usage(cmd, stderr);
        ret = -1;
-       goto out;
+       goto out_free_refglobs;
 }
 #endif /* WIM_MOUNTING_SUPPORTED */
 
 }
 #endif /* WIM_MOUNTING_SUPPORTED */
 
index ca9fe0b18993eedc604eac4d393665535fe1fe6d..a73828ba41c1ada58c7b9528d48033214b6c477c 100644 (file)
@@ -2596,9 +2596,6 @@ wimlib_reference_template_image(WIMStruct *wim, int new_image, int template_imag
        int ret;
        struct wim_image_metadata *new_imd;
 
        int ret;
        struct wim_image_metadata *new_imd;
 
-       if (wim->hdr.part_number != 1)
-               return WIMLIB_ERR_SPLIT_UNSUPPORTED;
-
        if (new_image < 1 || new_image > wim->hdr.image_count)
                return WIMLIB_ERR_INVALID_IMAGE;
 
        if (new_image < 1 || new_image > wim->hdr.image_count)
                return WIMLIB_ERR_INVALID_IMAGE;
 
@@ -2608,6 +2605,9 @@ wimlib_reference_template_image(WIMStruct *wim, int new_image, int template_imag
        if (new_image == template_image)
                return WIMLIB_ERR_INVALID_PARAM;
 
        if (new_image == template_image)
                return WIMLIB_ERR_INVALID_PARAM;
 
+       if (!wim_has_metadata(wim))
+               return WIMLIB_ERR_METADATA_NOT_FOUND;
+
        new_imd = wim->image_metadata[new_image - 1];
        if (!new_imd->modified)
                return WIMLIB_ERR_INVALID_PARAM;
        new_imd = wim->image_metadata[new_image - 1];
        if (!new_imd->modified)
                return WIMLIB_ERR_INVALID_PARAM;
index 17c4f7dd8f3e06f45ef191b62263ef44125b99c0..81c66594227c77c4f0cb2a64eeb6153b9c9354fe 100644 (file)
 #include "wimlib/error.h"
 #include "wimlib/lookup_table.h"
 #include "wimlib/metadata.h"
 #include "wimlib/error.h"
 #include "wimlib/lookup_table.h"
 #include "wimlib/metadata.h"
-#include "wimlib/swm.h"
 #include "wimlib/xml.h"
 #include "wimlib/xml.h"
+#include <stdlib.h>
 
 static int
 
 static int
-inode_allocate_needed_ltes(struct wim_inode *inode,
-                          struct wim_lookup_table *src_lookup_table,
-                          struct wim_lookup_table *dest_lookup_table,
-                          struct list_head *lte_list_head)
+inode_export_streams(struct wim_inode *inode,
+                    const struct wim_lookup_table *src_lookup_table,
+                    struct wim_lookup_table *dest_lookup_table)
 {
 {
-       struct wim_lookup_table_entry *src_lte, *dest_lte;
        unsigned i;
        unsigned i;
+       const u8 *hash;
+       struct wim_lookup_table_entry *src_lte, *dest_lte;
 
        inode_unresolve_ltes(inode);
        for (i = 0; i <= inode->i_num_ads; i++) {
 
        inode_unresolve_ltes(inode);
        for (i = 0; i <= inode->i_num_ads; i++) {
-               src_lte = inode_stream_lte_unresolved(inode, i,
-                                                     src_lookup_table);
-               if (src_lte && src_lte->out_refcnt == 0) {
-                       src_lte->out_refcnt = 1;
-                       dest_lte = inode_stream_lte_unresolved(inode, i,
-                                                              dest_lookup_table);
-                       if (!dest_lte) {
-                               dest_lte = clone_lookup_table_entry(src_lte);
-                               if (!dest_lte)
-                                       return WIMLIB_ERR_NOMEM;
-                               list_add_tail(&dest_lte->export_stream_list,
-                                             lte_list_head);
-                       }
+
+               /* Retrieve SHA1 message digest of stream to export.  */
+               hash = inode_stream_hash(inode, i);
+               if (is_zero_hash(hash))  /* Empty stream?  */
+                       continue;
+
+               /* Search for the stream (via SHA1 message digest) in the
+                * destination WIM.  */
+               dest_lte = __lookup_resource(dest_lookup_table, hash);
+               if (!dest_lte) {
+                       /* Stream not yet present in destination WIM.  Search
+                        * for it in the source WIM, then export it into the
+                        * destination WIM.  */
+                       src_lte = __lookup_resource(src_lookup_table, hash);
+                       if (!src_lte)
+                               return resource_not_found_error(inode, hash);
+
+                       dest_lte = clone_lookup_table_entry(src_lte);
+                       if (!dest_lte)
+                               return WIMLIB_ERR_NOMEM;
+                       dest_lte->refcnt = 0;
+                       dest_lte->out_refcnt = 0;
+                       lookup_table_insert(dest_lookup_table, dest_lte);
                }
                }
+
+               /* Stream is present in destination WIM (either pre-existing,
+                * already exported, or just exported above).  Increment its
+                * reference count appropriately.   Note: we use 'refcnt' for
+                * the raw reference count, but 'out_refcnt' for references
+                * arising just from the export operation; this is used to roll
+                * back a failed export if needed.  */
+               dest_lte->refcnt += inode->i_nlink;
+               dest_lte->out_refcnt += inode->i_nlink;
        }
        return 0;
 }
 
        }
        return 0;
 }
 
-static void
-inode_move_ltes_to_table(struct wim_inode *inode,
-                        struct wim_lookup_table *src_lookup_table,
-                        struct wim_lookup_table *dest_lookup_table,
-                        struct list_head *lte_list_head)
+static int
+lte_unexport(struct wim_lookup_table_entry *lte, void *_lookup_table)
 {
 {
-       struct wim_lookup_table_entry *src_lte, *dest_lte;
-       unsigned i;
+       struct wim_lookup_table *lookup_table = _lookup_table;
 
 
-       for (i = 0; i <= inode->i_num_ads; i++) {
-               src_lte = inode_stream_lte_unresolved(inode, i, src_lookup_table);
-               if (src_lte) {
-                       dest_lte = inode_stream_lte_unresolved(inode, i,
-                                                              dest_lookup_table);
-                       if (!dest_lte) {
-                               struct list_head *next;
-
-                               wimlib_assert(!list_empty(lte_list_head));
-                               next = lte_list_head->next;
-                               list_del(next);
-                               dest_lte = container_of(next,
-                                                       struct wim_lookup_table_entry,
-                                                       export_stream_list);
-                               dest_lte->part_number = 1;
-                               dest_lte->refcnt = 0;
-                               wimlib_assert(hashes_equal(dest_lte->hash, src_lte->hash));
-                               lookup_table_insert(dest_lookup_table, dest_lte);
-                       }
-                       dest_lte->refcnt += inode->i_nlink;
-               }
+       lte->refcnt -= lte->out_refcnt;
+       if (lte->refcnt == 0) {
+               lookup_table_unlink(lookup_table, lte);
+               free_lookup_table_entry(lte);
        }
        }
+       return 0;
 }
 
 /* API function documented in wimlib.h  */
 }
 
 /* API function documented in wimlib.h  */
@@ -103,91 +102,47 @@ wimlib_export_image(WIMStruct *src_wim,
                    const tchar *dest_name,
                    const tchar *dest_description,
                    int export_flags,
                    const tchar *dest_name,
                    const tchar *dest_description,
                    int export_flags,
-                   WIMStruct **additional_swms,
-                   unsigned num_additional_swms,
                    wimlib_progress_func_t progress_func)
 {
        int ret;
                    wimlib_progress_func_t progress_func)
 {
        int ret;
-       struct wim_image_metadata *src_imd;
-       struct list_head lte_list_head;
-       struct wim_inode *inode;
+       int start_image;
+       int end_image;
+       int image;
+       u32 orig_dest_boot_idx;
+       u32 orig_dest_image_count;
+
+       /* Check for sane parameters.  */
+       if (src_wim == NULL || dest_wim == NULL)
+               return WIMLIB_ERR_INVALID_PARAM;
+
+       if (!wim_has_metadata(src_wim) || !wim_has_metadata(dest_wim))
+               return WIMLIB_ERR_METADATA_NOT_FOUND;
 
 
+       /* Destination WIM must be writable.  */
        ret = can_modify_wim(dest_wim);
        if (ret)
                return ret;
 
        if (src_image == WIMLIB_ALL_IMAGES) {
        ret = can_modify_wim(dest_wim);
        if (ret)
                return ret;
 
        if (src_image == WIMLIB_ALL_IMAGES) {
-               if (src_wim->hdr.image_count > 1) {
-
-                       /* multi-image export. */
-
-                       if ((export_flags & WIMLIB_EXPORT_FLAG_BOOT) &&
-                             (src_wim->hdr.boot_idx == 0))
-                       {
-                               /* Specifying the boot flag on a multi-image
-                                * source WIM makes the boot index default to
-                                * the bootable image in the source WIM.  It is
-                                * an error if there is no such bootable image.
-                                * */
-                               ERROR("Cannot specify `boot' flag when "
-                                     "exporting multiple images from a WIM "
-                                     "with no bootable images");
-                               return WIMLIB_ERR_INVALID_PARAM;
-                       }
-                       if (dest_name || dest_description) {
-                               ERROR("Image name or image description was "
-                                     "specified, but we are exporting "
-                                     "multiple images");
-                               return WIMLIB_ERR_INVALID_PARAM;
-                       }
-                       for (int i = 1; i <= src_wim->hdr.image_count; i++) {
-                               int new_flags = export_flags;
-
-                               if (i != src_wim->hdr.boot_idx)
-                                       new_flags &= ~WIMLIB_EXPORT_FLAG_BOOT;
-
-                               ret = wimlib_export_image(src_wim, i, dest_wim,
-                                                         NULL, NULL,
-                                                         new_flags,
-                                                         additional_swms,
-                                                         num_additional_swms,
-                                                         progress_func);
-                               if (ret)
-                                       return ret;
-                       }
-                       return 0;
-               } else if (src_wim->hdr.image_count == 1) {
-                       src_image = 1;
-               } else {
-                       return 0;
+               /* Multi-image export.  */
+               if ((!(export_flags & WIMLIB_EXPORT_FLAG_NO_NAMES) &&
+                       dest_name) ||
+                   (!(export_flags & WIMLIB_EXPORT_FLAG_NO_DESCRIPTIONS) &&
+                       dest_description))
+               {
+                       ERROR("Image name or image description was "
+                             "specified, but we are exporting "
+                             "multiple images");
+                       return WIMLIB_ERR_INVALID_PARAM;
                }
                }
+               start_image = 1;
+               end_image = src_wim->hdr.image_count;
+       } else {
+               start_image = src_image;
+               end_image = src_image;
        }
 
        }
 
-       if (!dest_name) {
-               dest_name = wimlib_get_image_name(src_wim, src_image);
-               DEBUG("Using name `%"TS"' for source image %d",
-                     dest_name, src_image);
-       }
-
-       if (!dest_description) {
-               dest_description = wimlib_get_image_description(src_wim,
-                                                               src_image);
-               DEBUG("Using description `%"TS"' for source image %d",
-                     dest_description, src_image);
-       }
-
-       DEBUG("Exporting image %d from `%"TS"'", src_image, src_wim->filename);
-
-       if (wimlib_image_name_in_use(dest_wim, dest_name)) {
-               ERROR("There is already an image named `%"TS"' in the "
-                     "destination WIM", dest_name);
-               return WIMLIB_ERR_IMAGE_NAME_COLLISION;
-       }
-
-       ret = verify_swm_set(src_wim, additional_swms, num_additional_swms);
-       if (ret)
-               return ret;
-
+       /* Stream checksums must be known before proceeding.  */
        ret = wim_checksum_unhashed_streams(src_wim);
        if (ret)
                return ret;
        ret = wim_checksum_unhashed_streams(src_wim);
        if (ret)
                return ret;
@@ -195,77 +150,124 @@ wimlib_export_image(WIMStruct *src_wim,
        if (ret)
                return ret;
 
        if (ret)
                return ret;
 
-       if (num_additional_swms)
-               merge_lookup_tables(src_wim, additional_swms, num_additional_swms);
+       /* Zero 'out_refcnt' in all lookup table entries in the destination WIM;
+        * this tracks the number of references found from the source WIM
+        * image(s).  */
+       for_lookup_table_entry(dest_wim->lookup_table, lte_zero_out_refcnt,
+                              NULL);
 
 
-       ret = select_wim_image(src_wim, src_image);
-       if (ret) {
-               ERROR("Could not select image %d from the WIM `%"TS"' "
-                     "to export it", src_image, src_wim->filename);
-               goto out;
-       }
+       /* Save the original count of images in the destination WIM and the boot
+        * index (used if rollback necessary).  */
+       orig_dest_image_count = dest_wim->hdr.image_count;
+       orig_dest_boot_idx = dest_wim->hdr.boot_idx;
+
+       /* Export each requested image.  */
+       for (image = start_image; image <= end_image; image++) {
+               const tchar *next_dest_name, *next_dest_description;
+               struct wim_image_metadata *src_imd;
+               struct wim_inode *inode;
+
+               DEBUG("Exporting image %d from \"%"TS"\"",
+                     image, src_wim->filename);
 
 
-       /* Pre-allocate the new lookup table entries that will be needed.  This
-        * way, it's not possible to run out of memory part-way through
-        * modifying the lookup table of the destination WIM. */
-       for_lookup_table_entry(src_wim->lookup_table, lte_zero_out_refcnt, NULL);
-       src_imd = wim_get_current_image_metadata(src_wim);
-       INIT_LIST_HEAD(&lte_list_head);
-       image_for_each_inode(inode, src_imd) {
-               ret = inode_allocate_needed_ltes(inode,
-                                                src_wim->lookup_table,
-                                                dest_wim->lookup_table,
-                                                &lte_list_head);
+               /* Determine destination image name and description.  */
+
+               if (export_flags & WIMLIB_EXPORT_FLAG_NO_NAMES) {
+                       next_dest_name = NULL;
+               } else if (dest_name) {
+                       next_dest_name = dest_name;
+               } else {
+                       next_dest_name = wimlib_get_image_name(src_wim,
+                                                              image);
+               }
+
+               DEBUG("Using name \"%"TS"\"", next_dest_name);
+
+               if (export_flags & WIMLIB_EXPORT_FLAG_NO_DESCRIPTIONS) {
+                       next_dest_description = NULL;
+               } if (dest_description) {
+                       next_dest_description = dest_description;
+               } else {
+                       next_dest_description = wimlib_get_image_description(
+                                                       src_wim, image);
+               }
+
+               DEBUG("Using description \"%"TS"\"", next_dest_description);
+
+               /* Check for name conflict.  */
+               if (wimlib_image_name_in_use(dest_wim, next_dest_name)) {
+                       ERROR("There is already an image named \"%"TS"\" "
+                             "in the destination WIM", next_dest_name);
+                       ret = WIMLIB_ERR_IMAGE_NAME_COLLISION;
+                       goto out_rollback;
+               }
+
+               /* Load metadata for source image into memory.  */
+               ret = select_wim_image(src_wim, image);
                if (ret)
                if (ret)
-                       goto out_free_ltes;
-       }
+                       goto out_rollback;
 
 
-       ret = xml_export_image(src_wim->wim_info, src_image,
-                              &dest_wim->wim_info, dest_name,
-                              dest_description);
-       if (ret)
-               goto out_free_ltes;
+               src_imd = wim_get_current_image_metadata(src_wim);
 
 
-       ret = append_image_metadata(dest_wim, src_imd);
-       if (ret)
-               goto out_xml_delete_image;
-
-       /* The `struct image_metadata' is now referenced by both the @src_wim
-        * and the @dest_wim. */
-       src_imd->refcnt++;
-       src_imd->modified = 1;
-
-       /* All memory allocations have been taken care of, so it's no longer
-        * possible for this function to fail.  Go ahead and update the lookup
-        * table of the destination WIM and the boot index, if needed. */
-       image_for_each_inode(inode, src_imd) {
-               inode_move_ltes_to_table(inode,
-                                        src_wim->lookup_table,
-                                        dest_wim->lookup_table,
-                                        &lte_list_head);
-       }
+               /* Iterate through inodes in the source image and export their
+                * streams into the destination WIM.  */
+               image_for_each_inode(inode, src_imd) {
+                       ret = inode_export_streams(inode,
+                                                  src_wim->lookup_table,
+                                                  dest_wim->lookup_table);
+                       if (ret)
+                               goto out_rollback;
+               }
+
+               /* Export XML information into the destination WIM.  */
+               ret = xml_export_image(src_wim->wim_info, image,
+                                      &dest_wim->wim_info, next_dest_name,
+                                      next_dest_description);
+               if (ret)
+                       goto out_rollback;
+
+               /* Reference the source image metadata from the destination WIM.
+                */
+               ret = append_image_metadata(dest_wim, src_imd);
+               if (ret)
+                       goto out_rollback;
+               src_imd->refcnt++;
+
+               /* Lock the metadata into memory.  XXX: need better solution for
+                * this.  */
+               src_imd->modified = 1;
 
 
-       if (export_flags & WIMLIB_EXPORT_FLAG_BOOT)
-               dest_wim->hdr.boot_idx = dest_wim->hdr.image_count;
+               /* Set boot index in destination WIM.  */
+               if ((export_flags & WIMLIB_EXPORT_FLAG_BOOT) &&
+                   (src_image != WIMLIB_ALL_IMAGES ||
+                    image == src_wim->hdr.boot_idx))
+               {
+                       DEBUG("Marking destination image %u as bootable.",
+                             dest_wim->hdr.image_count);
+                       dest_wim->hdr.boot_idx = dest_wim->hdr.image_count;
+               }
+
+       }
+       /* Set the reparse point fixup flag on the destination WIM if the flag
+        * is set on the source WIM. */
        if (src_wim->hdr.flags & WIM_HDR_FLAG_RP_FIX)
        if (src_wim->hdr.flags & WIM_HDR_FLAG_RP_FIX)
-       {
-               /* Set the reparse point fixup flag on the destination WIM if
-                * the flag is set on the source WIM. */
                dest_wim->hdr.flags |= WIM_HDR_FLAG_RP_FIX;
                dest_wim->hdr.flags |= WIM_HDR_FLAG_RP_FIX;
+       DEBUG("Export operation successful.");
+       return 0;
+
+out_rollback:
+       while ((image = wim_info_get_num_images(dest_wim->wim_info))
+              > orig_dest_image_count)
+       {
+               xml_delete_image(&dest_wim->wim_info, image);
        }
        }
-       DEBUG("Successfully exported image.");
-       ret = 0;
-       goto out;
-out_xml_delete_image:
-       xml_delete_image(&dest_wim->wim_info, dest_wim->hdr.image_count + 1);
-out_free_ltes:
+       while (dest_wim->hdr.image_count > orig_dest_image_count)
        {
        {
-               struct wim_lookup_table_entry *lte, *tmp;
-               list_for_each_entry_safe(lte, tmp, &lte_list_head, export_stream_list)
-                       free_lookup_table_entry(lte);
+               put_image_metadata(dest_wim->image_metadata[
+                                       --dest_wim->hdr.image_count], NULL);
        }
        }
-out:
-       if (num_additional_swms)
-               unmerge_lookup_table(src_wim);
+       for_lookup_table_entry(dest_wim->lookup_table, lte_unexport,
+                              dest_wim->lookup_table);
+       dest_wim->hdr.boot_idx = orig_dest_boot_idx;
        return ret;
 }
        return ret;
 }
index c04f11b65b1c7d40f6dfc516a3f19fbbd7d19cd4..c9f6e21f0f8914aa21d1f0a84bea62d155bde0e7 100644 (file)
@@ -53,7 +53,6 @@
 #include "wimlib/reparse.h"
 #include "wimlib/resource.h"
 #include "wimlib/security.h"
 #include "wimlib/reparse.h"
 #include "wimlib/resource.h"
 #include "wimlib/security.h"
-#include "wimlib/swm.h"
 #ifdef __WIN32__
 #  include "wimlib/win32.h" /* for realpath() equivalent */
 #endif
 #ifdef __WIN32__
 #  include "wimlib/win32.h" /* for realpath() equivalent */
 #endif
@@ -2561,8 +2560,6 @@ wimlib_extract_files(WIMStruct *wim,
                     const struct wimlib_extract_command *cmds,
                     size_t num_cmds,
                     int default_extract_flags,
                     const struct wimlib_extract_command *cmds,
                     size_t num_cmds,
                     int default_extract_flags,
-                    WIMStruct **additional_swms,
-                    unsigned num_additional_swms,
                     wimlib_progress_func_t progress_func)
 {
        int ret;
                     wimlib_progress_func_t progress_func)
 {
        int ret;
@@ -2571,21 +2568,12 @@ wimlib_extract_files(WIMStruct *wim,
 
        default_extract_flags &= WIMLIB_EXTRACT_MASK_PUBLIC;
 
 
        default_extract_flags &= WIMLIB_EXTRACT_MASK_PUBLIC;
 
-       ret = verify_swm_set(wim, additional_swms, num_additional_swms);
-       if (ret)
-               goto out;
-
        if (num_cmds == 0)
        if (num_cmds == 0)
-               goto out;
-
-       if (num_additional_swms)
-               merge_lookup_tables(wim, additional_swms, num_additional_swms);
+               return 0;
 
        cmds_copy = CALLOC(num_cmds, sizeof(cmds[0]));
 
        cmds_copy = CALLOC(num_cmds, sizeof(cmds[0]));
-       if (!cmds_copy) {
-               ret = WIMLIB_ERR_NOMEM;
-               goto out_restore_lookup_table;
-       }
+       if (!cmds_copy)
+               return WIMLIB_ERR_NOMEM;
 
        for (size_t i = 0; i < num_cmds; i++) {
                cmds_copy[i].extract_flags = (default_extract_flags |
 
        for (size_t i = 0; i < num_cmds; i++) {
                cmds_copy[i].extract_flags = (default_extract_flags |
@@ -2622,10 +2610,6 @@ out_free_cmds_copy:
                FREE(cmds_copy[i].fs_dest_path);
        }
        FREE(cmds_copy);
                FREE(cmds_copy[i].fs_dest_path);
        }
        FREE(cmds_copy);
-out_restore_lookup_table:
-       if (num_additional_swms)
-               unmerge_lookup_table(wim);
-out:
        return ret;
 }
 
        return ret;
 }
 
@@ -2746,24 +2730,10 @@ do_wimlib_extract_image(WIMStruct *wim,
                        int image,
                        const tchar *target,
                        int extract_flags,
                        int image,
                        const tchar *target,
                        int extract_flags,
-                       WIMStruct **additional_swms,
-                       unsigned num_additional_swms,
                        wimlib_progress_func_t progress_func)
 {
        int ret;
 
                        wimlib_progress_func_t progress_func)
 {
        int ret;
 
-       if (extract_flags & WIMLIB_EXTRACT_FLAG_FROM_PIPE) {
-               wimlib_assert(wim->hdr.part_number == 1);
-               wimlib_assert(num_additional_swms == 0);
-       } else {
-               ret = verify_swm_set(wim, additional_swms, num_additional_swms);
-               if (ret)
-                       return ret;
-
-               if (num_additional_swms)
-                       merge_lookup_tables(wim, additional_swms, num_additional_swms);
-       }
-
        if (image == WIMLIB_ALL_IMAGES) {
                ret = extract_all_images(wim, target, extract_flags,
                                         progress_func);
        if (image == WIMLIB_ALL_IMAGES) {
                ret = extract_all_images(wim, target, extract_flags,
                                         progress_func);
@@ -2779,8 +2749,6 @@ do_wimlib_extract_image(WIMStruct *wim,
                                       lte_free_extracted_file,
                                       NULL);
        }
                                       lte_free_extracted_file,
                                       NULL);
        }
-       if (num_additional_swms)
-               unmerge_lookup_table(wim);
        return ret;
 }
 
        return ret;
 }
 
@@ -2934,7 +2902,7 @@ wimlib_extract_image_from_pipe(int pipe_fd, const tchar *image_num_or_name,
        /* Extract the image.  */
        extract_flags |= WIMLIB_EXTRACT_FLAG_FROM_PIPE;
        ret = do_wimlib_extract_image(pwm, image, target,
        /* Extract the image.  */
        extract_flags |= WIMLIB_EXTRACT_FLAG_FROM_PIPE;
        ret = do_wimlib_extract_image(pwm, image, target,
-                                     extract_flags, NULL, 0, progress_func);
+                                     extract_flags, progress_func);
        /* Clean up and return.  */
 out_wimlib_free:
        wimlib_free(pwm);
        /* Clean up and return.  */
 out_wimlib_free:
        wimlib_free(pwm);
@@ -2947,12 +2915,9 @@ wimlib_extract_image(WIMStruct *wim,
                     int image,
                     const tchar *target,
                     int extract_flags,
                     int image,
                     const tchar *target,
                     int extract_flags,
-                    WIMStruct **additional_swms,
-                    unsigned num_additional_swms,
                     wimlib_progress_func_t progress_func)
 {
        extract_flags &= WIMLIB_EXTRACT_MASK_PUBLIC;
        return do_wimlib_extract_image(wim, image, target, extract_flags,
                     wimlib_progress_func_t progress_func)
 {
        extract_flags &= WIMLIB_EXTRACT_MASK_PUBLIC;
        return do_wimlib_extract_image(wim, image, target, extract_flags,
-                                      additional_swms, num_additional_swms,
                                       progress_func);
 }
                                       progress_func);
 }
index 7502b6d2a6cc177a643a2bbd4ee17f02835ff8b2..99a9a9fd64b7e61c5fe7db52696e541e552ab42d 100644 (file)
@@ -328,13 +328,10 @@ write_integrity_table(WIMStruct *wim,
        struct integrity_table *old_table;
        struct integrity_table *new_table;
        int ret;
        struct integrity_table *old_table;
        struct integrity_table *new_table;
        int ret;
-       off_t cur_offset;
        u32 new_table_size;
 
        wimlib_assert(old_lookup_table_end <= new_lookup_table_end);
 
        u32 new_table_size;
 
        wimlib_assert(old_lookup_table_end <= new_lookup_table_end);
 
-       cur_offset = wim->out_fd.offset;
-
        if (wim->hdr.integrity.offset == 0 || old_lookup_table_end == 0) {
                old_table = NULL;
        } else {
        if (wim->hdr.integrity.offset == 0 || old_lookup_table_end == 0) {
                old_table = NULL;
        } else {
index 2157697d7eb556e5758a2662b1db422e81d38787..1045fc7187fccf739643547b412a264b17f626da 100644 (file)
 #endif
 
 #include "wimlib.h"
 #endif
 
 #include "wimlib.h"
+#include "wimlib/error.h"
 #include "wimlib/types.h"
 #include "wimlib/types.h"
-#include "wimlib/swm.h"
 #include "wimlib/util.h"
 #include "wimlib/wim.h"
 
 #include "wimlib/util.h"
 #include "wimlib/wim.h"
 
+/*
+ * verify_swm_set: - Sanity checks to make sure a set of WIMs correctly
+ *                  correspond to a spanned set.
+ *
+ * @wim:
+ *     Part 1 of the set.
+ *
+ * @additional_swms:
+ *     All parts of the set other than part 1.
+ *
+ * @num_additional_swms:
+ *     Number of WIMStructs in @additional_swms.  Or, the total number of parts
+ *     in the set minus 1.
+ *
+ * @return:
+ *     0 on success; WIMLIB_ERR_SPLIT_INVALID if the set is not valid.
+ */
+static int
+verify_swm_set(WIMStruct *wim, WIMStruct **additional_swms,
+              unsigned num_additional_swms)
+{
+       unsigned total_parts = wim->hdr.total_parts;
+       int ctype;
+       const u8 *guid;
+
+       if (total_parts != num_additional_swms + 1) {
+               ERROR("`%"TS"' says there are %u parts in the spanned set, "
+                     "but %"TS"%u part%"TS" provided",
+                     wim->filename, total_parts,
+                     (num_additional_swms + 1 < total_parts) ? T("only ") : T(""),
+                     num_additional_swms + 1,
+                     (num_additional_swms) ? T("s were") : T(" was"));
+               return WIMLIB_ERR_SPLIT_INVALID;
+       }
+       if (wim->hdr.part_number != 1) {
+               ERROR("WIM `%"TS"' is not the first part of the split WIM.",
+                     wim->filename);
+               return WIMLIB_ERR_SPLIT_INVALID;
+       }
+       for (unsigned i = 0; i < num_additional_swms; i++) {
+               if (additional_swms[i]->hdr.total_parts != total_parts) {
+                       ERROR("WIM `%"TS"' says there are %u parts in the "
+                             "spanned set, but %u parts were provided",
+                             additional_swms[i]->filename,
+                             additional_swms[i]->hdr.total_parts,
+                             total_parts);
+                       return WIMLIB_ERR_SPLIT_INVALID;
+               }
+       }
+
+       /* keep track of ctype and guid just to make sure they are the same for
+        * all the WIMs. */
+       ctype = wim->compression_type;
+       guid = wim->hdr.guid;
+
+       {
+               /* parts_to_swms is not allocated at function scope because it
+                * should only be allocated after num_additional_swms was
+                * checked to be the same as wim->hdr.total_parts.  Otherwise, it
+                * could be unexpectedly high and cause a stack overflow. */
+               WIMStruct *parts_to_swms[num_additional_swms];
+               ZERO_ARRAY(parts_to_swms);
+               for (unsigned i = 0; i < num_additional_swms; i++) {
+
+                       WIMStruct *swm = additional_swms[i];
+
+                       if (swm->compression_type != ctype) {
+                               ERROR("The split WIMs do not all have the same "
+                                     "compression type");
+                               return WIMLIB_ERR_SPLIT_INVALID;
+                       }
+                       if (memcmp(guid, swm->hdr.guid, WIM_GID_LEN) != 0) {
+                               ERROR("The split WIMs do not all have the same "
+                                     "GUID");
+                               return WIMLIB_ERR_SPLIT_INVALID;
+                       }
+                       if (swm->hdr.part_number == 1) {
+                               ERROR("WIMs `%"TS"' and `%"TS"' both are marked "
+                                     "as the first WIM in the spanned set",
+                                     wim->filename, swm->filename);
+                               return WIMLIB_ERR_SPLIT_INVALID;
+                       }
+                       if (swm->hdr.part_number == 0 ||
+                           swm->hdr.part_number > total_parts)
+                       {
+                               ERROR("WIM `%"TS"' says it is part %u in the "
+                                     "spanned set, but the part number must "
+                                     "be in the range [1, %u]",
+                                     swm->filename, swm->hdr.part_number, total_parts);
+                               return WIMLIB_ERR_SPLIT_INVALID;
+                       }
+                       if (parts_to_swms[swm->hdr.part_number - 2])
+                       {
+                               ERROR("`%"TS"' and `%"TS"' are both marked as "
+                                     "part %u of %u in the spanned set",
+                                     parts_to_swms[swm->hdr.part_number - 2]->filename,
+                                     swm->filename,
+                                     swm->hdr.part_number,
+                                     total_parts);
+                               return WIMLIB_ERR_SPLIT_INVALID;
+                       } else {
+                               parts_to_swms[swm->hdr.part_number - 2] = swm;
+                       }
+               }
+       }
+       return 0;
+}
+
 /* API function documented in wimlib.h  */
 WIMLIBAPI int
 wimlib_join(const tchar * const *swm_names,
 /* API function documented in wimlib.h  */
 WIMLIBAPI int
 wimlib_join(const tchar * const *swm_names,
@@ -82,10 +190,15 @@ wimlib_join(const tchar * const *swm_names,
        if (ret)
                goto out_free_swms;
 
        if (ret)
                goto out_free_swms;
 
-       merge_lookup_tables(swm0, additional_swms, num_additional_swms);
+       ret = wimlib_reference_resources(swm0, additional_swms,
+                                        num_additional_swms, 0);
+       if (ret)
+               goto out_free_swms;
 
        ret = wimlib_write(swm0, output_path, WIMLIB_ALL_IMAGES,
                           wim_write_flags, 1, progress_func);
 
        ret = wimlib_write(swm0, output_path, WIMLIB_ALL_IMAGES,
                           wim_write_flags, 1, progress_func);
+       wimlib_unreference_resources(swm0, additional_swms,
+                                    num_additional_swms);
 out_free_swms:
        for (i = 0; i < num_additional_swms; i++)
                wimlib_free(additional_swms[i]);
 out_free_swms:
        for (i = 0; i < num_additional_swms; i++)
                wimlib_free(additional_swms[i]);
index fee0f247f96d935c6b3a82b7434747c7a3151ec0..a6202ef2b6c185a03c9b2b355d80a6825ab7ec07 100644 (file)
@@ -31,6 +31,7 @@
 #include "wimlib/endianness.h"
 #include "wimlib/error.h"
 #include "wimlib/file_io.h"
 #include "wimlib/endianness.h"
 #include "wimlib/error.h"
 #include "wimlib/file_io.h"
+#include "wimlib/glob.h"
 #include "wimlib/lookup_table.h"
 #include "wimlib/metadata.h"
 #include "wimlib/paths.h"
 #include "wimlib/lookup_table.h"
 #include "wimlib/metadata.h"
 #include "wimlib/paths.h"
@@ -1010,6 +1011,18 @@ out:
 }
 #endif
 
 }
 #endif
 
+int
+resource_not_found_error(struct wim_inode *inode, const u8 *hash)
+{
+       if (wimlib_print_errors) {
+               ERROR("\"%"TS"\": resource not found", inode_first_full_path(inode));
+               tfprintf(stderr, T("        SHA-1 message digest of missing resource:\n        "));
+               print_hash(hash, stderr);
+               tputc(T('\n'), stderr);
+       }
+       return WIMLIB_ERR_RESOURCE_NOT_FOUND;
+}
+
 /*
  * Resolve an inode's lookup table entries.
  *
 /*
  * Resolve an inode's lookup table entries.
  *
@@ -1081,14 +1094,9 @@ inode_resolve_ltes(struct wim_inode *inode, struct wim_lookup_table *table,
                inode->i_resolved = 1;
        }
        return 0;
                inode->i_resolved = 1;
        }
        return 0;
+
 resource_not_found:
 resource_not_found:
-       if (wimlib_print_errors) {
-               ERROR("\"%"TS"\": resource not found", inode_first_full_path(inode));
-               tfprintf(stderr, T("        SHA-1 message digest of missing resource:\n        "));
-               print_hash(hash, stderr);
-               tputc(T('\n'), stderr);
-       }
-       return WIMLIB_ERR_RESOURCE_NOT_FOUND;
+       return resource_not_found_error(inode, hash);
 }
 
 void
 }
 
 void
@@ -1272,3 +1280,227 @@ hash_unhashed_stream(struct wim_lookup_table_entry *lte,
                *lte_ret = lte;
        return 0;
 }
                *lte_ret = lte;
        return 0;
 }
+
+static int
+move_lte_to_table(struct wim_lookup_table_entry *lte, void *_combined_table)
+{
+       struct wim_lookup_table *combined_table = _combined_table;
+
+       hlist_del(&lte->hash_list);
+       lookup_table_insert(combined_table, lte);
+       return 0;
+}
+
+static void
+lookup_table_join(struct wim_lookup_table *combined_table,
+                 struct wim_lookup_table *part_table)
+{
+       for_lookup_table_entry(part_table, move_lte_to_table, combined_table);
+       part_table->num_entries = 0;
+}
+
+static void
+merge_lookup_tables(WIMStruct *wim, WIMStruct **resource_wims,
+                   unsigned num_resource_wims)
+{
+       for (unsigned i = 0; i < num_resource_wims; i++) {
+               lookup_table_join(wim->lookup_table, resource_wims[i]->lookup_table);
+               list_add(&resource_wims[i]->resource_wim_node, &wim->resource_wims);
+               resource_wims[i]->master_wim = wim;
+       }
+}
+
+static int
+move_lte_to_orig_table(struct wim_lookup_table_entry *lte, void *_wim)
+{
+       WIMStruct *wim = _wim;
+
+       if (lte->resource_location == RESOURCE_IN_WIM &&
+           lte->wim->being_unmerged)
+       {
+               move_lte_to_table(lte, lte->wim->lookup_table);
+               wim->lookup_table->num_entries--;
+       }
+       return 0;
+}
+
+static int
+check_reference_params(WIMStruct *wim,
+                      WIMStruct **resource_wims, unsigned num_resource_wims,
+                      WIMStruct *expected_master)
+{
+       if (wim == NULL)
+               return WIMLIB_ERR_INVALID_PARAM;
+
+       if (wim->hdr.part_number != 1)
+               return WIMLIB_ERR_INVALID_PARAM;
+
+       if (num_resource_wims != 0 && resource_wims == NULL)
+               return WIMLIB_ERR_INVALID_PARAM;
+
+       for (unsigned i = 0; i < num_resource_wims; i++) {
+               if (resource_wims[i] == NULL)
+                       return WIMLIB_ERR_INVALID_PARAM;
+               if (resource_wims[i]->master_wim != expected_master)
+                       return WIMLIB_ERR_INVALID_PARAM;
+       }
+       return 0;
+}
+
+/* API function documented in wimlib.h  */
+WIMLIBAPI int
+wimlib_reference_resources(WIMStruct *wim,
+                          WIMStruct **resource_wims, unsigned num_resource_wims,
+                          int ref_flags)
+{
+       int ret;
+
+       ret = check_reference_params(wim, resource_wims,
+                                    num_resource_wims, NULL);
+       if (ret)
+               return ret;
+
+       merge_lookup_tables(wim, resource_wims, num_resource_wims);
+       return 0;
+}
+
+static int
+reference_resource_paths(WIMStruct *wim,
+                        const tchar * const *resource_wimfiles,
+                        unsigned num_resource_wimfiles,
+                        int ref_flags,
+                        int open_flags,
+                        wimlib_progress_func_t progress_func)
+{
+       WIMStruct **resource_wims;
+       unsigned i;
+       int ret;
+
+       open_flags |= WIMLIB_OPEN_FLAG_SPLIT_OK;
+
+       resource_wims = CALLOC(num_resource_wimfiles, sizeof(resource_wims[0]));
+       if (!resource_wims)
+               return WIMLIB_ERR_NOMEM;
+
+       for (i = 0; i < num_resource_wimfiles; i++) {
+               ret = wimlib_open_wim(resource_wimfiles[i], open_flags,
+                                     &resource_wims[i], progress_func);
+               if (ret)
+                       goto out_free_resource_wims;
+       }
+
+       ret = wimlib_reference_resources(wim, resource_wims,
+                                        num_resource_wimfiles, ref_flags);
+       if (ret)
+               goto out_free_resource_wims;
+
+       for (i = 0; i < num_resource_wimfiles; i++)
+               resource_wims[i]->is_owned_by_master = 1;
+
+       ret = 0;
+       goto out_free_array;
+
+out_free_resource_wims:
+       for (i = 0; i < num_resource_wimfiles; i++)
+               wimlib_free(resource_wims[i]);
+out_free_array:
+       FREE(resource_wims);
+       return ret;
+}
+
+static int
+reference_resource_glob(WIMStruct *wim, const tchar *refglob,
+                       int ref_flags, int open_flags,
+                       wimlib_progress_func_t progress_func)
+{
+       glob_t globbuf;
+       int ret;
+
+       /* Note: glob() is replaced in Windows native builds.  */
+       ret = tglob(refglob, GLOB_ERR | GLOB_NOSORT, NULL, &globbuf);
+       if (ret) {
+               if (ret == GLOB_NOMATCH) {
+                       if (ref_flags & WIMLIB_REF_FLAG_GLOB_ERR_ON_NOMATCH) {
+                               ERROR("Found no files for glob \"%"TS"\"", refglob);
+                               return WIMLIB_ERR_GLOB_HAD_NO_MATCHES;
+                       } else {
+                               return reference_resource_paths(wim,
+                                                               &refglob,
+                                                               1,
+                                                               ref_flags,
+                                                               open_flags,
+                                                               progress_func);
+                       }
+               } else {
+                       ERROR_WITH_ERRNO("Failed to process glob \"%"TS"\"", refglob);
+                       if (ret == GLOB_NOSPACE)
+                               return WIMLIB_ERR_NOMEM;
+                       else
+                               return WIMLIB_ERR_READ;
+               }
+       }
+
+       ret = reference_resource_paths(wim,
+                                      (const tchar * const *)globbuf.gl_pathv,
+                                      globbuf.gl_pathc,
+                                      ref_flags,
+                                      open_flags,
+                                      progress_func);
+       globfree(&globbuf);
+       return ret;
+}
+
+/* API function documented in wimlib.h  */
+WIMLIBAPI int
+wimlib_reference_resource_files(WIMStruct *wim,
+                               const tchar * const * resource_wimfiles_or_globs,
+                               unsigned count,
+                               int ref_flags,
+                               int open_flags,
+                               wimlib_progress_func_t progress_func)
+{
+       unsigned i;
+       int ret;
+
+       if (ref_flags & WIMLIB_REF_FLAG_GLOB_ENABLE) {
+               for (i = 0; i < count; i++) {
+                       ret = reference_resource_glob(wim,
+                                                     resource_wimfiles_or_globs[i],
+                                                     ref_flags,
+                                                     open_flags,
+                                                     progress_func);
+                       if (ret)
+                               return ret;
+               }
+               return 0;
+       } else {
+               return reference_resource_paths(wim, resource_wimfiles_or_globs,
+                                               count, ref_flags,
+                                               open_flags, progress_func);
+       }
+}
+
+/* API function documented in wimlib.h  */
+WIMLIBAPI int
+wimlib_unreference_resources(WIMStruct *wim,
+                            WIMStruct **resource_wims, unsigned num_resource_wims)
+{
+       int ret;
+       unsigned i;
+
+       ret = check_reference_params(wim, resource_wims, num_resource_wims, wim);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < num_resource_wims; i++)
+               resource_wims[i]->being_unmerged = 1;
+
+       for_lookup_table_entry(wim->lookup_table, move_lte_to_orig_table, wim);
+
+       for (i = 0; i < num_resource_wims; i++) {
+               resource_wims[i]->being_unmerged = 0;
+               list_del(&resource_wims[i]->resource_wim_node);
+               resource_wims[i]->master_wim = NULL;
+       }
+       return 0;
+}
index 12b193e3ad1081f6ba2f73bfbd9f12e8b1004361..85c0dee4c88d6ae848e76258e8ab37ad5b6b83ad 100644 (file)
@@ -46,7 +46,6 @@
 #include "wimlib/paths.h"
 #include "wimlib/reparse.h"
 #include "wimlib/resource.h"
 #include "wimlib/paths.h"
 #include "wimlib/reparse.h"
 #include "wimlib/resource.h"
-#include "wimlib/swm.h"
 #include "wimlib/timestamp.h"
 #include "wimlib/version.h"
 #include "wimlib/write.h"
 #include "wimlib/timestamp.h"
 #include "wimlib/version.h"
 #include "wimlib/write.h"
@@ -2390,9 +2389,7 @@ static struct fuse_operations wimfs_operations = {
 /* API function documented in wimlib.h  */
 WIMLIBAPI int
 wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
 /* API function documented in wimlib.h  */
 WIMLIBAPI int
 wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
-                  int mount_flags, WIMStruct **additional_swms,
-                  unsigned num_additional_swms,
-                  const char *staging_dir)
+                  int mount_flags, const char *staging_dir)
 {
        int argc;
        char *argv[16];
 {
        int argc;
        char *argv[16];
@@ -2405,27 +2402,18 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
        DEBUG("Mount: wim = %p, image = %d, dir = %s, flags = %d, ",
              wim, image, dir, mount_flags);
 
        DEBUG("Mount: wim = %p, image = %d, dir = %s, flags = %d, ",
              wim, image, dir, mount_flags);
 
-       if (!wim || !dir) {
-               ret = WIMLIB_ERR_INVALID_PARAM;
-               goto out;
-       }
-
-       ret = verify_swm_set(wim, additional_swms, num_additional_swms);
-       if (ret)
-               goto out;
+       if (!wim || !dir)
+               return WIMLIB_ERR_INVALID_PARAM;
 
        if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
                ret = can_delete_from_wim(wim);
                if (ret)
 
        if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
                ret = can_delete_from_wim(wim);
                if (ret)
-                       goto out;
+                       return ret;
        }
 
        }
 
-       if (num_additional_swms)
-               merge_lookup_tables(wim, additional_swms, num_additional_swms);
-
        ret = select_wim_image(wim, image);
        if (ret)
        ret = select_wim_image(wim, image);
        if (ret)
-               goto out_restore_lookup_table;
+               return ret;
 
        DEBUG("Selected image %d", image);
 
 
        DEBUG("Selected image %d", image);
 
@@ -2434,21 +2422,19 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
        if (imd->refcnt != 1) {
                ERROR("Cannot mount image that was just exported with "
                      "wimlib_export_image()");
        if (imd->refcnt != 1) {
                ERROR("Cannot mount image that was just exported with "
                      "wimlib_export_image()");
-               ret = WIMLIB_ERR_INVALID_PARAM;
-               goto out_restore_lookup_table;
+               return WIMLIB_ERR_INVALID_PARAM;
        }
 
        if (imd->modified) {
                ERROR("Cannot mount image that was added "
                      "with wimlib_add_image()");
        }
 
        if (imd->modified) {
                ERROR("Cannot mount image that was added "
                      "with wimlib_add_image()");
-               ret = WIMLIB_ERR_INVALID_PARAM;
-               goto out_restore_lookup_table;
+               return WIMLIB_ERR_INVALID_PARAM;
        }
 
        if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
                ret = lock_wim(wim, wim->in_fd.fd);
                if (ret)
        }
 
        if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
                ret = lock_wim(wim, wim->in_fd.fd);
                if (ret)
-                       goto out_restore_lookup_table;
+                       return ret;
        }
 
        /* Use default stream interface if one was not specified */
        }
 
        /* Use default stream interface if one was not specified */
@@ -2572,10 +2558,6 @@ out_unlock:
        wim->wim_locked = 0;
 out_free_message_queue_names:
        free_message_queue_names(&ctx);
        wim->wim_locked = 0;
 out_free_message_queue_names:
        free_message_queue_names(&ctx);
-out_restore_lookup_table:
-       if (num_additional_swms)
-               unmerge_lookup_table(wim);
-out:
        return ret;
 }
 
        return ret;
 }
 
@@ -2652,9 +2634,7 @@ wimlib_unmount_image(const tchar *dir, int unmount_flags,
 
 WIMLIBAPI int
 wimlib_mount_image(WIMStruct *wim, int image, const tchar *dir,
 
 WIMLIBAPI int
 wimlib_mount_image(WIMStruct *wim, int image, const tchar *dir,
-                  int mount_flags, WIMStruct **additional_swms,
-                  unsigned num_additional_swms,
-                  const tchar *staging_dir)
+                  int mount_flags, const tchar *staging_dir)
 {
        return mount_unsupported_error();
 }
 {
        return mount_unsupported_error();
 }
index afb4365cd7fec7f4e24c832518319e90dbe4aac8..2d855a6f0e10df18514f4cb3dd13367dd37782e0 100644 (file)
@@ -203,8 +203,8 @@ wimlib_split(WIMStruct *wim, const tchar *swm_name,
        if (swm_name == NULL || swm_name[0] == T('\0') || part_size == 0)
                return WIMLIB_ERR_INVALID_PARAM;
 
        if (swm_name == NULL || swm_name[0] == T('\0') || part_size == 0)
                return WIMLIB_ERR_INVALID_PARAM;
 
-       if (wim->hdr.total_parts != 1)
-               return WIMLIB_ERR_SPLIT_UNSUPPORTED;
+       if (!wim_has_metadata(wim))
+               return WIMLIB_ERR_INVALID_PARAM;
 
        memset(&swm_info, 0, sizeof(swm_info));
        swm_info.max_part_size = part_size;
 
        memset(&swm_info, 0, sizeof(swm_info));
        swm_info.max_part_size = part_size;
diff --git a/src/swm.c b/src/swm.c
deleted file mode 100644 (file)
index 5ea5d4f..0000000
--- a/src/swm.c
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * swm.c
- *
- * Functions to help handle split WIMs.
- */
-
-/*
- * Copyright (C) 2012, 2013 Eric Biggers
- *
- * This file is part of wimlib, a library for working with WIM files.
- *
- * wimlib is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU General Public License
- * along with wimlib; if not, see http://www.gnu.org/licenses/.
- */
-
-#ifdef HAVE_CONFIG_H
-#  include "config.h"
-#endif
-
-#include "wimlib/error.h"
-#include "wimlib/lookup_table.h"
-#include "wimlib/swm.h"
-#include "wimlib/wim.h"
-
-static int
-move_lte_to_table(struct wim_lookup_table_entry *lte, void *combined_table)
-{
-       hlist_del(&lte->hash_list);
-       lookup_table_insert((struct wim_lookup_table*)combined_table, lte);
-       return 0;
-}
-
-static void
-lookup_table_join(struct wim_lookup_table *combined_table,
-                 struct wim_lookup_table *part_table)
-{
-       for_lookup_table_entry(part_table, move_lte_to_table, combined_table);
-       part_table->num_entries = 0;
-}
-
-/*
- * merge_lookup_tables() - Merge lookup tables from the parts of a split WIM.
- *
- * @wim specifies the first part, while @additional_swms and @num_additional_swms
- * specify an array of pointers to the WIMStruct's for additional split WIM parts.
- *
- * 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 WIM.
- */
-void
-merge_lookup_tables(WIMStruct *wim,
-                   WIMStruct **additional_swms,
-                   unsigned num_additional_swms)
-{
-       for (unsigned i = 0; i < num_additional_swms; i++)
-               lookup_table_join(wim->lookup_table, additional_swms[i]->lookup_table);
-}
-
-static int
-move_lte_to_orig_table(struct wim_lookup_table_entry *lte, void *_wim)
-{
-       WIMStruct *wim = _wim;
-       if (lte->wim != wim) {
-               move_lte_to_table(lte, lte->wim->lookup_table);
-               wim->lookup_table->num_entries--;
-       }
-       return 0;
-}
-
-/* Undo merge_lookup_tables(), given the first WIM part that contains the merged
- * lookup table. */
-void
-unmerge_lookup_table(WIMStruct *wim)
-{
-       for_lookup_table_entry(wim->lookup_table, move_lte_to_orig_table, wim);
-}
-
-/*
- * verify_swm_set: - Sanity checks to make sure a set of WIMs correctly
- *                  correspond to a spanned set.
- *
- * @wim:
- *     Part 1 of the set.
- *
- * @additional_swms:
- *     All parts of the set other than part 1.
- *
- * @num_additional_swms:
- *     Number of WIMStructs in @additional_swms.  Or, the total number of parts
- *     in the set minus 1.
- *
- * @return:
- *     0 on success; WIMLIB_ERR_SPLIT_INVALID if the set is not valid.
- */
-int
-verify_swm_set(WIMStruct *wim, WIMStruct **additional_swms,
-              unsigned num_additional_swms)
-{
-       unsigned total_parts = wim->hdr.total_parts;
-       int ctype;
-       const u8 *guid;
-
-       if (total_parts != num_additional_swms + 1) {
-               ERROR("`%"TS"' says there are %u parts in the spanned set, "
-                     "but %"TS"%u part%"TS" provided",
-                     wim->filename, total_parts,
-                     (num_additional_swms + 1 < total_parts) ? T("only ") : T(""),
-                     num_additional_swms + 1,
-                     (num_additional_swms) ? T("s were") : T(" was"));
-               return WIMLIB_ERR_SPLIT_INVALID;
-       }
-       if (wim->hdr.part_number != 1) {
-               ERROR("WIM `%"TS"' is not the first part of the split WIM.",
-                     wim->filename);
-               return WIMLIB_ERR_SPLIT_INVALID;
-       }
-       for (unsigned i = 0; i < num_additional_swms; i++) {
-               if (additional_swms[i]->hdr.total_parts != total_parts) {
-                       ERROR("WIM `%"TS"' says there are %u parts in the "
-                             "spanned set, but %u parts were provided",
-                             additional_swms[i]->filename,
-                             additional_swms[i]->hdr.total_parts,
-                             total_parts);
-                       return WIMLIB_ERR_SPLIT_INVALID;
-               }
-       }
-
-       /* keep track of ctype and guid just to make sure they are the same for
-        * all the WIMs. */
-       ctype = wim->compression_type;
-       guid = wim->hdr.guid;
-
-       {
-               /* parts_to_swms is not allocated at function scope because it
-                * should only be allocated after num_additional_swms was
-                * checked to be the same as wim->hdr.total_parts.  Otherwise, it
-                * could be unexpectedly high and cause a stack overflow. */
-               WIMStruct *parts_to_swms[num_additional_swms];
-               ZERO_ARRAY(parts_to_swms);
-               for (unsigned i = 0; i < num_additional_swms; i++) {
-
-                       WIMStruct *swm = additional_swms[i];
-
-                       if (swm->compression_type != ctype) {
-                               ERROR("The split WIMs do not all have the same "
-                                     "compression type");
-                               return WIMLIB_ERR_SPLIT_INVALID;
-                       }
-                       if (memcmp(guid, swm->hdr.guid, WIM_GID_LEN) != 0) {
-                               ERROR("The split WIMs do not all have the same "
-                                     "GUID");
-                               return WIMLIB_ERR_SPLIT_INVALID;
-                       }
-                       if (swm->hdr.part_number == 1) {
-                               ERROR("WIMs `%"TS"' and `%"TS"' both are marked "
-                                     "as the first WIM in the spanned set",
-                                     wim->filename, swm->filename);
-                               return WIMLIB_ERR_SPLIT_INVALID;
-                       }
-                       if (swm->hdr.part_number == 0 ||
-                           swm->hdr.part_number > total_parts)
-                       {
-                               ERROR("WIM `%"TS"' says it is part %u in the "
-                                     "spanned set, but the part number must "
-                                     "be in the range [1, %u]",
-                                     swm->filename, swm->hdr.part_number, total_parts);
-                               return WIMLIB_ERR_SPLIT_INVALID;
-                       }
-                       if (parts_to_swms[swm->hdr.part_number - 2])
-                       {
-                               ERROR("`%"TS"' and `%"TS"' are both marked as "
-                                     "part %u of %u in the spanned set",
-                                     parts_to_swms[swm->hdr.part_number - 2]->filename,
-                                     swm->filename,
-                                     swm->hdr.part_number,
-                                     total_parts);
-                               return WIMLIB_ERR_SPLIT_INVALID;
-                       } else {
-                               parts_to_swms[swm->hdr.part_number - 2] = swm;
-                       }
-               }
-       }
-       return 0;
-}
index 6f17b5bf28371cc3a91340ae88e7b77977075a03..8416bb463ed498a1fa721274f2535a177a978bf1 100644 (file)
@@ -286,6 +286,8 @@ static const tchar *error_strings[] = {
        [WIMLIB_ERR_FUSERMOUNT]
                = T("Could not execute the `fusermount' program, or it exited "
                        "with a failure status"),
        [WIMLIB_ERR_FUSERMOUNT]
                = T("Could not execute the `fusermount' program, or it exited "
                        "with a failure status"),
+       [WIMLIB_ERR_GLOB_HAD_NO_MATCHES]
+               = T("The provided file glob did not match any files"),
        [WIMLIB_ERR_ICONV_NOT_AVAILABLE]
                = T("The iconv() function does not seem to work. "
                  "Maybe check to make sure the directory /usr/lib/gconv exists"),
        [WIMLIB_ERR_ICONV_NOT_AVAILABLE]
                = T("The iconv() function does not seem to work. "
                  "Maybe check to make sure the directory /usr/lib/gconv exists"),
@@ -345,6 +347,8 @@ static const tchar *error_strings[] = {
        [WIMLIB_ERR_LINK]
                = T("Failed to create a hard or symbolic link when extracting "
                        "a file from the WIM"),
        [WIMLIB_ERR_LINK]
                = T("Failed to create a hard or symbolic link when extracting "
                        "a file from the WIM"),
+       [WIMLIB_ERR_METADATA_NOT_FOUND]
+               = T("A required metadata resource could not be located"),
        [WIMLIB_ERR_MKDIR]
                = T("Failed to create a directory"),
        [WIMLIB_ERR_MQUEUE]
        [WIMLIB_ERR_MKDIR]
                = T("Failed to create a directory"),
        [WIMLIB_ERR_MQUEUE]
index 5ebf94ca4e3518fa6bd25d5668e24e49d4ccb46a..f91c98bc4b0b7d12add9c585c4314966a3493070 100644 (file)
--- a/src/wim.c
+++ b/src/wim.c
@@ -71,6 +71,7 @@ new_wim_struct(void)
                wim->in_fd.fd = -1;
                wim->out_fd.fd = -1;
        }
                wim->in_fd.fd = -1;
                wim->out_fd.fd = -1;
        }
+       INIT_LIST_HEAD(&wim->resource_wims);
        return wim;
 }
 
        return wim;
 }
 
@@ -167,9 +168,11 @@ select_wim_image(WIMStruct *wim, int image)
                return WIMLIB_ERR_INVALID_IMAGE;
        }
 
                return WIMLIB_ERR_INVALID_IMAGE;
        }
 
-       if (wim->hdr.part_number != 1) {
-               ERROR("Cannot select an image from a non-first part of a split WIM");
-               return WIMLIB_ERR_SPLIT_UNSUPPORTED;
+       if (!wim_has_metadata(wim)) {
+               ERROR("\"%"TS"\" does not contain metadata resources!", wim->filename);
+               if (wim->hdr.part_number != 1)
+                       ERROR("Specify the first part of the split WIM instead.");
+               return WIMLIB_ERR_METADATA_NOT_FOUND;
        }
 
        /* If a valid image is currently selected, it can be freed if it is not
        }
 
        /* If a valid image is currently selected, it can be freed if it is not
@@ -278,12 +281,6 @@ wimlib_print_available_images(const WIMStruct *wim, int image)
 WIMLIBAPI int
 wimlib_print_metadata(WIMStruct *wim, int image)
 {
 WIMLIBAPI int
 wimlib_print_metadata(WIMStruct *wim, int image)
 {
-       if (wim->hdr.part_number != 1) {
-               ERROR("Cannot show the metadata from part %hu of a %hu-part split WIM!",
-                      wim->hdr.part_number, wim->hdr.total_parts);
-               ERROR("Select the first part of the split WIM to see the metadata.");
-               return WIMLIB_ERR_SPLIT_UNSUPPORTED;
-       }
        return for_image(wim, image, image_print_metadata);
 }
 
        return for_image(wim, image, image_print_metadata);
 }
 
@@ -759,11 +756,26 @@ wimlib_free(WIMStruct *wim)
 
        if (!wim)
                return;
 
        if (!wim)
                return;
+
+       while (!list_empty(&wim->resource_wims)) {
+               WIMStruct *resource_wim;
+
+               resource_wim = list_entry(wim->resource_wims.next,
+                                         WIMStruct, resource_wim_node);
+               if (resource_wim->is_owned_by_master) {
+                       list_del(&resource_wim->resource_wim_node);
+                       wimlib_free(resource_wim);
+               } else {
+                       wimlib_unreference_resources(wim, &resource_wim, 1);
+               }
+       }
+
        if (filedes_valid(&wim->in_fd))
                filedes_close(&wim->in_fd);
        if (filedes_valid(&wim->out_fd))
                filedes_close(&wim->out_fd);
 
        if (filedes_valid(&wim->in_fd))
                filedes_close(&wim->in_fd);
        if (filedes_valid(&wim->out_fd))
                filedes_close(&wim->out_fd);
 
+
        free_lookup_table(wim->lookup_table);
 
        FREE(wim->filename);
        free_lookup_table(wim->lookup_table);
 
        FREE(wim->filename);
index 48dd66d319637769b881086ffae72e54581bba1e..b1253956f3587f9e025ca3d74fac31768c47d474 100644 (file)
@@ -191,7 +191,7 @@ win32_extract_stream(const wchar_t *path, const wchar_t *stream_name,
                stream_path = alloca(sizeof(wchar_t) *
                                     (wcslen(path) + 1 +
                                      wcslen(stream_name) + 1));
                stream_path = alloca(sizeof(wchar_t) *
                                     (wcslen(path) + 1 +
                                      wcslen(stream_name) + 1));
-               swprintf(stream_path, L"%ls:%ls", path, stream_name);
+               tsprintf(stream_path, L"%ls:%ls", path, stream_name);
        }
 
        h = CreateFile(stream_path, FILE_WRITE_DATA, 0, NULL,
        }
 
        h = CreateFile(stream_path, FILE_WRITE_DATA, 0, NULL,
index 3466ad47f1af8f36025e6b27fdf53545081723ff..14a6c134833e0b47860c60e75321560ea60258ba 100644 (file)
@@ -945,7 +945,7 @@ win32_capture_stream(const wchar_t *path,
        spath_buf_nbytes = (spath_nchars + 1) * sizeof(wchar_t);
        spath = MALLOC(spath_buf_nbytes);
 
        spath_buf_nbytes = (spath_nchars + 1) * sizeof(wchar_t);
        spath = MALLOC(spath_buf_nbytes);
 
-       swprintf(spath, L"%ls%ls%ls%ls",
+       tsprintf(spath, L"%ls%ls%ls%ls",
                 relpath_prefix, path, colonchar, stream_name);
 
        /* Make a new wim_lookup_table_entry */
                 relpath_prefix, path, colonchar, stream_name);
 
        /* Make a new wim_lookup_table_entry */
index 17861ef72d02be5349254b55f375b08c9049191c..4e9df0aee8a5a538676176fd74a3d20819222513 100644 (file)
 #  include "config.h"
 #endif
 
 #  include "config.h"
 #endif
 
+#include <errno.h>
 #include <pthread.h>
 #include <shlwapi.h> /* for PathMatchSpecW() */
 #include "wimlib/win32_common.h"
 
 #include "wimlib/assert.h"
 #include "wimlib/file_io.h"
 #include <pthread.h>
 #include <shlwapi.h> /* for PathMatchSpecW() */
 #include "wimlib/win32_common.h"
 
 #include "wimlib/assert.h"
 #include "wimlib/file_io.h"
+#include "wimlib/glob.h"
 #include "wimlib/error.h"
 #include "wimlib/util.h"
 
 #include "wimlib/error.h"
 #include "wimlib/util.h"
 
@@ -287,5 +289,109 @@ out:
        return ret;
 }
 
        return ret;
 }
 
+/* Replacement for glob() in Windows native builds that operates on wide
+ * characters.  */
+int
+win32_wglob(const wchar_t *pattern, int flags,
+           int (*errfunc)(const wchar_t *epath, int eerrno),
+           glob_t *pglob)
+{
+       WIN32_FIND_DATAW dat;
+       DWORD err;
+       HANDLE hFind;
+       int ret;
+       size_t nspaces;
+
+       const wchar_t *backslash, *end_slash;
+       size_t prefix_len;
+
+       backslash = wcsrchr(pattern, L'\\');
+       end_slash = wcsrchr(pattern, L'/');
+
+       if (backslash > end_slash)
+               end_slash = backslash;
+
+       if (end_slash)
+               prefix_len = end_slash - pattern + 1;
+       else
+               prefix_len = 0;
+
+       /* This function does not support all functionality of the POSIX glob(),
+        * so make sure the parameters are consistent with supported
+        * functionality. */
+       wimlib_assert(errfunc == NULL);
+       wimlib_assert((flags & GLOB_ERR) == GLOB_ERR);
+       wimlib_assert((flags & ~(GLOB_NOSORT | GLOB_ERR)) == 0);
+
+       hFind = FindFirstFileW(pattern, &dat);
+       if (hFind == INVALID_HANDLE_VALUE) {
+               err = GetLastError();
+               if (err == ERROR_FILE_NOT_FOUND) {
+                       errno = 0;
+                       return GLOB_NOMATCH;
+               } else {
+                       /* The other possible error codes for FindFirstFile()
+                        * are undocumented. */
+                       errno = EIO;
+                       return GLOB_ABORTED;
+               }
+       }
+       pglob->gl_pathc = 0;
+       pglob->gl_pathv = NULL;
+       nspaces = 0;
+       do {
+               wchar_t *path;
+               if (pglob->gl_pathc == nspaces) {
+                       size_t new_nspaces;
+                       wchar_t **pathv;
+
+                       new_nspaces = nspaces * 2 + 1;
+                       pathv = REALLOC(pglob->gl_pathv,
+                                       new_nspaces * sizeof(pglob->gl_pathv[0]));
+                       if (!pathv)
+                               goto oom;
+                       pglob->gl_pathv = pathv;
+                       nspaces = new_nspaces;
+               }
+               size_t filename_len = wcslen(dat.cFileName);
+               size_t len_needed = prefix_len + filename_len;
+
+               path = MALLOC((len_needed + 1) * sizeof(wchar_t));
+               if (!path)
+                       goto oom;
+
+               wmemcpy(path, pattern, prefix_len);
+               wmemcpy(path + prefix_len, dat.cFileName, filename_len + 1);
+               pglob->gl_pathv[pglob->gl_pathc++] = path;
+       } while (FindNextFileW(hFind, &dat));
+       err = GetLastError();
+       CloseHandle(hFind);
+       if (err == ERROR_NO_MORE_FILES) {
+               errno = 0;
+               return 0;
+       } else {
+               /* Other possible error codes for FindNextFile() are
+                * undocumented */
+               errno = EIO;
+               ret = GLOB_ABORTED;
+               goto fail_globfree;
+       }
+oom:
+       CloseHandle(hFind);
+       errno = ENOMEM;
+       ret = GLOB_NOSPACE;
+fail_globfree:
+       globfree(pglob);
+       return ret;
+}
+
+void
+globfree(glob_t *pglob)
+{
+       size_t i;
+       for (i = 0; i < pglob->gl_pathc; i++)
+               free(pglob->gl_pathv[i]);
+       free(pglob->gl_pathv);
+}
 
 #endif /* __WIN32__ */
 
 #endif /* __WIN32__ */
index 939fe459b4fd9bd8a48e7f36e3c4663b4b90b2fa..b1654e9a77b6fcb1c8878d42a8a8fdca39983684 100644 (file)
@@ -2416,10 +2416,12 @@ write_wim_part(WIMStruct *wim,
             (image < 1 || image > wim->hdr.image_count))
                return WIMLIB_ERR_INVALID_IMAGE;
 
             (image < 1 || image > wim->hdr.image_count))
                return WIMLIB_ERR_INVALID_IMAGE;
 
-       /* @wim must specify a standalone WIM, or at least the first part of a
-        * split WIM.  */
-       if (wim->hdr.part_number != 1)
-               return WIMLIB_ERR_SPLIT_UNSUPPORTED;
+       /* If we need to write metadata resources, make sure the ::WIMStruct has
+        * the needed information attached (e.g. is not a resource-only WIM,
+        * such as a non-first part of a split WIM).  */
+       if (!wim_has_metadata(wim) &&
+           !(write_flags & WIMLIB_WRITE_FLAG_NO_METADATA))
+               return WIMLIB_ERR_METADATA_NOT_FOUND;
 
        /* Check for contradictory flags.  */
        if ((write_flags & (WIMLIB_WRITE_FLAG_CHECK_INTEGRITY |
 
        /* Check for contradictory flags.  */
        if ((write_flags & (WIMLIB_WRITE_FLAG_CHECK_INTEGRITY |
index cd98a79584ce06d1a7ea7c1d276b17631dcb61e3..8d2b9106f3efb9d1ef3f971056ea4c44729a5c33 100644 (file)
--- a/src/xml.c
+++ b/src/xml.c
@@ -132,27 +132,37 @@ windows_info_xml_string_specs[] = {
 u64
 wim_info_get_total_bytes(const struct wim_info *info)
 {
 u64
 wim_info_get_total_bytes(const struct wim_info *info)
 {
-       if (!info)
+       if (info)
+               return info->total_bytes;
+       else
                return 0;
                return 0;
-       return info->total_bytes;
 }
 
 u64
 wim_info_get_image_hard_link_bytes(const struct wim_info *info, int image)
 {
 }
 
 u64
 wim_info_get_image_hard_link_bytes(const struct wim_info *info, int image)
 {
-       return info->images[image - 1].hard_link_bytes;
+       if (info)
+               return info->images[image - 1].hard_link_bytes;
+       else
+               return 0;
 }
 
 u64
 wim_info_get_image_total_bytes(const struct wim_info *info, int image)
 {
 }
 
 u64
 wim_info_get_image_total_bytes(const struct wim_info *info, int image)
 {
-       return info->images[image - 1].total_bytes;
+       if (info)
+               return info->images[image - 1].total_bytes;
+       else
+               return 0;
 }
 
 unsigned
 wim_info_get_num_images(const struct wim_info *info)
 {
 }
 
 unsigned
 wim_info_get_num_images(const struct wim_info *info)
 {
-       return info->num_images;
+       if (info)
+               return info->num_images;
+       else
+               return 0;
 }
 
 /* Returns a statically allocated string that is a string representation of the
 }
 
 /* Returns a statically allocated string that is a string representation of the