- /* This mode overrides the normal hard-link extraction and
- * instead either symlinks or hardlinks *all* identical files in
- * the WIM, even if they are in a different image (in the case
- * of a multi-image extraction) */
- wimlib_assert(lte->extracted_file);
-
- if (extract_flags & WIMLIB_EXTRACT_FLAG_HARDLINK) {
- if (link(lte->extracted_file, output_path) != 0) {
- ERROR_WITH_ERRNO("Failed to hard link "
- "`%s' to `%s'",
- output_path, lte->extracted_file);
- return WIMLIB_ERR_LINK;
- }
- } else {
- int num_path_components;
- int num_output_dir_path_components;
- size_t extracted_file_len;
- char *p;
- const char *p2;
- size_t i;
-
- wimlib_assert(extract_flags & WIMLIB_EXTRACT_FLAG_SYMLINK);
-
- num_path_components =
- get_num_path_components(dentry->full_path_utf8) - 1;
- num_output_dir_path_components =
- get_num_path_components(output_dir);
-
- if (extract_flags & WIMLIB_EXTRACT_FLAG_MULTI_IMAGE) {
- num_path_components++;
- num_output_dir_path_components--;
- }
- extracted_file_len = strlen(lte->extracted_file);
+ tchar *p;
+ size_t extraction_path_nchars;
+ struct wim_dentry *d;
+ LIST_HEAD(ancestor_list);
+
+ extraction_path_nchars = args->target_nchars;
+
+ for (d = dentry; d != args->extract_root; d = d->parent) {
+ if (d->not_extracted)
+ return 0;
+ extraction_path_nchars += d->extraction_name_nchars + 1;
+ list_add(&d->tmp_list, &ancestor_list);
+ }
+
+ tchar extraction_path[extraction_path_nchars + 1];
+ p = tmempcpy(extraction_path, args->target, args->target_nchars);
+
+ list_for_each_entry(d, &ancestor_list, tmp_list) {
+ *p++ = OS_PREFERRED_PATH_SEPARATOR;
+ p = tmempcpy(p, d->extraction_name, d->extraction_name_nchars);
+ }
+ *p = T('\0');
+ return (*apply_dentry_func)(extraction_path, extraction_path_nchars,
+ dentry, args);
+}
+
+
+/* Extracts a file, directory, or symbolic link from the WIM archive. */
+static int
+apply_dentry_normal(struct wim_dentry *dentry, void *arg)
+{
+#ifdef __WIN32__
+ return do_apply_op(dentry, arg, win32_do_apply_dentry);
+#else
+ return do_apply_op(dentry, arg, unix_do_apply_dentry);
+#endif
+}
+
+
+/* Apply timestamps to an extracted file or directory */
+static int
+apply_dentry_timestamps_normal(struct wim_dentry *dentry, void *arg)
+{
+#ifdef __WIN32__
+ return do_apply_op(dentry, arg, win32_do_apply_dentry_timestamps);
+#else
+ return do_apply_op(dentry, arg, unix_do_apply_dentry_timestamps);
+#endif
+}
+
+static bool
+dentry_is_dot_or_dotdot(const struct wim_dentry *dentry)
+{
+ const utf16lechar *file_name = dentry->file_name;
+ return file_name != NULL &&
+ file_name[0] == cpu_to_le16('.') &&
+ (file_name[1] == cpu_to_le16('\0') ||
+ (file_name[1] == cpu_to_le16('.') &&
+ file_name[2] == cpu_to_le16('\0')));
+}
+
+/* Extract a dentry if it hasn't already been extracted and either
+ * WIMLIB_EXTRACT_FLAG_NO_STREAMS is not specified, or the dentry is a directory
+ * and/or has no unnamed stream. */
+static int
+maybe_apply_dentry(struct wim_dentry *dentry, void *arg)
+{
+ struct apply_args *args = arg;
+ int ret;
+
+ if (!dentry->needs_extraction)
+ return 0;
+
+ if (args->extract_flags & WIMLIB_EXTRACT_FLAG_NO_STREAMS &&
+ !dentry_is_directory(dentry) &&
+ inode_unnamed_lte_resolved(dentry->d_inode) != NULL)
+ return 0;
+
+ if ((args->extract_flags & WIMLIB_EXTRACT_FLAG_VERBOSE) &&
+ args->progress_func) {
+ ret = calculate_dentry_full_path(dentry);
+ if (ret)
+ return ret;
+ args->progress.extract.cur_path = dentry->_full_path;
+ args->progress_func(WIMLIB_PROGRESS_MSG_EXTRACT_DENTRY,
+ &args->progress);
+ }
+ ret = args->apply_dentry(dentry, args);
+ if (ret == 0)
+ dentry->needs_extraction = 0;
+ return ret;
+}