X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Ftemplate.c;h=1a9a20690b6da7ebc7f1e120325e8b8a9a4c3140;hp=1c0e205f521ee33e371f6b4633e342c2f5b8c855;hb=873a86a1a5097f2a161494341d8d962453a30465;hpb=7251c7d0afac3b738dda1c4f45e6d3d3090f2622 diff --git a/src/template.c b/src/template.c index 1c0e205f..1a9a2069 100644 --- a/src/template.c +++ b/src/template.c @@ -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 @@ -26,19 +26,32 @@ #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 || @@ -50,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(<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_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 */ @@ -210,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; @@ -234,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; }