wimappend: add --create option to create WIM file if needed
authorEric Biggers <ebiggers3@gmail.com>
Sat, 21 Jul 2018 19:34:19 +0000 (12:34 -0700)
committerEric Biggers <ebiggers3@gmail.com>
Sat, 21 Jul 2018 20:00:39 +0000 (13:00 -0700)
NEWS
doc/man1/wimcapture.1
programs/imagex.c
tests/test-imagex

diff --git a/NEWS b/NEWS
index 5d7b94a..b75e380 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,9 @@ Version 1.13.0-BETA:
        example, listing "/dir/file" in [ExclusionException] now works even if
        "/dir" is matched by [ExclusionList].
 
+       Added a '--create' option to 'wimappend' which makes it create the WIM
+       file (like 'wimcapture') if it doesn't exist yet.
+
        Added an '--include-integrity' option to various wimlib-imagex commands.
        '--include-integrity' is like '--check', but it will just include an
        integrity table in the output WIM(s), while skipping verification of any
index 9426c81..40ef247 100644 (file)
@@ -10,7 +10,8 @@ The \fBwimcapture\fR (equivalently: \fBwimlib-imagex capture\fR) and
 \fBwimappend\fR (equivalently: \fBwimlib-imagex append\fR) commands create
 ("capture") a new Windows Imaging (WIM) image.  \fBwimcapture\fR creates a new
 WIM archive \fIWIMFILE\fR to contain the new image, while \fBwimappend\fR adds
-the image to the existing WIM archive \fIWIMFILE\fR.
+the image to the existing WIM archive \fIWIMFILE\fR (or with \fB--create\fR,
+creating it if needed).
 .PP
 \fISOURCE\fR specifies the location of the files from which to create the WIM
 image.  If \fISOURCE\fR is a directory or a symbolic link pointing to a
@@ -588,6 +589,10 @@ running into problems with locked files.  For the VSS snapshot to be
 successfully created, \fBwimlib-imagex\fR must be run as an Administrator, and
 it cannot be run in WoW64 mode (i.e. if Windows is 64-bit, then
 \fBwimlib-imagex\fR must be 64-bit as well).
+.TP
+\fB--create\fR
+With \fBwimappend\fR, if the WIM file doesn't exist yet, then create it (like
+\fBwimcapture\fR).
 .SH NOTES
 \fBwimappend\fR does not support appending an image to a split WIM.
 .PP
index ea0815a..a274f78 100644 (file)
@@ -171,6 +171,7 @@ enum {
        IMAGEX_COMPACT_OPTION,
        IMAGEX_COMPRESS_OPTION,
        IMAGEX_CONFIG_OPTION,
+       IMAGEX_CREATE_OPTION,
        IMAGEX_DEBUG_OPTION,
        IMAGEX_DELTA_FROM_OPTION,
        IMAGEX_DEREFERENCE_OPTION,
@@ -274,6 +275,7 @@ static const struct option capture_or_append_options[] = {
        {T("wimboot"),     no_argument,       NULL, IMAGEX_WIMBOOT_OPTION},
        {T("unsafe-compact"), no_argument,    NULL, IMAGEX_UNSAFE_COMPACT_OPTION},
        {T("snapshot"),    no_argument,       NULL, IMAGEX_SNAPSHOT_OPTION},
+       {T("create"),      no_argument,       NULL, IMAGEX_CREATE_OPTION},
        {NULL, 0, NULL, 0},
 };
 
@@ -1853,14 +1855,18 @@ out_usage:
        goto out_free_refglobs;
 }
 
-/* Create a WIM image from a directory tree, NTFS volume, or multiple files or
- * directory trees.  'wimlib-imagex capture': create a new WIM file containing
- * the desired image.  'wimlib-imagex append': add a new image to an existing
- * WIM file. */
+/*
+ * Create a WIM image from a directory tree, NTFS volume, or multiple files or
+ * directory trees.  'wimcapture': create a new WIM file containing the desired
+ * image.  'wimappend': add a new image to an existing WIM file; or, with
+ * '--create' behave like 'wimcapture' if the WIM file doesn't exist.
+ */
 static int
 imagex_capture_or_append(int argc, tchar **argv, int cmd)
 {
        int c;
+       bool create = false;
+       bool appending = (cmd == CMD_APPEND);
        int open_flags = 0;
        int add_flags = WIMLIB_ADD_FLAG_EXCLUDE_VERBOSE |
                        WIMLIB_ADD_FLAG_WINCONFIG |
@@ -2025,16 +2031,18 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                        add_flags |= WIMLIB_ADD_FLAG_WIMBOOT;
                        break;
                case IMAGEX_UNSAFE_COMPACT_OPTION:
-                       if (cmd != CMD_APPEND) {
-                               imagex_error(T("'--unsafe-compact' is only "
-                                              "valid for append!"));
-                               goto out_err;
-                       }
                        write_flags |= WIMLIB_WRITE_FLAG_UNSAFE_COMPACT;
                        break;
                case IMAGEX_SNAPSHOT_OPTION:
                        add_flags |= WIMLIB_ADD_FLAG_SNAPSHOT;
                        break;
+               case IMAGEX_CREATE_OPTION:
+                       if (cmd == CMD_CAPTURE) {
+                               imagex_error(T("'--create' is only valid for 'wimappend', not 'wimcapture'"));
+                               goto out_err;
+                       }
+                       create = true;
+                       break;
                default:
                        goto out_usage;
                }
@@ -2069,6 +2077,8 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
 
        if (!tstrcmp(wimfile, T("-"))) {
                /* Writing captured WIM to standard output.  */
+               if (create)
+                       appending = false;
        #if 0
                if (!(write_flags & WIMLIB_WRITE_FLAG_PIPABLE)) {
                        imagex_error("Can't write a non-pipable WIM to "
@@ -2080,7 +2090,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
        #else
                write_flags |= WIMLIB_WRITE_FLAG_PIPABLE;
        #endif
-               if (cmd == CMD_APPEND) {
+               if (appending) {
                        imagex_error(T("Using standard output for append does "
                                       "not make sense."));
                        goto out_err;
@@ -2089,6 +2099,16 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                wimfile = NULL;
                imagex_output_to_stderr();
                set_fd_to_binary_mode(wim_fd);
+       } else {
+               struct stat stbuf;
+
+               if (create && tstat(wimfile, &stbuf) != 0 && errno == ENOENT)
+                       appending = false;
+       }
+
+       if ((write_flags & WIMLIB_WRITE_FLAG_UNSAFE_COMPACT) && !appending) {
+               imagex_error(T("'--unsafe-compact' is only valid for append!"));
+               goto out_err;
        }
 
        /* If template image was specified using --update-of=IMAGE rather
@@ -2098,7 +2118,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                        /* Capturing delta WIM based on single WIM:  default to
                         * base WIM.  */
                        template_wimfile = base_wimfiles.strings[0];
-               } else if (cmd == CMD_APPEND) {
+               } else if (appending) {
                        /* Appending to WIM:  default to WIM being appended to.
                         */
                        template_wimfile = wimfile;
@@ -2176,7 +2196,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
        }
 
        /* Open the existing WIM, or create a new one.  */
-       if (cmd == CMD_APPEND) {
+       if (appending) {
                ret = wimlib_open_wim_with_progress(wimfile,
                                                    open_flags | WIMLIB_OPEN_FLAG_WRITE_ACCESS,
                                                    &wim,
@@ -2200,7 +2220,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
 
                int ctype = compression_type;
 
-               if (cmd == CMD_APPEND) {
+               if (appending) {
                        struct wimlib_wim_info info;
                        wimlib_get_wim_info(wim, &info);
                        ctype = info.compression_type;
@@ -2249,7 +2269,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
        /* If the user did not specify an image name, and the basename of the
         * source already exists as an image name in the WIM file, append a
         * suffix to make it unique. */
-       if (cmd == CMD_APPEND && name_defaulted) {
+       if (appending && name_defaulted) {
                unsigned long conflict_idx;
                tchar *name_end = tstrchr(name, T('\0'));
                for (conflict_idx = 1;
@@ -2301,7 +2321,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
         * open the WIM if needed and parse the image index.  */
        if (template_image_name_or_num) {
 
-               if (cmd == CMD_APPEND && !tstrcmp(template_wimfile, wimfile)) {
+               if (appending && !tstrcmp(template_wimfile, wimfile)) {
                        template_wim = wim;
                } else {
                        for (size_t i = 0; i < base_wimfiles.num_strings; i++) {
@@ -2386,7 +2406,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
 
        /* Write the new WIM or overwrite the existing WIM with the new image
         * appended.  */
-       if (cmd == CMD_APPEND) {
+       if (appending) {
                ret = wimlib_overwrite(wim, write_flags, num_threads);
        } else if (wimfile) {
                ret = wimlib_write(wim, wimfile, WIMLIB_ALL_IMAGES,
@@ -4426,7 +4446,7 @@ T(
 "                    [--threads=NUM_THREADS] [--no-acls] [--strict-acls]\n"
 "                    [--rpfix] [--norpfix] [--update-of=[WIMFILE:]IMAGE]\n"
 "                    [--delta-from=WIMFILE] [--wimboot] [--unix-data]\n"
-"                    [--dereference] [--snapshot]\n"
+"                    [--dereference] [--snapshot] [--create]\n"
 ),
 [CMD_APPLY] =
 T(
index d36bf82..9c92715 100755 (executable)
@@ -65,6 +65,21 @@ for comp_type in None LZX XPRESS; do
        rm -rf dir.wim tmp
 done
 
+# Test wimappend --create
+rm -f dir.wim
+if wimappend dir dir.wim; then
+       error "wimappend to nonexisting file unexpectedly succeeded"
+fi
+if ! wimappend dir dir.wim --create; then
+       error "wimappend --create to nonexisting file failed"
+fi
+if ! wimappend dir dir.wim --create; then
+       error "wimappend --create to existing file failed"
+fi
+if ! test "`wiminfo dir.wim | grep 'Image Count' | awk '{print $3}'`" = 2; then
+       error "Incorrect WIM image count after wimappend --create"
+fi
+
 # Capturing and modifying name, description, and bootable flag
 
 echo "Testing capture of WIM with default name and description"