4 * API to reference a template image to optimize later writing of a WIM file.
8 * Copyright (C) 2013, 2015 Eric Biggers
10 * This file is free software; you can redistribute it and/or modify it under
11 * the terms of the GNU Lesser General Public License as published by the Free
12 * Software Foundation; either version 3 of the License, or (at your option) any
15 * This file is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this file; if not, see http://www.gnu.org/licenses/.
29 #include "wimlib/blob_table.h"
30 #include "wimlib/assert.h"
31 #include "wimlib/dentry.h"
32 #include "wimlib/error.h"
33 #include "wimlib/metadata.h"
34 #include "wimlib/util.h"
37 stream_size(const struct wim_inode_stream *strm,
38 const struct blob_table *blob_table)
40 const struct blob_descriptor *blob;
42 blob = stream_blob(strm, blob_table);
48 /* Returns %true iff the metadata of @inode and @template_inode are reasonably
49 * consistent with them being the same, unmodified file. */
51 inode_metadata_consistent(const struct wim_inode *inode,
52 const struct wim_inode *template_inode,
53 const struct blob_table *blob_table,
54 const struct blob_table *template_blob_table)
56 /* Must have exact same creation time and last write time. */
57 if (inode->i_creation_time != template_inode->i_creation_time ||
58 inode->i_last_write_time != template_inode->i_last_write_time)
61 /* Last access time may have stayed the same or increased, but certainly
62 * shouldn't have decreased. */
63 if (inode->i_last_access_time < template_inode->i_last_access_time)
66 /* All stream sizes must match. */
67 for (unsigned i = 0; i < inode->i_num_streams; i++) {
68 const struct wim_inode_stream *strm, *template_strm;
70 strm = &inode->i_streams[i];
71 template_strm = inode_get_stream(template_inode,
77 if (stream_size(strm, blob_table) !=
78 stream_size(template_strm, template_blob_table))
86 * Given an inode @inode that has been determined to be "the same" as another
87 * inode @template_inode in either the same WIM or another WIM, copy stream
88 * checksums from @template_inode to @inode.
91 inode_copy_checksums(struct wim_inode *inode,
92 struct wim_inode *template_inode,
93 struct blob_table *blob_table,
94 struct blob_table *template_blob_table)
96 for (unsigned i = 0; i < inode->i_num_streams; i++) {
97 const struct wim_inode_stream *strm, *template_strm;
98 struct blob_descriptor *blob, *template_blob, **back_ptr;
100 strm = &inode->i_streams[i];
101 template_strm = inode_get_stream(template_inode,
105 blob = stream_blob(strm, blob_table);
106 template_blob = stream_blob(template_strm, template_blob_table);
108 /* To copy hashes: both blobs must exist, the blob for @inode
109 * must be unhashed, and the blob for @template_inode must be
111 if (!blob || !template_blob ||
112 !blob->unhashed || template_blob->unhashed)
115 back_ptr = retrieve_pointer_to_unhashed_blob(blob);
116 copy_hash(blob->hash, template_blob->hash);
117 if (after_blob_hashed(blob, back_ptr, blob_table) != blob)
118 free_blob_descriptor(blob);
122 struct reference_template_args {
124 WIMStruct *template_wim;
128 dentry_reference_template(struct wim_dentry *dentry, void *_args)
131 struct wim_dentry *template_dentry;
132 struct wim_inode *inode, *template_inode;
133 struct reference_template_args *args = _args;
134 WIMStruct *wim = args->wim;
135 WIMStruct *template_wim = args->template_wim;
137 if (dentry->d_inode->i_visited)
140 ret = calculate_dentry_full_path(dentry);
144 template_dentry = get_dentry(template_wim, dentry->d_full_path,
145 WIMLIB_CASE_SENSITIVE);
146 if (template_dentry == NULL) {
147 DEBUG("\"%"TS"\": newly added file", dentry->d_full_path);
151 inode = dentry->d_inode;
152 template_inode = template_dentry->d_inode;
154 if (inode_metadata_consistent(inode, template_inode, wim->blob_table,
155 template_wim->blob_table))
157 DEBUG("\"%"TS"\": No change detected", dentry->d_full_path);
158 inode_copy_checksums(inode, template_inode, wim->blob_table,
159 template_wim->blob_table);
160 inode->i_visited = 1;
162 DEBUG("\"%"TS"\": change detected!", dentry->d_full_path);
167 /* API function documented in wimlib.h */
169 wimlib_reference_template_image(WIMStruct *wim, int new_image,
170 WIMStruct *template_wim, int template_image,
174 struct wim_image_metadata *new_imd;
177 return WIMLIB_ERR_INVALID_PARAM;
179 if (wim == NULL || template_wim == NULL)
180 return WIMLIB_ERR_INVALID_PARAM;
182 if (wim == template_wim && new_image == template_image)
183 return WIMLIB_ERR_INVALID_PARAM;
185 if (new_image < 1 || new_image > wim->hdr.image_count)
186 return WIMLIB_ERR_INVALID_IMAGE;
188 if (!wim_has_metadata(wim))
189 return WIMLIB_ERR_METADATA_NOT_FOUND;
191 new_imd = wim->image_metadata[new_image - 1];
192 if (!new_imd->modified)
193 return WIMLIB_ERR_INVALID_PARAM;
195 ret = select_wim_image(template_wim, template_image);
199 struct reference_template_args args = {
201 .template_wim = template_wim,
204 ret = for_dentry_in_tree(new_imd->root_dentry,
205 dentry_reference_template, &args);
206 dentry_tree_clear_inode_visited(new_imd->root_dentry);