4 * Split a WIM file into parts.
8 * Copyright (C) 2012, 2013 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/.
29 #include "wimlib/alloca.h"
30 #include "wimlib/blob_table.h"
31 #include "wimlib/error.h"
32 #include "wimlib/list.h"
33 #include "wimlib/metadata.h"
34 #include "wimlib/progress.h"
35 #include "wimlib/resource.h"
36 #include "wimlib/wim.h"
37 #include "wimlib/write.h"
39 struct swm_part_info {
40 struct list_head blob_list;
45 copy_part_info(struct swm_part_info *dst, struct swm_part_info *src)
47 list_replace(&src->blob_list, &dst->blob_list);
48 dst->size = src->size;
52 struct swm_part_info *parts;
54 unsigned num_alloc_parts;
60 write_split_wim(WIMStruct *orig_wim, const tchar *swm_name,
61 struct swm_info *swm_info, int write_flags)
67 size_t swm_base_name_len;
69 union wimlib_progress_info progress;
74 swm_name_len = tstrlen(swm_name);
75 swm_name_buf = alloca((swm_name_len + 20) * sizeof(tchar));
76 tstrcpy(swm_name_buf, swm_name);
77 dot = tstrchr(swm_name_buf, T('.'));
79 swm_base_name_len = dot - swm_name_buf;
80 swm_suffix = alloca((tstrlen(dot) + 1) * sizeof(tchar));
81 tstrcpy(swm_suffix, dot);
83 swm_base_name_len = swm_name_len;
84 swm_suffix = alloca(1 * sizeof(tchar));
85 swm_suffix[0] = T('\0');
88 progress.split.completed_bytes = 0;
89 progress.split.total_bytes = 0;
90 for (part_number = 1; part_number <= swm_info->num_parts; part_number++)
91 progress.split.total_bytes += swm_info->parts[part_number - 1].size;
92 progress.split.total_parts = swm_info->num_parts;
96 for (part_number = 1; part_number <= swm_info->num_parts; part_number++) {
98 wimlib_progress_func_t progfunc;
100 if (part_number != 1) {
101 tsprintf(swm_name_buf + swm_base_name_len,
102 T("%u%"TS), part_number, swm_suffix);
105 progress.split.cur_part_number = part_number;
106 progress.split.part_name = swm_name_buf;
108 ret = call_progress(orig_wim->progfunc,
109 WIMLIB_PROGRESS_MSG_SPLIT_BEGIN_PART,
115 part_write_flags = write_flags;
116 part_write_flags |= WIMLIB_WRITE_FLAG_USE_EXISTING_TOTALBYTES;
117 if (part_number != 1)
118 part_write_flags |= WIMLIB_WRITE_FLAG_NO_METADATA;
120 progfunc = orig_wim->progfunc;
121 orig_wim->progfunc = NULL;
122 ret = write_wim_part(orig_wim,
123 progress.split.part_name,
129 &swm_info->parts[part_number - 1].blob_list,
131 orig_wim->progfunc = progfunc;
135 progress.split.completed_bytes += swm_info->parts[part_number - 1].size;
137 ret = call_progress(orig_wim->progfunc,
138 WIMLIB_PROGRESS_MSG_SPLIT_END_PART,
148 add_blob_to_swm(struct blob_descriptor *blob, void *_swm_info)
150 struct swm_info *swm_info = _swm_info;
151 u64 blob_stored_size;
153 if (blob->blob_location == BLOB_IN_WIM)
154 blob_stored_size = blob->rdesc->size_in_wim;
156 blob_stored_size = blob->size;
158 /* - Start first part if no parts have been started so far;
159 * - Start next part if adding this blob exceeds maximum part size,
160 * UNLESS the blob is metadata or if no blobs at all have been added
161 * to the current part.
163 if (swm_info->num_parts == 0 ||
164 ((swm_info->parts[swm_info->num_parts - 1].size +
165 blob_stored_size >= swm_info->max_part_size)
166 && !(blob->is_metadata ||
167 swm_info->parts[swm_info->num_parts - 1].size == 0)))
169 if (swm_info->num_parts == swm_info->num_alloc_parts) {
170 struct swm_part_info *parts;
171 size_t num_alloc_parts = swm_info->num_alloc_parts;
173 num_alloc_parts += 8;
174 parts = MALLOC(num_alloc_parts * sizeof(parts[0]));
176 return WIMLIB_ERR_NOMEM;
178 for (unsigned i = 0; i < swm_info->num_parts; i++)
179 copy_part_info(&parts[i], &swm_info->parts[i]);
181 FREE(swm_info->parts);
182 swm_info->parts = parts;
183 swm_info->num_alloc_parts = num_alloc_parts;
185 swm_info->num_parts++;
186 INIT_LIST_HEAD(&swm_info->parts[swm_info->num_parts - 1].blob_list);
187 swm_info->parts[swm_info->num_parts - 1].size = 0;
189 swm_info->parts[swm_info->num_parts - 1].size += blob_stored_size;
190 if (!blob->is_metadata) {
191 list_add_tail(&blob->write_blobs_list,
192 &swm_info->parts[swm_info->num_parts - 1].blob_list);
194 swm_info->total_bytes += blob_stored_size;
198 /* API function documented in wimlib.h */
200 wimlib_split(WIMStruct *wim, const tchar *swm_name,
201 u64 part_size, int write_flags)
203 struct swm_info swm_info;
207 if (swm_name == NULL || swm_name[0] == T('\0') || part_size == 0)
208 return WIMLIB_ERR_INVALID_PARAM;
210 if (write_flags & ~WIMLIB_WRITE_MASK_PUBLIC)
211 return WIMLIB_ERR_INVALID_PARAM;
213 if (!wim_has_metadata(wim))
214 return WIMLIB_ERR_METADATA_NOT_FOUND;
216 if (wim_has_solid_resources(wim)) {
217 ERROR("Splitting of WIM containing solid resources is not supported.\n"
218 " Export it in non-solid format first.");
219 return WIMLIB_ERR_UNSUPPORTED;
222 for (i = 0; i < wim->hdr.image_count; i++) {
223 if (!is_image_unchanged_from_wim(wim->image_metadata[i], wim)) {
224 ERROR("Only an unmodified, on-disk WIM file can be split.");
225 return WIMLIB_ERR_UNSUPPORTED;
229 memset(&swm_info, 0, sizeof(swm_info));
230 swm_info.max_part_size = part_size;
232 for (i = 0; i < wim->hdr.image_count; i++) {
233 ret = add_blob_to_swm(wim->image_metadata[i]->metadata_blob,
236 goto out_free_swm_info;
239 ret = for_blob_in_table_sorted_by_sequential_order(wim->blob_table,
243 goto out_free_swm_info;
245 ret = write_split_wim(wim, swm_name, &swm_info, write_flags);
247 FREE(swm_info.parts);