]> wimlib.net Git - wimlib/blob - src/reference.c
Use LGPLv3+ for src/*.c
[wimlib] / src / reference.c
1 /*
2  * reference.c
3  *
4  * Reference resources from external WIM file(s).
5  */
6
7 /*
8  * Copyright (C) 2013 Eric Biggers
9  *
10  * This file is free software; you can redistribute it and/or modify it under
11  * the terms of the GNU Lesser General Public License as published by the Free
12  * Software Foundation; either version 3 of the License, or (at your option) any
13  * later version.
14  *
15  * This file is distributed in the hope that it will be useful, but WITHOUT
16  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU Lesser General Public License
21  * along with this file; 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/glob.h"
31 #include "wimlib/lookup_table.h"
32 #include "wimlib/wim.h"
33
34 #define WIMLIB_REF_MASK_PUBLIC (WIMLIB_REF_FLAG_GLOB_ENABLE | \
35                                 WIMLIB_REF_FLAG_GLOB_ERR_ON_NOMATCH)
36
37 #define WIMLIB_REF_FLAG_GIFT 0x80000000
38
39 struct lookup_tables {
40         struct wim_lookup_table *src_table;
41         struct wim_lookup_table *dest_table;
42 };
43
44 static int
45 lte_gift(struct wim_lookup_table_entry *lte, void *_tables)
46 {
47         struct lookup_tables *tables = _tables;
48         struct wim_lookup_table *src_table = tables->src_table;
49         struct wim_lookup_table *dest_table = tables->dest_table;
50
51         lookup_table_unlink(src_table, lte);
52         if (lookup_stream(dest_table, lte->hash)) {
53                 free_lookup_table_entry(lte);
54         } else {
55                 lte->out_refcnt = 1;
56                 lookup_table_insert(dest_table, lte);
57         }
58         return 0;
59 }
60
61 static int
62 lte_clone_if_new(struct wim_lookup_table_entry *lte, void *_lookup_table)
63 {
64         struct wim_lookup_table *lookup_table = _lookup_table;
65
66         if (lookup_stream(lookup_table, lte->hash))
67                 return 0;  /*  Resource already present.  */
68
69         lte = clone_lookup_table_entry(lte);
70         if (lte == NULL)
71                 return WIMLIB_ERR_NOMEM;
72         lte->out_refcnt = 1;
73         lookup_table_insert(lookup_table, lte);
74         return 0;
75 }
76
77 static int
78 lte_delete_if_new(struct wim_lookup_table_entry *lte, void *_lookup_table)
79 {
80         struct wim_lookup_table *lookup_table = _lookup_table;
81
82         if (lte->out_refcnt) {
83                 lookup_table_unlink(lookup_table, lte);
84                 free_lookup_table_entry(lte);
85         }
86         return 0;
87 }
88
89 static int
90 do_wimlib_reference_resources(WIMStruct *wim, WIMStruct **resource_wims,
91                               unsigned num_resource_wims, int ref_flags)
92 {
93         unsigned i;
94         int ret;
95
96         if (ref_flags & WIMLIB_REF_FLAG_GIFT) {
97                 struct lookup_tables tables;
98
99                 tables.dest_table = wim->lookup_table;
100
101                 for (i = 0; i < num_resource_wims; i++) {
102
103                         tables.src_table = resource_wims[i]->lookup_table;
104
105                         ret = for_lookup_table_entry(resource_wims[i]->lookup_table,
106                                                      lte_gift, &tables);
107                         if (ret)
108                                 goto out_rollback;
109                 }
110         } else {
111                 for (i = 0; i < num_resource_wims; i++) {
112                         ret = for_lookup_table_entry(resource_wims[i]->lookup_table,
113                                                      lte_clone_if_new, wim->lookup_table);
114                         if (ret)
115                                 goto out_rollback;
116                 }
117         }
118         return 0;
119
120 out_rollback:
121         for_lookup_table_entry(wim->lookup_table, lte_delete_if_new,
122                                wim->lookup_table);
123         return ret;
124 }
125
126 /* API function documented in wimlib.h  */
127 WIMLIBAPI int
128 wimlib_reference_resources(WIMStruct *wim,
129                            WIMStruct **resource_wims, unsigned num_resource_wims,
130                            int ref_flags)
131 {
132         unsigned i;
133
134         if (wim == NULL)
135                 return WIMLIB_ERR_INVALID_PARAM;
136
137         if (num_resource_wims != 0 && resource_wims == NULL)
138                 return WIMLIB_ERR_INVALID_PARAM;
139
140         if (ref_flags & ~WIMLIB_REF_MASK_PUBLIC)
141                 return WIMLIB_ERR_INVALID_PARAM;
142
143         for (i = 0; i < num_resource_wims; i++)
144                 if (resource_wims[i] == NULL)
145                         return WIMLIB_ERR_INVALID_PARAM;
146
147         return do_wimlib_reference_resources(wim, resource_wims,
148                                              num_resource_wims, ref_flags);
149 }
150
151 static int
152 reference_resource_paths(WIMStruct *wim,
153                          const tchar * const *resource_wimfiles,
154                          unsigned num_resource_wimfiles,
155                          int ref_flags,
156                          int open_flags)
157 {
158         WIMStruct **resource_wims;
159         unsigned i;
160         int ret;
161
162         resource_wims = CALLOC(num_resource_wimfiles, sizeof(resource_wims[0]));
163         if (!resource_wims)
164                 return WIMLIB_ERR_NOMEM;
165
166         for (i = 0; i < num_resource_wimfiles; i++) {
167                 DEBUG("Referencing resources from path \"%"TS"\"",
168                       resource_wimfiles[i]);
169                 ret = wimlib_open_wim_with_progress(resource_wimfiles[i],
170                                                     open_flags,
171                                                     &resource_wims[i],
172                                                     wim->progfunc,
173                                                     wim->progctx);
174                 if (ret)
175                         goto out_free_resource_wims;
176         }
177
178         ret = do_wimlib_reference_resources(wim, resource_wims,
179                                             num_resource_wimfiles,
180                                             ref_flags | WIMLIB_REF_FLAG_GIFT);
181         if (ret)
182                 goto out_free_resource_wims;
183
184         for (i = 0; i < num_resource_wimfiles; i++)
185                 list_add_tail(&resource_wims[i]->subwim_node, &wim->subwims);
186
187         ret = 0;
188         goto out_free_array;
189
190 out_free_resource_wims:
191         for (i = 0; i < num_resource_wimfiles; i++)
192                 wimlib_free(resource_wims[i]);
193 out_free_array:
194         FREE(resource_wims);
195         return ret;
196 }
197
198 static int
199 reference_resource_glob(WIMStruct *wim, const tchar *refglob,
200                         int ref_flags, int open_flags)
201 {
202         glob_t globbuf;
203         int ret;
204
205         /* Note: glob() is replaced in Windows native builds.  */
206         ret = tglob(refglob, GLOB_ERR | GLOB_NOSORT, NULL, &globbuf);
207         if (ret) {
208                 if (ret == GLOB_NOMATCH) {
209                         if (ref_flags & WIMLIB_REF_FLAG_GLOB_ERR_ON_NOMATCH) {
210                                 ERROR("Found no files for glob \"%"TS"\"", refglob);
211                                 return WIMLIB_ERR_GLOB_HAD_NO_MATCHES;
212                         } else {
213                                 return reference_resource_paths(wim,
214                                                                 &refglob,
215                                                                 1,
216                                                                 ref_flags,
217                                                                 open_flags);
218                         }
219                 } else {
220                         ERROR_WITH_ERRNO("Failed to process glob \"%"TS"\"", refglob);
221                         if (ret == GLOB_NOSPACE)
222                                 return WIMLIB_ERR_NOMEM;
223                         else
224                                 return WIMLIB_ERR_READ;
225                 }
226         }
227
228         ret = reference_resource_paths(wim,
229                                        (const tchar * const *)globbuf.gl_pathv,
230                                        globbuf.gl_pathc,
231                                        ref_flags,
232                                        open_flags);
233         globfree(&globbuf);
234         return ret;
235 }
236
237 /* API function documented in wimlib.h  */
238 WIMLIBAPI int
239 wimlib_reference_resource_files(WIMStruct *wim,
240                                 const tchar * const * resource_wimfiles_or_globs,
241                                 unsigned count,
242                                 int ref_flags,
243                                 int open_flags)
244 {
245         unsigned i;
246         int ret;
247
248         if (ref_flags & ~WIMLIB_REF_MASK_PUBLIC)
249                 return WIMLIB_ERR_INVALID_PARAM;
250
251         if (ref_flags & WIMLIB_REF_FLAG_GLOB_ENABLE) {
252                 for (i = 0; i < count; i++) {
253                         ret = reference_resource_glob(wim,
254                                                       resource_wimfiles_or_globs[i],
255                                                       ref_flags,
256                                                       open_flags);
257                         if (ret)
258                                 return ret;
259                 }
260                 return 0;
261         } else {
262                 return reference_resource_paths(wim, resource_wimfiles_or_globs,
263                                                 count, ref_flags, open_flags);
264         }
265 }