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