7dcee10b01a4a55ac2ded3dad802dd2007fe5c73
[wimlib] / src / add_image.c
1 /*
2  * add_image.c - Add an image to a WIM file.
3  */
4
5 /*
6  * Copyright (C) 2012, 2013 Eric Biggers
7  *
8  * This file is part of wimlib, a library for working with WIM files.
9  *
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)
13  * any later version.
14  *
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
18  * details.
19  *
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/.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #include "wimlib.h"
29 #include "wimlib/capture.h"
30 #include "wimlib/error.h"
31 #include "wimlib/lookup_table.h"
32 #include "wimlib/metadata.h"
33 #include "wimlib/xml.h"
34
35 /*
36  * Adds the dentry tree and security data for a new image to the image metadata
37  * array of the WIMStruct.
38  */
39 static int
40 add_new_dentry_tree(WIMStruct *wim, struct wim_dentry *root_dentry,
41                     struct wim_security_data *sd)
42 {
43         struct wim_image_metadata *new_imd;
44         struct wim_lookup_table_entry *metadata_lte;
45         int ret;
46
47         metadata_lte = new_lookup_table_entry();
48         if (!metadata_lte)
49                 return WIMLIB_ERR_NOMEM;
50
51         metadata_lte->resource_entry.flags = WIM_RESHDR_FLAG_METADATA;
52         metadata_lte->unhashed = 1;
53
54         new_imd = new_image_metadata();
55         if (!new_imd) {
56                 free_lookup_table_entry(metadata_lte);
57                 return WIMLIB_ERR_NOMEM;
58         }
59
60         new_imd->root_dentry    = root_dentry;
61         new_imd->metadata_lte   = metadata_lte;
62         new_imd->security_data  = sd;
63         new_imd->modified       = 1;
64
65         ret = append_image_metadata(wim, new_imd);
66         if (ret)
67                 put_image_metadata(new_imd, NULL);
68         return ret;
69 }
70
71 /* Append an empty image to the WIMStruct. */
72 WIMLIBAPI int
73 wimlib_add_empty_image(WIMStruct *wim, const tchar *name, int *new_idx_ret)
74 {
75         int ret;
76         struct wim_security_data *sd;
77
78         DEBUG("Adding empty image \"%"TS"\"", name);
79
80         if (name == NULL)
81                 name = T("");
82
83         if (wim->hdr.total_parts != 1) {
84                 ERROR("Cannot add an image to a split WIM");
85                 ret = WIMLIB_ERR_SPLIT_UNSUPPORTED;
86                 goto out;
87         }
88
89         if (wimlib_image_name_in_use(wim, name)) {
90                 ERROR("There is already an image named \"%"TS"\" in the WIM!",
91                       name);
92                 ret = WIMLIB_ERR_IMAGE_NAME_COLLISION;
93                 goto out;
94         }
95
96         sd = new_wim_security_data();
97         if (!sd) {
98                 ret = WIMLIB_ERR_NOMEM;
99                 goto out;
100         }
101
102         ret = add_new_dentry_tree(wim, NULL, sd);
103         if (ret)
104                 goto out_free_security_data;
105
106         ret = xml_add_image(wim, name);
107         if (ret)
108                 goto out_put_image_metadata;
109
110         if (new_idx_ret)
111                 *new_idx_ret = wim->hdr.image_count;
112         DEBUG("Successfully added new image (index %d)",
113               wim->hdr.image_count);
114         goto out;
115 out_put_image_metadata:
116         put_image_metadata(wim->image_metadata[--wim->hdr.image_count],
117                            wim->lookup_table);
118         goto out;
119 out_free_security_data:
120         free_wim_security_data(sd);
121 out:
122         return ret;
123 }
124
125 static struct wimlib_update_command *
126 capture_sources_to_add_cmds(const struct wimlib_capture_source *sources,
127                             size_t num_sources,
128                             int add_flags,
129                             const struct wimlib_capture_config *config)
130 {
131         struct wimlib_update_command *add_cmds;
132
133         DEBUG("Translating %zu capture sources to `struct wimlib_update_command's",
134               num_sources);
135         add_cmds = CALLOC(num_sources, sizeof(add_cmds[0]));
136         if (add_cmds) {
137                 for (size_t i = 0; i < num_sources; i++) {
138                         DEBUG("Source %zu of %zu: fs_source_path=\"%"TS"\", "
139                               "wim_target_path=\"%"TS"\"",
140                               i + 1, num_sources,
141                               sources[i].fs_source_path,
142                               sources[i].wim_target_path);
143                         add_cmds[i].op = WIMLIB_UPDATE_OP_ADD;
144                         add_cmds[i].add.add_flags = add_flags;
145                         add_cmds[i].add.config = (struct wimlib_capture_config*)config;
146                         add_cmds[i].add.fs_source_path = sources[i].fs_source_path;
147                         add_cmds[i].add.wim_target_path = sources[i].wim_target_path;
148                 }
149         }
150         return add_cmds;
151 }
152
153 /* Adds an image to the WIMStruct from multiple on-disk directory trees, or a
154  * NTFS volume. */
155 WIMLIBAPI int
156 wimlib_add_image_multisource(WIMStruct *wim,
157                              const struct wimlib_capture_source *sources,
158                              size_t num_sources,
159                              const tchar *name,
160                              const struct wimlib_capture_config *config,
161                              int add_flags,
162                              wimlib_progress_func_t progress_func)
163 {
164         int ret;
165         struct wimlib_update_command *add_cmds;
166
167         DEBUG("Adding image \"%"TS"\" from %zu sources (add_flags=%#x)",
168               name, num_sources, add_flags);
169
170         /* Add the new image (initially empty) */
171         ret = wimlib_add_empty_image(wim, name, NULL);
172         if (ret)
173                 goto out;
174
175         /* Translate the "capture sources" into generic update commands. */
176         add_cmds = capture_sources_to_add_cmds(sources, num_sources,
177                                                add_flags, config);
178         if (!add_cmds) {
179                 ret = WIMLIB_ERR_NOMEM;
180                 goto out_delete_image;
181         }
182
183         /* Delegate the work to wimlib_update_image(). */
184         ret = wimlib_update_image(wim, wim->hdr.image_count, add_cmds,
185                                   num_sources, 0, progress_func);
186         FREE(add_cmds);
187         if (ret)
188                 goto out_delete_image;
189
190         /* Success; set boot index if requested. */
191         if (add_flags & WIMLIB_ADD_FLAG_BOOT)
192                 wim->hdr.boot_idx = wim->hdr.image_count;
193         ret = 0;
194         goto out;
195 out_delete_image:
196         /* Roll back the image we added */
197         put_image_metadata(wim->image_metadata[wim->hdr.image_count - 1],
198                            wim->lookup_table);
199         xml_delete_image(&wim->wim_info, wim->hdr.image_count);
200         wim->hdr.image_count--;
201 out:
202         return ret;
203 }
204
205 /* Adds an image to the WIMStruct from an on-disk directory tree or NTFS volume. */
206 WIMLIBAPI int
207 wimlib_add_image(WIMStruct *wim,
208                  const tchar *source,
209                  const tchar *name,
210                  const struct wimlib_capture_config *config,
211                  int add_flags,
212                  wimlib_progress_func_t progress_func)
213 {
214         /* Delegate the work to the more general wimlib_add_image_multisource().
215          * */
216         const struct wimlib_capture_source capture_src = {
217                 .fs_source_path = (tchar*)source,
218                 .wim_target_path = T(""),
219                 .reserved = 0,
220         };
221         return wimlib_add_image_multisource(wim, &capture_src, 1, name,
222                                             config, add_flags,
223                                             progress_func);
224 }