-static bool
-dentry_in_list(const struct wim_dentry *dentry)
-{
- return dentry->extraction_list.next != NULL;
-}
-
-static inline bool
-is_linked_extraction(const struct apply_ctx *ctx)
-{
- return 0 != (ctx->extract_flags & (WIMLIB_EXTRACT_FLAG_HARDLINK |
- WIMLIB_EXTRACT_FLAG_SYMLINK));
-}
-
-static inline bool
-can_extract_named_data_streams(const struct apply_ctx *ctx)
-{
- return ctx->supported_features.named_data_streams &&
- !is_linked_extraction(ctx);
-}
-/* Inform library user of progress of stream extraction following the successful
- * extraction of a copy of the stream specified by @lte. */
-static void
-update_extract_progress(struct apply_ctx *ctx,
- const struct wim_lookup_table_entry *lte)
-{
- wimlib_progress_func_t progress_func = ctx->progress_func;
- union wimlib_progress_info *progress = &ctx->progress;
-
- progress->extract.completed_bytes += lte->size;
- if (progress_func &&
- progress->extract.completed_bytes >= ctx->next_progress)
- {
- progress_func(WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS, progress);
- if (progress->extract.completed_bytes >=
- progress->extract.total_bytes)
- {
- ctx->next_progress = ~0ULL;
- } else {
- ctx->next_progress += progress->extract.total_bytes / 128;
- if (ctx->next_progress > progress->extract.total_bytes)
- ctx->next_progress = progress->extract.total_bytes;
- }
- }
-}
-
-#ifndef __WIN32__
-/* Extract a symbolic link (not directly as reparse data), handling fixing up
- * the target of absolute symbolic links and updating the extract progress.
- *
- * @inode must specify the WIM inode for a symbolic link or junction reparse
- * point.
- *
- * @lte_override overrides the resource used as the reparse data for the
- * symbolic link. */
-static int
-extract_symlink(const tchar *path, struct apply_ctx *ctx,
- struct wim_inode *inode,
- struct wim_lookup_table_entry *lte_override)
-{
- ssize_t bufsize = ctx->ops->path_max;
- tchar target[bufsize];
- tchar *buf = target;
- tchar *fixed_target;
- ssize_t sret;
- int ret;
-
- /* If absolute symbolic link fixups requested, reserve space in the link
- * target buffer for the absolute path of the target directory. */
- if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_RPFIX)
- {
- buf += ctx->realtarget_nchars;
- bufsize -= ctx->realtarget_nchars;
- }
-
- /* Translate the WIM inode's reparse data into the link target. */
- sret = wim_inode_readlink(inode, buf, bufsize - 1, lte_override);
- if (sret < 0) {
- errno = -sret;
- return WIMLIB_ERR_READLINK;
- }
- buf[sret] = '\0';
-
- if ((ctx->extract_flags & WIMLIB_EXTRACT_FLAG_RPFIX) &&
- buf[0] == '/')
- {
- /* Fix absolute symbolic link target to point into the
- * actual extraction destination. */
- tmemcpy(target, ctx->realtarget, ctx->realtarget_nchars);
- fixed_target = target;
- } else {
- /* Keep same link target. */
- fixed_target = buf;
- }
-
- /* Call into the apply_operations to create the symbolic link. */
- DEBUG("Creating symlink \"%"TS"\" => \"%"TS"\"",
- path, fixed_target);
- ret = ctx->ops->create_symlink(fixed_target, path, ctx);
- if (ret) {
- ERROR_WITH_ERRNO("Failed to create symlink "
- "\"%"TS"\" => \"%"TS"\"", path, fixed_target);
- return ret;
- }
-
- /* Account for reparse data consumed. */
- update_extract_progress(ctx,
- (lte_override ? lte_override :
- inode_unnamed_lte_resolved(inode)));
- return 0;
-}
-#endif /* !__WIN32__ */
-
-/* Create a file, directory, or symbolic link. */
-static int
-extract_inode(const tchar *path, struct apply_ctx *ctx, struct wim_inode *inode)
-{
- int ret;
-
-#ifndef __WIN32__
- if (ctx->supported_features.symlink_reparse_points &&
- !ctx->supported_features.reparse_points &&
- inode_is_symlink(inode))
- {
- ret = extract_symlink(path, ctx, inode, NULL);
- } else
-#endif /* !__WIN32__ */
- if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY) {
- ret = ctx->ops->create_directory(path, ctx, &inode->extract_cookie);
- if (ret) {
- ERROR_WITH_ERRNO("Failed to create the directory "
- "\"%"TS"\"", path);
- }
- } else if ((inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED) &&
- ctx->ops->extract_encrypted_stream_creates_file &&
- ctx->supported_features.encrypted_files) {
- ret = ctx->ops->extract_encrypted_stream(
- path, inode_unnamed_lte_resolved(inode), ctx);
- if (ret) {
- ERROR_WITH_ERRNO("Failed to create and extract "
- "encrypted file \"%"TS"\"", path);
- }
- } else {
- ret = ctx->ops->create_file(path, ctx, &inode->extract_cookie);
- if (ret) {
- ERROR_WITH_ERRNO("Failed to create the file "
- "\"%"TS"\"", path);
- }
- }
- return ret;
-}
-
-static int
-extract_hardlink(const tchar *oldpath, const tchar *newpath,
- struct apply_ctx *ctx)
-{
- int ret;
-
- DEBUG("Creating hardlink \"%"TS"\" => \"%"TS"\"", newpath, oldpath);
- ret = ctx->ops->create_hardlink(oldpath, newpath, ctx);
- if (ret) {
- ERROR_WITH_ERRNO("Failed to create hardlink "
- "\"%"TS"\" => \"%"TS"\"",
- newpath, oldpath);
- }
- return ret;
-}
-
-#ifdef __WIN32__
-static int
-try_extract_rpfix(u8 *rpbuf,
- u16 *rpbuflen_p,
- const wchar_t *extract_root_realpath,
- unsigned extract_root_realpath_nchars)
-{
- struct reparse_data rpdata;
- wchar_t *target;
- size_t target_nchars;
- size_t stripped_nchars;
- wchar_t *stripped_target;
- wchar_t stripped_target_nchars;
- int ret;
-
- utf16lechar *new_target;
- utf16lechar *new_print_name;
- size_t new_target_nchars;
- size_t new_print_name_nchars;
- utf16lechar *p;
-
- ret = parse_reparse_data(rpbuf, *rpbuflen_p, &rpdata);
- if (ret)
- return ret;
-
- if (extract_root_realpath[0] == L'\0' ||
- extract_root_realpath[1] != L':' ||
- extract_root_realpath[2] != L'\\')
- return WIMLIB_ERR_REPARSE_POINT_FIXUP_FAILED;
-
- ret = parse_substitute_name(rpdata.substitute_name,
- rpdata.substitute_name_nbytes,
- rpdata.rptag);
- if (ret < 0)
- return 0;
- stripped_nchars = ret;
- target = rpdata.substitute_name;
- target_nchars = rpdata.substitute_name_nbytes / sizeof(utf16lechar);
- stripped_target = target + stripped_nchars;
- stripped_target_nchars = target_nchars - stripped_nchars;
-
- new_target = alloca((6 + extract_root_realpath_nchars +
- stripped_target_nchars) * sizeof(utf16lechar));
-
- p = new_target;
- if (stripped_nchars == 6) {
- /* Include \??\ prefix if it was present before */
- p = wmempcpy(p, L"\\??\\", 4);
- }
-
- /* Print name excludes the \??\ if present. */
- new_print_name = p;
- if (stripped_nchars != 0) {
- /* Get drive letter from real path to extract root, if a drive
- * letter was present before. */
- *p++ = extract_root_realpath[0];
- *p++ = extract_root_realpath[1];
- }
- /* Copy the rest of the extract root */
- p = wmempcpy(p, extract_root_realpath + 2, extract_root_realpath_nchars - 2);
-
- /* Append the stripped target */
- p = wmempcpy(p, stripped_target, stripped_target_nchars);
- new_target_nchars = p - new_target;
- new_print_name_nchars = p - new_print_name;
-
- if (new_target_nchars * sizeof(utf16lechar) >= REPARSE_POINT_MAX_SIZE ||
- new_print_name_nchars * sizeof(utf16lechar) >= REPARSE_POINT_MAX_SIZE)
- return WIMLIB_ERR_REPARSE_POINT_FIXUP_FAILED;
-
- rpdata.substitute_name = new_target;
- rpdata.substitute_name_nbytes = new_target_nchars * sizeof(utf16lechar);
- rpdata.print_name = new_print_name;
- rpdata.print_name_nbytes = new_print_name_nchars * sizeof(utf16lechar);
- return make_reparse_buffer(&rpdata, rpbuf, rpbuflen_p);
-}
-#endif /* __WIN32__ */
-
-/* Set reparse data on extracted file or directory that has
- * FILE_ATTRIBUTE_REPARSE_POINT set. */
-static int
-extract_reparse_data(const tchar *path, struct apply_ctx *ctx,
- struct wim_inode *inode,
- struct wim_lookup_table_entry *lte_override)