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