]> wimlib.net Git - wimlib/blobdiff - src/lookup_table.c
wimlib_mount_image(): Correctly handle unnamed stream in ADS entries
[wimlib] / src / lookup_table.c
index a6202ef2b6c185a03c9b2b355d80a6825ab7ec07..9109c481771fa1166e85220d53dc442fef3e6ca4 100644 (file)
@@ -574,6 +574,13 @@ read_wim_lookup_table(WIMStruct *wim)
                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);
@@ -613,7 +620,7 @@ read_wim_lookup_table(WIMStruct *wim)
                } 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 "
@@ -671,7 +678,8 @@ static int
 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;
@@ -705,7 +713,8 @@ write_wim_lookup_table_from_stream_list(struct list_head *stream_list,
                                             WIMLIB_COMPRESSION_TYPE_NONE,
                                             out_res_entry,
                                             NULL,
-                                            write_resource_flags);
+                                            write_resource_flags,
+                                            comp_ctx);
        FREE(table_buf);
        return ret;
 }
@@ -713,8 +722,29 @@ write_wim_lookup_table_from_stream_list(struct list_head *stream_list,
 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(&lte->output_resource_entry,
+                                           &lte->resource_entry);
+               }
                list_add_tail(&lte->lookup_table_list, (struct list_head*)_list);
+       }
        return 0;
 }
 
@@ -761,7 +791,9 @@ write_wim_lookup_table(WIMStruct *wim, int image, int write_flags,
                }
        }
 
-       /* 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);
@@ -773,7 +805,8 @@ write_wim_lookup_table(WIMStruct *wim, int image, int write_flags,
        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);
 }
 
 
@@ -922,7 +955,7 @@ wimlib_iterate_lookup_table(WIMStruct *wim, int flags,
 /* 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;
@@ -946,12 +979,12 @@ __lookup_resource(const struct wim_lookup_table *table, const u8 hash[])
  * 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;
@@ -997,8 +1030,7 @@ lookup_resource(WIMStruct *wim,
                        return -ENOENT;
                }
        } else {
-               lte = inode->i_lte;
-               stream_idx = 0;
+               lte = inode_unnamed_stream_resolved(inode, &stream_idx);
        }
 out:
        if (dentry_ret)
@@ -1012,7 +1044,7 @@ out:
 #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));
@@ -1050,7 +1082,7 @@ inode_resolve_ltes(struct wim_inode *inode, struct wim_lookup_table *table,
                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();
@@ -1073,7 +1105,7 @@ inode_resolve_ltes(struct wim_inode *inode, struct wim_lookup_table *table,
                        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();
@@ -1137,19 +1169,28 @@ inode_stream_lte(const struct wim_inode *inode, unsigned stream_idx,
 }
 
 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)
@@ -1191,6 +1232,25 @@ inode_unnamed_lte(const struct wim_inode *inode,
                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)
 {
@@ -1256,7 +1316,7 @@ hash_unhashed_stream(struct wim_lookup_table_entry *lte,
                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(&lte->unhashed_list);
        if (duplicate_lte) {
                /* We have a duplicate stream.  Transfer the reference counts
@@ -1265,7 +1325,7 @@ hash_unhashed_stream(struct wim_lookup_table_entry *lte,
                 * 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;
@@ -1282,86 +1342,67 @@ hash_unhashed_stream(struct wim_lookup_table_entry *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;
-
-       hlist_del(&lte->hash_list);
-       lookup_table_insert(combined_table, lte);
-       return 0;
-}
+       struct wim_lookup_table *lookup_table = _lookup_table;
 
-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;
-}
+       if (lookup_resource(lookup_table, lte->hash))
+               return 0;  /*  Resource already present.  */
 
-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
@@ -1376,13 +1417,13 @@ reference_resource_paths(WIMStruct *wim,
        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)
@@ -1395,7 +1436,7 @@ reference_resource_paths(WIMStruct *wim,
                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;
@@ -1479,28 +1520,3 @@ wimlib_reference_resource_files(WIMStruct *wim,
                                                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;
-}