From: Eric Biggers Date: Fri, 31 Aug 2012 22:31:56 +0000 (-0500) Subject: split WIM apply, doc updates X-Git-Tag: v1.0.0~24 X-Git-Url: https://wimlib.net/git/?p=wimlib;a=commitdiff_plain;h=35dd893208119869db6a90b1d1663f9aea88a3f7 split WIM apply, doc updates --- diff --git a/programs/imagex.c b/programs/imagex.c index 5c5d42bc..12bfbc62 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -134,6 +135,7 @@ static const struct option apply_options[] = { {"hardlink", no_argument, NULL, 'h'}, {"symlink", no_argument, NULL, 's'}, {"verbose", no_argument, NULL, 'v'}, + {"ref", required_argument, NULL, 'r'}, {NULL, 0, NULL, 0}, }; static const struct option capture_options[] = { @@ -444,7 +446,8 @@ out: static int imagex_apply(int argc, const char **argv) { int c; - int open_flags = WIMLIB_OPEN_FLAG_SHOW_PROGRESS; + int open_flags = WIMLIB_OPEN_FLAG_SHOW_PROGRESS | + WIMLIB_OPEN_FLAG_SPLIT_OK; int image; int num_images; WIMStruct *w; @@ -454,6 +457,11 @@ static int imagex_apply(int argc, const char **argv) const char *image_num_or_name; int extract_flags = 0; + const char *swm_glob = NULL; + WIMStruct **additional_swms = NULL; + size_t num_additional_swms = 0; + glob_t globbuf; + for_opt(c, apply_options) { switch (c) { case 'c': @@ -468,6 +476,9 @@ static int imagex_apply(int argc, const char **argv) case 'v': extract_flags |= WIMLIB_EXTRACT_FLAG_VERBOSE; break; + case 'r': + swm_glob = optarg; + break; default: usage(APPLY); return -1; @@ -491,7 +502,7 @@ static int imagex_apply(int argc, const char **argv) ret = wimlib_open_wim(wimfile, open_flags, &w); if (ret != 0) - goto out; + return ret; image = wimlib_resolve_image(w, image_num_or_name); ret = verify_image_exists(image); @@ -507,6 +518,36 @@ static int imagex_apply(int argc, const char **argv) goto out; } + if (swm_glob) { + ret = glob(swm_glob, GLOB_ERR | GLOB_NOSORT, NULL, &globbuf); + if (ret != 0) { + imagex_error_with_errno("Failed to process glob " + "\"%s\"", swm_glob); + ret = -1; + goto out; + } + num_additional_swms = globbuf.gl_pathc; + additional_swms = calloc(num_additional_swms, sizeof(additional_swms[0])); + if (!additional_swms) { + imagex_error("Out of memory"); + ret = -1; + goto out; + } + size_t offset = 0; + for (size_t i = 0; i < num_additional_swms; i++) { + if (strcmp(globbuf.gl_pathv[i], wimfile) == 0) { + offset++; + continue; + } + ret = wimlib_open_wim(globbuf.gl_pathv[i], + open_flags | WIMLIB_OPEN_FLAG_SPLIT_OK, + &additional_swms[i - offset]); + if (ret != 0) + goto out; + } + num_additional_swms -= offset; + } + #ifdef WITH_NTFS_3G struct stat stbuf; @@ -518,7 +559,9 @@ static int imagex_apply(int argc, const char **argv) image, wimfile, ntfs_device); ret = wimlib_apply_image_to_ntfs_volume(w, image, ntfs_device, - extract_flags); + extract_flags, + additional_swms, + num_additional_swms); goto out; } } else { @@ -527,9 +570,13 @@ static int imagex_apply(int argc, const char **argv) } #endif - ret = wimlib_extract_image(w, image, dir, extract_flags); + ret = wimlib_extract_image(w, image, dir, extract_flags, + additional_swms, num_additional_swms); out: wimlib_free(w); + if (additional_swms) + for (size_t i = 0; i < num_additional_swms; i++) + wimlib_free(additional_swms[i]); return ret; } diff --git a/src/extract.c b/src/extract.c index 1d755cff..e42aba4d 100644 --- a/src/extract.c +++ b/src/extract.c @@ -393,25 +393,54 @@ static int extract_all_images(WIMStruct *w, const char *output_dir, return 0; } + /* Extracts a single image or all images from a WIM file. */ WIMLIBAPI int wimlib_extract_image(WIMStruct *w, int image, - const char *output_dir, int flags) + const char *output_dir, int flags, + WIMStruct **additional_swms, + unsigned num_additional_swms) { - if (!output_dir) + struct lookup_table *joined_tab, *w_tab_save; + int ret; + + DEBUG("w->filename = %s, image = %d, output_dir = %s, flags = 0x%x, " + "num_additional_swms = %u", + w->filename, image, output_dir, flags, num_additional_swms); + + if (!w || !output_dir) return WIMLIB_ERR_INVALID_PARAM; if ((flags & (WIMLIB_EXTRACT_FLAG_SYMLINK | WIMLIB_EXTRACT_FLAG_HARDLINK)) == (WIMLIB_EXTRACT_FLAG_SYMLINK | WIMLIB_EXTRACT_FLAG_HARDLINK)) return WIMLIB_ERR_INVALID_PARAM; + ret = verify_swm_set(w, additional_swms, num_additional_swms); + if (ret != 0) + return ret; + + if (num_additional_swms) { + ret = new_joined_lookup_table(w, additional_swms, + num_additional_swms, &joined_tab); + if (ret != 0) + return ret; + w_tab_save = w->lookup_table; + w->lookup_table = joined_tab; + } + + for_lookup_table_entry(w->lookup_table, zero_out_refcnts, NULL); if (image == WIM_ALL_IMAGES) { flags |= WIMLIB_EXTRACT_FLAG_MULTI_IMAGE; - return extract_all_images(w, output_dir, flags); + ret = extract_all_images(w, output_dir, flags); } else { flags &= ~WIMLIB_EXTRACT_FLAG_MULTI_IMAGE; - return extract_single_image(w, image, output_dir, flags); + ret = extract_single_image(w, image, output_dir, flags); + } + if (num_additional_swms) { + free_lookup_table(w->lookup_table); + w->lookup_table = w_tab_save; } + return ret; } diff --git a/src/join.c b/src/join.c index 1d895cf8..3710eec8 100644 --- a/src/join.c +++ b/src/join.c @@ -26,6 +26,145 @@ #include "wimlib_internal.h" #include "lookup_table.h" #include "xml.h" +#include + +static int copy_lte_to_table(struct lookup_table_entry *lte, void *table) +{ + struct lookup_table_entry *copy; + copy = new_lookup_table_entry(); + if (!copy) + return WIMLIB_ERR_NOMEM; + memcpy(copy, lte, sizeof(struct lookup_table_entry)); + lookup_table_insert(table, copy); + return 0; +} + +static int lookup_table_join(struct lookup_table *table, + struct lookup_table *new) +{ + return for_lookup_table_entry(new, copy_lte_to_table, table); +} + + +static int cmp_swms_by_part_number(const void *swm1, const void *swm2) +{ + u16 partno_1 = (*(WIMStruct**)swm1)->hdr.part_number; + u16 partno_2 = (*(WIMStruct**)swm2)->hdr.part_number; + return (int)partno_1 - (int)partno_2; +} + +int verify_swm_set(WIMStruct *w, WIMStruct **additional_swms, + unsigned num_additional_swms) +{ + unsigned total_parts = w->hdr.total_parts; + int ctype; + const u8 *guid; + + if (total_parts != num_additional_swms + 1) { + ERROR("`%s' says there are %u parts in the spanned set, " + "but %s%u part%s provided", + w->filename, w->hdr.total_parts, + (num_additional_swms + 1 < w->hdr.total_parts) ? "only " : "", + num_additional_swms + 1, + (num_additional_swms) ? "s were" : " was"); + return WIMLIB_ERR_SPLIT_INVALID; + } + if (w->hdr.part_number != 1) { + ERROR("WIM `%s' is not the first part of the split WIM.", + w->filename); + return WIMLIB_ERR_SPLIT_INVALID; + } + for (unsigned i = 0; i < num_additional_swms; i++) { + if (additional_swms[i]->hdr.total_parts != total_parts) { + ERROR("WIM `%s' says there are %u parts in the spanned set, " + "but %u parts were provided", + additional_swms[i]->filename, + additional_swms[i]->hdr.total_parts, + total_parts); + return WIMLIB_ERR_SPLIT_INVALID; + } + } + + /* keep track of ctype and guid just to make sure they are the same for + * all the WIMs. */ + ctype = wimlib_get_compression_type(w); + guid = w->hdr.guid; + + WIMStruct *parts_to_swms[num_additional_swms]; + ZERO_ARRAY(parts_to_swms); + for (unsigned i = 0; i < num_additional_swms; i++) { + + WIMStruct *swm = additional_swms[i]; + + if (wimlib_get_compression_type(swm) != ctype) { + ERROR("The split WIMs do not all have the same " + "compression type"); + return WIMLIB_ERR_SPLIT_INVALID; + } + if (memcmp(guid, swm->hdr.guid, WIM_GID_LEN) != 0) { + ERROR("The split WIMs do not all have the same " + "GUID"); + return WIMLIB_ERR_SPLIT_INVALID; + } + if (swm->hdr.part_number == 1) { + ERROR("WIMs `%s' and `%s' both are marked as the " + "first WIM in the spanned set", + w->filename, swm->filename); + return WIMLIB_ERR_SPLIT_INVALID; + } + if (swm->hdr.part_number == 0 || + swm->hdr.part_number > total_parts) + { + ERROR("WIM `%s' says it is part %u in the spanned set, " + "but the part number must be in the range " + "[1, %u]", + swm->filename, swm->hdr.part_number, total_parts); + return WIMLIB_ERR_SPLIT_INVALID; + } + if (parts_to_swms[swm->hdr.part_number - 2]) + { + ERROR("`%s' and `%s' are both marked as part %u of %u " + "in the spanned set", + parts_to_swms[swm->hdr.part_number - 2]->filename, + swm->filename, + swm->hdr.part_number, + total_parts); + return WIMLIB_ERR_SPLIT_INVALID; + } else { + parts_to_swms[swm->hdr.part_number - 2] = swm; + } + } + return 0; +} + +int new_joined_lookup_table(WIMStruct *w, + WIMStruct **additional_swms, + unsigned num_additional_swms, + struct lookup_table **table_ret) +{ + struct lookup_table *table; + int ret; + unsigned i; + + + table = new_lookup_table(9001); + if (!table) + return WIMLIB_ERR_NOMEM; + ret = lookup_table_join(table, w->lookup_table); + if (ret != 0) + goto out_free_table; + for (i = 0; i < num_additional_swms; i++) { + ret = lookup_table_join(table, additional_swms[i]->lookup_table); + if (ret != 0) + goto out_free_table; + } + *table_ret = table; + return 0; +out_free_table: + free_lookup_table(table); + return ret; +} + static int join_wims(WIMStruct **swms, uint num_swms, WIMStruct *joined_wim, int write_flags) @@ -105,81 +244,46 @@ static int join_wims(WIMStruct **swms, uint num_swms, WIMStruct *joined_wim, } -WIMLIBAPI int wimlib_join(const char **swm_names, int num_swms, +WIMLIBAPI int wimlib_join(const char **swm_names, unsigned 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; + if (num_swms < 1) + return WIMLIB_ERR_INVALID_PARAM; + ZERO_ARRAY(swms); + for (i = 0; i < num_swms; i++) { ret = wimlib_open_wim(swm_names[i], - flags | WIMLIB_OPEN_FLAG_SPLIT_OK, &w); + flags | WIMLIB_OPEN_FLAG_SPLIT_OK, &swms[i]); if (ret != 0) - goto err; + goto out; /* don't open all the parts at the same time, in case there are * a lot of them */ - fclose(w->fp); - w->fp = NULL; + fclose(swms[i]->fp); + swms[i]->fp = NULL; + } - 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"); - 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"); - ret = WIMLIB_ERR_SPLIT_INVALID; - goto err; - } - } - if (w->hdr.total_parts != num_swms) { - ERROR("`%s' (part %d) says there are %d total parts, " - "but %d parts were specified", - 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 " - "between 1 and %d", - 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", - swm_names[i], swms[part_idx]->filename, - w->hdr.part_number, num_swms); - ret = WIMLIB_ERR_SPLIT_INVALID; - goto err; - } - swms[part_idx] = w; + qsort(swms, num_swms, sizeof(swms[0]), cmp_swms_by_part_number); + + ret = verify_swm_set(swms[0], &swms[1], num_swms - 1); + if (ret != 0) + goto out; - } joined_wim = new_wim_struct(); if (!joined_wim) { ret = WIMLIB_ERR_NOMEM; - goto err; + goto out; } if (flags & WIMLIB_OPEN_FLAG_CHECK_INTEGRITY) @@ -189,9 +293,9 @@ WIMLIBAPI int wimlib_join(const char **swm_names, int num_swms, ret = begin_write(joined_wim, output_path, write_flags); if (ret != 0) - goto err; + goto out; ret = join_wims(swms, num_swms, joined_wim, write_flags); -err: +out: 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. */ diff --git a/src/lookup_table.c b/src/lookup_table.c index c1dca74f..5408baf6 100644 --- a/src/lookup_table.c +++ b/src/lookup_table.c @@ -113,7 +113,7 @@ static int do_free_lookup_table_entry(struct lookup_table_entry *entry, void free_lookup_table(struct lookup_table *table) { - DEBUG("Freeing lookup table"); + DEBUG2("Freeing lookup table"); if (table) { if (table->array) { for_lookup_table_entry(table, @@ -200,6 +200,7 @@ int read_lookup_table(WIMStruct *w) u8 buf[WIM_LOOKUP_TABLE_ENTRY_DISK_SIZE]; int ret; struct lookup_table *table; + struct lookup_table_entry *cur_entry = NULL, *duplicate_entry; DEBUG("Reading lookup table: offset %"PRIu64", size %"PRIu64"", w->hdr.lookup_table_res_entry.offset, @@ -220,7 +221,6 @@ int read_lookup_table(WIMStruct *w) while (num_entries--) { const u8 *p; - struct lookup_table_entry *cur_entry, *duplicate_entry; if (fread(buf, 1, sizeof(buf), w->fp) != sizeof(buf)) { if (feof(w->fp)) { @@ -245,12 +245,20 @@ int read_lookup_table(WIMStruct *w) p = get_u32(p, &cur_entry->refcnt); p = get_bytes(p, SHA1_HASH_SIZE, cur_entry->hash); + if (cur_entry->part_number != w->hdr.part_number) { + ERROR("A lookup table entry in part %hu of the WIM " + "points to part %hu", + w->hdr.part_number, cur_entry->part_number); + ret = WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY; + goto out_free_cur_entry; + + } + if (is_zero_hash(cur_entry->hash)) { ERROR("The WIM lookup table contains an entry with a " "SHA1 message digest of all 0's"); ret = WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY; - FREE(cur_entry); - goto out; + goto out_free_cur_entry; } duplicate_entry = __lookup_resource(table, cur_entry->hash); @@ -262,10 +270,8 @@ int read_lookup_table(WIMStruct *w) ERROR("The second entry is:"); print_lookup_table_entry(cur_entry); ret = WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY; - FREE(cur_entry); - goto out; + goto out_free_cur_entry; } - lookup_table_insert(table, cur_entry); if (!(cur_entry->resource_entry.flags & WIM_RESHDR_FLAG_COMPRESSED) && (cur_entry->resource_entry.size != @@ -276,12 +282,16 @@ int read_lookup_table(WIMStruct *w) ERROR("The lookup table entry for the resource is as follows:"); print_lookup_table_entry(cur_entry); ret = WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY; - goto out; + goto out_free_cur_entry; } + lookup_table_insert(table, cur_entry); + } DEBUG("Done reading lookup table."); w->lookup_table = table; return 0; +out_free_cur_entry: + FREE(cur_entry); out: free_lookup_table(table); return ret; diff --git a/src/modify.c b/src/modify.c index 3dc0de44..5223b819 100644 --- a/src/modify.c +++ b/src/modify.c @@ -364,6 +364,15 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim, struct wim_pair wims; struct wim_security_data *sd; + if (!src_wim || !dest_wim) + return WIMLIB_ERR_INVALID_PARAM; + + if (src_wim->hdr.total_parts != 1 || src_wim->hdr.total_parts != 1) { + ERROR("Exporting an image to or from a split WIM is " + "unsupported"); + return WIMLIB_ERR_SPLIT_UNSUPPORTED; + } + if (src_image == WIM_ALL_IMAGES) { if (src_wim->hdr.image_count > 1) { @@ -466,6 +475,11 @@ WIMLIBAPI int wimlib_delete_image(WIMStruct *w, int image) int i; int ret; + if (w->hdr.total_parts != 1) { + ERROR("Deleting an image from a split WIM is not supported."); + return WIMLIB_ERR_SPLIT_UNSUPPORTED; + } + if (image == WIM_ALL_IMAGES) { num_images = w->hdr.image_count; for (i = 1; i <= num_images; i++) { @@ -791,6 +805,11 @@ int do_add_image(WIMStruct *w, const char *dir, const char *name, return WIMLIB_ERR_INVALID_PARAM; } + if (w->hdr.total_parts != 1) { + ERROR("Cannot add an image to a split WIM"); + return WIMLIB_ERR_SPLIT_UNSUPPORTED; + } + if (wimlib_image_name_in_use(w, name)) { ERROR("There is already an image named \"%s\" in `%s'", name, w->filename); diff --git a/src/ntfs-apply.c b/src/ntfs-apply.c index ee1982af..7ae7fa17 100644 --- a/src/ntfs-apply.c +++ b/src/ntfs-apply.c @@ -729,11 +729,18 @@ out: * full filesystem to be applied to the volume. */ WIMLIBAPI int wimlib_apply_image_to_ntfs_volume(WIMStruct *w, int image, - const char *device, int flags) + const char *device, int flags, + WIMStruct **additional_swms, + unsigned num_additional_swms) { + struct lookup_table *joined_tab, *w_tab_save; int ret; - if (!device) + DEBUG("w->filename = %s, image = %d, device = %s, flags = 0x%x, " + "num_additional_swms = %u", + w->filename, image, device, flags, num_additional_swms); + + if (!w || !device) return WIMLIB_ERR_INVALID_PARAM; if (image == WIM_ALL_IMAGES) { ERROR("Can only apply a single image when applying " @@ -745,16 +752,39 @@ WIMLIBAPI int wimlib_apply_image_to_ntfs_volume(WIMStruct *w, int image, ERROR("directly to a NTFS volume"); return WIMLIB_ERR_INVALID_PARAM; } - ret = wimlib_select_image(w, image); + + ret = verify_swm_set(w, additional_swms, num_additional_swms); if (ret != 0) return ret; - return do_wim_apply_image_ntfs(w, device, flags); + if (num_additional_swms) { + ret = new_joined_lookup_table(w, additional_swms, + num_additional_swms, &joined_tab); + if (ret != 0) + return ret; + w_tab_save = w->lookup_table; + w->lookup_table = joined_tab; + } + + ret = wimlib_select_image(w, image); + if (ret != 0) + goto out; + + ret = do_wim_apply_image_ntfs(w, device, flags); + +out: + if (num_additional_swms) { + free_lookup_table(w->lookup_table); + w->lookup_table = w_tab_save; + } + return ret; } #else /* WITH_NTFS_3G */ WIMLIBAPI int wimlib_apply_image_to_ntfs_volume(WIMStruct *w, int image, - const char *device, int flags) + const char *device, int flags, + WIMStruct **additional_swms, + unsigned num_additional_swms) { ERROR("wimlib was compiled without support for NTFS-3g, so"); ERROR("we cannot apply a WIM image directly to a NTFS volume"); diff --git a/src/split.c b/src/split.c index f9811d97..b8cb6789 100644 --- a/src/split.c +++ b/src/split.c @@ -53,8 +53,6 @@ static int finish_swm(WIMStruct *w, struct lookup_table_entry *lte_chain_head, lookup_table_offset); while (lte_chain_head != NULL) { - print_lookup_table_entry(lte_chain_head); - ret = write_lookup_table_entry(lte_chain_head, w->out_fp); if (ret != 0) return ret; diff --git a/src/wim.c b/src/wim.c index 1a159578..5d5c8fef 100644 --- a/src/wim.c +++ b/src/wim.c @@ -328,6 +328,14 @@ WIMLIBAPI void wimlib_print_available_images(const WIMStruct *w, int image) * not WIM_NO_IMAGE. */ WIMLIBAPI int wimlib_print_metadata(WIMStruct *w, int image) { + if (!w) + return WIMLIB_ERR_INVALID_PARAM; + if (w->hdr.part_number != 1) { + ERROR("We cannot show the metadata from part %hu of a %hu-part split WIM", + w->hdr.part_number, w->hdr.total_parts); + ERROR("Select the first part of the split WIM to see the metadata."); + return WIMLIB_ERR_SPLIT_UNSUPPORTED; + } if (image == WIM_ALL_IMAGES) DEBUG("Printing metadata for all images"); else @@ -337,12 +345,26 @@ WIMLIBAPI int wimlib_print_metadata(WIMStruct *w, int image) WIMLIBAPI int wimlib_print_files(WIMStruct *w, int image) { + if (!w) + return WIMLIB_ERR_INVALID_PARAM; + if (w->hdr.part_number != 1) { + ERROR("We cannot list the files from part %hu of a %hu-part split WIM", + w->hdr.part_number, w->hdr.total_parts); + ERROR("Select the first part of the split WIM if you'd like to list the files."); + return WIMLIB_ERR_SPLIT_UNSUPPORTED; + } return for_image(w, image, print_files); } /* Sets the index of the bootable image. */ WIMLIBAPI int wimlib_set_boot_idx(WIMStruct *w, int boot_idx) { + if (!w) + return WIMLIB_ERR_INVALID_PARAM; + if (w->hdr.total_parts != 1) { + ERROR("We cannot modify the boot index of a split WIM"); + return WIMLIB_ERR_SPLIT_UNSUPPORTED; + } if (boot_idx < 0 || boot_idx > w->hdr.image_count) return WIMLIB_ERR_INVALID_IMAGE; w->hdr.boot_idx = boot_idx; @@ -535,7 +557,7 @@ WIMLIBAPI int wimlib_open_wim(const char *wim_file, int flags, * closes all files associated with the WIMStruct. */ WIMLIBAPI void wimlib_free(WIMStruct *w) { - DEBUG("Freeing WIMStruct"); + DEBUG2("Freeing WIMStruct"); if (!w) return; diff --git a/src/wimlib.h b/src/wimlib.h index 2de733cd..0debc5c2 100644 --- a/src/wimlib.h +++ b/src/wimlib.h @@ -95,13 +95,16 @@ * README for more information about installing it. To use wimlib in a program * after installing it, include @c wimlib.h and link your program with @c -lwim. * - * wimlib wraps up a WIM file in an opaque ::WIMStruct structure. + * wimlib wraps up a WIM file in an opaque ::WIMStruct structure. A ::WIMStruct + * may represent either a stand-alone WIM or one part of a split WIM. * * All functions in wimlib's public API are prefixed with @c wimlib. Most * return an integer error code on failure. Use wimlib_get_error_string() to * get a string that describes an error code. wimlib also can print error * messages itself when an error happens, and these may be more informative than - * the error code; to enable this, call wimlib_set_print_errors(). + * the error code; to enable this, call wimlib_set_print_errors(). Please note + * that this is for convenience only, and some errors can occur without a + * message being printed. * * wimlib is thread-safe as long as different ::WIMStruct's are used, with the * following exceptions: wimlib_set_print_errors() and @@ -163,7 +166,6 @@ * * While wimlib supports the main features of WIM files, wimlib currently has * the following limitations: - * - There is no way to directly extract or mount split WIMs. * - Different versions of the WIM file format are unsupported. There is one * different version of the format from development versions of Windows Vista, * but I'm not planning to support it. @@ -416,6 +418,9 @@ enum wimlib_error_code { * @retval ::WIMLIB_ERR_STAT * Failed obtain the metadata for a file or directory in the directory tree * rooted at @a dir. + * @retval ::WIMLIB_ERR_SPLIT_UNSUPPORTED + * @a wim is part of a split WIM. Adding an image to a split WIM is + * unsupported. */ extern int wimlib_add_image(WIMStruct *wim, const char *dir, const char *name, const char *config, @@ -444,7 +449,9 @@ extern int wimlib_add_image_from_ntfs_volume(WIMStruct *w, const char *device, * the WIM. */ extern int wimlib_apply_image_to_ntfs_volume(WIMStruct *w, int image, - const char *device, int flags); + const char *device, int flags, + WIMStruct **additional_swms, + unsigned num_additional_swms); /** * Creates a WIMStruct for a new WIM file. @@ -495,6 +502,9 @@ extern int wimlib_create_new_wim(int ctype, WIMStruct **wim_ret); * @retval ::WIMLIB_ERR_NOMEM Failed to allocate needed memory. * @retval ::WIMLIB_ERR_READ * Could not read the metadata resource for @a image from the WIM. + * @retval ::WIMLIB_ERR_SPLIT_UNSUPPORTED + * @a wim is part of a split WIM. Deleting an image from a split WIM is + * unsupported. */ extern int wimlib_delete_image(WIMStruct *wim, int image); @@ -548,7 +558,8 @@ extern int wimlib_delete_image(WIMStruct *wim, int image); * ::WIM_ALL_IMAGES, @a src_wim contains multiple images, and no images in * @a src_wim are marked as bootable; or @a dest_name and/or @a * dest_description were non-NULL, @a src_image was - * ::WIM_ALL_IMAGES, and @a src_wim contains multiple images. + * ::WIM_ALL_IMAGES, and @a src_wim contains multiple images; or @a src_wim + * or @a dest_wim was @c NULL. * @retval ::WIMLIB_ERR_INVALID_RESOURCE_SIZE * The metadata resource for @a src_image in @a src_wim is invalid. * @retval ::WIMLIB_ERR_INVALID_SECURITY_DATA @@ -557,25 +568,51 @@ extern int wimlib_delete_image(WIMStruct *wim, int image); * Failed to allocate needed memory. * @retval ::WIMLIB_ERR_READ * Could not read the metadata resource for @a src_image from @a src_wim. + * @retval ::WIMLIB_ERR_SPLIT_UNSUPPORTED + * @a src_wim or @a dest_wim is part of a split WIM. Exporting an image + * from or to a split WIM is unsupported. */ extern int wimlib_export_image(WIMStruct *src_wim, int src_image, WIMStruct *dest_wim, const char *dest_name, const char *dest_description, int flags); /** - * Extracts an image, or all images, from a WIM file. - * - * The output directory must have been previously set with - * wimlib_set_output_dir(). - * - * The link type used for extracted files is that specified by a previous call - * to wimlib_set_link_type(), or ::WIM_LINK_TYPE_NONE by default. + * Extracts an image, or all images, from a standalone or split WIM file. * * @param wim - * Pointer to the ::WIMStruct for a WIM file. + * Pointer to the ::WIMStruct for a standalone WIM file, or part 1 of a + * split WIM. * @param image * The image to extract. Can be the number of an image, or ::WIM_ALL_IMAGES * to specify that all images are to be extracted. + * @param output_dir + * Directory to extract the WIM image(s) to. It is created if it does not + * already exist. + * @param flags + * Bitwise or of the flags prefixed with WIMLIB_EXTRACT_FLAG. + * + * One or none of ::WIMLIB_EXTRACT_FLAG_HARDLINK or + * ::WIMLIB_EXTRACT_FLAG_SYMLINK may be specified. These flags cause + * extracted files that are identical to be hardlinked or symlinked + * together, depending on the flag. These flags override the hard link + * groups that are specified in the WIM file itself. If ::WIM_ALL_IMAGES + * is provided as the @a image parameter, files may be hardlinked or + * symlinked across images if a file is found to occur in more than one + * image. + * + * You may also specify the flag ::WIMLIB_EXTRACT_FLAG_VERBOSE to cause + * informational messages to be printed during the extraction, including + * the name of each extracted file or directory. + * @param additional_swms + * Array of pointers to the ::WIMStruct for each additional part in the + * split WIM. Ignored if @a num_additional_swms is 0. The pointers do not + * need to be in any particular order, but they must include all parts of + * the split WIM other than the first part, which must be provided in the + * @a wim parameter. + * @param num_additional_swms + * Number of additional WIM parts provided in the @a additional_swms array. + * This number should be one less than the total number of parts in the + * split WIM. * * @return 0 on success; nonzero on error. * @retval ::WIMLIB_ERR_DECOMPRESSION @@ -602,15 +639,23 @@ extern int wimlib_export_image(WIMStruct *src_wim, int src_image, * @retval ::WIMLIB_ERR_READ * A unexpected end-of-file or read error occurred when trying to read data * from the WIM file associated with @a wim. + * @retval ::WIMLIB_ERR_SPLIT_INVALID + * The WIM is a split WIM, but the parts specified do not form a complete + * split WIM because they do not include all the parts of the original WIM, + * there are duplicate parts, or not all the parts have the same GUID and + * compression type. * @retval ::WIMLIB_ERR_WRITE * Failed to write a file being extracted. */ extern int wimlib_extract_image(WIMStruct *wim, int image, - const char *output_dir, int flags); + const char *output_dir, int flags, + WIMStruct **additional_swms, + unsigned num_additional_swms); /** * Extracts the XML data for a WIM file to a file stream. Every WIM file * includes a string of XML that describes the images contained in the WIM. + * This function works on standalone WIMs as well as split WIM parts. * * @param wim * Pointer to the ::WIMStruct for a WIM file. @@ -687,7 +732,8 @@ extern const char *wimlib_get_error_string(enum wimlib_error_code code); * Returns the description of the specified image. * * @param wim - * Pointer to the ::WIMStruct for a WIM file. + * Pointer to the ::WIMStruct for a WIM file. It may be either a + * standalone WIM or a split WIM part. * @param image * The number of the image, numbered starting at 1. * @@ -701,7 +747,8 @@ extern const char *wimlib_get_image_description(const WIMStruct *wim, int image) * Returns the name of the specified image. * * @param wim - * Pointer to the ::WIMStruct for a WIM file. + * Pointer to the ::WIMStruct for a WIM file. It may be either a + * standalone WIM or a split WIM part. * @param image * The number of the image, numbered starting at 1. * @@ -715,7 +762,8 @@ extern const char *wimlib_get_image_name(const WIMStruct *wim, int image); * Gets the number of images contained in the WIM. * * @param wim - * Pointer to the ::WIMStruct for a WIM file. + * Pointer to the ::WIMStruct for a WIM file. It may be either a + * standalone WIM or a split WIM part. * * @return * The number of images contained in the WIM file. @@ -723,7 +771,7 @@ 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). + * Gets the part number of part of a split WIM. * * @param wim * Pointer to the ::WIMStruct for a WIM file. @@ -742,7 +790,7 @@ extern int wimlib_get_part_number(const WIMStruct *wim, int *total_parts_ret); * @param wim * Pointer to the ::WIMStruct for a WIM file. * @return - * @c true if the WIM has an integrity table; false otherwise. + * @c true if the WIM has an integrity table; @c false otherwise. */ extern bool wimlib_has_integrity_table(const WIMStruct *wim); @@ -790,7 +838,7 @@ extern bool wimlib_image_name_in_use(const WIMStruct *wim, const char *name); * Note that this function merely copies the resources, so it will not check to * see if the resources, including the metadata resource, are valid or not. */ -extern int wimlib_join(const char **swms, int num_swms, +extern int wimlib_join(const char **swms, unsigned num_swms, const char *output_path, int flags); /** @@ -846,7 +894,6 @@ extern int wimlib_join(const char **swms, int num_swms, * @retval ::WIMLIB_ERR_READ * An unexpected end-of-file or read error occurred when trying to read * data from the WIM file associated with @a wim. - * */ extern int wimlib_mount(WIMStruct *wim, int image, const char *dir, int flags); @@ -1031,6 +1078,8 @@ extern void wimlib_print_available_images(const WIMStruct *wim, int image); * @retval ::WIMLIB_ERR_INVALID_IMAGE * @a image does not specify a valid image in @a wim, and is not * ::WIM_ALL_IMAGES. + * @retval ::WIMLIB_ERR_INVALID_PARAM + * @a wim was @c NULL. * @retval ::WIMLIB_ERR_INVALID_RESOURCE_SIZE * The metadata resource for one of the specified images is invalid. * @retval ::WIMLIB_ERR_INVALID_SECURITY_DATA @@ -1040,6 +1089,9 @@ extern void wimlib_print_available_images(const WIMStruct *wim, int image); * @retval ::WIMLIB_ERR_READ * An unexpected read error or end-of-file occurred when reading the * metadata resource for one of the specified images. + * @retval ::WIMLIB_ERR_SPLIT_UNSUPPORTED + * @a wim was not a standalone WIM and was not the first part of a split + * WIM. */ extern int wimlib_print_files(WIMStruct *wim, int image); @@ -1047,7 +1099,8 @@ extern int wimlib_print_files(WIMStruct *wim, int image); * Prints detailed information from the header of a WIM file. * * @param wim - * Pointer to the ::WIMStruct for a WIM file. + * Pointer to the ::WIMStruct for a WIM file. It may be either a + * standalone WIM or part of a split WIM. * * @return This function has no return value. * @@ -1089,6 +1142,8 @@ extern void wimlib_print_lookup_table(WIMStruct *wim); * @retval ::WIMLIB_ERR_INVALID_IMAGE * @a image does not specify a valid image in @a wim, and is not * ::WIM_ALL_IMAGES. + * @retval ::WIMLIB_ERR_INVALID_PARAM + * @a wim was @c NULL. * @retval ::WIMLIB_ERR_INVALID_RESOURCE_SIZE * The metadata resource for one of the specified images is invalid. * @retval ::WIMLIB_ERR_INVALID_SECURITY_DATA @@ -1098,6 +1153,9 @@ extern void wimlib_print_lookup_table(WIMStruct *wim); * @retval ::WIMLIB_ERR_READ * An unexpected read error or end-of-file occurred when reading the * metadata resource for one of the specified images. + * @retval ::WIMLIB_ERR_SPLIT_UNSUPPORTED + * @a wim was not a standalone WIM and was not the first part of a split + * WIM. */ extern int wimlib_print_metadata(WIMStruct *wim, int image); @@ -1144,9 +1202,14 @@ extern int wimlib_resolve_image(WIMStruct *wim, const char *image_name_or_num); * The number of the image to mark as bootable, or 0 to mark no image as * bootable. * @return 0 on success; nonzero on error. + * @retval ::WIMLIB_ERR_INVALID_PARAM + * @a wim was @c NULL. * @retval ::WIMLIB_ERR_INVALID_IMAGE * @a boot_idx does not specify an existing image in @a wim, and it was not * 0. + * @retval ::WIMLIB_ERR_SPLIT_UNSUPPORTED + * @a wim is part of a split WIM. We do not support changing the boot + * index of a split WIM. */ extern int wimlib_set_boot_idx(WIMStruct *wim, int boot_idx); @@ -1154,7 +1217,9 @@ extern int wimlib_set_boot_idx(WIMStruct *wim, int boot_idx); * Changes the description of an image in the WIM. * * @param wim - * Pointer to the ::WIMStruct for a WIM file. + * Pointer to the ::WIMStruct for a WIM file. It may be either a + * standalone WIM or part of a split WIM; however, you should set the same + * description on all parts of a split WIM. * @param image * The number of the image for which to change the description. * @param description @@ -1164,6 +1229,8 @@ extern int wimlib_set_boot_idx(WIMStruct *wim, int boot_idx); * @return 0 on success; nonzero on error. * @retval ::WIMLIB_ERR_INVALID_IMAGE * @a image does not specify a single existing image in @a wim. + * @retval ::WIMLIB_ERR_INVALID_PARAM + * @a wim was @c NULL. * @retval ::WIMLIB_ERR_NOMEM * Failed to allocate the memory needed to duplicate the @a description * string. @@ -1171,6 +1238,28 @@ extern int wimlib_set_boot_idx(WIMStruct *wim, int boot_idx); extern int wimlib_set_image_descripton(WIMStruct *wim, int image, const char *description); +/** + * Changes what is written in the element in the WIM XML data (something + * like "Core" or "Ultimate") + * + * @param wim + * Pointer to the ::WIMStruct for a WIM file. It may be either a + * standalone WIM or part of a split WIM; however, you should set the same + * element on all parts of a split WIM. + * @param image + * The number of the image for which to change the description. + * @param flags + * The new element to give the image. It may be @c NULL, which + * indicates that the image is to be given no element. + * + * @return 0 on success; nonzero on error. + * @retval ::WIMLIB_ERR_INVALID_IMAGE + * @a image does not specify a single existing image in @a wim. + * @retval ::WIMLIB_ERR_INVALID_PARAM + * @a wim was @c NULL. + * @retval ::WIMLIB_ERR_NOMEM + * Failed to allocate the memory needed to duplicate the @a flags string. + */ extern int wimlib_set_image_flags(WIMStruct *w, int image, const char *flags); @@ -1178,17 +1267,19 @@ extern int wimlib_set_image_flags(WIMStruct *w, int image, * Changes the name of an image in the WIM. * * @param wim - * Pointer to the ::WIMStruct for a WIM file. + * Pointer to the ::WIMStruct for a WIM file. It may be either a + * standalone WIM or part of a split WIM; however, you should set the same + * name on all parts of a split WIM. * @param image * The number of the image for which to change the name. * @param name - * The new name to give the image. It must not be @c NULL. + * The new name to give the image. It must not a nonempty string. * * @return 0 on success; nonzero on error. * @retval ::WIMLIB_ERR_IMAGE_NAME_COLLISION * There is already an image named @a name in @a wim. * @retval ::WIMLIB_ERR_INVALID_PARAM - * @a name was @c NULL or the empty string. + * @a name was @c NULL or the empty string, or @a wim was @c NULL. * @retval ::WIMLIB_ERR_INVALID_IMAGE * @a image does not specify a single existing image in @a wim. * @retval ::WIMLIB_ERR_NOMEM @@ -1204,6 +1295,9 @@ extern int wimlib_set_image_name(WIMStruct *wim, int image, const char *name); * The default is to use the default @c malloc() and @c free() from the C * library. * + * Please note that some external functions we call still may use the standard + * memory allocation functions. + * * @param malloc_func * A function equivalent to @c malloc() that wimlib will use to allocate * memory. If @c NULL, the allocator function is set back to the default @@ -1227,8 +1321,9 @@ int wimlib_set_memory_allocator(void *(*malloc_func)(size_t), /** * Sets whether wimlib is to print error messages to @c stderr when a function - * fails or not. These error messages may provide information that cannot be - * determined only from the error code that is returned. + * fails. These error messages may provide information that cannot be + * determined only from the error code that is returned. Not every error will + * result in an error message being printed. * * This setting is global and not per-WIM. * @@ -1365,6 +1460,8 @@ extern int wimlib_unmount(const char *dir, int flags); * A file that had previously been scanned for inclusion in the WIM by the * wimlib_add_image() or wimlib_add_image_from_ntfs_volume() functions was * concurrently modified, so it failed the SHA1 message digest check. + * @retval ::WIMLIB_ERR_INVALID_PARAM + * @a wim or @a path was @c NULL. * @retval ::WIMLIB_ERR_INVALID_RESOURCE_SIZE * The metadata resource for @a image in @a wim is invalid. * @retval ::WIMLIB_ERR_INVALID_SECURITY_DATA @@ -1380,6 +1477,9 @@ extern int wimlib_unmount(const char *dir, int flags); * with @a wim, or some file resources in @a wim refer to files in the * outside filesystem, and a read error occurred when reading one of these * files. + * @retval ::WIMLIB_ERR_SPLIT_UNSUPPORTED + * @a wim is part of a split WIM. You may not call this function on a + * split WIM. * @retval ::WIMLIB_ERR_WRITE * An error occurred when trying to write data to the new WIM file at @a * path. diff --git a/src/wimlib_internal.h b/src/wimlib_internal.h index b90800bc..fa40f6af 100644 --- a/src/wimlib_internal.h +++ b/src/wimlib_internal.h @@ -354,6 +354,16 @@ extern int write_integrity_table(FILE *out, u64 end_header_offset, int show_progress); extern int check_wim_integrity(WIMStruct *w, int show_progress, int *status); +/* join.c */ + +extern int new_joined_lookup_table(WIMStruct *w, + WIMStruct **additional_swms, + unsigned num_additional_swms, + struct lookup_table **table_ret); + +extern int verify_swm_set(WIMStruct *w, + WIMStruct **additional_swms, + unsigned num_additional_swms); /* modify.c */ extern void destroy_image_metadata(struct image_metadata *imd, struct lookup_table *lt); diff --git a/src/write.c b/src/write.c index bc821fa7..49715899 100644 --- a/src/write.c +++ b/src/write.c @@ -60,6 +60,9 @@ WIMLIBAPI int wimlib_overwrite(WIMStruct *w, int flags) size_t wim_name_len; int ret; + if (!w) + return WIMLIB_ERR_INVALID_PARAM; + wimfile_name = w->filename; DEBUG("Replacing WIM file `%s'.", wimfile_name); @@ -401,10 +404,19 @@ WIMLIBAPI int wimlib_write(WIMStruct *w, const char *path, int image, int flags) { int ret; + if (!w || !path) + return WIMLIB_ERR_INVALID_PARAM; + if (image != WIM_ALL_IMAGES && (image < 1 || image > w->hdr.image_count)) return WIMLIB_ERR_INVALID_IMAGE; + + if (w->hdr.total_parts != 1) { + ERROR("Cannot call wimlib_write() on part of a split WIM"); + return WIMLIB_ERR_SPLIT_UNSUPPORTED; + } + if (image == WIM_ALL_IMAGES) DEBUG("Writing all images to `%s'.", path); else diff --git a/src/xml.c b/src/xml.c index 2f67c985..73ba38e4 100644 --- a/src/xml.c +++ b/src/xml.c @@ -1356,6 +1356,9 @@ WIMLIBAPI int wimlib_set_image_name(WIMStruct *w, int image, const char *name) DEBUG("Setting the name of image %d to %s", image, name); + if (!w) + return WIMLIB_ERR_INVALID_PARAM; + if (!name || !*name) { ERROR("Must specify a non-empty string for the image name"); return WIMLIB_ERR_INVALID_PARAM; @@ -1393,6 +1396,9 @@ WIMLIBAPI int wimlib_set_image_descripton(WIMStruct *w, int image, DEBUG("Setting the description of image %d to %s", image, description); + if (!w) + return WIMLIB_ERR_INVALID_PARAM; + if (image < 1 || image > w->hdr.image_count) { ERROR("%d is not a valid image", image); return WIMLIB_ERR_INVALID_IMAGE;