a544c7b8d6ca032449b1ab24b2b85d17ebbc05ef
[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, 2014 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/error.h"
30 #include "wimlib/lookup_table.h"
31 #include "wimlib/metadata.h"
32 #include "wimlib/security.h"
33 #include "wimlib/xml.h"
34
35 /* Creates and appends a 'struct wim_image_metadata' for an empty image.
36  *
37  * The resulting image will be the last in the WIM, so its index will be
38  * the new value of wim->hdr.image_count.  */
39 static int
40 add_empty_image_metadata(WIMStruct *wim)
41 {
42         int ret;
43         struct wim_lookup_table_entry *metadata_lte;
44         struct wim_security_data *sd;
45         struct wim_image_metadata *imd;
46
47         /* Create lookup table entry for this metadata resource (for now really
48          * just a dummy entry).  */
49         ret = WIMLIB_ERR_NOMEM;
50         metadata_lte = new_lookup_table_entry();
51         if (!metadata_lte)
52                 goto out;
53
54         metadata_lte->flags = WIM_RESHDR_FLAG_METADATA;
55         metadata_lte->unhashed = 1;
56
57         /* Create empty security data (no security descriptors).  */
58         sd = new_wim_security_data();
59         if (!sd)
60                 goto out_free_metadata_lte;
61
62         imd = new_image_metadata();
63         if (!imd)
64                 goto out_free_security_data;
65
66         /* A NULL root_dentry indicates a completely empty image, without even a
67          * root directory.  */
68         imd->root_dentry = NULL;
69         imd->metadata_lte = metadata_lte;
70         imd->security_data = sd;
71         imd->modified = 1;
72
73         /* Append as next image index.  */
74         ret = append_image_metadata(wim, imd);
75         if (ret)
76                 put_image_metadata(imd, NULL);
77         goto out;
78
79 out_free_security_data:
80         free_wim_security_data(sd);
81 out_free_metadata_lte:
82         free_lookup_table_entry(metadata_lte);
83 out:
84         return ret;
85 }
86
87 /* API function documented in wimlib.h  */
88 WIMLIBAPI int
89 wimlib_add_empty_image(WIMStruct *wim, const tchar *name, int *new_idx_ret)
90 {
91         int ret;
92
93         ret = can_modify_wim(wim);
94         if (ret)
95                 return ret;
96
97         if (!name)
98                 name = T("");
99
100         if (wimlib_image_name_in_use(wim, name)) {
101                 ERROR("There is already an image named \"%"TS"\" in the WIM!",
102                       name);
103                 return WIMLIB_ERR_IMAGE_NAME_COLLISION;
104         }
105
106         ret = add_empty_image_metadata(wim);
107         if (ret)
108                 return ret;
109
110         ret = xml_add_image(wim, name);
111         if (ret) {
112                 put_image_metadata(wim->image_metadata[--wim->hdr.image_count],
113                                    NULL);
114                 return ret;
115         }
116
117         if (new_idx_ret)
118                 *new_idx_ret = wim->hdr.image_count;
119         return 0;
120 }
121
122 /* Translate the 'struct wimlib_capture_source's passed to
123  * wimlib_add_image_multisource() into 'struct wimlib_update_command's for
124  * wimlib_update_image().  */
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 tchar *config_file)
130 {
131         struct wimlib_update_command *add_cmds;
132
133         add_cmds = CALLOC(num_sources, sizeof(add_cmds[0]));
134         if (!add_cmds)
135                 return NULL;
136
137         /* WIMLIB_ADD_FLAG_BOOT is handled by wimlib_add_image_multisource(),
138          * not wimlib_update_image(), so mask it out.
139          *
140          * However, WIMLIB_ADD_FLAG_WIMBOOT is handled by both.  */
141         add_flags &= ~WIMLIB_ADD_FLAG_BOOT;
142
143         for (size_t i = 0; i < num_sources; i++) {
144                 add_cmds[i].op = WIMLIB_UPDATE_OP_ADD;
145                 add_cmds[i].add.fs_source_path = sources[i].fs_source_path;
146                 add_cmds[i].add.wim_target_path = sources[i].wim_target_path;
147                 add_cmds[i].add.add_flags = add_flags;
148                 add_cmds[i].add.config_file = (tchar *)config_file;
149         }
150         return add_cmds;
151 }
152
153 /* API function documented in wimlib.h  */
154 WIMLIBAPI int
155 wimlib_add_image_multisource(WIMStruct *wim,
156                              const struct wimlib_capture_source *sources,
157                              size_t num_sources,
158                              const tchar *name,
159                              const tchar *config_file,
160                              int add_flags,
161                              wimlib_progress_func_t progress_func)
162 {
163         int ret;
164         struct wimlib_update_command *add_cmds;
165
166         /* Make sure no reserved fields are set.  */
167         for (size_t i = 0; i < num_sources; i++)
168                 if (sources[i].reserved != 0)
169                         return WIMLIB_ERR_INVALID_PARAM;
170
171         /* Add the new image (initially empty).  */
172         ret = wimlib_add_empty_image(wim, name, NULL);
173         if (ret)
174                 return ret;
175
176         /* Translate the "capture sources" into generic update commands.  */
177         ret = WIMLIB_ERR_NOMEM;
178         add_cmds = capture_sources_to_add_cmds(sources, num_sources,
179                                                add_flags, config_file);
180         if (!add_cmds)
181                 goto out_delete_image;
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         /* If requested, set this image as the WIM's bootable image.  */
191         if (add_flags & WIMLIB_ADD_FLAG_BOOT)
192                 wim->hdr.boot_idx = wim->hdr.image_count;
193
194         /* If requested, mark new image as WIMBoot-compatible.  */
195         if (add_flags & WIMLIB_ADD_FLAG_WIMBOOT)
196                 wim_info_set_wimboot(wim->wim_info, wim->hdr.image_count, true);
197
198         return 0;
199
200 out_delete_image:
201         /* Unsuccessful; rollback the WIM to its original state.  */
202
203         /* wimlib_update_image() is now all-or-nothing, so no dentries remain
204          * and there's no need to pass the lookup table here.  */
205         put_image_metadata(wim->image_metadata[wim->hdr.image_count - 1], NULL);
206
207         xml_delete_image(&wim->wim_info, wim->hdr.image_count);
208         wim->hdr.image_count--;
209         return ret;
210 }
211
212 /* API function documented in wimlib.h  */
213 WIMLIBAPI int
214 wimlib_add_image(WIMStruct *wim,
215                  const tchar *source,
216                  const tchar *name,
217                  const tchar *config_file,
218                  int add_flags,
219                  wimlib_progress_func_t progress_func)
220 {
221         /* Use the more general wimlib_add_image_multisource().  */
222         const struct wimlib_capture_source capture_src = {
223                 .fs_source_path = (tchar *)source,
224                 .wim_target_path = WIMLIB_WIM_ROOT_PATH,
225                 .reserved = 0,
226         };
227         return wimlib_add_image_multisource(wim, &capture_src, 1, name,
228                                             config_file, add_flags,
229                                             progress_func);
230 }