]> wimlib.net Git - wimlib/blobdiff - src/extract_image.c
apply_stream_list(): Improve comments
[wimlib] / src / extract_image.c
index ba9b8c675d47e90dd98c70e502236330dcfbf199..d9912c7bb0b313c9e5c11b59073c568b283eedf1 100644 (file)
@@ -283,25 +283,8 @@ static int extract_directory(const char *output_path, bool is_root)
 static int apply_dentry_normal(struct dentry *dentry, void *arg)
 {
        struct apply_args *args = arg;
-       int extract_flags = args->extract_flags;
        struct inode *inode = dentry->d_inode;
        size_t len;
-       int ret;
-
-       if (dentry->is_extracted)
-               return 0;
-
-       if (extract_flags & WIMLIB_EXTRACT_FLAG_NO_STREAMS)
-               if (inode_unnamed_lte_resolved(inode))
-                       return 0;
-
-       if ((extract_flags & WIMLIB_EXTRACT_FLAG_VERBOSE) &&
-            args->progress_func)
-       {
-               args->progress.extract.cur_path = dentry->full_path_utf8;
-               args->progress_func(WIMLIB_PROGRESS_MSG_EXTRACT_DENTRY,
-                                   &args->progress);
-       }
 
        len = strlen(args->target);
        char output_path[len + dentry->full_path_utf8_len + 1];
@@ -310,14 +293,11 @@ static int apply_dentry_normal(struct dentry *dentry, void *arg)
        output_path[len + dentry->full_path_utf8_len] = '\0';
 
        if (inode_is_symlink(inode))
-               ret = extract_symlink(dentry, args, output_path);
+               return extract_symlink(dentry, args, output_path);
        else if (inode_is_directory(inode))
-               ret = extract_directory(output_path, false);
+               return extract_directory(output_path, false);
        else
-               ret = extract_regular_file(dentry, args, output_path);
-       if (ret == 0)
-               dentry->is_extracted = 1;
-       return ret;
+               return extract_regular_file(dentry, args, output_path);
 }
 
 /* Apply timestamp to extracted file */
@@ -361,6 +341,30 @@ static int apply_dentry_timestamps_normal(struct dentry *dentry, void *arg)
        return 0;
 }
 
+static int maybe_apply_dentry(struct dentry *dentry, void *arg)
+{
+       struct apply_args *args = arg;
+       int ret;
+
+       if (dentry->is_extracted)
+               return 0;
+
+       if (args->extract_flags & WIMLIB_EXTRACT_FLAG_NO_STREAMS)
+               if (inode_unnamed_lte_resolved(dentry->d_inode))
+                       return 0;
+
+       if ((args->extract_flags & WIMLIB_EXTRACT_FLAG_VERBOSE) &&
+            args->progress_func) {
+               args->progress.extract.cur_path = dentry->full_path_utf8;
+               args->progress_func(WIMLIB_PROGRESS_MSG_EXTRACT_DENTRY,
+                                   &args->progress);
+       }
+       ret = args->apply_dentry(dentry, args);
+       if (ret == 0)
+               dentry->is_extracted = 1;
+       return ret;
+}
+
 static int cmp_streams_by_wim_position(const void *p1, const void *p2)
 {
        const struct lookup_table_entry *lte1, *lte2;
@@ -529,12 +533,15 @@ static int apply_stream_list(struct list_head *stream_list,
        struct lookup_table_entry *lte;
        struct inode *inode;
        struct dentry *dentry;
-       int ret = 0;
+       int ret;
 
-       /* This complicated loop is actually just looping through the dentries
-        * (as for_dentry_in_tree() does), but the outer loop is actually over
-        * the distinct streams to be extracted so that sequential reading of
-        * the WIM can be implemented. */
+       /* This complicated loop is essentially looping through the dentries,
+        * although dentries may be visited more than once (if a dentry contains
+        * two different nonempty streams) or not at all (if a dentry contains
+        * no non-empty streams).
+        *
+        * The outer loop is over the distinct streams to be extracted so that
+        * sequential reading of the WIM can be implemented. */
 
        /* For each distinct stream to be extracted */
        list_for_each_entry(lte, stream_list, staging_list) {
@@ -542,22 +549,31 @@ static int apply_stream_list(struct list_head *stream_list,
                list_for_each_entry(inode, &lte->inode_list, lte_inode_list) {
                        /* For each dentry that points to the inode */
                        inode_for_each_dentry(dentry, inode) {
-                               ret = ops->apply_dentry(dentry, args);
+                               /* Extract the dentry if it was not already
+                                * extracted */
+                               ret = maybe_apply_dentry(dentry, args);
                                if (ret != 0)
-                                       goto out;
+                                       return ret;
                                if (progress_func &&
-                                   args->progress.extract.completed_bytes >= next_progress &&
-                                   args->progress.extract.total_bytes != 0)
+                                   args->progress.extract.completed_bytes >= next_progress)
                                {
                                        progress_func(WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS,
                                                      &args->progress);
-                                       next_progress += bytes_per_progress;
+                                       if (args->progress.extract.completed_bytes >=
+                                           args->progress.extract.total_bytes)
+                                       {
+                                               next_progress = ~0ULL;
+                                       } else {
+                                               next_progress =
+                                                       min (args->progress.extract.completed_bytes +
+                                                            bytes_per_progress,
+                                                            args->progress.extract.total_bytes);
+                                       }
                                }
                        }
                }
        }
-out:
-       return ret;
+       return 0;
 }
 
 static int extract_single_image(WIMStruct *w, int image,
@@ -631,7 +647,8 @@ static int extract_single_image(WIMStruct *w, int image,
        }
 
        args.extract_flags |= WIMLIB_EXTRACT_FLAG_NO_STREAMS;
-       ret = for_dentry_in_tree(wim_root_dentry(w), ops->apply_dentry, &args);
+       args.apply_dentry = ops->apply_dentry;
+       ret = for_dentry_in_tree(wim_root_dentry(w), maybe_apply_dentry, &args);
        args.extract_flags &= ~WIMLIB_EXTRACT_FLAG_NO_STREAMS;
        if (ret != 0)
                goto out;
@@ -645,8 +662,10 @@ static int extract_single_image(WIMStruct *w, int image,
        if (ret != 0)
                goto out;
 
-       if (progress_func)
-               progress_func(WIMLIB_PROGRESS_MSG_APPLY_TIMESTAMPS, NULL);
+       if (progress_func) {
+               progress_func(WIMLIB_PROGRESS_MSG_APPLY_TIMESTAMPS,
+                             &args.progress);
+       }
 
        ret = for_dentry_in_tree_depth(wim_root_dentry(w),
                                       ops->apply_dentry_timestamps, &args);