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:
* 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. */
* @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. */
* ::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.
*
*
* 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
#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"
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
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, \
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,
* 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;
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)
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;
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;
}
* 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;
ret = ntfs_3g_create_nondirectory(inode, ctx);
if (ret)
return ret;
+ ret = report_file_created(&ctx->common);
+ if (ret)
+ return ret;
}
return 0;
}
/* 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;
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
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
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;
* 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;
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;
ret = create_any_empty_ads(dentry, ctx);
if (ret)
return ret;
+
+ ret = report_file_created(&ctx->common);
+ if (ret)
+ return ret;
}
return 0;
}
ret = create_nondirectory(inode, ctx);
if (ret)
return ret;
+ ret = report_file_created(&ctx->common);
+ if (ret)
+ return ret;
}
return 0;
}
ret = apply_metadata_to_file(dentry, ctx);
if (ret)
return ret;
+ ret = report_file_metadata_applied(&ctx->common);
+ if (ret)
+ return ret;
}
return 0;
}
goto out;
}
+ reset_file_progress(&ctx->common);
+
ret = create_directories(dentry_list, ctx);
if (ret)
goto out;
if (ret)
goto out;
+ reset_file_progress(&ctx->common);
+
ret = apply_metadata(dentry_list, ctx);
if (ret)
goto out;