6 * Copyright (C) 2012, 2013, 2014 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 http://www.gnu.org/licenses/.
27 #include "wimlib/error.h"
28 #include "wimlib/inode.h"
29 #include "wimlib/lookup_table.h"
30 #include "wimlib/metadata.h"
31 #include "wimlib/xml.h"
34 lte_set_not_exported(struct wim_lookup_table_entry *lte, void *_ignore)
37 lte->was_exported = 0;
42 lte_rollback_export(struct wim_lookup_table_entry *lte, void *_lookup_table)
44 struct wim_lookup_table *lookup_table = _lookup_table;
46 lte->refcnt -= lte->out_refcnt;
47 if (lte->was_exported) {
48 lookup_table_unlink(lookup_table, lte);
49 free_lookup_table_entry(lte);
55 inode_export_streams(struct wim_inode *inode,
56 struct wim_lookup_table *src_lookup_table,
57 struct wim_lookup_table *dest_lookup_table,
62 struct wim_lookup_table_entry *src_lte, *dest_lte;
64 inode_unresolve_streams(inode);
65 for (i = 0; i <= inode->i_num_ads; i++) {
67 /* Retrieve SHA1 message digest of stream to export. */
68 hash = inode_stream_hash(inode, i);
69 if (is_zero_hash(hash)) /* Empty stream? */
72 /* Search for the stream (via SHA1 message digest) in the
74 dest_lte = lookup_stream(dest_lookup_table, hash);
76 /* Stream not yet present in destination WIM. Search
77 * for it in the source WIM, then export it into the
79 src_lte = lookup_stream(src_lookup_table, hash);
81 return stream_not_found_error(inode, hash);
85 lookup_table_unlink(src_lookup_table, src_lte);
87 dest_lte = clone_lookup_table_entry(src_lte);
89 return WIMLIB_ERR_NOMEM;
92 dest_lte->out_refcnt = 0;
93 dest_lte->was_exported = 1;
94 lookup_table_insert(dest_lookup_table, dest_lte);
97 /* Stream is present in destination WIM (either pre-existing,
98 * already exported, or just exported above). Increment its
99 * reference count appropriately. Note: we use 'refcnt' for
100 * the raw reference count, but 'out_refcnt' for references
101 * arising just from the export operation; this is used to roll
102 * back a failed export if needed. */
103 dest_lte->refcnt += inode->i_nlink;
104 dest_lte->out_refcnt += inode->i_nlink;
109 /* API function documented in wimlib.h */
111 wimlib_export_image(WIMStruct *src_wim,
114 const tchar *dest_name,
115 const tchar *dest_description,
121 int orig_dest_image_count;
123 bool all_images = (src_image == WIMLIB_ALL_IMAGES);
125 /* Check for sane parameters. */
126 if (export_flags & ~(WIMLIB_EXPORT_FLAG_BOOT |
127 WIMLIB_EXPORT_FLAG_NO_NAMES |
128 WIMLIB_EXPORT_FLAG_NO_DESCRIPTIONS |
129 WIMLIB_EXPORT_FLAG_GIFT |
130 WIMLIB_EXPORT_FLAG_WIMBOOT))
131 return WIMLIB_ERR_INVALID_PARAM;
133 if (src_wim == NULL || dest_wim == NULL)
134 return WIMLIB_ERR_INVALID_PARAM;
136 if (!wim_has_metadata(src_wim) || !wim_has_metadata(dest_wim))
137 return WIMLIB_ERR_METADATA_NOT_FOUND;
140 /* Multi-image export. */
141 if ((!(export_flags & WIMLIB_EXPORT_FLAG_NO_NAMES) &&
143 (!(export_flags & WIMLIB_EXPORT_FLAG_NO_DESCRIPTIONS) &&
146 ERROR("Image name and description must be "
147 "left NULL for multi-image export");
148 return WIMLIB_ERR_INVALID_PARAM;
151 end_src_image = src_wim->hdr.image_count;
153 start_src_image = src_image;
154 end_src_image = src_image;
156 orig_dest_image_count = dest_wim->hdr.image_count;
158 /* Stream checksums must be known before proceeding. */
159 ret = wim_checksum_unhashed_streams(src_wim);
162 ret = wim_checksum_unhashed_streams(dest_wim);
166 /* Enable rollbacks */
167 for_lookup_table_entry(dest_wim->lookup_table, lte_set_not_exported, NULL);
169 /* Export each requested image. */
170 for (src_image = start_src_image;
171 src_image <= end_src_image;
174 const tchar *next_dest_name, *next_dest_description;
175 struct wim_image_metadata *src_imd;
176 struct wim_inode *inode;
178 /* Determine destination image name and description. */
180 if (export_flags & WIMLIB_EXPORT_FLAG_NO_NAMES)
181 next_dest_name = T("");
183 next_dest_name = dest_name;
185 next_dest_name = wimlib_get_image_name(src_wim, src_image);
187 if (export_flags & WIMLIB_EXPORT_FLAG_NO_DESCRIPTIONS)
188 next_dest_description = T("");
189 else if (dest_description)
190 next_dest_description = dest_description;
192 next_dest_description = wimlib_get_image_description(src_wim, src_image);
194 /* Check for name conflict. */
195 if (wimlib_image_name_in_use(dest_wim, next_dest_name)) {
196 ERROR("There is already an image named \"%"TS"\" "
197 "in the destination WIM", next_dest_name);
198 ret = WIMLIB_ERR_IMAGE_NAME_COLLISION;
202 /* Load metadata for source image into memory. */
203 ret = select_wim_image(src_wim, src_image);
207 src_imd = wim_get_current_image_metadata(src_wim);
209 /* Iterate through inodes in the source image and export their
210 * streams into the destination WIM. */
211 image_for_each_inode(inode, src_imd) {
212 ret = inode_export_streams(inode,
213 src_wim->lookup_table,
214 dest_wim->lookup_table,
215 export_flags & WIMLIB_EXPORT_FLAG_GIFT);
220 /* Export XML information into the destination WIM. */
221 ret = xml_export_image(src_wim->wim_info, src_image,
222 &dest_wim->wim_info, next_dest_name,
223 next_dest_description);
227 /* Reference the source image metadata from the destination WIM.
229 ret = append_image_metadata(dest_wim, src_imd);
234 /* Lock the metadata into memory. XXX: need better solution for
236 src_imd->modified = 1;
240 /* Image export complete. Finish by setting any needed special metadata
241 * on the destination WIM. */
243 if (src_wim->hdr.flags & WIM_HDR_FLAG_RP_FIX)
244 dest_wim->hdr.flags |= WIM_HDR_FLAG_RP_FIX;
246 for (src_image = start_src_image;
247 src_image <= end_src_image;
250 int dst_image = orig_dest_image_count + 1 +
251 (src_image - start_src_image);
253 if (export_flags & WIMLIB_EXPORT_FLAG_WIMBOOT)
254 wim_info_set_wimboot(dest_wim->wim_info, dst_image, true);
256 if ((export_flags & WIMLIB_EXPORT_FLAG_BOOT) &&
257 (!all_images || src_image == src_wim->hdr.boot_idx))
258 dest_wim->hdr.boot_idx = dst_image;
261 if (export_flags & WIMLIB_EXPORT_FLAG_GIFT) {
262 free_lookup_table(src_wim->lookup_table);
263 src_wim->lookup_table = NULL;
268 while ((image = wim_info_get_num_images(dest_wim->wim_info))
269 > orig_dest_image_count)
271 xml_delete_image(&dest_wim->wim_info, image);
273 while (dest_wim->hdr.image_count > orig_dest_image_count)
275 put_image_metadata(dest_wim->image_metadata[
276 --dest_wim->hdr.image_count], NULL);
278 for_lookup_table_entry(dest_wim->lookup_table, lte_rollback_export,
279 dest_wim->lookup_table);