*/
/*
- * Copyright (C) 2012, 2013, 2014, 2015 Eric Biggers
+ * Copyright (C) 2012-2016 Eric Biggers
*
* 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
#include "wimlib/assert.h"
#include "wimlib/bitops.h"
#include "wimlib/blob_table.h"
+#include "wimlib/dentry.h"
#include "wimlib/encoding.h"
#include "wimlib/endianness.h"
#include "wimlib/error.h"
#include "wimlib/resource.h"
#include "wimlib/unaligned.h"
#include "wimlib/util.h"
+#include "wimlib/win32.h"
#include "wimlib/write.h"
/* A hash table mapping SHA-1 message digests to blob descriptors */
size_t mask; /* capacity - 1; capacity is a power of 2 */
};
-static size_t
-next_power_of_2(size_t n)
-{
- if (n <= 1)
- return 1;
- return (size_t)1 << (1 + flsw(n - 1));
-}
-
struct blob_table *
new_blob_table(size_t capacity)
{
struct blob_table *table;
struct hlist_head *array;
- capacity = next_power_of_2(capacity);
+ capacity = roundup_pow_of_2(capacity);
table = MALLOC(sizeof(struct blob_table));
if (table == NULL)
break;
case BLOB_IN_FILE_ON_DISK:
-#ifdef __WIN32__
- case BLOB_IN_WINNT_FILE_ON_DISK:
- case BLOB_WIN32_ENCRYPTED:
-#endif
#ifdef WITH_FUSE
case BLOB_IN_STAGING_FILE:
STATIC_ASSERT((void*)&old->file_on_disk ==
if (new->file_on_disk == NULL)
goto out_free;
break;
+#ifdef __WIN32__
+ case BLOB_IN_WINDOWS_FILE:
+ new->windows_file = clone_windows_file(old->windows_file);
+ break;
+#endif
case BLOB_IN_ATTACHED_BUFFER:
new->attached_buffer = memdup(old->attached_buffer, old->size);
if (new->attached_buffer == NULL)
return NULL;
}
-static void
+/* Release a blob descriptor from its location, if any, and set its new location
+ * to BLOB_NONEXISTENT. */
+void
blob_release_location(struct blob_descriptor *blob)
{
switch (blob->blob_location) {
- case BLOB_IN_WIM:
+ case BLOB_IN_WIM: {
+ struct wim_resource_descriptor *rdesc = blob->rdesc;
+
list_del(&blob->rdesc_node);
- if (list_empty(&blob->rdesc->blob_list))
- FREE(blob->rdesc);
+ if (list_empty(&rdesc->blob_list)) {
+ wim_decrement_refcnt(rdesc->wim);
+ FREE(rdesc);
+ }
break;
+ }
case BLOB_IN_FILE_ON_DISK:
-#ifdef __WIN32__
- case BLOB_IN_WINNT_FILE_ON_DISK:
- case BLOB_WIN32_ENCRYPTED:
-#endif
#ifdef WITH_FUSE
case BLOB_IN_STAGING_FILE:
STATIC_ASSERT((void*)&blob->file_on_disk ==
(void*)&blob->attached_buffer);
FREE(blob->file_on_disk);
break;
+#ifdef __WIN32__
+ case BLOB_IN_WINDOWS_FILE:
+ free_windows_file(blob->windows_file);
+ break;
+#endif
#ifdef WITH_NTFS_3G
case BLOB_IN_NTFS_VOLUME:
- if (blob->ntfs_loc)
- free_ntfs_location(blob->ntfs_loc);
+ free_ntfs_location(blob->ntfs_loc);
break;
#endif
}
+ blob->blob_location = BLOB_NONEXISTENT;
}
void
v = (int)blob1->blob_location - (int)blob2->blob_location;
- /* Different locations? */
+ /* Different locations? Note: "unsafe compaction mode" requires that
+ * blobs in WIMs sort before all others. For the logic here to ensure
+ * this, BLOB_IN_WIM must have the lowest value among all defined
+ * blob_locations. Statically verify that the enum values haven't
+ * changed. */
+ STATIC_ASSERT(BLOB_NONEXISTENT == 0 && BLOB_IN_WIM == 1);
if (v)
return v;
/* Different WIM files? */
if (wim1 != wim2) {
+ /* Resources from the WIM file currently being compacted
+ * (if any) must always sort first. */
+ v = (int)wim2->being_compacted - (int)wim1->being_compacted;
+ if (v)
+ return v;
+
/* Different split WIMs? */
v = cmp_guids(wim1->hdr.guid, wim2->hdr.guid);
if (v)
case BLOB_IN_FILE_ON_DISK:
#ifdef WITH_FUSE
case BLOB_IN_STAGING_FILE:
-#endif
-#ifdef __WIN32__
- case BLOB_IN_WINNT_FILE_ON_DISK:
- case BLOB_WIN32_ENCRYPTED:
- /* Windows: compare by starting LCN (logical cluster number) */
- v = cmp_u64(blob1->sort_key, blob2->sort_key);
- if (v)
- return v;
#endif
/* Compare files by path: just a heuristic that will place files
* in the same directory next to each other. */
return tstrcmp(blob1->file_on_disk, blob2->file_on_disk);
+#ifdef __WIN32__
+ case BLOB_IN_WINDOWS_FILE:
+ return cmp_windows_files(blob1->windows_file, blob2->windows_file);
+#endif
#ifdef WITH_NTFS_3G
case BLOB_IN_NTFS_VOLUME:
return cmp_ntfs_locations(blob1->ntfs_loc, blob2->ntfs_loc);
if (ret)
goto out_free_rdescs;
+ wim->refcnt += num_rdescs;
+
*rdescs_ret = rdescs;
*num_rdescs_ret = num_rdescs;
return 0;
free_solid_rdescs(struct wim_resource_descriptor **rdescs, size_t num_rdescs)
{
if (rdescs) {
- for (size_t i = 0; i < num_rdescs; i++)
- if (list_empty(&rdescs[i]->blob_list))
+ for (size_t i = 0; i < num_rdescs; i++) {
+ if (list_empty(&rdescs[i]->blob_list)) {
+ rdescs[i]->wim->refcnt--;
FREE(rdescs[i]);
+ }
+ }
FREE(rdescs);
}
}
if (!table)
goto oom;
- /* Allocate and initalize blob descriptors from the raw blob table
+ /* Allocate and initialize blob descriptors from the raw blob table
* buffer. */
for (size_t i = 0; i < num_entries; i++) {
const struct blob_descriptor_disk *disk_entry =
goto oom;
wim_reshdr_to_desc_and_blob(&reshdr, wim, rdesc, cur_blob);
+ wim->refcnt++;
}
/* cur_blob is now a blob bound to a resource. */
}
if (reshdr.flags & WIM_RESHDR_FLAG_METADATA) {
-
- cur_blob->is_metadata = 1;
-
/* Blob table entry for a metadata resource. */
/* Metadata entries with no references must be ignored.
* this overrides the actual locations of the metadata
* resources themselves in the WIM file as well as any
* information written in the XML data. */
- wim->image_metadata[image_index++]->metadata_blob = cur_blob;
+ wim->image_metadata[image_index] = new_unloaded_image_metadata(cur_blob);
+ if (!wim->image_metadata[image_index])
+ goto oom;
+ image_index++;
} else {
/* Blob table entry for a non-metadata blob. */
if (wim->hdr.part_number == 1 && image_index != wim->hdr.image_count) {
WARNING("Could not find metadata resources for all images");
- for (u32 i = image_index; i < wim->hdr.image_count; i++)
- put_image_metadata(wim->image_metadata[i], NULL);
wim->hdr.image_count = image_index;
}
struct blob_descriptor *
after_blob_hashed(struct blob_descriptor *blob,
struct blob_descriptor **back_ptr,
- struct blob_table *blob_table)
+ struct blob_table *blob_table, struct wim_inode *inode)
{
struct blob_descriptor *duplicate_blob;
* this blob to the duplicate and update the reference to this
* blob (from a stream) to point to the duplicate. The caller
* is responsible for freeing @blob if needed. */
- wimlib_assert(duplicate_blob->size == blob->size);
+ if (duplicate_blob->size != blob->size) {
+ tchar hash_str[SHA1_HASH_SIZE * 2 + 1];
+
+ sprint_hash(blob->hash, hash_str);
+ WARNING("SHA-1 collision at \"%"TS"\"\n"
+ " (hash=%"TS", size=%"PRIu64", other_size=%"PRIu64").\n"
+ " File will be corrupted!",
+ inode_any_full_path(inode), hash_str,
+ blob->size, duplicate_blob->size);
+ }
duplicate_blob->refcnt += blob->refcnt;
blob->refcnt = 0;
*back_ptr = duplicate_blob;
struct blob_descriptor **blob_ret)
{
struct blob_descriptor **back_ptr;
+ struct wim_inode *inode;
int ret;
back_ptr = retrieve_pointer_to_unhashed_blob(blob);
+ inode = blob->back_inode;
ret = sha1_blob(blob);
if (ret)
return ret;
- *blob_ret = after_blob_hashed(blob, back_ptr, blob_table);
+ *blob_ret = after_blob_hashed(blob, back_ptr, blob_table, inode);
return 0;
}