+ return match_pattern_list(path, path_nchars, pats);
+}
+
+/* Returns %true if the specified absolute path to a file in the WIM image can
+ * be subject to external backing when extracted. Otherwise returns %false. */
+static bool
+can_externally_back_path(const wchar_t *path, size_t path_nchars,
+ const struct win32_apply_ctx *ctx)
+{
+ if (in_prepopulate_list(path, path_nchars, ctx))
+ return false;
+
+ /* Since we attempt to modify the SYSTEM registry after it's extracted
+ * (see end_wimboot_extraction()), it can't be extracted as externally
+ * backed. This extends to associated files such as SYSTEM.LOG that
+ * also must be writable in order to write to the registry. Normally,
+ * SYSTEM is in [PrepopulateList], and the SYSTEM.* files match patterns
+ * in [ExclusionList] and therefore are not captured in the WIM at all.
+ * However, a WIM that wasn't specifically captured in "WIMBoot mode"
+ * may contain SYSTEM.* files. So to make things "just work", hard-code
+ * the pattern. */
+ if (match_path(path, path_nchars, L"\\Windows\\System32\\config\\SYSTEM*",
+ OS_PREFERRED_PATH_SEPARATOR, false))
+ return false;
+
+ return true;
+}
+
+static const wchar_t *
+current_path(struct win32_apply_ctx *ctx);
+
+static void
+build_extraction_path(const struct wim_dentry *dentry,
+ struct win32_apply_ctx *ctx);
+
+#define WIM_BACKING_NOT_ENABLED -1
+#define WIM_BACKING_NOT_POSSIBLE -2
+#define WIM_BACKING_EXCLUDED -3
+
+/*
+ * Determines if the unnamed data stream of a file will be created as an
+ * external backing, as opposed to a standard extraction.
+ */
+static int
+win32_will_externally_back(struct wim_dentry *dentry, struct apply_ctx *_ctx)
+{
+ struct win32_apply_ctx *ctx = (struct win32_apply_ctx *)_ctx;
+ struct wim_lookup_table_entry *stream;
+ int ret;
+
+ if (!(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT))
+ return WIM_BACKING_NOT_ENABLED;
+
+ if (!ctx->wimboot.tried_to_load_prepopulate_list) {
+ ret = load_prepopulate_pats(ctx);
+ if (ret == WIMLIB_ERR_NOMEM)
+ return ret;
+ }
+
+ if (dentry->d_inode->i_attributes & (FILE_ATTRIBUTE_DIRECTORY |
+ FILE_ATTRIBUTE_REPARSE_POINT |
+ FILE_ATTRIBUTE_ENCRYPTED))
+ return WIM_BACKING_NOT_POSSIBLE;
+
+ stream = inode_unnamed_lte_resolved(dentry->d_inode);
+
+ if (!stream ||
+ stream->resource_location != RESOURCE_IN_WIM ||
+ stream->rspec->wim != ctx->common.wim ||
+ stream->size != stream->rspec->uncompressed_size)
+ return WIM_BACKING_NOT_POSSIBLE;
+
+ ret = calculate_dentry_full_path(dentry);
+ if (ret)
+ return ret;
+
+ if (!can_externally_back_path(dentry->_full_path,
+ wcslen(dentry->_full_path), ctx))
+ return WIM_BACKING_EXCLUDED;
+
+ return 0;
+}
+
+static int
+set_external_backing(HANDLE h, struct wim_dentry *dentry, struct win32_apply_ctx *ctx)
+{
+ int ret;
+
+ ret = win32_will_externally_back(dentry, &ctx->common);
+ if (ret > 0) /* Error. */
+ return ret;
+
+ if (ret < 0 && ret != WIM_BACKING_EXCLUDED)
+ return 0; /* Not externally backing, other than due to exclusion. */
+
+ build_extraction_path(dentry, ctx);
+
+ if (ret == WIM_BACKING_EXCLUDED) {
+ /* Not externally backing due to exclusion. */
+ union wimlib_progress_info info;
+
+ info.wimboot_exclude.path_in_wim = dentry->_full_path;
+ info.wimboot_exclude.extraction_path = current_path(ctx);
+
+ return call_progress(ctx->common.progfunc,
+ WIMLIB_PROGRESS_MSG_WIMBOOT_EXCLUDE,
+ &info, ctx->common.progctx);
+ } else {
+ /* Externally backing. */
+ return wimboot_set_pointer(h,
+ current_path(ctx),
+ inode_unnamed_lte_resolved(dentry->d_inode),
+ ctx->wimboot.data_source_id,
+ ctx->wimboot.wim_lookup_table_hash,
+ ctx->wimboot.wof_running);
+ }