'_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,
DIR,
EXPORT,
INFO,
+ JOIN,
MOUNT,
MOUNTRW,
UNMOUNT,
" 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",
{"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'},
int image;
int ret;
int num_images;
+ int part_number;
if (argc < 2) {
imagex_error("Must specify a WIM file!\n");
}
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);
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) {
}
}
- 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",
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);
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;
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)
{
{"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},
header.c \
integrity.c \
io.h \
+ join.c \
lookup_table.c \
lookup_table.h \
modify.c \
$(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)
header.c \
integrity.c \
io.h \
+ join.c \
lookup_table.c \
lookup_table.h \
modify.c \
@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@
* 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);
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;
'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];
}
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);
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);
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);
--- /dev/null
+/*
+ * 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;
+}
= "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]
NULL);
}
-static WIMStruct *new_wim_struct()
+WIMStruct *new_wim_struct()
{
WIMStruct *w;
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));
+ }
}
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));
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;
* 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;
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;
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;
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);
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);
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)
/** 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.
*
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,
*/
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.
*
* @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);
/**
*/
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.
*
* 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
* 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.
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. */
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;
/* 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);
#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"
* 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;
}
/* 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;
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;
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");
* 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);
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
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;
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;
}
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++)