lte = CALLOC(1, sizeof(struct wim_lookup_table_entry));
if (lte) {
- lte->part_number = 1;
- lte->refcnt = 1;
+ lte->part_number = 1;
+ lte->refcnt = 1;
+ BUILD_BUG_ON(RESOURCE_NONEXISTENT != 0);
+ BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_NONE != 0);
} else {
ERROR("Out of memory (tried to allocate %zu bytes for "
"lookup table entry)",
return 1;
return 0;
case RESOURCE_IN_FILE_ON_DISK:
+#ifdef WITH_FUSE
+ case RESOURCE_IN_STAGING_FILE:
+#endif
#ifdef __WIN32__
case RESOURCE_WIN32_ENCRYPTED:
#endif
if (cur_entry->resource_entry.flags & WIM_RESHDR_FLAG_METADATA) {
/* Lookup table entry for a metadata resource */
if (cur_entry->refcnt != 1) {
+ /* Metadata entries with no references must be
+ * ignored. See for example the WinPE WIMs from
+ * WAIK v2.1. */
+ if (cur_entry->refcnt == 0) {
+ free_lookup_table_entry(cur_entry);
+ continue;
+ }
if (wimlib_print_errors) {
ERROR("Found metadata resource with refcnt != 1:");
print_lookup_table_entry(cur_entry, stderr);
} else {
/* Lookup table entry for a stream that is not a
* metadata resource */
- duplicate_entry = __lookup_resource(table, cur_entry->hash);
+ duplicate_entry = lookup_resource(table, cur_entry->hash);
if (duplicate_entry) {
if (wimlib_print_errors) {
WARNING("The WIM lookup table contains two entries with the "
write_wim_lookup_table_from_stream_list(struct list_head *stream_list,
struct filedes *out_fd,
struct resource_entry *out_res_entry,
- int write_resource_flags)
+ int write_resource_flags,
+ struct wimlib_lzx_context **comp_ctx)
{
size_t table_size;
struct wim_lookup_table_entry *lte;
WIM_RESHDR_FLAG_METADATA,
out_fd,
WIMLIB_COMPRESSION_TYPE_NONE,
+ 0,
out_res_entry,
NULL,
- write_resource_flags);
+ write_resource_flags,
+ comp_ctx);
FREE(table_buf);
+ DEBUG("ret=%d", ret);
return ret;
}
static int
append_lookup_table_entry(struct wim_lookup_table_entry *lte, void *_list)
{
- if (lte->out_refcnt != 0)
+ /* Lookup table entries with 'out_refcnt' == 0 correspond to streams not
+ * written and not present in the resulting WIM file, and should not be
+ * included in the lookup table.
+ *
+ * Lookup table entries marked as filtered (EXTERNAL_WIM) with
+ * 'out_refcnt != 0' were referenced as part of the logical write but
+ * correspond to streams that were not in fact written, and should not
+ * be included in the lookup table.
+ *
+ * Lookup table entries marked as filtered (SAME_WIM) with 'out_refcnt
+ * != 0' were referenced as part of the logical write but correspond to
+ * streams that were not in fact written, but nevertheless were already
+ * present in the WIM being overwritten in-place. These entries must be
+ * included in the lookup table, and the resource information to write
+ * needs to be copied from the resource information read originally.
+ */
+ if (lte->out_refcnt != 0 && !(lte->filtered & FILTERED_EXTERNAL_WIM)) {
+ if (lte->filtered & FILTERED_SAME_WIM) {
+ copy_resource_entry(<e->output_resource_entry,
+ <e->resource_entry);
+ }
list_add_tail(<e->lookup_table_list, (struct list_head*)_list);
+ }
return 0;
}
}
}
- /* Append additional lookup table entries that have out_refcnt != 0. */
+ /* Append additional lookup table entries that need to be written, with
+ * some special handling for streams that have been marked as filtered.
+ */
if (!stream_list_override) {
for_lookup_table_entry(wim->lookup_table,
append_lookup_table_entry, stream_list);
return write_wim_lookup_table_from_stream_list(stream_list,
&wim->out_fd,
out_res_entry,
- write_resource_flags);
+ write_resource_flags,
+ &wim->lzx_context);
}
/* Given a SHA1 message digest, return the corresponding entry in the WIM's
* lookup table, or NULL if there is none. */
struct wim_lookup_table_entry *
-__lookup_resource(const struct wim_lookup_table *table, const u8 hash[])
+lookup_resource(const struct wim_lookup_table *table, const u8 hash[])
{
size_t i;
struct wim_lookup_table_entry *lte;
* This is only for pre-resolved inodes.
*/
int
-lookup_resource(WIMStruct *wim,
- const tchar *path,
- int lookup_flags,
- struct wim_dentry **dentry_ret,
- struct wim_lookup_table_entry **lte_ret,
- u16 *stream_idx_ret)
+wim_pathname_to_stream(WIMStruct *wim,
+ const tchar *path,
+ int lookup_flags,
+ struct wim_dentry **dentry_ret,
+ struct wim_lookup_table_entry **lte_ret,
+ u16 *stream_idx_ret)
{
struct wim_dentry *dentry;
struct wim_lookup_table_entry *lte;
return -ENOENT;
}
} else {
- lte = inode->i_lte;
- stream_idx = 0;
+ lte = inode_unnamed_stream_resolved(inode, &stream_idx);
}
out:
if (dentry_ret)
#endif
int
-resource_not_found_error(struct wim_inode *inode, const u8 *hash)
+resource_not_found_error(const struct wim_inode *inode, const u8 *hash)
{
if (wimlib_print_errors) {
ERROR("\"%"TS"\": resource not found", inode_first_full_path(inode));
lte = NULL;
hash = inode->i_hash;
if (!is_zero_hash(hash)) {
- lte = __lookup_resource(table, hash);
+ lte = lookup_resource(table, hash);
if (!lte) {
if (force) {
lte = new_lookup_table_entry();
cur_entry = &inode->i_ads_entries[i];
hash = cur_entry->hash;
if (!is_zero_hash(hash)) {
- ads_lte = __lookup_resource(table, hash);
+ ads_lte = lookup_resource(table, hash);
if (!ads_lte) {
if (force) {
ads_lte = new_lookup_table_entry();
}
struct wim_lookup_table_entry *
-inode_unnamed_lte_resolved(const struct wim_inode *inode)
+inode_unnamed_stream_resolved(const struct wim_inode *inode, u16 *stream_idx_ret)
{
wimlib_assert(inode->i_resolved);
for (unsigned i = 0; i <= inode->i_num_ads; i++) {
if (inode_stream_name_nbytes(inode, i) == 0 &&
!is_zero_hash(inode_stream_hash_resolved(inode, i)))
{
+ *stream_idx_ret = i;
return inode_stream_lte_resolved(inode, i);
}
}
+ *stream_idx_ret = 0;
return NULL;
}
+struct wim_lookup_table_entry *
+inode_unnamed_lte_resolved(const struct wim_inode *inode)
+{
+ u16 stream_idx;
+ return inode_unnamed_stream_resolved(inode, &stream_idx);
+}
+
struct wim_lookup_table_entry *
inode_unnamed_lte_unresolved(const struct wim_inode *inode,
const struct wim_lookup_table *table)
return inode_unnamed_lte_unresolved(inode, table);
}
+/* Returns the SHA1 message digest of the unnamed data stream of a WIM inode, or
+ * 'zero_hash' if the unnamed data stream is missing has all zeroes in its SHA1
+ * message digest field. */
+const u8 *
+inode_unnamed_stream_hash(const struct wim_inode *inode)
+{
+ const u8 *hash;
+
+ for (unsigned i = 0; i <= inode->i_num_ads; i++) {
+ if (inode_stream_name_nbytes(inode, i) == 0) {
+ hash = inode_stream_hash(inode, i);
+ if (!is_zero_hash(hash))
+ return hash;
+ }
+ }
+ return zero_hash;
+}
+
+
static int
lte_add_stream_size(struct wim_lookup_table_entry *lte, void *total_bytes_p)
{
return ret;
/* Look for a duplicate stream */
- duplicate_lte = __lookup_resource(lookup_table, lte->hash);
+ duplicate_lte = lookup_resource(lookup_table, lte->hash);
list_del(<e->unhashed_list);
if (duplicate_lte) {
/* We have a duplicate stream. Transfer the reference counts
* duplicate, then free this stream. */
wimlib_assert(!(duplicate_lte->unhashed));
duplicate_lte->refcnt += lte->refcnt;
- duplicate_lte->out_refcnt += lte->refcnt;
+ duplicate_lte->out_refcnt += lte->out_refcnt;
*back_ptr = duplicate_lte;
free_lookup_table_entry(lte);
lte = duplicate_lte;
}
static int
-move_lte_to_table(struct wim_lookup_table_entry *lte, void *_combined_table)
+lte_clone_if_new(struct wim_lookup_table_entry *lte, void *_lookup_table)
{
- struct wim_lookup_table *combined_table = _combined_table;
+ struct wim_lookup_table *lookup_table = _lookup_table;
- hlist_del(<e->hash_list);
- lookup_table_insert(combined_table, lte);
- return 0;
-}
+ if (lookup_resource(lookup_table, lte->hash))
+ return 0; /* Resource already present. */
-static void
-lookup_table_join(struct wim_lookup_table *combined_table,
- struct wim_lookup_table *part_table)
-{
- for_lookup_table_entry(part_table, move_lte_to_table, combined_table);
- part_table->num_entries = 0;
-}
-
-static void
-merge_lookup_tables(WIMStruct *wim, WIMStruct **resource_wims,
- unsigned num_resource_wims)
-{
- for (unsigned i = 0; i < num_resource_wims; i++) {
- lookup_table_join(wim->lookup_table, resource_wims[i]->lookup_table);
- list_add(&resource_wims[i]->resource_wim_node, &wim->resource_wims);
- resource_wims[i]->master_wim = wim;
- }
+ lte = clone_lookup_table_entry(lte);
+ if (!lte)
+ return WIMLIB_ERR_NOMEM;
+ lte->out_refcnt = 1;
+ lookup_table_insert(lookup_table, lte);
+ return 0;
}
static int
-move_lte_to_orig_table(struct wim_lookup_table_entry *lte, void *_wim)
+lte_delete_if_new(struct wim_lookup_table_entry *lte, void *_lookup_table)
{
- WIMStruct *wim = _wim;
+ struct wim_lookup_table *lookup_table = _lookup_table;
- if (lte->resource_location == RESOURCE_IN_WIM &&
- lte->wim->being_unmerged)
- {
- move_lte_to_table(lte, lte->wim->lookup_table);
- wim->lookup_table->num_entries--;
+ if (lte->out_refcnt) {
+ lookup_table_unlink(lookup_table, lte);
+ free_lookup_table_entry(lte);
}
return 0;
}
-static int
-check_reference_params(WIMStruct *wim,
- WIMStruct **resource_wims, unsigned num_resource_wims,
- WIMStruct *expected_master)
+/* API function documented in wimlib.h */
+WIMLIBAPI int
+wimlib_reference_resources(WIMStruct *wim,
+ WIMStruct **resource_wims, unsigned num_resource_wims,
+ int ref_flags)
{
- if (wim == NULL)
- return WIMLIB_ERR_INVALID_PARAM;
+ int ret;
+ unsigned i;
- if (wim->hdr.part_number != 1)
+ if (wim == NULL)
return WIMLIB_ERR_INVALID_PARAM;
if (num_resource_wims != 0 && resource_wims == NULL)
return WIMLIB_ERR_INVALID_PARAM;
- for (unsigned i = 0; i < num_resource_wims; i++) {
+ for (i = 0; i < num_resource_wims; i++)
if (resource_wims[i] == NULL)
return WIMLIB_ERR_INVALID_PARAM;
- if (resource_wims[i]->master_wim != expected_master)
- return WIMLIB_ERR_INVALID_PARAM;
- }
- return 0;
-}
-/* API function documented in wimlib.h */
-WIMLIBAPI int
-wimlib_reference_resources(WIMStruct *wim,
- WIMStruct **resource_wims, unsigned num_resource_wims,
- int ref_flags)
-{
- int ret;
-
- ret = check_reference_params(wim, resource_wims,
- num_resource_wims, NULL);
- if (ret)
- return ret;
+ for_lookup_table_entry(wim->lookup_table, lte_zero_out_refcnt, NULL);
- merge_lookup_tables(wim, resource_wims, num_resource_wims);
+ for (i = 0; i < num_resource_wims; i++) {
+ ret = for_lookup_table_entry(resource_wims[i]->lookup_table,
+ lte_clone_if_new,
+ wim->lookup_table);
+ if (ret)
+ goto out_rollback;
+ }
return 0;
+
+out_rollback:
+ for_lookup_table_entry(wim->lookup_table, lte_delete_if_new,
+ wim->lookup_table);
+ return ret;
}
static int
unsigned i;
int ret;
- open_flags |= WIMLIB_OPEN_FLAG_SPLIT_OK;
-
resource_wims = CALLOC(num_resource_wimfiles, sizeof(resource_wims[0]));
if (!resource_wims)
return WIMLIB_ERR_NOMEM;
for (i = 0; i < num_resource_wimfiles; i++) {
+ DEBUG("Referencing resources from path \"%"TS"\"",
+ resource_wimfiles[i]);
ret = wimlib_open_wim(resource_wimfiles[i], open_flags,
&resource_wims[i], progress_func);
if (ret)
goto out_free_resource_wims;
for (i = 0; i < num_resource_wimfiles; i++)
- resource_wims[i]->is_owned_by_master = 1;
+ list_add_tail(&resource_wims[i]->subwim_node, &wim->subwims);
ret = 0;
goto out_free_array;
open_flags, progress_func);
}
}
-
-/* API function documented in wimlib.h */
-WIMLIBAPI int
-wimlib_unreference_resources(WIMStruct *wim,
- WIMStruct **resource_wims, unsigned num_resource_wims)
-{
- int ret;
- unsigned i;
-
- ret = check_reference_params(wim, resource_wims, num_resource_wims, wim);
- if (ret)
- return ret;
-
- for (i = 0; i < num_resource_wims; i++)
- resource_wims[i]->being_unmerged = 1;
-
- for_lookup_table_entry(wim->lookup_table, move_lte_to_orig_table, wim);
-
- for (i = 0; i < num_resource_wims; i++) {
- resource_wims[i]->being_unmerged = 0;
- list_del(&resource_wims[i]->resource_wim_node);
- resource_wims[i]->master_wim = NULL;
- }
- return 0;
-}