4 * Reference resources from external WIM file(s).
8 * Copyright (C) 2013, 2014 Eric Biggers
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
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
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/.
29 #include "wimlib/error.h"
30 #include "wimlib/glob.h"
31 #include "wimlib/lookup_table.h"
32 #include "wimlib/wim.h"
34 #define WIMLIB_REF_MASK_PUBLIC (WIMLIB_REF_FLAG_GLOB_ENABLE | \
35 WIMLIB_REF_FLAG_GLOB_ERR_ON_NOMATCH)
37 struct reference_info {
39 struct list_head new_streams;
40 struct list_head new_subwims;
42 struct wim_lookup_table *src_table;
46 init_reference_info(struct reference_info *info, WIMStruct *dest_wim,
49 info->dest_wim = dest_wim;
50 INIT_LIST_HEAD(&info->new_streams);
51 INIT_LIST_HEAD(&info->new_subwims);
52 info->ref_flags = ref_flags;
56 commit_reference_info(struct reference_info *info)
58 list_splice(&info->new_subwims, &info->dest_wim->subwims);
62 rollback_reference_info(struct reference_info *info)
65 struct wim_lookup_table_entry *lte;
67 while (!list_empty(&info->new_subwims)) {
68 subwim = list_first_entry(&info->new_subwims,
69 WIMStruct, subwim_node);
70 list_del(&subwim->subwim_node);
74 while (!list_empty(&info->new_streams)) {
75 lte = list_first_entry(&info->new_streams,
76 struct wim_lookup_table_entry,
78 list_del(<e->lookup_table_list);
79 lookup_table_unlink(info->dest_wim->lookup_table, lte);
80 free_lookup_table_entry(lte);
85 commit_or_rollback_reference_info(struct reference_info *info, int ret)
88 rollback_reference_info(info);
90 commit_reference_info(info);
95 need_stream(const struct reference_info *info,
96 const struct wim_lookup_table_entry *lte)
98 return !lookup_stream(info->dest_wim->lookup_table, lte->hash);
102 reference_stream(struct reference_info *info,
103 struct wim_lookup_table_entry *lte)
105 lookup_table_insert(info->dest_wim->lookup_table, lte);
106 list_add(<e->lookup_table_list, &info->new_streams);
110 reference_subwim(struct reference_info *info, WIMStruct *subwim)
112 list_add(&subwim->subwim_node, &info->new_subwims);
116 lte_clone_if_new(struct wim_lookup_table_entry *lte, void *_info)
118 struct reference_info *info = _info;
120 if (need_stream(info, lte)) {
121 lte = clone_lookup_table_entry(lte);
123 return WIMLIB_ERR_NOMEM;
124 reference_stream(info, lte);
129 /* API function documented in wimlib.h */
131 wimlib_reference_resources(WIMStruct *wim, WIMStruct **resource_wims,
132 unsigned num_resource_wims, int ref_flags)
135 struct reference_info info;
139 return WIMLIB_ERR_INVALID_PARAM;
141 if (num_resource_wims != 0 && resource_wims == NULL)
142 return WIMLIB_ERR_INVALID_PARAM;
144 if (ref_flags & ~WIMLIB_REF_MASK_PUBLIC)
145 return WIMLIB_ERR_INVALID_PARAM;
147 for (i = 0; i < num_resource_wims; i++)
148 if (resource_wims[i] == NULL)
149 return WIMLIB_ERR_INVALID_PARAM;
151 init_reference_info(&info, wim, ref_flags);
153 for (i = 0; i < num_resource_wims; i++) {
154 ret = for_lookup_table_entry(resource_wims[i]->lookup_table,
155 lte_clone_if_new, &info);
160 return commit_or_rollback_reference_info(&info, ret);
164 lte_gift(struct wim_lookup_table_entry *lte, void *_info)
166 struct reference_info *info = _info;
168 lookup_table_unlink(info->src_table, lte);
169 if (need_stream(info, lte))
170 reference_stream(info, lte);
172 free_lookup_table_entry(lte);
177 reference_resource_path(struct reference_info *info, const tchar *path,
183 ret = wimlib_open_wim_with_progress(path, open_flags, &src_wim,
184 info->dest_wim->progfunc,
185 info->dest_wim->progctx);
189 info->src_table = src_wim->lookup_table;
190 for_lookup_table_entry(src_wim->lookup_table, lte_gift, info);
191 reference_subwim(info, src_wim);
196 reference_resource_paths(struct reference_info *info,
197 const tchar * const *paths, unsigned num_paths,
200 for (unsigned i = 0; i < num_paths; i++) {
201 int ret = reference_resource_path(info, paths[i], open_flags);
209 reference_resource_glob(struct reference_info *info,
210 const tchar *refglob, int open_flags)
215 /* Note: glob() is replaced in Windows native builds. */
216 ret = tglob(refglob, GLOB_ERR | GLOB_NOSORT, NULL, &globbuf);
218 if (ret == GLOB_NOMATCH) {
219 if (info->ref_flags &
220 WIMLIB_REF_FLAG_GLOB_ERR_ON_NOMATCH)
222 ERROR("Found no files for glob \"%"TS"\"", refglob);
223 return WIMLIB_ERR_GLOB_HAD_NO_MATCHES;
225 return reference_resource_path(info,
229 ERROR_WITH_ERRNO("Failed to process glob \"%"TS"\"", refglob);
230 if (ret == GLOB_NOSPACE)
231 return WIMLIB_ERR_NOMEM;
232 return WIMLIB_ERR_READ;
235 ret = reference_resource_paths(info,
236 (const tchar * const *)globbuf.gl_pathv,
244 reference_resource_globs(struct reference_info *info,
245 const tchar * const *globs, unsigned num_globs,
248 for (unsigned i = 0; i < num_globs; i++) {
249 int ret = reference_resource_glob(info, globs[i], open_flags);
256 /* API function documented in wimlib.h */
258 wimlib_reference_resource_files(WIMStruct *wim,
259 const tchar * const *paths_or_globs,
260 unsigned count, int ref_flags, int open_flags)
262 struct reference_info info;
265 if (ref_flags & ~WIMLIB_REF_MASK_PUBLIC)
266 return WIMLIB_ERR_INVALID_PARAM;
268 init_reference_info(&info, wim, ref_flags);
270 if (ref_flags & WIMLIB_REF_FLAG_GLOB_ENABLE)
271 ret = reference_resource_globs(&info, paths_or_globs, count, open_flags);
273 ret = reference_resource_paths(&info, paths_or_globs, count, open_flags);
275 return commit_or_rollback_reference_info(&info, ret);