Add WIMLIB_PROGRESS_MSG_EXTRACT_{FILE_STRUCTURE,METADATA}
authorEric Biggers <ebiggers3@gmail.com>
Tue, 29 Jul 2014 02:12:25 +0000 (21:12 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Tue, 29 Jul 2014 03:11:24 +0000 (22:11 -0500)
These are essentially updated versions of
WIMLIB_PROGRESS_MSG_EXTRACT_{DIR_STRUCTURE,TIMESTAMPS} which were removed
in v1.7.0.  The new versions will file periodically, so they can be used
as cancellation points where the library user provides
WIMLIB_PROGRESS_STATUS_ABORT.

NEWS
include/wimlib.h
include/wimlib/apply.h
src/extract.c
src/ntfs-3g_apply.c
src/unix_apply.c
src/win32_apply.c

diff --git a/NEWS b/NEWS
index 982089e..d929624 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -27,6 +27,10 @@ Version 1.7.1-BETA:
                error messages to be sent to, rather than the default of
                standard error.
 
+               New progress messages:
+               WIMLIB_PROGRESS_MSG_EXTRACT_FILE_STRUCTURE,
+               WIMLIB_PROGRESS_MSG_EXTRACT_METADATA.
+
                New function: wimlib_verify_wim().
 
 Version 1.7.0:
index db8d5d5..f1734fc 100644 (file)
@@ -504,6 +504,12 @@ enum wimlib_progress_msg {
         * single extraction operation for optimization purposes.  */
        WIMLIB_PROGRESS_MSG_EXTRACT_TREE_BEGIN = 1,
 
+       /** This message may be sent periodically (not for every file) while
+        * files or directories are being created, prior to data stream
+        * extraction.  @p info will point to ::wimlib_progress_info.extract.
+        */
+       WIMLIB_PROGRESS_MSG_EXTRACT_FILE_STRUCTURE = 3,
+
        /** File data is currently being extracted.  @p info will point to
         * ::wimlib_progress_info.extract.  This is the main message to track
         * the progress of an extraction operation.  */
@@ -513,6 +519,12 @@ enum wimlib_progress_msg {
         * @p info will point to ::wimlib_progress_info.extract.  */
        WIMLIB_PROGRESS_MSG_EXTRACT_SPWM_PART_BEGIN = 5,
 
+       /** This message may be sent periodically (not for every file) while
+        * file and directory metadata is being applied, following data stream
+        * extraction.  @p info will point to ::wimlib_progress_info.extract.
+        */
+       WIMLIB_PROGRESS_MSG_EXTRACT_METADATA = 6,
+
        /** Confirms that the image has been successfully extracted.  @p info
         * will point to ::wimlib_progress_info.extract.  This is paired with
         * ::WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_BEGIN.  */
@@ -850,7 +862,9 @@ union wimlib_progress_info {
         * ::WIMLIB_PROGRESS_MSG_EXTRACT_SPWM_PART_BEGIN,
         * ::WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_BEGIN,
         * ::WIMLIB_PROGRESS_MSG_EXTRACT_TREE_BEGIN,
+        * ::WIMLIB_PROGRESS_MSG_EXTRACT_FILE_STRUCTURE,
         * ::WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS,
+        * ::WIMLIB_PROGRESS_MSG_EXTRACT_METADATA,
         * ::WIMLIB_PROGRESS_MSG_EXTRACT_TREE_END, and
         * ::WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_END.
         *
@@ -2657,7 +2671,9 @@ wimlib_export_image(WIMStruct *src_wim, int src_image,
  *
  * If a progress function is registered with @p wim, then as each image is
  * extracted it will receive ::WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_BEGIN, then
- * zero or more ::WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS messages, then
+ * zero or more ::WIMLIB_PROGRESS_MSG_EXTRACT_FILE_STRUCTURE messages, then zero
+ * or more ::WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS messages, then zero or more
+ * ::WIMLIB_PROGRESS_MSG_EXTRACT_METADATA messages, then
  * ::WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_END.
  */
 extern int
index 2f3b1cb..8a1bf87 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _WIMLIB_APPLY_H
 #define _WIMLIB_APPLY_H
 
+#include "wimlib/compiler.h"
 #include "wimlib/file_io.h"
 #include "wimlib/list.h"
 #include "wimlib/progress.h"
@@ -70,6 +71,7 @@ struct apply_ctx {
        u64 cur_stream_offset;
        struct filedes tmpfile_fd;
        tchar *tmpfile_name;
+       unsigned int count_until_file_progress;
 };
 
 /* Maximum number of UNIX file descriptors, NTFS attributes, or Windows file
@@ -83,6 +85,39 @@ extract_progress(struct apply_ctx *ctx, enum wimlib_progress_msg msg)
        return call_progress(ctx->progfunc, msg, &ctx->progress, ctx->progctx);
 }
 
+extern int
+do_file_extract_progress(struct apply_ctx *ctx, enum wimlib_progress_msg msg);
+
+static inline int
+maybe_do_file_progress(struct apply_ctx *ctx, enum wimlib_progress_msg msg)
+{
+       if (unlikely(!--ctx->count_until_file_progress))
+               return do_file_extract_progress(ctx, msg);
+       return 0;
+}
+
+/* Call this to reset the counter for report_file_created() and
+ * report_file_metadata_applied().  */
+static inline void
+reset_file_progress(struct apply_ctx *ctx)
+{
+       ctx->count_until_file_progress = 1;
+}
+
+/* Report that a file was created, prior to stream extraction.  */
+static inline int
+report_file_created(struct apply_ctx *ctx)
+{
+       return maybe_do_file_progress(ctx, WIMLIB_PROGRESS_MSG_EXTRACT_FILE_STRUCTURE);
+}
+
+/* Report that file metadata was applied, after stream extraction.  */
+static inline int
+report_file_metadata_applied(struct apply_ctx *ctx)
+{
+       return maybe_do_file_progress(ctx, WIMLIB_PROGRESS_MSG_EXTRACT_METADATA);
+}
+
 /* Returns any of the aliases of an inode that are being extracted.  */
 #define inode_first_extraction_dentry(inode)           \
        list_first_entry(&(inode)->i_extraction_aliases,        \
index eaee41d..e8fd7a6 100644 (file)
         WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE  |       \
         WIMLIB_EXTRACT_FLAG_WIMBOOT)
 
+/* Send WIMLIB_PROGRESS_MSG_EXTRACT_FILE_STRUCTURE or
+ * WIMLIB_PROGRESS_MSG_EXTRACT_METADATA.  */
+int
+do_file_extract_progress(struct apply_ctx *ctx, enum wimlib_progress_msg msg)
+{
+       ctx->count_until_file_progress = 512;  /* Arbitrary value to limit calls  */
+       return extract_progress(ctx, msg);
+}
+
 /* Check whether the extraction of a dentry should be skipped completely.  */
 static bool
 dentry_is_supported(struct wim_dentry *dentry,
index d1cebb9..5f0e7c7 100644 (file)
@@ -425,7 +425,7 @@ ntfs_3g_set_metadata(ntfs_inode *ni, const struct wim_inode *inode,
  * the NTFS inode @dir_ni.  */
 static int
 ntfs_3g_create_dirs_recursive(ntfs_inode *dir_ni, struct wim_dentry *dir,
-                             const struct ntfs_3g_apply_ctx *ctx)
+                             struct ntfs_3g_apply_ctx *ctx)
 {
        struct wim_dentry *child;
 
@@ -448,7 +448,9 @@ ntfs_3g_create_dirs_recursive(ntfs_inode *dir_ni, struct wim_dentry *dir,
 
                child->d_inode->i_mft_no = ni->mft_no;
 
-               ret = ntfs_3g_set_metadata(ni, child->d_inode, ctx);
+               ret = report_file_created(&ctx->common);
+               if (!ret)
+                       ret = ntfs_3g_set_metadata(ni, child->d_inode, ctx);
                if (!ret)
                        ret = ntfs_3g_create_any_empty_ads(ni, child->d_inode, ctx);
                if (!ret)
@@ -470,7 +472,7 @@ ntfs_3g_create_dirs_recursive(ntfs_inode *dir_ni, struct wim_dentry *dir,
 static int
 ntfs_3g_create_directories(struct wim_dentry *root,
                           struct list_head *dentry_list,
-                          const struct ntfs_3g_apply_ctx *ctx)
+                          struct ntfs_3g_apply_ctx *ctx)
 {
        ntfs_inode *root_ni;
        int ret;
@@ -504,6 +506,9 @@ ntfs_3g_create_directories(struct wim_dentry *root,
                ret = ntfs_3g_restore_dos_name(NULL, NULL, dentry, ctx->vol);
                if (ret)
                        return ret;
+               ret = report_file_created(&ctx->common);
+               if (ret)
+                       return ret;
        }
        return 0;
 }
@@ -660,7 +665,7 @@ out_close_ni:
  * Directories must have already been created.  */
 static int
 ntfs_3g_create_nondirectories(struct list_head *dentry_list,
-                             const struct ntfs_3g_apply_ctx *ctx)
+                             struct ntfs_3g_apply_ctx *ctx)
 {
        struct wim_dentry *dentry;
        struct wim_inode *inode;
@@ -675,6 +680,9 @@ ntfs_3g_create_nondirectories(struct list_head *dentry_list,
                ret = ntfs_3g_create_nondirectory(inode, ctx);
                if (ret)
                        return ret;
+               ret = report_file_created(&ctx->common);
+               if (ret)
+                       return ret;
        }
        return 0;
 }
@@ -908,6 +916,8 @@ ntfs_3g_extract(struct list_head *dentry_list, struct apply_ctx *_ctx)
        /* Create all inodes and aliases, including short names, and set
         * metadata (attributes, security descriptors, and timestamps).  */
 
+       reset_file_progress(&ctx->common);
+
        ret = ntfs_3g_create_directories(root, dentry_list, ctx);
        if (ret)
                goto out_unmount;
index a683b4d..7ed1422 100644 (file)
@@ -372,7 +372,8 @@ unix_create_if_directory(const struct wim_dentry *dentry,
                ERROR_WITH_ERRNO("Can't create directory \"%s\"", path);
                return WIMLIB_ERR_MKDIR;
        }
-       return 0;
+
+       return report_file_created(&ctx->common);
 }
 
 /* If @dentry represents an empty regular file or a special file, create it, set
@@ -444,7 +445,11 @@ unix_extract_if_empty_file(const struct wim_dentry *dentry,
        if (ret)
                return ret;
 
-       return unix_create_hardlinks(inode, dentry, path, ctx);
+       ret = unix_create_hardlinks(inode, dentry, path, ctx);
+       if (ret)
+               return ret;
+
+       return report_file_created(&ctx->common);
 }
 
 static int
@@ -680,6 +685,9 @@ unix_set_dir_metadata(struct list_head *dentry_list, struct unix_apply_ctx *ctx)
                        ret = unix_set_metadata(-1, dentry->d_inode, NULL, ctx);
                        if (ret)
                                return ret;
+                       ret = report_file_metadata_applied(&ctx->common);
+                       if (ret)
+                               return ret;
                }
        }
        return 0;
@@ -712,6 +720,7 @@ unix_extract(struct list_head *dentry_list, struct apply_ctx *_ctx)
         * because we can't extract any other files until their directories
         * exist.  Empty files are needed because they don't have
         * representatives in the stream list.  */
+       reset_file_progress(&ctx->common);
        ret = unix_create_dirs_and_empty_files(dentry_list, ctx);
        if (ret)
                goto out;
@@ -742,8 +751,10 @@ unix_extract(struct list_head *dentry_list, struct apply_ctx *_ctx)
        if (ret)
                goto out;
 
+
        /* Set directory metadata.  We do this last so that we get the right
         * directory timestamps.  */
+       reset_file_progress(&ctx->common);
        ret = unix_set_dir_metadata(dentry_list, ctx);
        if (ret)
                goto out;
index 0da0793..c0487c6 100644 (file)
@@ -974,6 +974,10 @@ create_directories(struct list_head *dentry_list,
                ret = create_any_empty_ads(dentry, ctx);
                if (ret)
                        return ret;
+
+               ret = report_file_created(&ctx->common);
+               if (ret)
+                       return ret;
        }
        return 0;
 }
@@ -1221,6 +1225,9 @@ create_nondirectories(struct list_head *dentry_list, struct win32_apply_ctx *ctx
                ret = create_nondirectory(inode, ctx);
                if (ret)
                        return ret;
+               ret = report_file_created(&ctx->common);
+               if (ret)
+                       return ret;
        }
        return 0;
 }
@@ -1984,6 +1991,9 @@ apply_metadata(struct list_head *dentry_list, struct win32_apply_ctx *ctx)
                ret = apply_metadata_to_file(dentry, ctx);
                if (ret)
                        return ret;
+               ret = report_file_metadata_applied(&ctx->common);
+               if (ret)
+                       return ret;
        }
        return 0;
 }
@@ -2031,6 +2041,8 @@ win32_extract(struct list_head *dentry_list, struct apply_ctx *_ctx)
                        goto out;
        }
 
+       reset_file_progress(&ctx->common);
+
        ret = create_directories(dentry_list, ctx);
        if (ret)
                goto out;
@@ -2051,6 +2063,8 @@ win32_extract(struct list_head *dentry_list, struct apply_ctx *_ctx)
        if (ret)
                goto out;
 
+       reset_file_progress(&ctx->common);
+
        ret = apply_metadata(dentry_list, ctx);
        if (ret)
                goto out;