6 * Copyright (C) 2012-2016 Eric Biggers
8 * This file is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU Lesser General Public License as published by the Free
10 * Software Foundation; either version 3 of the License, or (at your option) any
13 * This file is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public License
19 * along with this file; if not, see https://www.gnu.org/licenses/.
27 #include "wimlib/blob_table.h"
28 #include "wimlib/error.h"
29 #include "wimlib/inode.h"
30 #include "wimlib/metadata.h"
31 #include "wimlib/xml.h"
34 blob_set_not_exported(struct blob_descriptor *blob, void *_ignore)
37 blob->was_exported = 0;
42 blob_rollback_export(struct blob_descriptor *blob, void *_blob_table)
44 struct blob_table *blob_table = _blob_table;
46 blob->refcnt -= blob->out_refcnt;
47 if (blob->was_exported) {
48 blob_table_unlink(blob_table, blob);
49 free_blob_descriptor(blob);
55 inode_export_blobs(struct wim_inode *inode, struct blob_table *src_blob_table,
56 struct blob_table *dest_blob_table, bool gift)
60 struct blob_descriptor *src_blob, *dest_blob;
62 for (i = 0; i < inode->i_num_streams; i++) {
64 /* Retrieve SHA-1 message digest of blob to export. */
65 hash = stream_hash(&inode->i_streams[i]);
66 if (is_zero_hash(hash)) /* Empty stream? */
69 /* Search for the blob (via SHA-1 message digest) in the
71 dest_blob = lookup_blob(dest_blob_table, hash);
73 /* Blob not yet present in destination WIM. Search for
74 * it in the source WIM, then export it into the
76 src_blob = stream_blob(&inode->i_streams[i],
79 return blob_not_found_error(inode, hash);
83 blob_table_unlink(src_blob_table, src_blob);
85 dest_blob = clone_blob_descriptor(src_blob);
87 return WIMLIB_ERR_NOMEM;
89 dest_blob->refcnt = 0;
90 dest_blob->out_refcnt = 0;
91 dest_blob->was_exported = 1;
92 blob_table_insert(dest_blob_table, dest_blob);
95 /* Blob is present in destination WIM (either pre-existing,
96 * already exported, or just exported above). Increment its
97 * reference count appropriately. Note: we use 'refcnt' for
98 * the raw reference count, but 'out_refcnt' for references
99 * arising just from the export operation; this is used to roll
100 * back a failed export if needed. */
101 dest_blob->refcnt += inode->i_nlink;
102 dest_blob->out_refcnt += inode->i_nlink;
107 /* API function documented in wimlib.h */
109 wimlib_export_image(WIMStruct *src_wim,
112 const tchar *dest_name,
113 const tchar *dest_description,
119 int orig_dest_image_count;
121 bool all_images = (src_image == WIMLIB_ALL_IMAGES);
123 /* Check for sane parameters. */
124 if (export_flags & ~(WIMLIB_EXPORT_FLAG_BOOT |
125 WIMLIB_EXPORT_FLAG_NO_NAMES |
126 WIMLIB_EXPORT_FLAG_NO_DESCRIPTIONS |
127 WIMLIB_EXPORT_FLAG_GIFT |
128 WIMLIB_EXPORT_FLAG_WIMBOOT))
129 return WIMLIB_ERR_INVALID_PARAM;
131 if (!src_wim || !dest_wim)
132 return WIMLIB_ERR_INVALID_PARAM;
134 if (!wim_has_metadata(src_wim) || !wim_has_metadata(dest_wim))
135 return WIMLIB_ERR_METADATA_NOT_FOUND;
138 /* Multi-image export. */
139 if ((!(export_flags & WIMLIB_EXPORT_FLAG_NO_NAMES) &&
141 (!(export_flags & WIMLIB_EXPORT_FLAG_NO_DESCRIPTIONS) &&
144 ERROR("Image name and description must be "
145 "left NULL for multi-image export");
146 return WIMLIB_ERR_INVALID_PARAM;
149 end_src_image = src_wim->hdr.image_count;
151 start_src_image = src_image;
152 end_src_image = src_image;
154 orig_dest_image_count = dest_wim->hdr.image_count;
156 /* We don't yet support having a single WIMStruct contain duplicate
157 * 'image_metadata' structures, so we must forbid this from happening.
158 * A duplication is possible if 'src_wim == dest_wim', if the same image
159 * is exported to the same destination WIMStruct multiple times, or if
160 * an image is exported in an A => B => A manner. */
161 for (src_image = start_src_image;
162 src_image <= end_src_image; src_image++)
164 const struct wim_image_metadata *src_imd =
165 src_wim->image_metadata[src_image - 1];
166 for (int i = 0; i < dest_wim->hdr.image_count; i++)
167 if (dest_wim->image_metadata[i] == src_imd)
168 return WIMLIB_ERR_DUPLICATE_EXPORTED_IMAGE;
171 /* Blob checksums must be known before proceeding. */
172 ret = wim_checksum_unhashed_blobs(src_wim);
175 ret = wim_checksum_unhashed_blobs(dest_wim);
179 /* Enable rollbacks */
180 for_blob_in_table(dest_wim->blob_table, blob_set_not_exported, NULL);
182 /* Forbid exports where the destination WIM already contains image(s)
183 * with the requested name(s). However, allow multi-image exports where
184 * there is a duplication among the source names only. */
185 if (!(export_flags & WIMLIB_EXPORT_FLAG_NO_NAMES)) {
186 for (src_image = start_src_image;
187 src_image <= end_src_image;
190 const tchar *name = dest_name ? dest_name :
191 wimlib_get_image_name(src_wim, src_image);
193 if (wimlib_image_name_in_use(dest_wim, name)) {
194 ERROR("There is already an image named \"%"TS"\" "
195 "in the destination WIM", name);
196 ret = WIMLIB_ERR_IMAGE_NAME_COLLISION;
202 /* Export each requested image. */
203 for (src_image = start_src_image;
204 src_image <= end_src_image;
207 const tchar *next_dest_name, *next_dest_description;
208 struct wim_image_metadata *src_imd;
209 struct wim_inode *inode;
211 /* Determine destination image name and description. */
213 if (export_flags & WIMLIB_EXPORT_FLAG_NO_NAMES)
214 next_dest_name = NULL;
216 next_dest_name = dest_name;
218 next_dest_name = wimlib_get_image_name(src_wim, src_image);
220 if (export_flags & WIMLIB_EXPORT_FLAG_NO_DESCRIPTIONS)
221 next_dest_description = NULL;
222 else if (dest_description)
223 next_dest_description = dest_description;
225 next_dest_description = wimlib_get_image_description(src_wim, src_image);
227 /* Load metadata for source image into memory. */
228 ret = select_wim_image(src_wim, src_image);
232 src_imd = wim_get_current_image_metadata(src_wim);
234 /* Iterate through inodes in the source image and export their
235 * blobs into the destination WIM. */
236 image_for_each_inode(inode, src_imd) {
237 ret = inode_export_blobs(inode,
239 dest_wim->blob_table,
240 export_flags & WIMLIB_EXPORT_FLAG_GIFT);
245 /* Export XML information into the destination WIM. */
246 ret = xml_export_image(src_wim->xml_info, src_image,
247 dest_wim->xml_info, next_dest_name,
248 next_dest_description,
249 export_flags & WIMLIB_EXPORT_FLAG_WIMBOOT);
253 /* Reference the source image metadata from the destination WIM.
255 ret = append_image_metadata(dest_wim, src_imd);
261 /* Image export complete. Finish by setting any needed special metadata
262 * on the destination WIM. */
264 if (src_wim->hdr.flags & WIM_HDR_FLAG_RP_FIX)
265 dest_wim->hdr.flags |= WIM_HDR_FLAG_RP_FIX;
267 for (src_image = start_src_image;
268 src_image <= end_src_image;
271 int dst_image = orig_dest_image_count + 1 +
272 (src_image - start_src_image);
274 if ((export_flags & WIMLIB_EXPORT_FLAG_BOOT) &&
275 (!all_images || src_image == src_wim->hdr.boot_idx))
276 dest_wim->hdr.boot_idx = dst_image;
282 while ((image = xml_get_image_count(dest_wim->xml_info))
283 > orig_dest_image_count)
285 xml_delete_image(dest_wim->xml_info, image);
287 while (dest_wim->hdr.image_count > orig_dest_image_count)
289 put_image_metadata(dest_wim->image_metadata[
290 --dest_wim->hdr.image_count]);
292 for_blob_in_table(dest_wim->blob_table, blob_rollback_export,
293 dest_wim->blob_table);