From 1449ca7e974c27bec75cb6784873be3c0e6eb78a Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 19 May 2012 12:28:05 -0500 Subject: [PATCH] Support for joining WIMs. - 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 --- autom4te.cache/requests | 120 ++++++++++++------------ programs/imagex.c | 103 ++++++++++++++++++-- src/Makefile.am | 1 + src/Makefile.in | 4 +- src/extract.c | 12 ++- src/header.c | 54 +++++++---- src/join.c | 203 ++++++++++++++++++++++++++++++++++++++++ src/util.c | 6 +- src/wim.c | 50 +++++----- src/wimlib.h | 50 +++++++++- src/wimlib_internal.h | 21 ++--- src/write.c | 96 +++++++++++-------- src/xml.c | 1 - 13 files changed, 552 insertions(+), 169 deletions(-) create mode 100644 src/join.c diff --git a/autom4te.cache/requests b/autom4te.cache/requests index 38a2931f..4324d28c 100644 --- a/autom4te.cache/requests +++ b/autom4te.cache/requests @@ -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, @@ -77,20 +77,20 @@ '_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, @@ -111,47 +111,47 @@ '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, @@ -174,37 +174,37 @@ '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, @@ -213,28 +213,28 @@ '_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, @@ -254,57 +254,57 @@ '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, diff --git a/programs/imagex.c b/programs/imagex.c index 2b2cf48d..6dcc62d3 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -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}, diff --git a/src/Makefile.am b/src/Makefile.am index edcd1eab..547892e2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -30,6 +30,7 @@ other_srcs = \ header.c \ integrity.c \ io.h \ + join.c \ lookup_table.c \ lookup_table.h \ modify.c \ diff --git a/src/Makefile.in b/src/Makefile.in index 575a633e..b1bb54c9 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -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@ diff --git a/src/extract.c b/src/extract.c index 7dd957cc..53dc9ec2 100644 --- a/src/extract.c +++ b/src/extract.c @@ -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; diff --git a/src/header.c b/src/header.c index a3669309..c7bad0f2 100644 --- a/src/header.c +++ b/src/header.c @@ -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 index 00000000..b804f8f8 --- /dev/null +++ b/src/join.c @@ -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(<e->output_resource_entry, <e->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; +} diff --git a/src/util.c b/src/util.c index 64b8c667..de5eec5b 100644 --- a/src/util.c +++ b/src/util.c @@ -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] diff --git a/src/wim.c b/src/wim.c index b8ee8fb8..eb33bd39 100644 --- 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) diff --git a/src/wimlib.h b/src/wimlib.h index 24000473..c284dbc3 100644 --- a/src/wimlib.h +++ b/src/wimlib.h @@ -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, @@ -639,6 +646,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. * @@ -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); /** @@ -664,6 +685,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. * @@ -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. diff --git a/src/wimlib_internal.h b/src/wimlib_internal.h index e9a10798..269f0a5b 100644 --- a/src/wimlib_internal.h +++ b/src/wimlib_internal.h @@ -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" diff --git a/src/write.c b/src/write.c index 94e4fc9f..6b674980 100644 --- a/src/write.c +++ b/src/write.c @@ -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; } diff --git a/src/xml.c b/src/xml.c index 03b0b700..ee75e175 100644 --- 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++) -- 2.43.0