4 * Join split WIMs (sometimes named as .swm files) together into one WIM.
8 * Copyright (C) 2012-2016 Eric Biggers
10 * This file is free software; you can redistribute it and/or modify it under
11 * the terms of the GNU Lesser General Public License as published by the Free
12 * Software Foundation; either version 3 of the License, or (at your option) any
15 * This file is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this file; if not, see http://www.gnu.org/licenses/.
31 #include "wimlib/error.h"
32 #include "wimlib/types.h"
33 #include "wimlib/util.h"
34 #include "wimlib/wim.h"
37 * Verify that a list of WIM files sorted by part number is a spanned set.
39 * Return: 0 on success; WIMLIB_ERR_SPLIT_INVALID if the set is not valid.
42 verify_swm_set(WIMStruct * const *swms, unsigned num_swms)
44 for (unsigned i = 0; i < num_swms; i++) {
45 if (!guids_equal(swms[i]->hdr.guid, swms[0]->hdr.guid)) {
46 ERROR("The split WIM parts specified belong to "
47 "different split WIMs!");
48 return WIMLIB_ERR_SPLIT_INVALID;
50 if (swms[i]->hdr.total_parts != num_swms) {
51 ERROR("\"%"TS"\" says there are %u parts in the split "
52 "WIM, but %s%u part%s provided",
53 swms[i]->filename, swms[i]->hdr.total_parts,
54 num_swms < swms[i]->hdr.total_parts ? "only ":"",
55 num_swms, num_swms > 1 ? "s were" : " was");
56 return WIMLIB_ERR_SPLIT_INVALID;
58 if (swms[i]->hdr.part_number != i + 1) {
59 ERROR("The parts of the split WIM are not numbered "
60 "1..%u as expected. Did you specify duplicate "
62 return WIMLIB_ERR_SPLIT_INVALID;
69 cmp_swms_by_part_number(const void *p1, const void *p2)
71 WIMStruct *swm1 = *(WIMStruct **)p1;
72 WIMStruct *swm2 = *(WIMStruct **)p2;
74 return (int)swm1->hdr.part_number - (int)swm2->hdr.part_number;
78 wimlib_join_with_progress(const tchar * const *swm_names,
80 const tchar *output_path,
83 wimlib_progress_func_t progfunc,
90 if (num_swms < 1 || num_swms > 0xffff)
91 return WIMLIB_ERR_INVALID_PARAM;
93 swms = CALLOC(num_swms, sizeof(swms[0]));
95 return WIMLIB_ERR_NOMEM;
97 for (i = 0; i < num_swms; i++) {
98 ret = wimlib_open_wim_with_progress(swm_names[i],
107 qsort(swms, num_swms, sizeof(swms[0]), cmp_swms_by_part_number);
109 ret = verify_swm_set(swms, num_swms);
113 ret = wimlib_reference_resources(swms[0], swms + 1, num_swms - 1, 0);
117 /* It is reasonably safe to provide WIMLIB_WRITE_FLAG_STREAMS_OK, as we
118 * have verified that the specified split WIM parts form a spanned set.
120 ret = wimlib_write(swms[0], output_path, WIMLIB_ALL_IMAGES,
122 WIMLIB_WRITE_FLAG_STREAMS_OK |
123 WIMLIB_WRITE_FLAG_RETAIN_GUID,
126 for (i = 0; i < num_swms; i++)
127 wimlib_free(swms[i]);
132 /* API function documented in wimlib.h */
134 wimlib_join(const tchar * const *swm_names,
136 const tchar *output_path,
140 return wimlib_join_with_progress(swm_names, num_swms, output_path,
141 swm_open_flags, wim_write_flags,