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/paths.h"
35 #include "wimlib/progress.h"
36 #include "wimlib/resource.h"
37 #include "wimlib/wim.h"
38 #include "wimlib/write.h"
40 struct swm_part_info {
41 struct list_head blob_list;
46 copy_part_info(struct swm_part_info *dst, struct swm_part_info *src)
48 list_replace(&src->blob_list, &dst->blob_list);
49 dst->size = src->size;
53 struct swm_part_info *parts;
55 unsigned num_alloc_parts;
61 write_split_wim(WIMStruct *orig_wim, const tchar *swm_name,
62 struct swm_info *swm_info, int write_flags)
68 size_t swm_base_name_len;
70 union wimlib_progress_info progress;
75 swm_name_len = tstrlen(swm_name);
76 swm_name_buf = alloca((swm_name_len + 20) * sizeof(tchar));
77 tstrcpy(swm_name_buf, swm_name);
78 dot = tstrrchr(path_basename(swm_name_buf), T('.'));
80 swm_base_name_len = dot - swm_name_buf;
81 swm_suffix = alloca((tstrlen(dot) + 1) * sizeof(tchar));
82 tstrcpy(swm_suffix, dot);
84 swm_base_name_len = swm_name_len;
85 swm_suffix = alloca(1 * sizeof(tchar));
86 swm_suffix[0] = T('\0');
89 progress.split.completed_bytes = 0;
90 progress.split.total_bytes = 0;
91 for (part_number = 1; part_number <= swm_info->num_parts; part_number++)
92 progress.split.total_bytes += swm_info->parts[part_number - 1].size;
93 progress.split.total_parts = swm_info->num_parts;
97 for (part_number = 1; part_number <= swm_info->num_parts; part_number++) {
99 wimlib_progress_func_t progfunc;
101 if (part_number != 1) {
102 tsprintf(swm_name_buf + swm_base_name_len,
103 T("%u%"TS), part_number, swm_suffix);
106 progress.split.cur_part_number = part_number;
107 progress.split.part_name = swm_name_buf;
109 ret = call_progress(orig_wim->progfunc,
110 WIMLIB_PROGRESS_MSG_SPLIT_BEGIN_PART,
116 part_write_flags = write_flags;
117 part_write_flags |= WIMLIB_WRITE_FLAG_USE_EXISTING_TOTALBYTES;
118 if (part_number != 1)
119 part_write_flags |= WIMLIB_WRITE_FLAG_NO_METADATA;
121 progfunc = orig_wim->progfunc;
122 orig_wim->progfunc = NULL;
123 ret = write_wim_part(orig_wim,
124 progress.split.part_name,
130 &swm_info->parts[part_number - 1].blob_list,
132 orig_wim->progfunc = progfunc;
136 progress.split.completed_bytes += swm_info->parts[part_number - 1].size;
138 ret = call_progress(orig_wim->progfunc,
139 WIMLIB_PROGRESS_MSG_SPLIT_END_PART,
149 start_new_swm_part(struct swm_info *swm_info)
151 if (swm_info->num_parts == swm_info->num_alloc_parts) {
152 struct swm_part_info *parts;
153 size_t num_alloc_parts = swm_info->num_alloc_parts;
155 num_alloc_parts += 8;
156 parts = MALLOC(num_alloc_parts * sizeof(parts[0]));
158 return WIMLIB_ERR_NOMEM;
160 for (unsigned i = 0; i < swm_info->num_parts; i++)
161 copy_part_info(&parts[i], &swm_info->parts[i]);
163 FREE(swm_info->parts);
164 swm_info->parts = parts;
165 swm_info->num_alloc_parts = num_alloc_parts;
167 swm_info->num_parts++;
168 INIT_LIST_HEAD(&swm_info->parts[swm_info->num_parts - 1].blob_list);
169 swm_info->parts[swm_info->num_parts - 1].size = 0;
174 add_blob_to_swm(struct blob_descriptor *blob, void *_swm_info)
176 struct swm_info *swm_info = _swm_info;
177 u64 blob_stored_size;
180 if (blob->blob_location == BLOB_IN_WIM)
181 blob_stored_size = blob->rdesc->size_in_wim;
183 blob_stored_size = blob->size;
185 /* Start the next part if adding this blob exceeds the maximum part
186 * size, UNLESS the blob is metadata or if no blobs at all have been
187 * added to the current part. */
188 if ((swm_info->parts[swm_info->num_parts - 1].size +
189 blob_stored_size >= swm_info->max_part_size)
190 && !(blob->is_metadata ||
191 swm_info->parts[swm_info->num_parts - 1].size == 0))
193 ret = start_new_swm_part(swm_info);
197 swm_info->parts[swm_info->num_parts - 1].size += blob_stored_size;
198 if (!blob->is_metadata) {
199 list_add_tail(&blob->write_blobs_list,
200 &swm_info->parts[swm_info->num_parts - 1].blob_list);
202 swm_info->total_bytes += blob_stored_size;
206 /* API function documented in wimlib.h */
208 wimlib_split(WIMStruct *wim, const tchar *swm_name,
209 u64 part_size, int write_flags)
211 struct swm_info swm_info;
215 if (swm_name == NULL || swm_name[0] == T('\0') || part_size == 0)
216 return WIMLIB_ERR_INVALID_PARAM;
218 if (write_flags & ~WIMLIB_WRITE_MASK_PUBLIC)
219 return WIMLIB_ERR_INVALID_PARAM;
221 if (!wim_has_metadata(wim))
222 return WIMLIB_ERR_METADATA_NOT_FOUND;
224 if (wim_has_solid_resources(wim)) {
225 ERROR("Splitting of WIM containing solid resources is not supported.\n"
226 " Export it in non-solid format first.");
227 return WIMLIB_ERR_UNSUPPORTED;
230 for (i = 0; i < wim->hdr.image_count; i++) {
231 if (!is_image_unchanged_from_wim(wim->image_metadata[i], wim)) {
232 ERROR("Only an unmodified, on-disk WIM file can be split.");
233 return WIMLIB_ERR_UNSUPPORTED;
237 memset(&swm_info, 0, sizeof(swm_info));
238 swm_info.max_part_size = part_size;
240 ret = start_new_swm_part(&swm_info);
242 goto out_free_swm_info;
244 for (i = 0; i < wim->hdr.image_count; i++) {
245 ret = add_blob_to_swm(wim->image_metadata[i]->metadata_blob,
248 goto out_free_swm_info;
251 ret = for_blob_in_table_sorted_by_sequential_order(wim->blob_table,
255 goto out_free_swm_info;
257 ret = write_split_wim(wim, swm_name, &swm_info, write_flags);
259 FREE(swm_info.parts);