]> wimlib.net Git - wimlib/blob - src/join.c
configure.ac: generate version number from git commit and tags
[wimlib] / src / join.c
1 /*
2  * join.c
3  *
4  * Join split WIMs (sometimes named as .swm files) together into one WIM.
5  */
6
7 /*
8  * Copyright (C) 2012-2016 Eric Biggers
9  *
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
13  * later version.
14  *
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
18  * details.
19  *
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/.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #include <stdlib.h>
29
30 #include "wimlib.h"
31 #include "wimlib/error.h"
32 #include "wimlib/types.h"
33 #include "wimlib/util.h"
34 #include "wimlib/wim.h"
35
36 /*
37  * Verify that a list of WIM files sorted by part number is a spanned set.
38  *
39  * Return: 0 on success; WIMLIB_ERR_SPLIT_INVALID if the set is not valid.
40  */
41 static int
42 verify_swm_set(WIMStruct * const *swms, unsigned num_swms)
43 {
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;
49                 }
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;
57                 }
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 "
61                               "parts?", num_swms);
62                         return WIMLIB_ERR_SPLIT_INVALID;
63                 }
64         }
65         return 0;
66 }
67
68 static int
69 cmp_swms_by_part_number(const void *p1, const void *p2)
70 {
71         WIMStruct *swm1 = *(WIMStruct **)p1;
72         WIMStruct *swm2 = *(WIMStruct **)p2;
73
74         return (int)swm1->hdr.part_number - (int)swm2->hdr.part_number;
75 }
76
77 WIMLIBAPI int
78 wimlib_join_with_progress(const tchar * const *swm_names,
79                           unsigned num_swms,
80                           const tchar *output_path,
81                           int swm_open_flags,
82                           int wim_write_flags,
83                           wimlib_progress_func_t progfunc,
84                           void *progctx)
85 {
86         WIMStruct **swms;
87         unsigned i;
88         int ret;
89
90         if (num_swms < 1 || num_swms > 0xffff)
91                 return WIMLIB_ERR_INVALID_PARAM;
92
93         swms = CALLOC(num_swms, sizeof(swms[0]));
94         if (!swms)
95                 return WIMLIB_ERR_NOMEM;
96
97         for (i = 0; i < num_swms; i++) {
98                 ret = wimlib_open_wim_with_progress(swm_names[i],
99                                                     swm_open_flags,
100                                                     &swms[i],
101                                                     progfunc,
102                                                     progctx);
103                 if (ret)
104                         goto out;
105         }
106
107         qsort(swms, num_swms, sizeof(swms[0]), cmp_swms_by_part_number);
108
109         ret = verify_swm_set(swms, num_swms);
110         if (ret)
111                 goto out;
112
113         ret = wimlib_reference_resources(swms[0], swms + 1, num_swms - 1, 0);
114         if (ret)
115                 goto out;
116
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.
119          */
120         ret = wimlib_write(swms[0], output_path, WIMLIB_ALL_IMAGES,
121                            wim_write_flags |
122                                 WIMLIB_WRITE_FLAG_STREAMS_OK |
123                                 WIMLIB_WRITE_FLAG_RETAIN_GUID,
124                            1);
125 out:
126         for (i = 0; i < num_swms; i++)
127                 wimlib_free(swms[i]);
128         FREE(swms);
129         return ret;
130 }
131
132 /* API function documented in wimlib.h  */
133 WIMLIBAPI int
134 wimlib_join(const tchar * const *swm_names,
135             unsigned num_swms,
136             const tchar *output_path,
137             int swm_open_flags,
138             int wim_write_flags)
139 {
140         return wimlib_join_with_progress(swm_names, num_swms, output_path,
141                                          swm_open_flags, wim_write_flags,
142                                          NULL, NULL);
143 }