goto err_free_imd;
metadata_lte->resource_entry.flags = WIM_RESHDR_FLAG_METADATA;
- random_hash(metadata_lte->hash);
- lookup_table_insert(w->lookup_table, metadata_lte);
new_imd = &imd[w->hdr.image_count];
hash = inode_stream_hash(inode, 0);
if (hash) {
tprintf(T("Hash = 0x"));
- print_hash(hash);
+ print_hash(hash, stdout);
tputchar(T('\n'));
tputchar(T('\n'));
}
hash = inode_stream_hash(inode, i + 1);
if (hash) {
tprintf(T("Hash = 0x"));
- print_hash(hash);
+ print_hash(hash, stdout);
tputchar(T('\n'));
}
print_lookup_table_entry(inode_stream_lte(inode, i + 1, lookup_table),
tprintf(T("Chunk Size = %u\n"), WIM_CHUNK_SIZE);
tfputs (T("GUID = "), stdout);
- print_byte_field(hdr->guid, WIM_GID_LEN);
+ print_byte_field(hdr->guid, WIM_GID_LEN, stdout);
tputchar(T('\n'));
tprintf(T("Part Number = %hu\n"), w->hdr.part_number);
tprintf(T("Total Parts = %hu\n"), w->hdr.total_parts);
progress_func(WIMLIB_PROGRESS_MSG_JOIN_STREAMS, &progress);
}
- /* Write the resources (streams and metadata resources) from each SWM
- * part */
- swms[0]->write_metadata = true;
+ /* Write the non-metadata resources from each SWM part */
for (i = 0; i < num_swms; i++) {
swms[i]->fp = tfopen(swms[i]->filename, T("rb"));
if (!swms[i]->fp) {
ret = for_lookup_table_entry(swms[i]->lookup_table,
copy_resource, swms[i]);
swms[i]->out_fp = NULL;
- fclose(swms[i]->fp);
- swms[i]->fp = NULL;
+
+ if (i != 0) {
+ fclose(swms[i]->fp);
+ swms[i]->fp = NULL;
+ }
if (ret != 0)
return ret;
}
}
+ /* Write metadata resources from the first SWM part */
+ swms[0]->out_fp = joined_wim->out_fp;
+ ret = for_image(swms[0], WIMLIB_ALL_IMAGES, write_metadata_resource);
+ swms[0]->out_fp = NULL;
+ fclose(swms[0]->fp);
+ swms[0]->fp = NULL;
+
+ if (ret)
+ return ret;
+
+ /* Write lookup table, XML data, and optional integrity table */
joined_wim->hdr.image_count = swms[0]->hdr.image_count;
for (i = 0; i < num_swms; i++)
lookup_table_join(joined_wim->lookup_table, swms[i]->lookup_table);
free_wim_info(joined_wim->wim_info);
joined_wim->wim_info = swms[0]->wim_info;
+ joined_wim->image_metadata = swms[0]->image_metadata;
ret = finish_write(joined_wim, WIMLIB_ALL_IMAGES, write_flags, progress_func);
joined_wim->wim_info = NULL;
+ joined_wim->image_metadata = NULL;
return ret;
}
hlist_for_each_entry_safe(lte, pos, tmp, &table->array[i],
hash_list)
{
+ wimlib_assert2(!(lte->resource_entry.flags & WIM_RESHDR_FLAG_METADATA));
ret = visitor(lte, arg);
if (ret != 0)
return ret;
/*
* Reads the lookup table from a WIM file.
+ *
+ * Saves lookup table entries for non-metadata streams in a hash table, and
+ * saves the metadata entry for each image in a special per-image location (the
+ * image_metadata array).
*/
int
read_lookup_table(WIMStruct *w)
u8 buf[WIM_LOOKUP_TABLE_ENTRY_DISK_SIZE];
int ret;
struct wim_lookup_table *table;
- struct wim_lookup_table_entry *cur_entry = NULL, *duplicate_entry;
+ struct wim_lookup_table_entry *cur_entry, *duplicate_entry;
if (resource_is_compressed(&w->hdr.lookup_table_res_entry)) {
ERROR("Didn't expect a compressed lookup table!");
if (!table)
return WIMLIB_ERR_NOMEM;
+ w->current_image = 0;
while (num_entries--) {
const u8 *p;
"table");
}
ret = WIMLIB_ERR_READ;
- goto out;
+ goto out_free_lookup_table;
}
cur_entry = new_lookup_table_entry();
if (!cur_entry) {
ret = WIMLIB_ERR_NOMEM;
- goto out;
+ goto out_free_lookup_table;
}
+
cur_entry->wim = w;
cur_entry->resource_location = RESOURCE_IN_WIM;
-
p = get_resource_entry(buf, &cur_entry->resource_entry);
p = get_u16(p, &cur_entry->part_number);
p = get_u32(p, &cur_entry->refcnt);
goto out_free_cur_entry;
}
- /* Ordinarily, no two streams should share the same SHA1 message
- * digest. However, this constraint can be broken for metadata
- * resources--- two identical images will have the same metadata
- * resource, but their lookup table entries are not shared. */
- duplicate_entry = __lookup_resource(table, cur_entry->hash);
- if (duplicate_entry
- && !((duplicate_entry->resource_entry.flags & WIM_RESHDR_FLAG_METADATA)
- && cur_entry->resource_entry.flags & WIM_RESHDR_FLAG_METADATA))
- {
- #ifdef ENABLE_ERROR_MESSAGES
- ERROR("The WIM lookup table contains two entries with the "
- "same SHA1 message digest!");
- ERROR("The first entry is:");
- print_lookup_table_entry(duplicate_entry, stderr);
- ERROR("The second entry is:");
- print_lookup_table_entry(cur_entry, stderr);
- #endif
- ret = WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY;
- goto out_free_cur_entry;
- }
-
if (!(cur_entry->resource_entry.flags & WIM_RESHDR_FLAG_COMPRESSED)
&& (cur_entry->resource_entry.size !=
cur_entry->resource_entry.original_size))
ret = WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY;
goto out_free_cur_entry;
}
- if ((cur_entry->resource_entry.flags & WIM_RESHDR_FLAG_METADATA)
- && cur_entry->refcnt != 1)
- {
- #ifdef ENABLE_ERROR_MESSAGES
- ERROR("Found metadata resource with refcnt != 1:");
- print_lookup_table_entry(cur_entry, stderr);
- #endif
- ret = WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY;
- goto out_free_cur_entry;
+
+ if (cur_entry->resource_entry.flags & WIM_RESHDR_FLAG_METADATA) {
+ /* Lookup table entry for a metadata resource */
+ if (cur_entry->refcnt != 1) {
+ #ifdef ENABLE_ERROR_MESSAGES
+ ERROR("Found metadata resource with refcnt != 1:");
+ print_lookup_table_entry(cur_entry, stderr);
+ #endif
+ ret = WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY;
+ goto out_free_cur_entry;
+ }
+
+ if (w->hdr.part_number != 1) {
+ ERROR("Found a metadata resource in a "
+ "non-first part of the split WIM!");
+ ret = WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY;
+ goto out_free_cur_entry;
+ }
+ if (w->current_image == w->hdr.image_count) {
+ ERROR("The WIM header says there are %u images "
+ "in the WIM, but we found more metadata "
+ "resources than this", w->hdr.image_count);
+ ret = WIMLIB_ERR_IMAGE_COUNT;
+ goto out_free_cur_entry;
+ }
+
+ /* Notice very carefully: We are assigning the metadata
+ * resources in the exact order mirrored by their lookup
+ * table entries on disk, which is the behavior of
+ * Microsoft's software. In particular, this overrides
+ * the actual locations of the metadata resources
+ * themselves in the WIM file as well as any information
+ * written in the XML data. */
+ DEBUG("Found metadata resource for image %u at "
+ "offset %"PRIu64".",
+ w->current_image + 1,
+ cur_entry->resource_entry.offset);
+ w->image_metadata[
+ w->current_image++].metadata_lte = cur_entry;
+ } else {
+ /* Lookup table entry for a stream that is not a
+ * metadata resource */
+ duplicate_entry = __lookup_resource(table, cur_entry->hash);
+ if (duplicate_entry) {
+ #ifdef ENABLE_ERROR_MESSAGES
+ ERROR("The WIM lookup table contains two entries with the "
+ "same SHA1 message digest!");
+ ERROR("The first entry is:");
+ print_lookup_table_entry(duplicate_entry, stderr);
+ ERROR("The second entry is:");
+ print_lookup_table_entry(cur_entry, stderr);
+ #endif
+ ret = WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY;
+ goto out_free_cur_entry;
+ }
+ lookup_table_insert(table, cur_entry);
}
- lookup_table_insert(table, cur_entry);
+ }
+ if (w->hdr.part_number == 1 &&
+ w->current_image != w->hdr.image_count)
+ {
+ ERROR("The WIM header says there are %u images "
+ "in the WIM, but we only found %d metadata "
+ "resources!", w->hdr.image_count, w->current_image);
+ ret = WIMLIB_ERR_IMAGE_COUNT;
+ goto out_free_lookup_table;
}
DEBUG("Done reading lookup table.");
w->lookup_table = table;
- return 0;
+ ret = 0;
+ goto out;
out_free_cur_entry:
FREE(cur_entry);
-out:
+out_free_lookup_table:
free_lookup_table(table);
+out:
+ w->current_image = 0;
return ret;
}
* Writes a lookup table entry to the output file.
*/
int
-write_lookup_table_entry(struct wim_lookup_table_entry *lte, void *__out)
+write_lookup_table_entry(struct wim_lookup_table_entry *lte, void *_out)
{
FILE *out;
u8 buf[WIM_LOOKUP_TABLE_ENTRY_DISK_SIZE];
u8 *p;
- out = __out;
+ out = _out;
/* Don't write entries that have not had file resources or metadata
* resources written for them. */
return 0;
}
-/* Writes the lookup table to the output file. */
+/* Writes the WIM lookup table to the output file. */
int
-write_lookup_table(struct wim_lookup_table *table, FILE *out,
- struct resource_entry *out_res_entry)
+write_lookup_table(WIMStruct *w, int image, struct resource_entry *out_res_entry)
{
+ FILE *out = w->out_fp;
off_t start_offset, end_offset;
int ret;
+ int start_image, end_image;
start_offset = ftello(out);
if (start_offset == -1)
return WIMLIB_ERR_WRITE;
- ret = for_lookup_table_entry(table, write_lookup_table_entry, out);
- if (ret != 0)
+ if (image == WIMLIB_ALL_IMAGES) {
+ start_image = 1;
+ end_image = w->hdr.image_count;
+ } else {
+ start_image = image;
+ end_image = image;
+ }
+ for (int i = start_image; i <= end_image; i++) {
+ struct wim_lookup_table_entry *metadata_lte;
+
+ metadata_lte = w->image_metadata[i - 1].metadata_lte;
+ metadata_lte->out_refcnt = 1;
+ metadata_lte->output_resource_entry.flags |= WIM_RESHDR_FLAG_METADATA;
+ ret = write_lookup_table_entry(metadata_lte, out);
+ if (ret)
+ return ret;
+ }
+
+ ret = for_lookup_table_entry(w->lookup_table, write_lookup_table_entry, out);
+ if (ret)
return ret;
end_offset = ftello(out);
out_res_entry->size = end_offset - start_offset;
out_res_entry->original_size = end_offset - start_offset;
out_res_entry->flags = WIM_RESHDR_FLAG_METADATA;
-
return 0;
}
tfprintf(out, T("Reference Count = %u\n"), lte->refcnt);
tfprintf(out, T("Hash = 0x"));
- print_hash(lte->hash);
+ print_hash(lte->hash, out);
tputc(T('\n'), out);
tfprintf(out, T("Flags = "));
read_lookup_table(WIMStruct *w);
extern int
-write_lookup_table(struct wim_lookup_table *table, FILE *out,
- struct resource_entry *out_res_entry);
+write_lookup_table(WIMStruct *w, int image, struct resource_entry *out_res_entry);
+
extern void
free_lookup_table(struct wim_lookup_table *table);
u64 metadata_original_size;
struct wim_security_data *sd;
+ wimlib_assert(w->out_fp != NULL);
+ wimlib_assert(w->current_image != WIMLIB_NO_IMAGE);
+
DEBUG("Writing metadata resource for image %d (offset = %"PRIu64")",
w->current_image, ftello(w->out_fp));
+
root = wim_root_dentry(w);
sd = wim_security_data(w);
if (ret != 0)
goto out;
- /* It's very likely the SHA1 message digest of the metadata resource
- * changed, so re-insert the lookup table entry into the lookup table.
- *
- * We do not check for other lookup table entries having the same SHA1
- * message digest. It's possible for 2 absolutely identical images to
- * be added, therefore causing 2 identical metadata resources to be in
- * the WIM. However, in this case, it's expected for 2 separate lookup
- * table entries to be created, even though this doesn't make a whole
- * lot of sense since they will share the same SHA1 message digest.
- * */
- lookup_table_unlink(w->lookup_table, lte);
- lookup_table_insert(w->lookup_table, lte);
+ /* Note that although the SHA1 message digest of the metadata resource
+ * is very likely to have changed, the corresponding lookup table entry
+ * is not actually located in the hash table, so it need not be
+ * re-inserted in the hash table. */
lte->out_refcnt = 1;
-
- /* Make sure that the lookup table entry for this metadata resource is
- * marked with the metadata flag. */
lte->output_resource_entry.flags |= WIM_RESHDR_FLAG_METADATA;
out:
/* All the data has been written to the new WIM; no need for the buffer
WIMStruct *w = wim;
int ret;
- if ((lte->resource_entry.flags & WIM_RESHDR_FLAG_METADATA) &&
- !w->write_metadata)
- return 0;
-
ret = write_wim_resource(lte, w->out_fp,
wim_resource_compression_type(lte),
<e->output_resource_entry, 0);
- if (ret != 0)
- return ret;
- lte->out_refcnt = lte->refcnt;
- lte->part_number = w->hdr.part_number;
- return 0;
+ if (ret == 0) {
+ lte->out_refcnt = lte->refcnt;
+ lte->part_number = w->hdr.part_number;
+ }
+ return ret;
}
tprintf(T(" Subauthority count = %u\n"), sid->sub_authority_count);
tprintf(T(" Identifier authority = "));
print_byte_field(sid->identifier_authority,
- sizeof(sid->identifier_authority));
+ sizeof(sid->identifier_authority), stdout);
tputchar(T('\n'));
for (u8 i = 0; i < sid->sub_authority_count; i++) {
tprintf(T(" Subauthority %u = %u\n"),
}
static inline void
-print_hash(const u8 hash[SHA1_HASH_SIZE])
+print_hash(const u8 hash[SHA1_HASH_SIZE], FILE *out)
{
- print_byte_field(hash, SHA1_HASH_SIZE);
+ print_byte_field(hash, SHA1_HASH_SIZE, out);
}
static inline bool
}
args->size_remaining -= lte->resource_entry.size;
args->progress.split.completed_bytes += lte->resource_entry.size;
- list_add(<e->staging_list, &args->lte_list);
+ list_add_tail(<e->staging_list, &args->lte_list);
return copy_resource(lte, w);
}
&args.progress);
}
- w->write_metadata = true;
for (int i = 0; i < w->hdr.image_count; i++) {
struct wim_lookup_table_entry *metadata_lte;
metadata_lte = w->image_metadata[i].metadata_lte;
goto out;
args.size_remaining -= metadata_lte->resource_entry.size;
args.progress.split.completed_bytes += metadata_lte->resource_entry.size;
- list_add(&metadata_lte->staging_list, &args.lte_list);
+ /* Careful: The metadata lookup table entries must be added in
+ * order of the images. */
+ list_add_tail(&metadata_lte->staging_list, &args.lte_list);
}
- w->write_metadata = false;
ret = for_lookup_table_entry(w->lookup_table,
copy_resource_to_swm, &args);
path_stream_name(const tchar *path);
static inline void
-print_byte_field(const u8 field[], size_t len)
+print_byte_field(const u8 field[], size_t len, FILE *out)
{
while (len--)
- tprintf(T("%02hhx"), *field++);
+ tfprintf(out, T("%02hhx"), *field++);
}
static inline u32
int ret;
for_lookup_table_entry(w->lookup_table, lte_zero_real_refcnt, NULL);
+
+ w->all_images_verified = 1; /* Set *before* image_run_full_verifications,
+ because of check in read_metadata_resource() */
ret = for_image(w, WIMLIB_ALL_IMAGES, image_run_full_verifications);
if (ret == 0) {
- w->all_images_verified = 1;
-
unsigned long num_ltes_with_bogus_refcnt = 0;
for (int i = 0; i < w->hdr.image_count; i++)
w->image_metadata[i].metadata_lte->real_refcnt++;
" their reference counts fixed.",
num_ltes_with_bogus_refcnt);
}
+ } else {
+ w->all_images_verified = 0;
}
return ret;
}
return 0;
}
-static int
-sort_image_metadata_by_position(const void *p1, const void *p2)
-{
- const struct wim_image_metadata *imd1 = p1;
- const struct wim_image_metadata *imd2 = p2;
- u64 offset1 = imd1->metadata_lte->resource_entry.offset;
- u64 offset2 = imd2->metadata_lte->resource_entry.offset;
- if (offset1 < offset2)
- return -1;
- else if (offset1 > offset2)
- return 1;
- else
- return 0;
-}
-
-/*
- * If @lte points to a metadata resource, append it to the list of metadata
- * resources in the WIMStruct. Otherwise, do nothing.
- */
-static int
-append_metadata_resource_entry(struct wim_lookup_table_entry *lte, void *wim_p)
-{
- WIMStruct *w = wim_p;
- int ret = 0;
-
- if (lte->resource_entry.flags & WIM_RESHDR_FLAG_METADATA) {
- if (w->current_image == w->hdr.image_count) {
- ERROR("The WIM header says there are %u images in the WIM,\n"
- " but we found more metadata resources than this",
- w->hdr.image_count);
- ret = WIMLIB_ERR_IMAGE_COUNT;
- } else {
- DEBUG("Found metadata resource for image %u at "
- "offset %"PRIu64".",
- w->current_image + 1,
- lte->resource_entry.offset);
- w->image_metadata[
- w->current_image++].metadata_lte = lte;
- }
- }
- return ret;
-}
-
/* Returns the compression type given in the flags of a WIM header. */
static int
wim_hdr_flags_compression_type(int wim_hdr_flags)
#ifdef ENABLE_DEBUG
DEBUG("Reading metadata resource specified by the following "
"lookup table entry:");
- print_lookup_table_entry(imd->metadata_lte, stdout);
+ print_lookup_table_entry(imd->metadata_lte, stderr);
#endif
ret = read_metadata_resource(w, imd);
if (ret)
tputs(T("----------------"));
tprintf(T("Path: %"TS"\n"), w->filename);
tfputs(T("GUID: 0x"), stdout);
- print_byte_field(hdr->guid, WIM_GID_LEN);
+ print_byte_field(hdr->guid, WIM_GID_LEN, stdout);
tputchar(T('\n'));
tprintf(T("Image Count: %d\n"), hdr->image_count);
tprintf(T("Compression: %"TS"\n"),
}
ret = read_header(w->fp, &w->hdr, open_flags);
- if (ret != 0)
+ if (ret)
return ret;
DEBUG("According to header, WIM contains %u images", w->hdr.image_count);
}
}
- ret = read_lookup_table(w);
- if (ret != 0)
- return ret;
-
- if (w->hdr.image_count != 0) {
+ if (w->hdr.image_count != 0 && w->hdr.part_number == 1) {
w->image_metadata = CALLOC(w->hdr.image_count,
sizeof(struct wim_image_metadata));
return WIMLIB_ERR_NOMEM;
}
}
- w->current_image = 0;
-
- DEBUG("Looking for metadata resources in the lookup table.");
- /* Find the images in the WIM by searching the lookup table. */
- ret = for_lookup_table_entry(w->lookup_table,
- append_metadata_resource_entry, w);
-
- if (ret != 0)
+ ret = read_lookup_table(w);
+ if (ret)
return ret;
- /* Make sure all the expected images were found. (We already have
- * returned WIMLIB_ERR_IMAGE_COUNT if *extra* images were found) */
- if (w->current_image != w->hdr.image_count &&
- w->hdr.part_number == 1)
- {
- ERROR("Only found %d images in WIM, but expected %u",
- w->current_image, w->hdr.image_count);
- return WIMLIB_ERR_IMAGE_COUNT;
- }
-
- /* Sort images by the position of their metadata resources. I'm
- * assuming that is what determines the other of the images in the WIM
- * file, rather than their order in the lookup table, which is random
- * because of hashing. */
- qsort(w->image_metadata, w->current_image,
- sizeof(struct wim_image_metadata), sort_image_metadata_by_position);
-
- w->current_image = WIMLIB_NO_IMAGE;
-
- /* Read the XML data. */
ret = read_xml_data(w->fp, &w->hdr.xml_res_entry,
&w->xml_data, &w->wim_info);
-
- if (ret != 0)
+ if (ret)
return ret;
xml_num_images = wim_info_get_num_images(w->wim_info);
{
free_dentry_tree(imd->root_dentry, table);
free_security_data(imd->security_data);
-
- /* Get rid of the lookup table entry for this image's metadata resource
- * */
- if (table) {
- lookup_table_unlink(table, imd->metadata_lte);
+ if (table)
free_lookup_table_entry(imd->metadata_lte);
- }
}
/* Frees the memory for the WIMStruct, including all internal memory; also
FREE(w->xml_data);
free_wim_info(w->wim_info);
if (w->image_metadata) {
- for (unsigned i = 0; i < w->hdr.image_count; i++)
+ for (unsigned i = 0; i < w->hdr.image_count; i++) {
destroy_image_metadata(&w->image_metadata[i], NULL);
+ free_lookup_table_entry(w->image_metadata[i].metadata_lte);
+ }
FREE(w->image_metadata);
}
#ifdef WITH_NTFS_3G
/* The header of the WIM file. */
struct wim_header hdr;
- /* Temporary fields */
- union {
- bool write_metadata;
- void *private;
- };
+ /* Temporary field */
+ void *private;
+
#ifdef WITH_NTFS_3G
struct _ntfs_volume *ntfs_vol;
#endif
lte->out_refcnt = lte->refcnt;
memcpy(<e->output_resource_entry, <e->resource_entry,
sizeof(struct resource_entry));
- if (!(lte->resource_entry.flags & WIM_RESHDR_FLAG_METADATA)) {
- wimlib_assert(lte->resource_location != RESOURCE_NONEXISTENT);
+ if (!(lte->resource_entry.flags & WIM_RESHDR_FLAG_METADATA))
if (lte->resource_location != RESOURCE_IN_WIM || lte->wim != args->wim)
list_add(<e->staging_list, args->stream_list);
- }
return 0;
}
static int
-wim_find_new_streams(WIMStruct *wim, off_t end_offset,
- struct list_head *stream_list)
+wim_prepare_streams(WIMStruct *wim, off_t end_offset,
+ struct list_head *stream_list)
{
struct lte_overwrite_prepare_args args = {
.wim = wim,
.end_offset = end_offset,
.stream_list = stream_list,
};
+ int ret;
+ for (int i = 0; i < wim->hdr.image_count; i++) {
+ ret = lte_overwrite_prepare(wim->image_metadata[i].metadata_lte,
+ &args);
+ if (ret)
+ return ret;
+ }
return for_lookup_table_entry(wim->lookup_table,
lte_overwrite_prepare, &args);
}
memcpy(&hdr, &w->hdr, sizeof(struct wim_header));
if (!(write_flags & WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE)) {
- ret = write_lookup_table(w->lookup_table, out, &hdr.lookup_table_res_entry);
+ ret = write_lookup_table(w, image, &hdr.lookup_table_res_entry);
if (ret != 0)
goto out;
}
WIMLIB_WRITE_FLAG_CHECKPOINT_AFTER_XML;
}
INIT_LIST_HEAD(&stream_list);
- ret = wim_find_new_streams(w, old_wim_end, &stream_list);
+ ret = wim_prepare_streams(w, old_wim_end, &stream_list);
if (ret != 0)
return ret;