*/
/*
- * Copyright (C) 2013 Eric Biggers
+ * Copyright (C) 2013, 2015 Eric Biggers
*
- * This file is part of wimlib, a library for working with WIM files.
+ * 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
+ * Software Foundation; either version 3 of the License, or (at your option) any
+ * later version.
*
- * wimlib is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 3 of the License, or (at your option)
- * any later version.
- *
- * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * This file is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
- * You should have received a copy of the GNU General Public License
- * along with wimlib; if not, see http://www.gnu.org/licenses/.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this file; if not, see http://www.gnu.org/licenses/.
*/
#ifdef HAVE_CONFIG_H
#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 ||
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;
-
- /* 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);
+ /* All stream sizes must match. */
+ for (unsigned i = 0; i < inode->i_num_streams; i++) {
+ const struct wim_inode_stream *strm, *template_strm;
- /* 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(<e->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_first_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 */
{
int ret;
struct wim_image_metadata *new_imd;
+ struct wim_inode *inode;
if (flags != 0)
return WIMLIB_ERR_INVALID_PARAM;
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;
}