/*
* Copyright (C) 2012, 2013 Eric Biggers
*
- * This file is part of wimlib, a library for working with WIM files.
+ * This file is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option) any
+ * later version.
*
- * wimlib is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * This file is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
- * You should have received a copy of the GNU General Public License
- * along with wimlib; if not, see http://www.gnu.org/licenses/.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this file; if not, see http://www.gnu.org/licenses/.
*/
#ifdef HAVE_CONFIG_H
#endif
#include "wimlib.h"
+#include "wimlib/alloca.h"
+#include "wimlib/blob_table.h"
#include "wimlib/error.h"
#include "wimlib/list.h"
-#include "wimlib/lookup_table.h"
#include "wimlib/metadata.h"
+#include "wimlib/paths.h"
+#include "wimlib/progress.h"
#include "wimlib/resource.h"
#include "wimlib/wim.h"
#include "wimlib/write.h"
-#ifdef HAVE_ALLOCA_H
-# include <alloca.h>
-#else
-# include <stdlib.h>
-#endif
-
struct swm_part_info {
- struct list_head stream_list;
+ struct list_head blob_list;
u64 size;
};
static void
copy_part_info(struct swm_part_info *dst, struct swm_part_info *src)
{
- list_transfer(&src->stream_list, &dst->stream_list);
+ list_replace(&src->blob_list, &dst->blob_list);
dst->size = src->size;
}
static int
write_split_wim(WIMStruct *orig_wim, const tchar *swm_name,
- struct swm_info *swm_info, int write_flags,
- wimlib_progress_func_t progress_func)
+ struct swm_info *swm_info, int write_flags)
{
size_t swm_name_len;
tchar *swm_name_buf;
union wimlib_progress_info progress;
unsigned part_number;
int ret;
- u8 guid[WIMLIB_GUID_LEN];
+ u8 guid[GUID_SIZE];
swm_name_len = tstrlen(swm_name);
swm_name_buf = alloca((swm_name_len + 20) * sizeof(tchar));
tstrcpy(swm_name_buf, swm_name);
- dot = tstrchr(swm_name_buf, T('.'));
+ dot = tstrrchr(path_basename(swm_name_buf), T('.'));
if (dot) {
swm_base_name_len = dot - swm_name_buf;
swm_suffix = alloca((tstrlen(dot) + 1) * sizeof(tchar));
for (part_number = 1; part_number <= swm_info->num_parts; part_number++)
progress.split.total_bytes += swm_info->parts[part_number - 1].size;
progress.split.total_parts = swm_info->num_parts;
- progress.split.part_name = swm_name_buf;
- randomize_byte_array(guid, WIMLIB_GUID_LEN);
+ generate_guid(guid);
for (part_number = 1; part_number <= swm_info->num_parts; part_number++) {
int part_write_flags;
}
progress.split.cur_part_number = part_number;
- if (progress_func) {
- progress_func(WIMLIB_PROGRESS_MSG_SPLIT_BEGIN_PART,
- &progress);
- }
+ progress.split.part_name = swm_name_buf;
+
+ ret = call_progress(orig_wim->progfunc,
+ WIMLIB_PROGRESS_MSG_SPLIT_BEGIN_PART,
+ &progress,
+ orig_wim->progctx);
+ if (ret)
+ return ret;
- part_write_flags = write_flags & WIMLIB_WRITE_MASK_PUBLIC;
+ part_write_flags = write_flags;
part_write_flags |= WIMLIB_WRITE_FLAG_USE_EXISTING_TOTALBYTES;
if (part_number != 1)
part_write_flags |= WIMLIB_WRITE_FLAG_NO_METADATA;
ret = write_wim_part(orig_wim,
- swm_name_buf,
+ progress.split.part_name,
WIMLIB_ALL_IMAGES,
part_write_flags,
1,
- NULL,
part_number,
swm_info->num_parts,
- &swm_info->parts[part_number - 1].stream_list,
+ &swm_info->parts[part_number - 1].blob_list,
guid);
if (ret)
return ret;
progress.split.completed_bytes += swm_info->parts[part_number - 1].size;
- if (progress_func) {
- progress_func(WIMLIB_PROGRESS_MSG_SPLIT_END_PART,
- &progress);
- }
+
+ ret = call_progress(orig_wim->progfunc,
+ WIMLIB_PROGRESS_MSG_SPLIT_END_PART,
+ &progress,
+ orig_wim->progctx);
+ if (ret)
+ return ret;
}
return 0;
}
static int
-add_stream_to_swm(struct wim_lookup_table_entry *lte, void *_swm_info)
+start_new_swm_part(struct swm_info *swm_info)
{
- struct swm_info *swm_info = _swm_info;
- u64 stream_size;
-
- /* TODO */
- stream_size = lte->rspec->size_in_wim;
-
- /* - Start first part if no parts have been started so far;
- * - Start next part if adding this stream exceeds maximum part size,
- * UNLESS the stream is metadata or if no streams at all have been
- * added to the current part.
- */
- if (swm_info->num_parts == 0 ||
- ((swm_info->parts[swm_info->num_parts - 1].size +
- stream_size >= swm_info->max_part_size)
- && !((lte->flags & WIM_RESHDR_FLAG_METADATA) ||
- swm_info->parts[swm_info->num_parts - 1].size == 0)))
- {
- if (swm_info->num_parts == swm_info->num_alloc_parts) {
- struct swm_part_info *parts;
- size_t num_alloc_parts = swm_info->num_alloc_parts;
+ if (swm_info->num_parts == swm_info->num_alloc_parts) {
+ struct swm_part_info *parts;
+ size_t num_alloc_parts = swm_info->num_alloc_parts;
- num_alloc_parts += 8;
- parts = MALLOC(num_alloc_parts * sizeof(parts[0]));
- if (!parts)
- return WIMLIB_ERR_NOMEM;
+ num_alloc_parts += 8;
+ parts = MALLOC(num_alloc_parts * sizeof(parts[0]));
+ if (!parts)
+ return WIMLIB_ERR_NOMEM;
- for (unsigned i = 0; i < swm_info->num_parts; i++)
- copy_part_info(&parts[i], &swm_info->parts[i]);
+ for (unsigned i = 0; i < swm_info->num_parts; i++)
+ copy_part_info(&parts[i], &swm_info->parts[i]);
- FREE(swm_info->parts);
- swm_info->parts = parts;
- swm_info->num_alloc_parts = num_alloc_parts;
- }
- swm_info->num_parts++;
- INIT_LIST_HEAD(&swm_info->parts[swm_info->num_parts - 1].stream_list);
- swm_info->parts[swm_info->num_parts - 1].size = 0;
+ FREE(swm_info->parts);
+ swm_info->parts = parts;
+ swm_info->num_alloc_parts = num_alloc_parts;
+ }
+ swm_info->num_parts++;
+ INIT_LIST_HEAD(&swm_info->parts[swm_info->num_parts - 1].blob_list);
+ swm_info->parts[swm_info->num_parts - 1].size = 0;
+ return 0;
+}
+
+static int
+add_blob_to_swm(struct blob_descriptor *blob, void *_swm_info)
+{
+ struct swm_info *swm_info = _swm_info;
+ u64 blob_stored_size;
+ int ret;
+
+ if (blob->blob_location == BLOB_IN_WIM)
+ blob_stored_size = blob->rdesc->size_in_wim;
+ else
+ blob_stored_size = blob->size;
+
+ /* Start the next part if adding this blob exceeds the maximum part
+ * size, UNLESS the blob is metadata or if no blobs at all have been
+ * added to the current part. */
+ if ((swm_info->parts[swm_info->num_parts - 1].size +
+ blob_stored_size >= swm_info->max_part_size)
+ && !(blob->is_metadata ||
+ swm_info->parts[swm_info->num_parts - 1].size == 0))
+ {
+ ret = start_new_swm_part(swm_info);
+ if (ret)
+ return ret;
}
- swm_info->parts[swm_info->num_parts - 1].size += stream_size;
- if (!(lte->flags & WIM_RESHDR_FLAG_METADATA)) {
- list_add_tail(<e->write_streams_list,
- &swm_info->parts[swm_info->num_parts - 1].stream_list);
+ swm_info->parts[swm_info->num_parts - 1].size += blob_stored_size;
+ if (!blob->is_metadata) {
+ list_add_tail(&blob->write_blobs_list,
+ &swm_info->parts[swm_info->num_parts - 1].blob_list);
}
- swm_info->total_bytes += stream_size;
+ swm_info->total_bytes += blob_stored_size;
return 0;
}
/* API function documented in wimlib.h */
WIMLIBAPI int
wimlib_split(WIMStruct *wim, const tchar *swm_name,
- u64 part_size, int write_flags,
- wimlib_progress_func_t progress_func)
+ u64 part_size, int write_flags)
{
struct swm_info swm_info;
unsigned i;
if (swm_name == NULL || swm_name[0] == T('\0') || part_size == 0)
return WIMLIB_ERR_INVALID_PARAM;
+ if (write_flags & ~WIMLIB_WRITE_MASK_PUBLIC)
+ return WIMLIB_ERR_INVALID_PARAM;
+
if (!wim_has_metadata(wim))
return WIMLIB_ERR_METADATA_NOT_FOUND;
+ if (wim_has_solid_resources(wim)) {
+ ERROR("Splitting of WIM containing solid resources is not supported.\n"
+ " Export it in non-solid format first.");
+ return WIMLIB_ERR_UNSUPPORTED;
+ }
+
+ for (i = 0; i < wim->hdr.image_count; i++) {
+ if (!is_image_unchanged_from_wim(wim->image_metadata[i], wim)) {
+ ERROR("Only an unmodified, on-disk WIM file can be split.");
+ return WIMLIB_ERR_UNSUPPORTED;
+ }
+ }
+
memset(&swm_info, 0, sizeof(swm_info));
swm_info.max_part_size = part_size;
+ ret = start_new_swm_part(&swm_info);
+ if (ret)
+ goto out_free_swm_info;
+
for (i = 0; i < wim->hdr.image_count; i++) {
- ret = add_stream_to_swm(wim->image_metadata[i]->metadata_lte,
- &swm_info);
+ ret = add_blob_to_swm(wim->image_metadata[i]->metadata_blob,
+ &swm_info);
if (ret)
goto out_free_swm_info;
}
- ret = for_lookup_table_entry_pos_sorted(wim->lookup_table,
- add_stream_to_swm,
- &swm_info);
+ ret = for_blob_in_table_sorted_by_sequential_order(wim->blob_table,
+ add_blob_to_swm,
+ &swm_info);
if (ret)
goto out_free_swm_info;
- ret = write_split_wim(wim, swm_name, &swm_info, write_flags,
- progress_func);
+ ret = write_split_wim(wim, swm_name, &swm_info, write_flags);
out_free_swm_info:
FREE(swm_info.parts);
return ret;