]> wimlib.net Git - wimlib/blobdiff - src/template.c
WIMBoot / system compression: try WOFADK in addition to WOF
[wimlib] / src / template.c
index 438ff25c3c83f9b8256704b13b521723f85b1718..1a9a20690b6da7ebc7f1e120325e8b8a9a4c3140 100644 (file)
@@ -5,7 +5,7 @@
  */
 
 /*
- * Copyright (C) 2013 Eric Biggers
+ * Copyright (C) 2013, 2015 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
 #endif
 
 #include "wimlib.h"
+#include "wimlib/blob_table.h"
+#include "wimlib/assert.h"
 #include "wimlib/dentry.h"
 #include "wimlib/error.h"
-#include "wimlib/lookup_table.h"
 #include "wimlib/metadata.h"
 #include "wimlib/util.h"
 
+static u64
+stream_size(const struct wim_inode_stream *strm,
+           const struct blob_table *blob_table)
+{
+       const struct blob_descriptor *blob;
+
+       blob = stream_blob(strm, blob_table);
+       if (!blob)
+               return 0;
+       return blob->size;
+}
+
 /* Returns %true iff the metadata of @inode and @template_inode are reasonably
  * consistent with them being the same, unmodified file.  */
 static bool
 inode_metadata_consistent(const struct wim_inode *inode,
                          const struct wim_inode *template_inode,
-                         const struct wim_lookup_table *template_lookup_table)
+                         const struct blob_table *blob_table,
+                         const struct blob_table *template_blob_table)
 {
        /* Must have exact same creation time and last write time.  */
        if (inode->i_creation_time != template_inode->i_creation_time ||
@@ -49,156 +63,87 @@ inode_metadata_consistent(const struct wim_inode *inode,
        if (inode->i_last_access_time < template_inode->i_last_access_time)
                return false;
 
-       /* Must have same number of alternate data stream entries.  */
-       if (inode->i_num_ads != template_inode->i_num_ads)
-               return false;
+       /* All stream sizes must match.  */
+       for (unsigned i = 0; i < inode->i_num_streams; i++) {
+               const struct wim_inode_stream *strm, *template_strm;
 
-       /* If the stream entries for the inode are for some reason not resolved,
-        * then the hashes are already available and the point of this function
-        * is defeated.  */
-       if (!inode->i_resolved)
-               return false;
-
-       /* Iterate through each stream and do some more checks.  */
-       for (unsigned i = 0; i <= inode->i_num_ads; i++) {
-               const struct wim_lookup_table_entry *lte, *template_lte;
-
-               lte = inode_stream_lte_resolved(inode, i);
-               template_lte = inode_stream_lte(template_inode, i,
-                                               template_lookup_table);
-
-               /* Compare stream sizes.  */
-               if (lte && template_lte) {
-                       if (lte->size != template_lte->size)
-                               return false;
-
-                       /* If hash happens to be available, compare with template.  */
-                       if (!lte->unhashed && !template_lte->unhashed &&
-                           !hashes_equal(lte->hash, template_lte->hash))
-                               return false;
-
-               } else if (lte && lte->size) {
+               strm = &inode->i_streams[i];
+               template_strm = inode_get_stream(template_inode,
+                                                strm->stream_type,
+                                                strm->stream_name);
+               if (!template_strm)
                        return false;
-               } else if (template_lte && template_lte->size) {
+
+               if (stream_size(strm, blob_table) !=
+                   stream_size(template_strm, template_blob_table))
                        return false;
-               }
        }
 
-       /* All right, barring a full checksum and given that the inodes share a
-        * path and the user isn't trying to trick us, these inodes most likely
-        * refer to the same file.  */
        return true;
 }
 
 /**
  * Given an inode @inode that has been determined to be "the same" as another
- * inode @template_inode in either the same WIM or another WIM, retrieve some
- * useful stream information (e.g. checksums) from @template_inode.
- *
- * This assumes that the streams for @inode have been resolved (to point
- * directly to the appropriate `struct wim_lookup_table_entry's)  but do not
- * necessarily have checksum information filled in.
+ * inode @template_inode in either the same WIM or another WIM, copy stream
+ * checksums from @template_inode to @inode.
  */
-static int
+static void
 inode_copy_checksums(struct wim_inode *inode,
                     struct wim_inode *template_inode,
-                    WIMStruct *wim,
-                    WIMStruct *template_wim)
+                    struct blob_table *blob_table,
+                    struct blob_table *template_blob_table)
 {
-       for (unsigned i = 0; i <= inode->i_num_ads; i++) {
-               struct wim_lookup_table_entry *lte, *template_lte;
-               struct wim_lookup_table_entry *replace_lte;
-
-               lte = inode_stream_lte_resolved(inode, i);
-               template_lte = inode_stream_lte(template_inode, i,
-                                               template_wim->lookup_table);
-
-               /* Only take action if both entries exist, the entry for @inode
-                * has no checksum calculated, but the entry for @template_inode
-                * does.  */
-               if (lte == NULL || template_lte == NULL ||
-                   !lte->unhashed || template_lte->unhashed)
+       for (unsigned i = 0; i < inode->i_num_streams; i++) {
+               const struct wim_inode_stream *strm, *template_strm;
+               struct blob_descriptor *blob, *template_blob, **back_ptr;
+
+               strm = &inode->i_streams[i];
+               template_strm = inode_get_stream(template_inode,
+                                                strm->stream_type,
+                                                strm->stream_name);
+
+               blob = stream_blob(strm, blob_table);
+               template_blob = stream_blob(template_strm, template_blob_table);
+
+               /* To copy hashes: both blobs must exist, the blob for @inode
+                * must be unhashed, and the blob for @template_inode must be
+                * hashed.  */
+               if (!blob || !template_blob ||
+                   !blob->unhashed || template_blob->unhashed)
                        continue;
 
-               wimlib_assert(lte->refcnt == inode->i_nlink);
-
-               /* If the WIM of the template image is the same as the WIM of
-                * the new image, then @template_lte can be used directly.
-                *
-                * Otherwise, look for a stream with the same hash in the WIM of
-                * the new image.  If found, use it; otherwise re-use the entry
-                * being discarded, filling in the hash.  */
-
-               if (wim == template_wim)
-                       replace_lte = template_lte;
-               else
-                       replace_lte = lookup_stream(wim->lookup_table,
-                                                   template_lte->hash);
-
-               list_del(&lte->unhashed_list);
-               if (replace_lte) {
-                       free_lookup_table_entry(lte);
-               } else {
-                       copy_hash(lte->hash, template_lte->hash);
-                       lte->unhashed = 0;
-                       lookup_table_insert(wim->lookup_table, lte);
-                       lte->refcnt = 0;
-                       replace_lte = lte;
-               }
-
-               if (i == 0)
-                       inode->i_lte = replace_lte;
-               else
-                       inode->i_ads_entries[i - 1].lte = replace_lte;
-
-               replace_lte->refcnt += inode->i_nlink;
+               back_ptr = retrieve_pointer_to_unhashed_blob(blob);
+               copy_hash(blob->hash, template_blob->hash);
+               if (after_blob_hashed(blob, back_ptr, blob_table) != blob)
+                       free_blob_descriptor(blob);
        }
-       return 0;
 }
 
-struct reference_template_args {
-       WIMStruct *wim;
-       WIMStruct *template_wim;
-};
-
 static int
-dentry_reference_template(struct wim_dentry *dentry, void *_args)
+reference_template_file(struct wim_inode *inode, WIMStruct *wim,
+                       WIMStruct *template_wim)
 {
-       int ret;
+       struct wim_dentry *dentry = inode_any_dentry(inode);
        struct wim_dentry *template_dentry;
-       struct wim_inode *inode, *template_inode;
-       struct reference_template_args *args = _args;
-       WIMStruct *wim = args->wim;
-       WIMStruct *template_wim = args->template_wim;
-
-       if (dentry->d_inode->i_visited)
-               return 0;
+       int ret;
 
        ret = calculate_dentry_full_path(dentry);
        if (ret)
                return ret;
 
-       template_dentry = get_dentry(template_wim, dentry->_full_path,
+       template_dentry = get_dentry(template_wim, dentry->d_full_path,
                                     WIMLIB_CASE_SENSITIVE);
-       if (template_dentry == NULL) {
-               DEBUG("\"%"TS"\": newly added file", dentry->_full_path);
-               return 0;
+       if (template_dentry != NULL &&
+           inode_metadata_consistent(inode, template_dentry->d_inode,
+                                     wim->blob_table, template_wim->blob_table))
+       {
+               inode_copy_checksums(inode, template_dentry->d_inode,
+                                    wim->blob_table, template_wim->blob_table);
        }
 
-       inode = dentry->d_inode;
-       template_inode = template_dentry->d_inode;
-
-       if (inode_metadata_consistent(inode, template_inode,
-                                     template_wim->lookup_table)) {
-               /*DEBUG("\"%"TS"\": No change detected", dentry->_full_path);*/
-               ret = inode_copy_checksums(inode, template_inode,
-                                          wim, template_wim);
-               inode->i_visited = 1;
-       } else {
-               DEBUG("\"%"TS"\": change detected!", dentry->_full_path);
-               ret = 0;
-       }
-       return ret;
+       FREE(dentry->d_full_path);
+       dentry->d_full_path = NULL;
+       return 0;
 }
 
 /* API function documented in wimlib.h  */
@@ -209,6 +154,7 @@ wimlib_reference_template_image(WIMStruct *wim, int new_image,
 {
        int ret;
        struct wim_image_metadata *new_imd;
+       struct wim_inode *inode;
 
        if (flags != 0)
                return WIMLIB_ERR_INVALID_PARAM;
@@ -233,13 +179,11 @@ wimlib_reference_template_image(WIMStruct *wim, int new_image,
        if (ret)
                return ret;
 
-       struct reference_template_args args = {
-               .wim = wim,
-               .template_wim = template_wim,
-       };
+       image_for_each_inode(inode, new_imd) {
+               ret = reference_template_file(inode, wim, template_wim);
+               if (ret)
+                       return ret;
+       }
 
-       ret = for_dentry_in_tree(new_imd->root_dentry,
-                                dentry_reference_template, &args);
-       dentry_tree_clear_inode_visited(new_imd->root_dentry);
-       return ret;
+       return 0;
 }