Support for joining WIMs.
authorEric Biggers <ebiggers3@gmail.com>
Sat, 19 May 2012 17:28:05 +0000 (12:28 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Sat, 19 May 2012 17:28:05 +0000 (12:28 -0500)
- join command for imagex
- wimlib_join() function
- wimlib_get_part_number() functions
- Various modifications in other files to make this possible.  wimlib_open_wim()
  will open a split wim given the WIMLIB_OPEN_FLAG_SPLIT_OK flag.
- Allow finish_write() to skip writing lookup table in case it is written
  elsewhere (join_wims())
- Show more header flags in wimlib_print_header() (including
  WIMLIB_HDR_FLAG_SPANNED)
- Allow images with no name, and when extracting them, extract to directory
  named after image number rather than name

13 files changed:
autom4te.cache/requests
programs/imagex.c
src/Makefile.am
src/Makefile.in
src/extract.c
src/header.c
src/join.c [new file with mode: 0644]
src/util.c
src/wim.c
src/wimlib.h
src/wimlib_internal.h
src/write.c
src/xml.c

index 38a2931..4324d28 100644 (file)
@@ -62,8 +62,8 @@
                         '_m4_warn' => 1,
                         'AC_LIBTOOL_OBJDIR' => 1,
                         'gl_FUNC_ARGZ' => 1,
-                        'AM_SANITY_CHECK' => 1,
                         'LTOBSOLETE_VERSION' => 1,
+                        'AM_SANITY_CHECK' => 1,
                         'AC_LIBTOOL_LANG_GCJ_CONFIG' => 1,
                         'AC_LIBTOOL_PROG_COMPILER_PIC' => 1,
                         'LT_LIB_M' => 1,
                         '_LT_WITH_SYSROOT' => 1,
                         'LT_SYS_DLOPEN_DEPLIBS' => 1,
                         'LT_FUNC_DLSYM_USCORE' => 1,
-                        '_LT_AC_LANG_F77' => 1,
-                        'AC_LIBTOOL_CONFIG' => 1,
                         'AC_LIB_ARG_WITH' => 1,
-                        '_AM_SUBST_NOTMAKE' => 1,
+                        'AC_LIBTOOL_CONFIG' => 1,
+                        '_LT_AC_LANG_F77' => 1,
                         'AC_LTDL_DLLIB' => 1,
+                        '_AM_SUBST_NOTMAKE' => 1,
                         '_AM_AUTOCONF_VERSION' => 1,
                         'AM_DISABLE_SHARED' => 1,
                         '_LT_PROG_ECHO_BACKSLASH' => 1,
                         '_LTDL_SETUP' => 1,
-                        '_LT_AC_LANG_CXX' => 1,
                         'AM_PROG_LIBTOOL' => 1,
-                        'AC_LIB_LTDL' => 1,
-                        '_LT_AC_FILE_LTDLL_C' => 1,
+                        '_LT_AC_LANG_CXX' => 1,
                         'AM_PROG_LD' => 1,
+                        '_LT_AC_FILE_LTDLL_C' => 1,
+                        'AC_LIB_LTDL' => 1,
                         'AM_ICONV_LINK' => 1,
                         'AC_LIB_PREPARE_MULTILIB' => 1,
                         'AU_DEFUN' => 1,
                         'AC_LIBTOOL_PROG_CC_C_O' => 1,
                         'gl_PREREQ_ARGZ' => 1,
                         'AC_LIB_PREFIX' => 1,
-                        'AM_OUTPUT_DEPENDENCY_COMMANDS' => 1,
                         'LT_SUPPORTED_TAG' => 1,
-                        'LT_SYS_MODULE_EXT' => 1,
+                        'AM_OUTPUT_DEPENDENCY_COMMANDS' => 1,
                         'LT_PROG_RC' => 1,
+                        'LT_SYS_MODULE_EXT' => 1,
                         'AC_DEFUN_ONCE' => 1,
                         '_LT_AC_LANG_GCJ' => 1,
                         'AC_' => 1,
                         'AC_LTDL_OBJDIR' => 1,
                         '_LT_PATH_TOOL_PREFIX' => 1,
-                        'AC_LIBTOOL_RC' => 1,
                         'AM_ICONV' => 1,
-                        'AM_SILENT_RULES' => 1,
-                        'AC_DISABLE_FAST_INSTALL' => 1,
+                        'AC_LIBTOOL_RC' => 1,
                         '_LT_AC_PROG_ECHO_BACKSLASH' => 1,
-                        '_LT_AC_SYS_LIBPATH_AIX' => 1,
-                        '_LT_AC_TRY_DLOPEN_SELF' => 1,
+                        'AC_DISABLE_FAST_INSTALL' => 1,
+                        'AM_SILENT_RULES' => 1,
                         'include' => 1,
+                        '_LT_AC_TRY_DLOPEN_SELF' => 1,
+                        '_LT_AC_SYS_LIBPATH_AIX' => 1,
                         'LT_AC_PROG_SED' => 1,
                         'AM_ENABLE_SHARED' => 1,
                         'AC_LIB_APPENDTOVAR' => 1,
-                        'LTDL_INSTALLABLE' => 1,
                         'AM_PROG_AR' => 1,
+                        'LTDL_INSTALLABLE' => 1,
                         '_LT_AC_LANG_GCJ_CONFIG' => 1,
                         'AC_ENABLE_SHARED' => 1,
                         'AC_LIB_WITH_FINAL_PREFIX' => 1,
-                        'AC_ENABLE_STATIC' => 1,
-                        'AC_LIBTOOL_SYS_HARD_LINK_LOCKS' => 1,
                         '_LT_REQUIRED_DARWIN_CHECKS' => 1,
+                        'AC_LIBTOOL_SYS_HARD_LINK_LOCKS' => 1,
+                        'AC_ENABLE_STATIC' => 1,
                         '_LT_AC_TAGVAR' => 1,
                         'AC_LIBTOOL_LANG_F77_CONFIG' => 1,
                         'AM_CONDITIONAL' => 1,
                         'LT_LIB_DLLOAD' => 1,
-                        'LTDL_INIT' => 1,
-                        '_LT_PROG_F77' => 1,
-                        '_LT_PROG_CXX' => 1,
                         'LTVERSION_VERSION' => 1,
-                        'AM_PROG_INSTALL_SH' => 1,
+                        '_LT_PROG_CXX' => 1,
+                        '_LT_PROG_F77' => 1,
+                        'LTDL_INIT' => 1,
                         'm4_include' => 1,
+                        'AM_PROG_INSTALL_SH' => 1,
                         'AC_PROG_EGREP' => 1,
-                        '_AC_AM_CONFIG_HEADER_HOOK' => 1,
                         'AC_PATH_MAGIC' => 1,
+                        '_AC_AM_CONFIG_HEADER_HOOK' => 1,
                         'AC_LTDL_SYSSEARCHPATH' => 1,
                         'AM_MAKE_INCLUDE' => 1,
                         'LT_CMD_MAX_LEN' => 1,
                         'LT_OUTPUT' => 1,
                         'AC_LIB_PROG_LD_GNU' => 1,
                         'AC_LIBTOOL_PROG_LD_SHLIBS' => 1,
-                        'AC_LIBTOOL_LINKER_OPTION' => 1,
                         'AC_WITH_LTDL' => 1,
-                        'AC_LIBTOOL_CXX' => 1,
+                        'AC_LIBTOOL_LINKER_OPTION' => 1,
                         'LT_AC_PROG_RC' => 1,
+                        'AC_LIBTOOL_CXX' => 1,
                         'LT_INIT' => 1,
-                        'LT_SYS_DLOPEN_SELF' => 1,
                         'LT_AC_PROG_GCJ' => 1,
-                        '_LT_AC_PROG_CXXCPP' => 1,
-                        'AM_DISABLE_STATIC' => 1,
+                        'LT_SYS_DLOPEN_SELF' => 1,
                         'AM_DEP_TRACK' => 1,
+                        'AM_DISABLE_STATIC' => 1,
+                        '_LT_AC_PROG_CXXCPP' => 1,
                         '_AC_PROG_LIBTOOL' => 1,
                         '_AM_IF_OPTION' => 1,
                         'AC_PATH_TOOL_PREFIX' => 1,
-                        'AC_LIBTOOL_F77' => 1,
                         'm4_pattern_allow' => 1,
+                        'AC_LIBTOOL_F77' => 1,
                         'AM_SET_LEADING_DOT' => 1,
-                        'LT_AC_PROG_EGREP' => 1,
                         '_LT_PROG_FC' => 1,
+                        'LT_AC_PROG_EGREP' => 1,
                         '_AM_DEPENDENCIES' => 1,
                         'AC_LIBTOOL_LANG_C_CONFIG' => 1,
                         'LTOPTIONS_VERSION' => 1,
-                        '_LT_AC_SYS_COMPILER' => 1,
                         'AC_LIB_LINKFLAGS' => 1,
+                        '_LT_AC_SYS_COMPILER' => 1,
                         'AM_PROG_NM' => 1,
                         'AC_LIBLTDL_CONVENIENCE' => 1,
                         'AC_DEPLIBS_CHECK_METHOD' => 1,
-                        'AM_SET_CURRENT_AUTOMAKE_VERSION' => 1,
                         'AC_LIBLTDL_INSTALLABLE' => 1,
+                        'AM_SET_CURRENT_AUTOMAKE_VERSION' => 1,
                         'AC_LTDL_ENABLE_INSTALL' => 1,
-                        'AC_LIBTOOL_SYS_DYNAMIC_LINKER' => 1,
                         'LT_PROG_GCJ' => 1,
+                        'AC_LIBTOOL_SYS_DYNAMIC_LINKER' => 1,
                         'AM_INIT_AUTOMAKE' => 1,
                         'AC_DISABLE_STATIC' => 1,
                         'LT_PATH_NM' => 1,
                         '_LT_AC_LANG_RC_CONFIG' => 1,
                         'LT_PROG_GO' => 1,
                         'LT_SYS_MODULE_PATH' => 1,
-                        'AC_LIBTOOL_POSTDEP_PREDEP' => 1,
                         'LT_WITH_LTDL' => 1,
+                        'AC_LIBTOOL_POSTDEP_PREDEP' => 1,
                         'AC_LTDL_SHLIBPATH' => 1,
                         'AM_AUX_DIR_EXPAND' => 1,
                         'AC_LIB_LINKFLAGS_FROM_LIBS' => 1,
-                        '_LT_AC_LANG_F77_CONFIG' => 1,
                         'AC_LIBTOOL_PROG_COMPILER_NO_RTTI' => 1,
-                        '_AM_SET_OPTIONS' => 1,
+                        '_LT_AC_LANG_F77_CONFIG' => 1,
                         '_LT_COMPILER_OPTION' => 1,
-                        '_AM_OUTPUT_DEPENDENCY_COMMANDS' => 1,
+                        '_AM_SET_OPTIONS' => 1,
                         'AM_RUN_LOG' => 1,
-                        'AC_LIBTOOL_SYS_OLD_ARCHIVE' => 1,
-                        'AC_LTDL_SYS_DLOPEN_DEPLIBS' => 1,
+                        '_AM_OUTPUT_DEPENDENCY_COMMANDS' => 1,
                         'AC_LIBTOOL_PICMODE' => 1,
+                        'AC_LTDL_SYS_DLOPEN_DEPLIBS' => 1,
+                        'AC_LIBTOOL_SYS_OLD_ARCHIVE' => 1,
                         'AC_LIB_LINKFLAGS_BODY' => 1,
-                        'LT_PATH_LD' => 1,
                         'AC_CHECK_LIBM' => 1,
-                        'AC_LIBTOOL_SYS_LIB_STRIP' => 1,
+                        'LT_PATH_LD' => 1,
                         'AC_LIB_FROMPACKAGE' => 1,
+                        'AC_LIBTOOL_SYS_LIB_STRIP' => 1,
                         '_AM_MANGLE_OPTION' => 1,
-                        'AC_LTDL_SYMBOL_USCORE' => 1,
                         'AC_LIBTOOL_SYS_MAX_CMD_LEN' => 1,
+                        'AC_LTDL_SYMBOL_USCORE' => 1,
                         'AM_SET_DEPDIR' => 1,
                         '_LT_CC_BASENAME' => 1,
                         'AX_PROG_NASM' => 1,
                         'configure.ac'
                       ],
                       {
-                        'AM_PROG_F77_C_O' => 1,
                         '_LT_AC_TAGCONFIG' => 1,
-                        'm4_pattern_forbid' => 1,
+                        'AM_PROG_F77_C_O' => 1,
                         'AC_INIT' => 1,
-                        '_AM_COND_IF' => 1,
+                        'm4_pattern_forbid' => 1,
                         'AC_CANONICAL_TARGET' => 1,
-                        'AC_SUBST' => 1,
+                        '_AM_COND_IF' => 1,
                         'AC_CONFIG_LIBOBJ_DIR' => 1,
-                        'AC_FC_SRCEXT' => 1,
+                        'AC_SUBST' => 1,
                         'AC_CANONICAL_HOST' => 1,
+                        'AC_FC_SRCEXT' => 1,
                         'AC_PROG_LIBTOOL' => 1,
                         'AM_INIT_AUTOMAKE' => 1,
-                        'AM_PATH_GUILE' => 1,
                         'AC_CONFIG_SUBDIRS' => 1,
+                        'AM_PATH_GUILE' => 1,
                         'AM_AUTOMAKE_VERSION' => 1,
                         'LT_CONFIG_LTDL_DIR' => 1,
-                        'AC_REQUIRE_AUX_FILE' => 1,
                         'AC_CONFIG_LINKS' => 1,
-                        'LT_SUPPORTED_TAG' => 1,
+                        'AC_REQUIRE_AUX_FILE' => 1,
                         'm4_sinclude' => 1,
+                        'LT_SUPPORTED_TAG' => 1,
                         'AM_MAINTAINER_MODE' => 1,
                         'AM_NLS' => 1,
                         'AC_FC_PP_DEFINE' => 1,
                         'AM_GNU_GETTEXT_INTL_SUBDIR' => 1,
-                        'AM_MAKEFILE_INCLUDE' => 1,
                         '_m4_warn' => 1,
+                        'AM_MAKEFILE_INCLUDE' => 1,
                         'AM_PROG_CXX_C_O' => 1,
-                        '_AM_MAKEFILE_INCLUDE' => 1,
                         '_AM_COND_ENDIF' => 1,
+                        '_AM_MAKEFILE_INCLUDE' => 1,
                         'AM_ENABLE_MULTILIB' => 1,
                         'AM_PROG_MOC' => 1,
                         'AM_SILENT_RULES' => 1,
                         'AC_CONFIG_FILES' => 1,
-                        'LT_INIT' => 1,
                         'include' => 1,
-                        'AM_PROG_AR' => 1,
+                        'LT_INIT' => 1,
                         'AM_GNU_GETTEXT' => 1,
+                        'AM_PROG_AR' => 1,
                         'AC_LIBSOURCE' => 1,
-                        'AM_PROG_FC_C_O' => 1,
                         'AC_CANONICAL_BUILD' => 1,
+                        'AM_PROG_FC_C_O' => 1,
                         'AC_FC_FREEFORM' => 1,
-                        'AH_OUTPUT' => 1,
                         'AC_FC_PP_SRCEXT' => 1,
-                        '_AM_SUBST_NOTMAKE' => 1,
+                        'AH_OUTPUT' => 1,
                         'AC_CONFIG_AUX_DIR' => 1,
-                        'm4_pattern_allow' => 1,
-                        'sinclude' => 1,
+                        '_AM_SUBST_NOTMAKE' => 1,
                         'AM_PROG_CC_C_O' => 1,
-                        'AM_XGETTEXT_OPTION' => 1,
-                        'AC_CANONICAL_SYSTEM' => 1,
+                        'sinclude' => 1,
+                        'm4_pattern_allow' => 1,
                         'AM_CONDITIONAL' => 1,
+                        'AC_CANONICAL_SYSTEM' => 1,
+                        'AM_XGETTEXT_OPTION' => 1,
                         'AC_CONFIG_HEADERS' => 1,
                         'AC_DEFINE_TRACE_LITERAL' => 1,
                         'AM_POT_TOOLS' => 1,
index 2b2cf48..6dcc62d 100644 (file)
@@ -45,6 +45,7 @@ enum imagex_op_type {
        DIR,
        EXPORT,
        INFO,
+       JOIN,
        MOUNT,
        MOUNTRW,
        UNMOUNT,
@@ -91,6 +92,8 @@ static const char *usage_strings[] = {
 "    imagex info WIMFILE [IMAGE_NUM | IMAGE_NAME] [NEW_NAME]\n"
 "        [NEW_DESC] [--boot] [--check] [--header] [--lookup-table]\n"
 "        [--xml] [--extract-xml FILE] [--metadata]\n",
+[JOIN] = 
+"    imagex join [--check] --output WIMFILE SPLIT_WIM...\n",
 [MOUNT] = 
 "    imagex mount WIMFILE (IMAGE_NUM | IMAGE_NAME) DIRECTORY\n"
 "        [--check] [--debug]\n",
@@ -156,6 +159,13 @@ static const struct option info_options[] = {
        {"metadata",     no_argument, NULL, 'm'},
        {NULL, 0, NULL, 0},
 };
+
+static const struct option join_options[] = {
+       {"check", no_argument, NULL, 'c'},
+       {"output", required_argument, NULL, 'o'},
+       {NULL, 0, NULL, 0},
+};
+
 static const struct option mount_options[] = {
        {"check", no_argument, NULL, 'c'},
        {"debug", no_argument, NULL, 'd'},
@@ -556,6 +566,7 @@ static int imagex_dir(int argc, const char **argv)
        int image;
        int ret;
        int num_images;
+       int part_number;
 
        if (argc < 2) {
                imagex_error("Must specify a WIM file!\n");
@@ -569,10 +580,19 @@ static int imagex_dir(int argc, const char **argv)
        }
 
        wimfile = argv[1];
-       ret = wimlib_open_wim(wimfile, 0, &w);
+       ret = wimlib_open_wim(wimfile, WIMLIB_OPEN_FLAG_SPLIT_OK, &w);
        if (ret != 0)
                return ret;
 
+       part_number = wimlib_get_part_number(w, NULL);
+       if (part_number != 1) {
+               imagex_error("`%s' is part %d of a split WIM!  Specify the first part "
+                               "to see the files.\n",
+                               wimfile, part_number);
+               ret = WIMLIB_ERR_SPLIT_UNSUPPORTED;
+               goto done;
+       }
+
        if (argc == 3) {
                image = wimlib_resolve_image(w, argv[2]);
                ret = verify_image_exists(image);
@@ -735,6 +755,10 @@ static int imagex_info(int argc, const char **argv)
        FILE *fp;
        int image;
        int ret;
+       int open_flags = WIMLIB_OPEN_FLAG_SHOW_PROGRESS | 
+                        WIMLIB_OPEN_FLAG_SPLIT_OK;
+       int part_number;
+       int total_parts;
 
        for_opt(c, info_options) {
                switch (c) {
@@ -787,15 +811,22 @@ static int imagex_info(int argc, const char **argv)
                }
        }
 
-       ret = wimlib_open_wim(wimfile, 
-                             check ? 
-                               WIMLIB_OPEN_FLAG_CHECK_INTEGRITY |
-                                       WIMLIB_OPEN_FLAG_SHOW_PROGRESS
-                               : 0, 
-                             &w);
+       if (check)
+               open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
+
+       ret = wimlib_open_wim(wimfile, open_flags, &w);
        if (ret != 0)
                return ret;
 
+       part_number = wimlib_get_part_number(w, &total_parts);
+
+       /*if (total_parts > 1 && part_number > 1) {*/
+               /*printf("Warning: this is part %d of a %d-part split WIM.\n"*/
+                      /*"         Select the first part if you want to see information\n"*/
+                      /*"         about images in the WIM.\n", */
+                      /*part_number, total_parts);*/
+       /*}*/
+
        image = wimlib_resolve_image(w, image_num_or_name);
        if (image == WIM_NO_IMAGE && strcmp(image_num_or_name, "0") != 0) {
                imagex_error("The image `%s' does not exist!\n", 
@@ -842,8 +873,14 @@ static int imagex_info(int argc, const char **argv)
                if (header)
                        wimlib_print_header(w);
 
-               if (lookup_table)
+               if (lookup_table) {
+                       if (total_parts != 1) {
+                               printf("Warning: Only showing the lookup table "
+                                               "for part %d of a %d-part WIM.\n",
+                                               part_number, total_parts);
+                       }
                        wimlib_print_lookup_table(w);
+               }
 
                if (xml) {
                        ret = wimlib_extract_xml_data(w, stdout);
@@ -874,11 +911,21 @@ static int imagex_info(int argc, const char **argv)
                        wimlib_print_available_images(w, image);
 
                if (metadata) {
+                       if (total_parts != 1 && part_number != 1) {
+                               imagex_error("Select part 1 of this %d-part WIM "
+                                               "to see the image metadata.\n",
+                                               total_parts);
+                               return WIMLIB_ERR_SPLIT_UNSUPPORTED;
+                       }
                        ret = wimlib_print_metadata(w, image);
                        if (ret != 0)
                                goto done;
                }
        } else {
+               if (total_parts != 1) {
+                       imagex_error("Modifying a split WIM is not supported.\n");
+                       return -1;
+               }
                if (image == WIM_ALL_IMAGES)
                        image = 1;
 
@@ -950,6 +997,45 @@ done:
        return ret;
 }
 
+/* Join split WIMs into one part WIM */
+static int imagex_join(int argc, const char **argv)
+{
+       int c;
+       int flags = WIMLIB_OPEN_FLAG_SPLIT_OK | WIMLIB_OPEN_FLAG_SHOW_PROGRESS;
+       int image;
+       int ret;
+       const char *output_path = NULL;
+
+       for_opt(c, join_options) {
+               switch (c) {
+               case 'c':
+                       flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
+                       break;
+               case 'o':
+                       output_path = optarg;
+                       break;
+               default:
+                       goto err;
+               }
+       }
+       argc -= optind;
+       argv += optind;
+
+       if (argc < 2) {
+               imagex_error("Must specify at least two split WIM "
+                               "(.swm) parts to join!\n");
+               goto err;
+       }
+       if (!output_path) {
+               imagex_error("Must specify output_path!\n");
+               goto err;
+       }
+       return wimlib_join(argv, argc, output_path, flags);
+err:
+       usage(JOIN);
+       return -1;
+}
+
 /* Mounts an image using a FUSE mount. */
 static int imagex_mount_rw_or_ro(int argc, const char **argv)
 {
@@ -1070,6 +1156,7 @@ static struct imagex_command imagex_commands[] = {
        {"dir",     imagex_dir,            DIR},
        {"export",  imagex_export,         EXPORT},
        {"info",    imagex_info,           INFO},
+       {"join",    imagex_join,           JOIN},
        {"mount",   imagex_mount_rw_or_ro, MOUNT},
        {"mountrw", imagex_mount_rw_or_ro, MOUNTRW},
        {"unmount", imagex_unmount,        UNMOUNT},
index edcd1ea..547892e 100644 (file)
@@ -30,6 +30,7 @@ other_srcs = \
        header.c \
        integrity.c \
        io.h \
+       join.c \
        lookup_table.c \
        lookup_table.h \
        modify.c \
index 575a633..b1bb54c 100644 (file)
@@ -102,7 +102,7 @@ libwim_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
        $(am__DEPENDENCIES_1)
 am__objects_1 = comp.lo decomp.lo huffman.lo lz.lo lzx-common.lo \
        lzx-comp.lo lzx-decomp.lo xpress-comp.lo xpress-decomp.lo
-am__objects_2 = dentry.lo extract.lo header.lo integrity.lo \
+am__objects_2 = dentry.lo extract.lo header.lo integrity.lo join.lo \
        lookup_table.lo modify.lo mount.lo resource.lo sha1.lo util.lo \
        wim.lo write.lo xml.lo
 am_libwim_la_OBJECTS = $(am__objects_1) $(am__objects_2)
@@ -287,6 +287,7 @@ other_srcs = \
        header.c \
        integrity.c \
        io.h \
+       join.c \
        lookup_table.c \
        lookup_table.h \
        modify.c \
@@ -397,6 +398,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/header.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/huffman.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/integrity.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/join.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lookup_table.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lz.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lzx-common.Plo@am__quote@
index 7dd957c..53dc9ec 100644 (file)
@@ -239,11 +239,12 @@ static int extract_single_image(WIMStruct *w, int image)
  * subdirectories named by their image names. */
 static int extract_all_images(WIMStruct *w)
 {
-       size_t image_name_max_len = xml_get_max_image_name_len(w);
+       size_t image_name_max_len = max(xml_get_max_image_name_len(w), 20);
        size_t output_path_len = strlen(w->output_dir);
        char buf[output_path_len + 1 + image_name_max_len + 1];
        int ret;
        int image;
+       const char *image_name;
 
        DEBUG("Attempting to extract all images from `%s'\n", w->filename);
 
@@ -251,8 +252,15 @@ static int extract_all_images(WIMStruct *w)
        buf[output_path_len] = '/';
        for (image = 1; image <= w->hdr.image_count; image++) {
                buf[output_path_len + 1] = '\0';
-               strncat(buf + output_path_len + 1, wimlib_get_image_name(w, image),
+               
+               image_name = wimlib_get_image_name(w, image);
+               if (*image_name) {
+                       strncat(buf + output_path_len + 1, image_name, 
                                image_name_max_len);
+               } else {
+                       /* Image name is empty. Use image number instead */
+                       sprintf(buf + output_path_len + 1, "%d", image);
+               }
                ret = wimlib_set_output_dir(w, buf);
                if (ret != 0)
                        goto done;
index a366930..c7bad0f 100644 (file)
@@ -30,7 +30,7 @@ static const u8 wim_magic_chars[WIM_MAGIC_LEN] = {
                        'M', 'S', 'W', 'I', 'M', '\0', '\0', '\0' };
 
 /* Reads the header for a WIM file.  */
-int read_header(FILE *fp, struct wim_header *hdr)
+int read_header(FILE *fp, struct wim_header *hdr, int split_ok)
 {
        size_t bytes_read;
        u8 buf[WIM_HEADER_DISK_SIZE];
@@ -101,18 +101,20 @@ int read_header(FILE *fp, struct wim_header *hdr)
        }
 
        p = get_bytes(p, WIM_GID_LEN, hdr->guid);
-       p = get_u16(p, &part_number);
-       p = get_u16(p, &total_parts);
-
-       if (part_number != 1 || total_parts != 1) {
-               ERROR("Error: This WIM is part %u of a %u-part WIM.  Wimlib "
-                               "does not support multi-part (split/spanned) "
-                               "WIMs.\n", part_number, total_parts);
-               return WIMLIB_ERR_SPLIT;
+       p = get_u16(p, &hdr->part_number);
+       p = get_u16(p, &hdr->total_parts);
+
+       if (!split_ok && (hdr->part_number != 1 || hdr->total_parts != 1)) {
+               ERROR("This WIM is part %u of a %u-part WIM.\n",
+                       hdr->part_number, hdr->total_parts);
+               return WIMLIB_ERR_SPLIT_UNSUPPORTED;
        }
 
        p = get_u32(p, &hdr->image_count);
 
+       DEBUG("part_number = %u, total_parts = %u, image_count = %u\n",
+                       hdr->part_number, hdr->total_parts, hdr->image_count);
+
        /* Byte 48 */
 
        p = get_resource_entry(p, &hdr->lookup_table_res_entry);
@@ -165,8 +167,8 @@ int write_header(const struct wim_header *hdr, FILE *out)
                                WIM_CHUNK_SIZE : 0);
        randomize_byte_array(p, WIM_GID_LEN);
        p += WIM_GID_LEN;
-       p = put_u16(p, 1);
-       p = put_u16(p, 1);
+       p = put_u16(p, 1); /* part number */
+       p = put_u16(p, 1); /* total parts */
        p = put_u32(p, hdr->image_count);
        p = put_resource_entry(p, &hdr->lookup_table_res_entry);
        p = put_resource_entry(p, &hdr->xml_res_entry);
@@ -207,20 +209,38 @@ int init_header(struct wim_header *hdr, int ctype)
        return 0;
 }
 
+struct hdr_flag {
+       u32 flag;
+       const char *name;
+};
+struct hdr_flag hdr_flags[] = {
+       {WIM_HDR_FLAG_RESERVED,         "RESERVED"},
+       {WIM_HDR_FLAG_COMPRESSION,      "COMPRESSION"},
+       {WIM_HDR_FLAG_READONLY,         "READONLY"},
+       {WIM_HDR_FLAG_SPANNED,          "SPANNED"},
+       {WIM_HDR_FLAG_RESOURCE_ONLY,    "RESOURCE_ONLY"},
+       {WIM_HDR_FLAG_METADATA_ONLY,    "METADATA_ONLY"},
+       {WIM_HDR_FLAG_WRITE_IN_PROGRESS,"WRITE_IN_PROGRESS"},
+       {WIM_HDR_FLAG_RP_FIX,           "RP_FIX"},
+       {WIM_HDR_FLAG_COMPRESS_RESERVED,"COMPRESS_RESERVED"},
+       {WIM_HDR_FLAG_COMPRESS_LZX,     "COMPRESS_LZX"},
+       {WIM_HDR_FLAG_COMPRESS_XPRESS,  "COMPRESS_XPRESS"},
+};
+
 /* Prints information from the header of the WIM file associated with @w. */
 WIMLIBAPI void wimlib_print_header(const WIMStruct *w)
 {
        const struct wim_header *hdr = &w->hdr;
+       uint i;
+
        printf("Magic Characters            = MSWIM\\000\\000\\000\n");
        printf("Header Size                 = %u\n", WIM_HEADER_DISK_SIZE);
        printf("Version                     = 0x%x\n", WIM_VERSION);
-       printf("Flags                       = 0x%x\n", hdr->flags);
-
-       if (hdr->flags & WIM_HDR_FLAG_COMPRESS_XPRESS)
-               printf("    COMPRESS XPRESS FLAG is set\n");
 
-       if (hdr->flags & WIM_HDR_FLAG_COMPRESS_LZX)
-               printf("    COMPRESS LZX FLAG is set\n");
+       printf("Flags                       = 0x%x\n", hdr->flags);
+       for (i = 0; i < ARRAY_LEN(hdr_flags); i++)
+               if (hdr_flags[i].flag & hdr->flags)
+                       printf("    WIM_HDR_FLAG_%s is set\n", hdr_flags[i].name);
 
        printf("Chunk Size                  = %u\n", WIM_CHUNK_SIZE);
        fputs ("GUID                        = ", stdout);
diff --git a/src/join.c b/src/join.c
new file mode 100644 (file)
index 0000000..b804f8f
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * join.c
+ *
+ * Join split WIMs (sometimes named as .swm files) together into one WIM.
+ *
+ * Copyright (C) 2010 Carl Thijssen
+ * Copyright (C) 2012 Eric Biggers
+ *
+ * wimlib - Library for working with WIM files 
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2.1 of the License, or (at your option) any
+ * later version.
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along
+ * with this library; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ */
+
+#include "wimlib.h"
+#include "lookup_table.h"
+#include "xml.h"
+
+static int join_resource(struct lookup_table_entry *lte, void *split_wim)
+{
+       FILE *split_wim_fp = ((WIMStruct*)split_wim)->fp;
+       FILE *joined_wim_fp = ((WIMStruct*)split_wim)->out_fp;
+       int ret;
+
+       u64 size = lte->resource_entry.size;
+       u64 offset = lte->resource_entry.offset;
+       off_t new_offset = ftello(joined_wim_fp);
+
+       if (new_offset == -1)
+               return WIMLIB_ERR_WRITE;
+
+       ret = copy_between_files(split_wim_fp, offset, joined_wim_fp, size);
+       if (ret != 0)
+               return ret;
+
+       memcpy(&lte->output_resource_entry, &lte->resource_entry, 
+                       sizeof(struct resource_entry));
+
+       lte->output_resource_entry.offset = new_offset;
+       lte->out_refcnt = lte->refcnt;
+       lte->part_number = 1;
+       return 0;
+}
+
+static int join_wims(WIMStruct **swms, uint num_swms, WIMStruct *joined_wim,
+                    int write_flags)
+{
+       uint i;
+       int ret;
+       FILE *out_fp = joined_wim->out_fp;
+       u64 total_bytes = wim_info_get_total_bytes(swms[0]->wim_info);
+
+       /* The following loop writes both file resources and metadata resources
+        * because it loops over the lookup table entries rather than the dentry
+        * tree for the images */
+       for (i = 0; i < num_swms; i++) {
+               if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS) {
+                       off_t cur_offset = ftello(out_fp);
+                       printf("Writing resources from part %u of %u "
+                                       "(%"PRIu64" of %"PRIu64" bytes, %.2f%% done)\n",
+                                       i + 1, num_swms,
+                                       cur_offset, total_bytes,
+                                       (double)cur_offset / total_bytes * 100.0);
+               }
+               swms[i]->out_fp = out_fp;
+               ret = for_lookup_table_entry(swms[i]->lookup_table, 
+                                            join_resource, swms[i]);
+               if (ret != 0)
+                       return ret;
+       }
+
+       off_t lookup_table_offset = ftello(out_fp);
+
+       if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS)
+               printf("Writing lookup tables, XML data, and header\n");
+       /* Now write the lookup table for the joined wim.  Since the lookup
+        * table has no header, we can just concatenate the lookup tables of all
+        * the SWM parts. */
+       for (i = 0; i < num_swms; i++) {
+               ret = write_lookup_table(swms[i]->lookup_table, out_fp);
+               if (ret != 0)
+                       return ret;
+       }
+       off_t xml_data_offset = ftello(out_fp);
+
+       if (lookup_table_offset == -1 || xml_data_offset == -1) {
+               ERROR("Failed to get file offset: %m\n");
+               return WIMLIB_ERR_WRITE;
+       }
+       swms[0]->hdr.lookup_table_res_entry.offset = lookup_table_offset;
+       swms[0]->hdr.lookup_table_res_entry.size = 
+                                       xml_data_offset - lookup_table_offset;
+
+       swms[0]->hdr.flags &= ~WIM_HDR_FLAG_SPANNED;
+
+       /* finish_write is called on the first swm, not the joined_wim, because
+        * the first swm is the one that has the image metadata and XML data
+        * attached to it.  */
+       return finish_write(swms[0], WIM_ALL_IMAGES, write_flags, 0);
+}
+
+
+WIMLIBAPI int wimlib_join(const char **swm_names, int num_swms, 
+                         const char *output_path, int flags)
+{
+       int i;
+       int ret;
+       int part_idx;
+       int write_flags = 0;
+       WIMStruct *w;
+       WIMStruct *joined_wim = NULL;
+       WIMStruct *swms[num_swms];
+
+       /* keep track of ctype and guid just to make sure they are the same for
+        * all the WIMs. */
+       int ctype;
+       u8 *guid;
+
+       ZERO_ARRAY(swms);
+       for (i = 0; i < num_swms; i++) {
+               ret = wimlib_open_wim(swm_names[i], 
+                                     flags | WIMLIB_OPEN_FLAG_SPLIT_OK, &w);
+               if (ret != 0)
+                       goto err;
+
+               if (i == 0) {
+                       ctype = wimlib_get_compression_type(w);
+                       guid = w->hdr.guid;
+               } else {
+                       if (wimlib_get_compression_type(w) != ctype) {
+                               ERROR("The split WIMs do not all have the same "
+                                               "compression type!\n");
+                               ret = WIMLIB_ERR_SPLIT_INVALID;
+                               goto err;
+                       }
+                       if (memcmp(guid, w->hdr.guid, WIM_GID_LEN) != 0) {
+                               ERROR("The split WIMs do not all have the "
+                                               "same GUID!\n");
+                               ret = WIMLIB_ERR_SPLIT_INVALID;
+                               goto err;
+                       }
+               }
+               if (w->hdr.total_parts != num_swms) {
+                       ERROR("`%s' (part %d) says there are %d total parts,\n"
+                                       "but %d parts were specified!\n",
+                                       swm_names[i], w->hdr.part_number,
+                                       w->hdr.total_parts, num_swms);
+                       ret = WIMLIB_ERR_SPLIT_INVALID;
+                       goto err;
+               }
+               if (w->hdr.part_number == 0 || w->hdr.part_number > num_swms) {
+                       ERROR("`%s' says it is part %d, but expected a number\n"
+                                       "between 1 and %d!\n",
+                               swm_names[i], w->hdr.part_number, num_swms);
+                       ret = WIMLIB_ERR_SPLIT_INVALID;
+                       goto err;
+               }
+               part_idx = w->hdr.part_number - 1;
+               if (swms[part_idx] != NULL) {
+                       ERROR("`%s' and `%s' both say they are part %d of %d!\n",
+                               swm_names[i], swms[part_idx]->filename,
+                               w->hdr.part_number, num_swms);
+                       ret = WIMLIB_ERR_SPLIT_INVALID;
+                       goto err;
+               }
+               swms[part_idx] = w;
+
+       }
+       joined_wim = new_wim_struct();
+       if (!joined_wim) {
+               ret = WIMLIB_ERR_NOMEM;
+               goto err;
+       }
+
+       if (flags & WIMLIB_OPEN_FLAG_CHECK_INTEGRITY)
+               write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
+       if (flags & WIMLIB_OPEN_FLAG_SHOW_PROGRESS)
+               write_flags |= WIMLIB_WRITE_FLAG_SHOW_PROGRESS;
+
+       ret = begin_write(joined_wim, output_path, write_flags);
+       if (ret != 0)
+               goto err;
+       ret = join_wims(swms, num_swms, joined_wim, write_flags);
+err:
+       for (i = 0; i < num_swms; i++) {
+               /* out_fp is the same in all the swms and joined_wim; only close
+                * it one time, when freeing joined_wim. */
+               swms[i]->out_fp = NULL;
+               wimlib_free(swms[i]);
+       }
+       wimlib_free(joined_wim);
+       return ret;
+}
index 64b8c66..de5eec5 100644 (file)
@@ -147,8 +147,10 @@ static const char *error_strings[] = {
                = "Could not read data from a file",
        [WIMLIB_ERR_RENAME] 
                = "Could not rename a file",
-       [WIMLIB_ERR_SPLIT] 
-               = "The WIM is part of a split WIM, which Wimlib does not support",
+       [WIMLIB_ERR_SPLIT_INVALID] 
+               = "The WIM is part of an invalid split WIM",
+       [WIMLIB_ERR_SPLIT_UNSUPPORTED] 
+               = "The WIM is part of a split WIM, which is not supported for this operation",
        [WIMLIB_ERR_STAT] 
                = "Could not read the metadata for a file or directory",
        [WIMLIB_ERR_TIMEOUT] 
index b8ee8fb..eb33bd3 100644 (file)
--- a/src/wim.c
+++ b/src/wim.c
@@ -43,7 +43,7 @@ static int print_files(WIMStruct *w)
                                  NULL);
 }
 
-static WIMStruct *new_wim_struct()
+WIMStruct *new_wim_struct()
 {
        WIMStruct *w;
        
@@ -228,14 +228,20 @@ int wimlib_select_image(WIMStruct *w, int image)
 
        w->current_image = image;
 
-       if (wim_root_dentry(w))
+       if (wim_root_dentry(w)) {
                return 0;
-       else
+       } else {
+               #ifdef ENABLE_DEBUG
+               DEBUG("Reading metadata resource specified by the following "
+                               "lookup table entry:\n");
+               print_lookup_table_entry(wim_metadata_lookup_table_entry(w), NULL);
+               #endif
                return read_metadata_resource(w->fp, 
                                wim_metadata_resource_entry(w),
                                wimlib_get_compression_type(w), 
                                /*wim_security_data(w), */
                                wim_root_dentry_p(w));
+       }
 }
 
 
@@ -306,7 +312,7 @@ WIMLIBAPI void wimlib_print_wim_information(const WIMStruct *w)
        printf("Image Count:    %d\n", hdr->image_count);
        printf("Compression:    %s\n", wimlib_get_compression_type_string(
                                                wimlib_get_compression_type(w)));
-       printf("Part Number:    %d/%d\n", 1, 1);
+       printf("Part Number:    %d/%d\n", hdr->part_number, hdr->total_parts);
        printf("Boot Index:     %d\n", hdr->boot_idx);
        printf("Size:           %"PRIu64" bytes\n", 
                                wim_info_get_total_bytes(w->wim_info));
@@ -369,6 +375,14 @@ WIMLIBAPI int wimlib_set_boot_idx(WIMStruct *w, int boot_idx)
        return 0;
 }
 
+WIMLIBAPI int wimlib_get_part_number(const WIMStruct *w, int *total_parts_ret)
+{
+       if (total_parts_ret)
+               *total_parts_ret = w->hdr.total_parts;
+       return w->hdr.part_number;
+}
+                                   
+
 WIMLIBAPI int wimlib_get_boot_idx(const WIMStruct *w)
 {
        return w->hdr.boot_idx;
@@ -378,7 +392,7 @@ WIMLIBAPI int wimlib_get_boot_idx(const WIMStruct *w)
  * Begins the reading of a WIM file; opens the file and reads its header and
  * lookup table, and optionally checks the integrity.
  */
-static int wim_begin_read(WIMStruct *w, const char *in_wim_path, int flags)
+static int begin_read(WIMStruct *w, const char *in_wim_path, int flags)
 {
        int ret;
        uint xml_num_images;
@@ -401,7 +415,7 @@ static int wim_begin_read(WIMStruct *w, const char *in_wim_path, int flags)
                goto done;
        }
 
-       ret = read_header(w->fp, &w->hdr);
+       ret = read_header(w->fp, &w->hdr, flags & WIMLIB_OPEN_FLAG_SPLIT_OK);
        if (ret != 0)
                goto done;
 
@@ -432,8 +446,8 @@ static int wim_begin_read(WIMStruct *w, const char *in_wim_path, int flags)
                        goto done;
                }
                if (integrity_status == WIM_INTEGRITY_NONEXISTENT) {
-                       WARNING("No integrity information; skipping "
-                                       "integrity check.\n");
+                       WARNING("No integrity information for `%s'; skipping "
+                                       "integrity check.\n", w->filename);
                } else if (integrity_status == WIM_INTEGRITY_NOT_OK) {
                        ERROR("WIM is not intact! (Failed integrity check)\n");
                        ret = WIMLIB_ERR_INTEGRITY;
@@ -471,27 +485,28 @@ static int wim_begin_read(WIMStruct *w, const char *in_wim_path, int flags)
        ret = for_lookup_table_entry(w->lookup_table, 
                                     append_metadata_resource_entry, w);
 
-       if (ret != 0)
+       if (ret != 0 && w->hdr.part_number == 1)
                goto done;
 
        /* Make sure all the expected images were found.  (We already have
         * returned false if *extra* images were found) */
-       if (w->current_image != w->hdr.image_count) {
+       if (w->current_image != w->hdr.image_count && w->hdr.part_number == 1) {
                ERROR("Only found %u images in WIM, but expected %u!\n",
                                w->current_image, w->hdr.image_count);
                ret = WIMLIB_ERR_IMAGE_COUNT;
                goto done;
        }
 
-       w->current_image = WIM_NO_IMAGE;
 
        /* Sort images by the position of their metadata resources.  I'm
         * assuming that is what determines the other of the images in the WIM
         * file, rather than their order in the lookup table, which may be
         * random because of hashing. */
-       qsort(w->image_metadata, w->hdr.image_count, 
+       qsort(w->image_metadata, w->current_image,
              sizeof(struct image_metadata), sort_image_metadata_by_position);
 
+       w->current_image = WIM_NO_IMAGE;
+
        /* Read the XML data. */
        ret = read_xml_data(w->fp, &w->hdr.xml_res_entry, 
                            &w->xml_data, &w->wim_info);
@@ -534,7 +549,7 @@ WIMLIBAPI int wimlib_open_wim(const char *wim_file, int flags,
        if (!w)
                return WIMLIB_ERR_NOMEM;
 
-       ret = wim_begin_read(w, wim_file, flags);
+       ret = begin_read(w, wim_file, flags);
        if (ret != 0) {
                ERROR("Could not begin reading the WIM file `%s'\n", wim_file);
                FREE(w);
@@ -544,15 +559,6 @@ WIMLIBAPI int wimlib_open_wim(const char *wim_file, int flags,
        return 0;
 }
 
-/**
- * Frees internal memory allocated by WIMLIB for a WIM file, and closes it if it
- * is still open.
- */
-void wimlib_destroy(WIMStruct *w)
-{
-
-}
-
 /* Frees the memory for the WIMStruct, including all internal memory; also
  * closes all files associated with the WIMStruct.  */
 WIMLIBAPI void wimlib_free(WIMStruct *w)
index 2400047..c284dbc 100644 (file)
@@ -264,6 +264,12 @@ enum wim_compression_type {
 /** Print progress information when verifying integrity table. */
 #define WIMLIB_OPEN_FLAG_SHOW_PROGRESS         0x2
 
+/** If this flag is not given, an error is issued if the WIM is part of a split
+ * WIM.  Giving this flag makes the function allows split WIMS to be opened, but
+ * beware: wimlib has little support for split WIMs and only certain functions
+ * will work on them. */
+#define WIMLIB_OPEN_FLAG_SPLIT_OK              0x4
+
 /**
  * Possible values of the error code returned by many functions in wimlib.
  *
@@ -300,7 +306,8 @@ enum wimlib_error_code {
        WIMLIB_ERR_OPENDIR,
        WIMLIB_ERR_READ,
        WIMLIB_ERR_RENAME,
-       WIMLIB_ERR_SPLIT,
+       WIMLIB_ERR_SPLIT_INVALID,
+       WIMLIB_ERR_SPLIT_UNSUPPORTED,
        WIMLIB_ERR_STAT,
        WIMLIB_ERR_TIMEOUT,
        WIMLIB_ERR_UNKNOWN_VERSION,
@@ -640,6 +647,20 @@ extern const char *wimlib_get_image_name(const WIMStruct *wim, int image);
 extern int wimlib_get_num_images(const WIMStruct *wim);
 
 /**
+ * Gets the part number of the wim (in a split WIM).
+ *
+ * @param wim
+ *     Pointer to the ::WIMStruct for a WIM file.
+ * @param total_parts_ret
+ *     If non-@c NULL, the total number of parts in the split WIM (1 for
+ *     non-split WIMs) is written to this location.
+ *
+ * @return 
+ *     The part number of the WIM (1 for non-split WIMs)
+ */
+extern int wimlib_get_part_number(const WIMStruct *wim, int *total_parts_ret);
+
+/**
  * Returns true if the WIM has an integrity table.
  *
  * @param wim
@@ -647,7 +668,7 @@ extern int wimlib_get_num_images(const WIMStruct *wim);
  * @return
  *     @c true if the WIM has an integrity table; false otherwise.
  */
-bool wimlib_has_integrity_table(const WIMStruct *wim);
+extern bool wimlib_has_integrity_table(const WIMStruct *wim);
 
 
 /**
@@ -665,6 +686,25 @@ bool wimlib_has_integrity_table(const WIMStruct *wim);
 extern bool wimlib_image_name_in_use(const WIMStruct *wim, const char *name);
 
 /**
+ * Joins a set of split WIMs into a one-part WIM.
+ *
+ * @param swms
+ *     An array of strings that give the filenames of all parts of the split
+ *     WIM.
+ * @param num_swms
+ *     Number of filenames in @a swms.
+ * @param output_path
+ *     The path to write the one-part WIM to.
+ * @param flags
+ *     ::WIMLIB_OPEN_FLAG_CHECK_INTEGRITY to check the split WIMs' integrity
+ *     tables (if present) when opening them, and include an integrity table in
+ *     the output WIM.
+ * @return 0 on success; nonzero on error.
+ */
+extern int wimlib_join(const char **swms, int num_swms,
+                      const char *output_path, int flags);
+
+/**
  * Mounts an image in a WIM file on a directory read-only or read-write.
  *
  * A daemon will be forked to service the filesystem.
@@ -730,6 +770,8 @@ extern int wimlib_mount(WIMStruct *wim, int image, const char *dir, int flags);
  *     digests given in the integrity table.
  *     If ::WIMLIB_OPEN_FLAG_SHOW_PROGRESS is given, progress information will
  *     be shown if the integrity of the WIM is checked.
+ *     If ::WIMLIB_OPEN_FLAG_SPLIT_OK is given, no error will be issued if the
+ *     WIM is part of a split WIM.
  *
  * @param wim_ret
  *     On success, a pointer to an opaque ::WIMStruct for the opened WIM file
@@ -773,8 +815,8 @@ extern int wimlib_mount(WIMStruct *wim, int image, const char *dir, int flags);
  *     An unexpected end-of-file or read error occurred when trying to read
  *     data from @a wim_file.
  * @retval ::WIMLIB_ERR_SPLIT
- *     @a wim_file is a split WIM. wimlib does not support this kind of
- *     WIM.
+ *     @a wim_file is a split WIM, but ::WIMLIB_OPEN_FLAG_SPLIT_OK was not
+ *     givin in @a flags.
  * @retval ::WIMLIB_ERR_UNKNOWN_VERSION
  *     A number other than 0x10d00 is written in the version field of the WIM
  *     header of @a wim_file.
index e9a1079..269f0a5 100644 (file)
@@ -52,13 +52,6 @@ enum wim_integrity_status {
        WIM_INTEGRITY_NONEXISTENT,
 };
 
-
-#define RINOK(expr) do { \
-       int __ret = (expr); \
-       if (__ret != 0) \
-               return __ret; \
-} while (0) 
-
 /* Metadata for a resource in a WIM file. */
 struct resource_entry {
        /* Size, in bytes, of the resource in the WIM file. */
@@ -117,10 +110,10 @@ struct wim_header {
        u8  guid[WIM_GID_LEN];
 
        /* Part number of the WIM file in a spanned set. */
-       //u16 part_number;
+       u16 part_number;
 
        /* Total number of parts in a spanned set. */
-       //u16 total_parts;
+       u16 total_parts;
 
        /* Number of images in the WIM file. */
        u32 image_count;
@@ -327,7 +320,7 @@ static inline void print_hash(const u8 hash[])
 
 
 /* header.c */
-extern int read_header(FILE *fp, struct wim_header *hdr);
+extern int read_header(FILE *fp, struct wim_header *hdr, int split_ok);
 extern int write_header(const struct wim_header *hdr, FILE *out);
 extern int init_header(struct wim_header *hdr, int ctype);
 
@@ -388,18 +381,24 @@ void destroy_security_data(WIMSecurityData *sd);
 #endif
 
 /* wim.c */
+extern WIMStruct *new_wim_struct();
 extern int wimlib_select_image(WIMStruct *w, int image);
-extern void wimlib_destroy(WIMStruct *w);
 extern int wim_hdr_flags_compression_type(int wim_hdr_flags);
 extern int wim_resource_compression_type(const WIMStruct *w, 
                                         const struct resource_entry *entry);
 extern int for_image(WIMStruct *w, int image, int (*visitor)(WIMStruct *));
 
 /* write.c */
+extern int finish_write(WIMStruct *w, int image, int flags, 
+                       int write_lookup_table);
+extern int copy_between_files(FILE *in, off_t in_offset, FILE *out, size_t len);
 extern int write_resource_from_memory(const u8 resource[], int out_ctype,
                                      u64 resource_original_size, FILE *out,
                                      u64 *resource_size_ret);
 
+extern int begin_write(WIMStruct *w, const char *path, int flags);
+extern int write_metadata_resource(WIMStruct *w);
+
 
 #include "wimlib.h"
 
index 94e4fc9..6b67498 100644 (file)
@@ -43,7 +43,7 @@
  * Copies @len bytes from @in to @out, at the current position in @out, and at
  * an offset of @in_offset in @in.
  */
-static int copy_between_files(FILE *in, off_t in_offset, FILE *out, size_t len)
+int copy_between_files(FILE *in, off_t in_offset, FILE *out, size_t len)
 {
        u8 buf[BUFFER_SIZE];
        size_t n;
@@ -688,7 +688,7 @@ err:
 }
 
 /* Write the metadata resource for the current image. */
-static int write_metadata_resource(WIMStruct *w)
+int write_metadata_resource(WIMStruct *w)
 {
        FILE *out;
        u8 *buf;
@@ -775,8 +775,11 @@ static int write_file_resources(WIMStruct *w)
        return for_dentry_in_tree(wim_root_dentry(w), write_file_resource, w);
 }
 
-/* Write lookup table, xml data, lookup table, and rewrite header */
-static int finish_write(WIMStruct *w, int image, FILE *out, int flags)
+/* Write lookup table, xml data, lookup table, and rewrite header 
+ *
+ * write_lt is zero iff the lookup table is not to be written; i.e. it is
+ * handled elsewhere. */
+int finish_write(WIMStruct *w, int image, int flags, int write_lt)
 {
        off_t lookup_table_offset;
        off_t xml_data_offset;
@@ -788,16 +791,19 @@ static int finish_write(WIMStruct *w, int image, FILE *out, int flags)
        int ret;
        int i;
        struct wim_header hdr;
+       FILE *out = w->out_fp;
 
-       lookup_table_offset = ftello(out);
-       if (lookup_table_offset == -1)
-               return WIMLIB_ERR_WRITE;
+       if (write_lt) {
+               lookup_table_offset = ftello(out);
+               if (lookup_table_offset == -1)
+                       return WIMLIB_ERR_WRITE;
 
-       DEBUG("Writing lookup table.\n");
-       /* Write the lookup table. */
-       ret = write_lookup_table(w->lookup_table, out);
-       if (ret != 0)
-               return ret;
+               DEBUG("Writing lookup table.\n");
+               /* Write the lookup table. */
+               ret = write_lookup_table(w->lookup_table, out);
+               if (ret != 0)
+                       return ret;
+       }
 
        DEBUG("Writing XML data.\n");
 
@@ -810,10 +816,12 @@ static int finish_write(WIMStruct *w, int image, FILE *out, int flags)
         * have changed, including the resource entries, boot index, and image
         * count.  */
        memcpy(&hdr, &w->hdr, sizeof(struct wim_header));
-       lookup_table_size = xml_data_offset - lookup_table_offset;
-       hdr.lookup_table_res_entry.offset        = lookup_table_offset;
-       hdr.lookup_table_res_entry.size          = lookup_table_size;
-       hdr.lookup_table_res_entry.original_size = lookup_table_size;
+       if (write_lt) {
+               lookup_table_size = xml_data_offset - lookup_table_offset;
+               hdr.lookup_table_res_entry.offset        = lookup_table_offset;
+               hdr.lookup_table_res_entry.size          = lookup_table_size;
+       }
+       hdr.lookup_table_res_entry.original_size = hdr.lookup_table_res_entry.size;
        hdr.lookup_table_res_entry.flags         = WIM_RESHDR_FLAG_METADATA;
 
        ret = write_xml_data(w->wim_info, image, out);
@@ -887,21 +895,11 @@ static int finish_write(WIMStruct *w, int image, FILE *out, int flags)
        return write_header(&hdr, out);
 }
 
-/* Writes the WIM to a file.  */
-WIMLIBAPI int wimlib_write(WIMStruct *w, const char *path, int image, int flags)
+/* Open file stream and write dummy header for WIM. */
+int begin_write(WIMStruct *w, const char *path, int flags)
 {
-       int ret;
        const char *mode;
-       FILE *out;
-
-       if (image != WIM_ALL_IMAGES && 
-                       (image < 1 || image > w->hdr.image_count))
-               return WIMLIB_ERR_INVALID_IMAGE;
-
-       if (image == WIM_ALL_IMAGES)
-               DEBUG("Writing all images to `%s'\n", path);
-       else
-               DEBUG("Writing image %d to `%s'\n", image, path);
+       DEBUG("Opening `%s' for new WIM\n", path);
 
        /* checking the integrity requires going back over the file to read it.
         * XXX 
@@ -912,17 +910,31 @@ WIMLIBAPI int wimlib_write(WIMStruct *w, const char *path, int image, int flags)
        else
                mode = "wb";
 
-       out = fopen(path, mode);
-       if (!out) {
-               ERROR("Failed to open the file `%s' for writing!\n", 
-                               path);
+       w->out_fp = fopen(path, mode);
+       if (!w->out_fp) {
+               ERROR("Failed to open the file `%s' for writing!\n", path);
                return WIMLIB_ERR_OPEN;
        }
 
-       w->out_fp = out;
-
        /* Write dummy header. It will be overwritten later. */
-       ret = write_header(&w->hdr, out);
+       return write_header(&w->hdr, w->out_fp);
+}
+
+/* Writes the WIM to a file.  */
+WIMLIBAPI int wimlib_write(WIMStruct *w, const char *path, int image, int flags)
+{
+       int ret;
+
+       if (image != WIM_ALL_IMAGES && 
+                       (image < 1 || image > w->hdr.image_count))
+               return WIMLIB_ERR_INVALID_IMAGE;
+
+       if (image == WIM_ALL_IMAGES)
+               DEBUG("Writing all images to `%s'\n", path);
+       else
+               DEBUG("Writing image %d to `%s'\n", image, path);
+
+       ret = begin_write(w, path, flags);
        if (ret != 0)
                goto done;
 
@@ -941,14 +953,16 @@ WIMLIBAPI int wimlib_write(WIMStruct *w, const char *path, int image, int flags)
                goto done;
        }
 
-       ret = finish_write(w, image, out, flags);
+       ret = finish_write(w, image, flags, 1);
 
 done:
        DEBUG("Closing output file.\n");
-       w->out_fp = NULL;
-       if (fclose(out) != 0) {
-               ERROR("Failed to close the file `%s': %m\n", path);
-               ret = WIMLIB_ERR_WRITE;
+       if (w->out_fp != NULL) {
+               if (fclose(w->out_fp) != 0) {
+                       ERROR("Failed to close the file `%s': %m\n", path);
+                       ret = WIMLIB_ERR_WRITE;
+               }
+               w->out_fp = NULL;
        }
        return ret;
 }
index 03b0b70..ee75e17 100644 (file)
--- a/src/xml.c
+++ b/src/xml.c
@@ -1040,7 +1040,6 @@ void print_image_info(const struct wim_info *wim_info, int image)
        time_t ctime;
        time_t mtime;
 
-       DEBUG("Printing the image info for image %d\n", image);
 
        if (image == WIM_ALL_IMAGES) {
                for (i = 1; i <= wim_info->num_images; i++)