+
+/* API function documented in wimlib.h */
+WIMLIBAPI int
+wimlib_extract_pathlist(WIMStruct *wim, int image,
+ const tchar *target,
+ const tchar *path_list_file,
+ int extract_flags,
+ wimlib_progress_func_t progress_func)
+{
+ int ret;
+ tchar **paths;
+ size_t num_paths;
+ void *mem;
+
+ ret = read_path_list_file(path_list_file, &paths, &num_paths, &mem);
+ if (ret)
+ return ret;
+
+ ret = wimlib_extract_paths(wim, image, target,
+ (const tchar * const *)paths, num_paths,
+ extract_flags, progress_func);
+ FREE(paths);
+ FREE(mem);
+ return ret;
+}
+
+struct append_dentry_ctx {
+ struct wim_dentry **dentries;
+ size_t num_dentries;
+ size_t num_alloc_dentries;
+};
+
+static int
+append_dentry_cb(struct wim_dentry *dentry, void *_ctx)
+{
+ struct append_dentry_ctx *ctx = _ctx;
+
+ if (ctx->num_dentries == ctx->num_alloc_dentries) {
+ struct wim_dentry **new_dentries;
+ size_t new_length;
+
+ new_length = max(ctx->num_alloc_dentries + 8,
+ ctx->num_alloc_dentries * 3 / 2);
+ new_dentries = REALLOC(ctx->dentries,
+ new_length * sizeof(ctx->dentries[0]));
+ if (new_dentries == NULL)
+ return WIMLIB_ERR_NOMEM;
+ ctx->dentries = new_dentries;
+ ctx->num_alloc_dentries = new_length;
+ }
+ ctx->dentries[ctx->num_dentries++] = dentry;
+ return 0;
+}
+
+/* API function documented in wimlib.h */
+WIMLIBAPI int
+wimlib_extract_paths(WIMStruct *wim,
+ int image,
+ const tchar *target,
+ const tchar * const *paths,
+ size_t num_paths,
+ int extract_flags,
+ wimlib_progress_func_t progress_func)
+{
+ int ret;
+ struct append_dentry_ctx append_dentry_ctx = {
+ .dentries = NULL,
+ .num_dentries = 0,
+ .num_alloc_dentries = 0,
+ };
+ struct wim_dentry **trees;
+ size_t num_trees;
+
+ extract_flags &= WIMLIB_EXTRACT_MASK_PUBLIC;
+
+ if (target == NULL || (num_paths != 0 && paths == NULL))
+ return WIMLIB_ERR_INVALID_PARAM;
+
+ ret = select_wim_image(wim, image);
+ if (ret)
+ return ret;
+
+ if (extract_flags & WIMLIB_EXTRACT_FLAG_GLOB_PATHS) {
+ u32 wildcard_flags = 0;
+
+ if (extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_GLOB)
+ wildcard_flags |= WILDCARD_FLAG_ERROR_IF_NO_MATCH;
+ else
+ wildcard_flags |= WILDCARD_FLAG_WARN_IF_NO_MATCH;
+
+ if (default_ignore_case)
+ wildcard_flags |= WILDCARD_FLAG_CASE_INSENSITIVE;
+
+ for (size_t i = 0; i < num_paths; i++) {
+ ret = expand_wildcard(wim, paths[i],
+ append_dentry_cb,
+ &append_dentry_ctx,
+ wildcard_flags);
+ if (ret) {
+ trees = append_dentry_ctx.dentries;
+ goto out_free_trees;
+ }
+ }
+ trees = append_dentry_ctx.dentries;
+ num_trees = append_dentry_ctx.num_dentries;
+ } else {
+ trees = MALLOC(num_paths * sizeof(trees[0]));
+ if (trees == NULL)
+ return WIMLIB_ERR_NOMEM;
+
+ for (size_t i = 0; i < num_paths; i++) {
+ trees[i] = get_dentry(wim, paths[i],
+ WIMLIB_CASE_PLATFORM_DEFAULT);
+ if (trees[i] == NULL) {
+ ERROR("Path \"%"TS"\" does not exist "
+ "in WIM image %d",
+ paths[i], wim->current_image);
+ ret = WIMLIB_ERR_PATH_DOES_NOT_EXIST;
+ goto out_free_trees;
+ }
+ }
+ num_trees = num_paths;
+ }
+
+ if (num_trees == 0) {
+ ret = 0;
+ goto out_free_trees;
+ }
+
+ ret = extract_trees(wim, trees, num_trees,
+ T(""), target,
+ ((extract_flags &
+ ~WIMLIB_EXTRACT_FLAG_GLOB_PATHS)
+ | WIMLIB_EXTRACT_FLAG_PATHMODE),
+ progress_func);
+out_free_trees:
+ FREE(trees);
+ return ret;
+}