- /* The root of the dentry tree being extracted may not be extracted to
- * its original name, so its short name should be ignored. */
- if (dentry == ctx->target_dentry)
- return 0;
-
- if (ctx->supported_features.short_names) {
- ret = ctx->ops->set_short_name(path,
- dentry->short_name,
- dentry->short_name_nbytes / 2,
- ctx);
- if (ret && (ctx->extract_flags &
- WIMLIB_EXTRACT_FLAG_STRICT_SHORT_NAMES))
- {
- ERROR_WITH_ERRNO("Failed to set short name of "
- "\"%"TS"\"", path);
- return ret;
- }
- }
- return 0;
-}
-
-/* Set security descriptor, UNIX data, or neither on an extracted file, taking
- * into account the current extraction mode and flags. */
-static int
-extract_security(const tchar *path, struct apply_ctx *ctx,
- struct wim_dentry *dentry)
-{
- int ret;
- struct wim_inode *inode = dentry->d_inode;
-
- if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_NO_ACLS)
- return 0;
-
- if ((ctx->target_dentry == dentry) && ctx->root_dentry_is_special)
- return 0;
-
-#ifndef __WIN32__
- if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA) {
- struct wimlib_unix_data data;
-
- ret = inode_get_unix_data(inode, &data, NULL);
- if (ret < 0)
- ret = 0;
- else if (ret == 0)
- ret = ctx->ops->set_unix_data(path, &data, ctx);
- if (ret) {
- if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_ACLS) {
- ERROR_WITH_ERRNO("Failed to set UNIX owner, "
- "group, and/or mode on "
- "\"%"TS"\"", path);
- return ret;
- } else {
- WARNING_WITH_ERRNO("Failed to set UNIX owner, "
- "group, and/or/mode on "
- "\"%"TS"\"", path);
- }
- }
- }
- else
-#endif /* __WIN32__ */
- if (ctx->supported_features.security_descriptors &&
- inode->i_security_id != -1)
- {
- const struct wim_security_data *sd;
- const u8 *desc;
- size_t desc_size;
-
- sd = wim_const_security_data(ctx->wim);
- desc = sd->descriptors[inode->i_security_id];
- desc_size = sd->sizes[inode->i_security_id];
-
- ret = ctx->ops->set_security_descriptor(path, desc,
- desc_size, ctx);
- if (ret) {
- if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_ACLS) {
- ERROR_WITH_ERRNO("Failed to set security "
- "descriptor on \"%"TS"\"", path);
- return ret;
- } else {
- #if 0
- if (errno != EACCES) {
- WARNING_WITH_ERRNO("Failed to set "
- "security descriptor "
- "on \"%"TS"\"", path);
- }
- #endif
- ctx->no_security_descriptors++;
- }
- }
- }
- return 0;
-}
-
-/* Set timestamps on an extracted file. Failure is warning-only unless
- * WIMLIB_EXTRACT_FLAG_STRICT_TIMESTAMPS is set. */
-static int
-extract_timestamps(const tchar *path, struct apply_ctx *ctx,
- struct wim_dentry *dentry)
-{
- struct wim_inode *inode = dentry->d_inode;
- int ret;
-
- if ((ctx->target_dentry == dentry) && ctx->root_dentry_is_special)
- return 0;
-
- if (ctx->ops->set_timestamps) {
- ret = ctx->ops->set_timestamps(path,
- inode->i_creation_time,
- inode->i_last_write_time,
- inode->i_last_access_time,
- ctx);
- if (ret) {
- if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_TIMESTAMPS) {
- ERROR_WITH_ERRNO("Failed to set timestamps "
- "on \"%"TS"\"", path);
- return ret;
- } else {
- WARNING_WITH_ERRNO("Failed to set timestamps "
- "on \"%"TS"\"", path);
- }
- }
- }
- return 0;
-}
-
-/* Check whether the extraction of a dentry should be skipped completely. */
-static bool
-dentry_is_supported(struct wim_dentry *dentry,
- const struct wim_features *supported_features)
-{
- struct wim_inode *inode = dentry->d_inode;
-
- if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
- return supported_features->reparse_points ||
- (inode_is_symlink(inode) &&
- supported_features->symlink_reparse_points);
- }
- if (inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED) {
- if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
- return supported_features->encrypted_directories != 0;
- else
- return supported_features->encrypted_files != 0;
- }
- return true;
-}
-
-/* Given a WIM dentry to extract, build the path to which to extract it, in the
- * format understood by the callbacks in the apply_operations being used.
- *
- * Write the resulting path into @path, which must have room for at least
- * ctx->ops->path_max characters.
- *
- * Return %true if successful; %false if this WIM dentry doesn't actually need
- * to be extracted or if the calculated path exceeds ctx->ops->max_path
- * characters.
- *
- * This function clobbers the tmp_list member of @dentry and its ancestors up
- * until the extraction root. */
-static bool
-build_extraction_path(tchar path[], struct wim_dentry *dentry,
- const struct apply_ctx *ctx)
-{
- size_t path_nchars;
- LIST_HEAD(ancestor_list);
- tchar *p = path;
- const tchar *target_prefix;
- size_t target_prefix_nchars;
- struct wim_dentry *d;
-
- path_nchars = ctx->ops->path_prefix_nchars;
-
- if (ctx->ops->requires_realtarget_in_paths) {
- target_prefix = ctx->realtarget;
- target_prefix_nchars = ctx->realtarget_nchars;
- } else if (ctx->ops->requires_target_in_paths) {
- target_prefix = ctx->target;
- target_prefix_nchars = ctx->target_nchars;
- } else {
- target_prefix = NULL;
- target_prefix_nchars = 0;
- }
- path_nchars += target_prefix_nchars;
-
- for (d = dentry; d != ctx->target_dentry; d = d->parent) {
- if (!dentry_in_list(d))
- break;
-
- path_nchars += d->extraction_name_nchars + 1;
- list_add(&d->tmp_list, &ancestor_list);
- }
-
- path_nchars++; /* null terminator */
-
- if (path_nchars > ctx->ops->path_max) {
- WARNING("\"%"TS"\": Path too long to extract",
- dentry_full_path(dentry));
- return false;
- }
-
- p = tmempcpy(p, ctx->ops->path_prefix, ctx->ops->path_prefix_nchars);
- p = tmempcpy(p, target_prefix, target_prefix_nchars);
- list_for_each_entry(d, &ancestor_list, tmp_list) {
- *p++ = ctx->ops->path_separator;
- p = tmempcpy(p, d->extraction_name, d->extraction_name_nchars);
- }
- *p++ = T('\0');
- wimlib_assert(p - path == path_nchars);
- return true;
-}
-
-static unsigned
-get_num_path_components(const tchar *path, tchar path_separator)
-{
- unsigned num_components = 0;
-#ifdef __WIN32__
- /* Ignore drive letter. */
- if (path[0] != L'\0' && path[1] == L':')
- path += 2;
-#endif
-
- while (*path) {
- while (*path == path_separator)
- path++;
- if (*path)
- num_components++;
- while (*path && *path != path_separator)
- path++;
- }
- return num_components;
-}
-
-static int
-extract_multiimage_symlink(const tchar *oldpath, const tchar *newpath,
- struct apply_ctx *ctx, struct wim_dentry *dentry)
-{
- size_t num_raw_path_components;
- const struct wim_dentry *d;
- size_t num_target_path_components;
- tchar *p;
- const tchar *p_old;
- int ret;
-
- num_raw_path_components = 0;
- for (d = dentry; d != ctx->target_dentry; d = d->parent)
- num_raw_path_components++;
-
- if (ctx->ops->requires_realtarget_in_paths)
- num_target_path_components = get_num_path_components(ctx->realtarget,
- ctx->ops->path_separator);
- else if (ctx->ops->requires_target_in_paths)
- num_target_path_components = get_num_path_components(ctx->target,
- ctx->ops->path_separator);
- else
- num_target_path_components = 0;
-
- if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_MULTI_IMAGE) {
- wimlib_assert(num_target_path_components > 0);
- num_raw_path_components++;
- num_target_path_components--;
- }
-
- p_old = oldpath + ctx->ops->path_prefix_nchars;
-#ifdef __WIN32__
- if (p_old[0] != L'\0' && p_old[1] == ':')
- p_old += 2;
-#endif
- while (*p_old == ctx->ops->path_separator)
- p_old++;
- while (--num_target_path_components) {
- while (*p_old != ctx->ops->path_separator)
- p_old++;
- while (*p_old == ctx->ops->path_separator)
- p_old++;
- }
-
- tchar symlink_target[tstrlen(p_old) + 3 * num_raw_path_components + 1];
-
- p = &symlink_target[0];
- while (num_raw_path_components--) {
- *p++ = '.';
- *p++ = '.';
- *p++ = ctx->ops->path_separator;
- }
- tstrcpy(p, p_old);
- DEBUG("Creating symlink \"%"TS"\" => \"%"TS"\"",
- newpath, symlink_target);
- ret = ctx->ops->create_symlink(symlink_target, newpath, ctx);
- if (ret) {
- ERROR_WITH_ERRNO("Failed to create symlink "
- "\"%"TS"\" => \"%"TS"\"",
- newpath, symlink_target);
- }
- return ret;
-}
-
-/* Create the "skeleton" of an extracted file or directory. Don't yet extract
- * data streams, reparse data (including symbolic links), timestamps, and
- * security descriptors. Basically, everything that doesn't require reading
- * non-metadata resources from the WIM file and isn't delayed until the final
- * pass. */
-static int
-do_dentry_extract_skeleton(tchar path[], struct wim_dentry *dentry,
- struct apply_ctx *ctx)
-{
- struct wim_inode *inode = dentry->d_inode;
- int ret;
- const tchar *oldpath;
-
- if (unlikely(is_linked_extraction(ctx))) {
- struct wim_lookup_table_entry *unnamed_lte;
-
- unnamed_lte = inode_unnamed_lte_resolved(dentry->d_inode);
- if (unnamed_lte && unnamed_lte->extracted_file) {
- oldpath = unnamed_lte->extracted_file;
- if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_HARDLINK)
- goto hardlink;
- else
- goto symlink;
- }
- }
-
- /* Create hard link if this dentry corresponds to an already-extracted
- * inode. */
- if (inode->i_extracted_file) {
- oldpath = inode->i_extracted_file;
- goto hardlink;
- }
-
- /* Skip symlinks unless they can be extracted as reparse points rather
- * than created directly. */
- if (inode_is_symlink(inode) && !ctx->supported_features.reparse_points)
- return 0;
-
- /* Create this file or directory unless it's the extraction root, which
- * was already created if necessary. */
- if (dentry != ctx->target_dentry) {
- ret = extract_inode(path, ctx, inode);
- if (ret)
- return ret;
- }