- int ret;
- u8 rpbuf[REPARSE_POINT_MAX_SIZE];
- u16 rpbuflen;
-
- ret = wim_inode_get_reparse_data(inode, rpbuf, &rpbuflen, lte_override);
- if (ret)
- goto error;
-
-#ifdef __WIN32__
- /* Fix up target of absolute symbolic link or junction points so
- * that they point into the actual extraction target. */
- if ((ctx->extract_flags & WIMLIB_EXTRACT_FLAG_RPFIX) &&
- (inode->i_reparse_tag == WIM_IO_REPARSE_TAG_SYMLINK ||
- inode->i_reparse_tag == WIM_IO_REPARSE_TAG_MOUNT_POINT) &&
- !inode->i_not_rpfixed)
- {
- ret = try_extract_rpfix(rpbuf, &rpbuflen, ctx->realtarget,
- ctx->realtarget_nchars);
- if (ret && !(ctx->extract_flags &
- WIMLIB_EXTRACT_FLAG_STRICT_SYMLINKS))
- {
- WARNING("Reparse point fixup of \"%"TS"\" "
- "failed", path);
- ret = 0;
- }
- if (ret)
- goto error;
- }
-#endif
-
- ret = ctx->ops->set_reparse_data(path, rpbuf, rpbuflen, ctx);
-
- /* On Windows, the SeCreateSymbolicLink privilege is required to create
- * symbolic links. To be more friendly towards non-Administrator users,
- * we merely warn the user if symbolic links cannot be created due to
- * insufficient permissions or privileges, unless
- * WIMLIB_EXTRACT_FLAG_STRICT_SYMLINKS was provided. */
-#ifdef __WIN32__
- if (ret && inode_is_symlink(inode) &&
- (errno == EACCES || errno == EPERM) &&
- !(ctx->extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_SYMLINKS))
- {
- WARNING("Can't set reparse data on \"%"TS"\": "
- "Access denied!\n"
- " You may be trying to "
- "extract a symbolic link without the\n"
- " SeCreateSymbolicLink privilege, "
- "which by default non-Administrator\n"
- " accounts do not have.",
- path);
- ret = 0;
- }
-#endif
- if (ret)
- goto error;
-
- /* Account for reparse data consumed. */
- update_extract_progress(ctx,
- (lte_override ? lte_override :
- inode_unnamed_lte_resolved(inode)));
- return 0;
-
-error:
- ERROR_WITH_ERRNO("Failed to set reparse data on \"%"TS"\"", path);
- return ret;
-}
-
-/*
- * Extract zero or more streams to a file.
- *
- * This function operates slightly differently depending on whether @lte_spec is
- * NULL or not. When @lte_spec is NULL, the behavior is to extract the default
- * file contents (unnamed stream), and, if named data streams are supported in
- * the extract mode and volume, any named data streams. When @lte_spec is not
- * NULL, the behavior is to extract only all copies of the stream @lte_spec, and
- * in addition use @lte_spec to set the reparse data or create the symbolic link
- * if appropriate.
- *
- * @path
- * Path to file to extract (as can be passed to apply_operations
- * functions).
- * @ctx
- * Apply context.
- * @dentry
- * WIM dentry that corresponds to the file being extracted.
- * @lte_spec
- * If non-NULL, specifies the lookup table entry for a stream to extract,
- * and only that stream will be extracted (although there may be more than
- * one instance of it).
- * @lte_override
- * Used only if @lte_spec != NULL; it is passed to the extraction functions
- * rather than @lte_spec, allowing the location of the stream to be
- * overridden. (This is used when the WIM is being read from a nonseekable
- * file, such as a pipe, when streams need to be used more than once; each
- * such stream is extracted to a temporary file.)
- */
-static int
-extract_streams(const tchar *path, struct apply_ctx *ctx,
- struct wim_dentry *dentry,
- struct wim_lookup_table_entry *lte_spec,
- struct wim_lookup_table_entry *lte_override)
-{
- struct wim_inode *inode = dentry->d_inode;
- struct wim_lookup_table_entry *lte;
- file_spec_t file_spec;
- int ret;
-
- if (dentry->was_linked)
- return 0;
-
-#ifdef ENABLE_DEBUG
- if (lte_spec) {
- char sha1_str[100];
- char *p = sha1_str;
- for (unsigned i = 0; i < SHA1_HASH_SIZE; i++)
- p += sprintf(p, "%02x", lte_override->hash[i]);
- DEBUG("Extracting stream SHA1=%s to \"%"TS"\"",
- sha1_str, path, inode->i_ino);
- } else {
- DEBUG("Extracting streams to \"%"TS"\"", path, inode->i_ino);
- }
-#endif
-
- if (ctx->ops->uses_cookies)
- file_spec.cookie = inode->extract_cookie;
- else
- file_spec.path = path;
-
- /* Unnamed data stream. */
- lte = inode_unnamed_lte_resolved(inode);
- if (lte && (!lte_spec || lte == lte_spec)) {
- if (lte_spec)
- lte = lte_override;
- if (!(inode->i_attributes & (FILE_ATTRIBUTE_DIRECTORY |
- FILE_ATTRIBUTE_REPARSE_POINT)))
- {
- if (inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED &&
- ctx->supported_features.encrypted_files) {
- if (!ctx->ops->extract_encrypted_stream_creates_file) {
- ret = ctx->ops->extract_encrypted_stream(
- path, lte, ctx);
- if (ret)
- goto error;
- }
- } else {
- ret = ctx->ops->extract_unnamed_stream(
- file_spec, lte, ctx,
- dentry);
- if (ret)
- goto error;
- }
- update_extract_progress(ctx, lte);
- }
- else if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT)
- {
- ret = 0;
- if (ctx->supported_features.reparse_points)
- ret = extract_reparse_data(path, ctx, inode, lte);
- #ifndef __WIN32__
- else if ((inode_is_symlink(inode) &&
- ctx->supported_features.symlink_reparse_points))
- ret = extract_symlink(path, ctx, inode, lte);
- #endif
- if (ret)
- return ret;
- }
- }
-
- /* Named data streams. */
- if (can_extract_named_data_streams(ctx)) {
- for (u16 i = 0; i < inode->i_num_ads; i++) {
- struct wim_ads_entry *entry = &inode->i_ads_entries[i];
-
- if (!ads_entry_is_named_stream(entry))
- continue;
- lte = entry->lte;
- if (!lte)
- continue;
- if (lte_spec && lte_spec != lte)
- continue;
- if (lte_spec)
- lte = lte_override;
- ret = ctx->ops->extract_named_stream(file_spec, entry->stream_name,
- entry->stream_name_nbytes / 2,
- lte, ctx);
- if (ret)
- goto error;
- update_extract_progress(ctx, lte);
- }
- }
- return 0;
-
-error:
- ERROR_WITH_ERRNO("Failed to extract data of \"%"TS"\"", path);
- return ret;
-}
-
-/* Set attributes on an extracted file or directory if supported by the
- * extraction mode. */
-static int
-extract_file_attributes(const tchar *path, struct apply_ctx *ctx,
- struct wim_dentry *dentry, unsigned pass)
-{
- int ret;
-
- if (ctx->ops->set_file_attributes &&
- !(ctx->extract_flags & WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES) &&
- !(dentry == ctx->target_dentry && ctx->root_dentry_is_special)) {
- u32 attributes = dentry->d_inode->i_attributes;
-
- /* Clear unsupported attributes. */
- attributes &= ctx->supported_attributes_mask;
-
- if ((attributes & FILE_ATTRIBUTE_DIRECTORY &&
- !ctx->supported_features.encrypted_directories) ||
- (!(attributes & FILE_ATTRIBUTE_DIRECTORY) &&
- !ctx->supported_features.encrypted_files))
- {
- attributes &= ~FILE_ATTRIBUTE_ENCRYPTED;
- }
-
- if (attributes == 0)
- attributes = FILE_ATTRIBUTE_NORMAL;
-
- ret = ctx->ops->set_file_attributes(path, attributes, ctx, pass);
- if (ret) {
- ERROR_WITH_ERRNO("Failed to set attributes on "
- "\"%"TS"\"", path);
- return ret;
- }
- }
- return 0;