6 * Copyright (C) 2012, 2013 Eric Biggers
8 * This file is part of wimlib, a library for working with WIM files.
10 * wimlib is free software; you can redistribute it and/or modify it under the
11 * terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 3 of the License, or (at your option)
15 * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
16 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
17 * A PARTICULAR PURPOSE. See the GNU General Public License for more
20 * You should have received a copy of the GNU General Public License
21 * along with wimlib; if not, see http://www.gnu.org/licenses/.
29 #include "wimlib/dentry.h"
30 #include "wimlib/error.h"
31 #include "wimlib/inode.h"
32 #include "wimlib/lookup_table.h"
33 #include "wimlib/metadata.h"
34 #include "wimlib/xml.h"
38 inode_export_streams(struct wim_inode *inode,
39 struct wim_lookup_table *src_lookup_table,
40 struct wim_lookup_table *dest_lookup_table,
45 struct wim_lookup_table_entry *src_lte, *dest_lte;
47 inode_unresolve_streams(inode);
48 for (i = 0; i <= inode->i_num_ads; i++) {
50 /* Retrieve SHA1 message digest of stream to export. */
51 hash = inode_stream_hash(inode, i);
52 if (is_zero_hash(hash)) /* Empty stream? */
55 /* Search for the stream (via SHA1 message digest) in the
57 dest_lte = lookup_stream(dest_lookup_table, hash);
59 /* Stream not yet present in destination WIM. Search
60 * for it in the source WIM, then export it into the
62 src_lte = lookup_stream(src_lookup_table, hash);
64 return stream_not_found_error(inode, hash);
68 lookup_table_unlink(src_lookup_table, src_lte);
70 dest_lte = clone_lookup_table_entry(src_lte);
72 return WIMLIB_ERR_NOMEM;
75 dest_lte->out_refcnt = 0;
76 lookup_table_insert(dest_lookup_table, dest_lte);
79 /* Stream is present in destination WIM (either pre-existing,
80 * already exported, or just exported above). Increment its
81 * reference count appropriately. Note: we use 'refcnt' for
82 * the raw reference count, but 'out_refcnt' for references
83 * arising just from the export operation; this is used to roll
84 * back a failed export if needed. */
85 dest_lte->refcnt += inode->i_nlink;
86 dest_lte->out_refcnt += inode->i_nlink;
92 lte_unexport(struct wim_lookup_table_entry *lte, void *_lookup_table)
94 struct wim_lookup_table *lookup_table = _lookup_table;
96 if (lte->out_refcnt) {
97 lte->refcnt -= lte->out_refcnt;
98 if (lte->refcnt == 0) {
99 lookup_table_unlink(lookup_table, lte);
100 free_lookup_table_entry(lte);
106 /* API function documented in wimlib.h */
108 wimlib_export_image(WIMStruct *src_wim,
111 const tchar *dest_name,
112 const tchar *dest_description,
114 wimlib_progress_func_t progress_func)
120 u32 orig_dest_boot_idx;
121 u32 orig_dest_image_count;
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 == NULL || dest_wim == NULL)
132 return WIMLIB_ERR_INVALID_PARAM;
134 if (!wim_has_metadata(dest_wim))
135 return WIMLIB_ERR_METADATA_NOT_FOUND;
137 /* Destination WIM must be writable. */
138 ret = can_modify_wim(dest_wim);
142 if (src_image == WIMLIB_ALL_IMAGES) {
143 /* Multi-image export. */
144 if ((!(export_flags & WIMLIB_EXPORT_FLAG_NO_NAMES) &&
146 (!(export_flags & WIMLIB_EXPORT_FLAG_NO_DESCRIPTIONS) &&
149 ERROR("Image name or image description was "
150 "specified, but we are exporting "
152 return WIMLIB_ERR_INVALID_PARAM;
155 end_image = src_wim->hdr.image_count;
157 start_image = src_image;
158 end_image = src_image;
161 /* Stream checksums must be known before proceeding. */
162 ret = wim_checksum_unhashed_streams(src_wim);
165 ret = wim_checksum_unhashed_streams(dest_wim);
169 /* Zero 'out_refcnt' in all lookup table entries in the destination WIM;
170 * this tracks the number of references found from the source WIM
172 for_lookup_table_entry(dest_wim->lookup_table, lte_zero_out_refcnt,
175 /* Save the original count of images in the destination WIM and the boot
176 * index (used if rollback necessary). */
177 orig_dest_image_count = dest_wim->hdr.image_count;
178 orig_dest_boot_idx = dest_wim->hdr.boot_idx;
180 /* Export each requested image. */
181 for (image = start_image; image <= end_image; image++) {
182 const tchar *next_dest_name, *next_dest_description;
183 struct wim_image_metadata *src_imd;
184 struct wim_inode *inode;
186 DEBUG("Exporting image %d from \"%"TS"\"",
187 image, src_wim->filename);
189 /* Determine destination image name and description. */
191 if (export_flags & WIMLIB_EXPORT_FLAG_NO_NAMES) {
192 next_dest_name = T("");
193 } else if (dest_name) {
194 next_dest_name = dest_name;
196 next_dest_name = wimlib_get_image_name(src_wim,
200 DEBUG("Using name \"%"TS"\"", next_dest_name);
202 if (export_flags & WIMLIB_EXPORT_FLAG_NO_DESCRIPTIONS) {
203 next_dest_description = T("");
204 } else if (dest_description) {
205 next_dest_description = dest_description;
207 next_dest_description = wimlib_get_image_description(
211 DEBUG("Using description \"%"TS"\"", next_dest_description);
213 /* Check for name conflict. */
214 if (wimlib_image_name_in_use(dest_wim, next_dest_name)) {
215 ERROR("There is already an image named \"%"TS"\" "
216 "in the destination WIM", next_dest_name);
217 ret = WIMLIB_ERR_IMAGE_NAME_COLLISION;
221 /* Load metadata for source image into memory. */
222 ret = select_wim_image(src_wim, image);
226 src_imd = wim_get_current_image_metadata(src_wim);
228 /* Iterate through inodes in the source image and export their
229 * streams into the destination WIM. */
230 image_for_each_inode(inode, src_imd) {
231 ret = inode_export_streams(inode,
232 src_wim->lookup_table,
233 dest_wim->lookup_table,
234 export_flags & WIMLIB_EXPORT_FLAG_GIFT);
239 /* Export XML information into the destination WIM. */
240 ret = xml_export_image(src_wim->wim_info, image,
241 &dest_wim->wim_info, next_dest_name,
242 next_dest_description);
246 /* Reference the source image metadata from the destination WIM.
248 ret = append_image_metadata(dest_wim, src_imd);
253 /* Lock the metadata into memory. XXX: need better solution for
255 src_imd->modified = 1;
257 /* Set boot index in destination WIM. */
258 if ((export_flags & WIMLIB_EXPORT_FLAG_BOOT) &&
259 (src_image != WIMLIB_ALL_IMAGES ||
260 image == src_wim->hdr.boot_idx))
262 DEBUG("Marking destination image %u as bootable.",
263 dest_wim->hdr.image_count);
264 dest_wim->hdr.boot_idx = dest_wim->hdr.image_count;
267 /* Possibly set WIMBoot flag */
268 if (export_flags & WIMLIB_EXPORT_FLAG_WIMBOOT) {
269 wim_info_set_wimboot(dest_wim->wim_info,
270 dest_wim->hdr.image_count,
275 /* Set the reparse point fixup flag on the destination WIM if the flag
276 * is set on the source WIM. */
277 if (src_wim->hdr.flags & WIM_HDR_FLAG_RP_FIX)
278 dest_wim->hdr.flags |= WIM_HDR_FLAG_RP_FIX;
280 if (export_flags & WIMLIB_EXPORT_FLAG_GIFT) {
281 free_lookup_table(src_wim->lookup_table);
282 src_wim->lookup_table = NULL;
284 DEBUG("Export operation successful.");
288 while ((image = wim_info_get_num_images(dest_wim->wim_info))
289 > orig_dest_image_count)
291 xml_delete_image(&dest_wim->wim_info, image);
293 while (dest_wim->hdr.image_count > orig_dest_image_count)
295 put_image_metadata(dest_wim->image_metadata[
296 --dest_wim->hdr.image_count], NULL);
298 for_lookup_table_entry(dest_wim->lookup_table, lte_unexport,
299 dest_wim->lookup_table);
300 dest_wim->hdr.boot_idx = orig_dest_boot_idx;