#include <getopt.h>
#include <stdlib.h>
#include <stdarg.h>
+#include <glob.h>
#include <string.h>
#include <errno.h>
#include <sys/stat.h>
{"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[] = {
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;
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':
case 'v':
extract_flags |= WIMLIB_EXTRACT_FLAG_VERBOSE;
break;
+ case 'r':
+ swm_glob = optarg;
+ break;
default:
usage(APPLY);
return -1;
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);
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;
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 {
}
#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;
}
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;
}
#include "wimlib_internal.h"
#include "lookup_table.h"
#include "xml.h"
+#include <stdlib.h>
+
+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)
}
-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)
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. */
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,
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,
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)) {
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);
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 !=
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;
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) {
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++) {
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);
* 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 "
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");
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;
* 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
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;
* closes all files associated with the WIMStruct. */
WIMLIBAPI void wimlib_free(WIMStruct *w)
{
- DEBUG("Freeing WIMStruct");
+ DEBUG2("Freeing WIMStruct");
if (!w)
return;
* 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
*
* 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.
* @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,
* 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.
* @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);
* ::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-<code>NULL</code>, @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
* 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
* @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.
* 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.
*
* 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.
*
* 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.
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.
* @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);
* 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);
/**
* @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);
* @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
* @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);
* 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.
*
* @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
* @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);
* 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);
* 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
* @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.
extern int wimlib_set_image_descripton(WIMStruct *wim, int image,
const char *description);
+/**
+ * Changes what is written in the <FLAGS> 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
+ * <FLAGS> 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 <FLAGS> element to give the image. It may be @c NULL, which
+ * indicates that the image is to be given no <FLAGS> 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);
* 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
* 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
/**
* 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.
*
* 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
* 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.
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);
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);
{
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
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;
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;