From: Eric Biggers Date: Tue, 20 Nov 2012 17:12:05 +0000 (-0600) Subject: Fix sequential extraction, and include progress info X-Git-Tag: v1.2.0~24 X-Git-Url: https://wimlib.net/git/?p=wimlib;a=commitdiff_plain;h=5cdd60306facd14cc9dcc24471386451294ca73c;hp=edd7e04ddef20c47975bd2535960b6223496d99b Fix sequential extraction, and include progress info --- diff --git a/programs/imagex.c b/programs/imagex.c index f9a3d767..9b8af6e0 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -403,7 +403,8 @@ static int imagex_apply(int argc, const char **argv) const char *wimfile; const char *dir; const char *image_num_or_name; - int extract_flags = WIMLIB_EXTRACT_FLAG_SEQUENTIAL; + int extract_flags = WIMLIB_EXTRACT_FLAG_SEQUENTIAL | + WIMLIB_EXTRACT_FLAG_SHOW_PROGRESS; const char *swm_glob = NULL; WIMStruct **additional_swms = NULL; diff --git a/src/dentry.h b/src/dentry.h index 68f118d8..2e2ba8bf 100644 --- a/src/dentry.h +++ b/src/dentry.h @@ -252,6 +252,9 @@ struct inode { /* %true iff verify_inode() has run on this dentry. */ u8 verified : 1; + /* temporary flag */ + u8 found : 1; + /* Number of alternate data streams associated with this inode */ u16 num_ads; diff --git a/src/extract.c b/src/extract.c index 145ea78a..8f445980 100644 --- a/src/extract.c +++ b/src/extract.c @@ -63,7 +63,7 @@ static int extract_regular_file_linked(const struct dentry *dentry, * 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); + wimlib_assert(lte->extracted_file != NULL); if (extract_flags & WIMLIB_EXTRACT_FLAG_HARDLINK) { if (link(lte->extracted_file, output_path) != 0) { @@ -301,18 +301,9 @@ static int extract_dentry(struct dentry *dentry, void *arg) size_t len = strlen(args->output_dir); char output_path[len + dentry->full_path_utf8_len + 1]; - if (dentry_is_directory(dentry)) { - if (extract_flags & WIMLIB_EXTRACT_FLAG_SKIP_DIRS) + if (extract_flags & WIMLIB_EXTRACT_FLAG_NO_STREAMS) + if (inode_unnamed_lte(dentry->d_inode, w->lookup_table) != NULL) return 0; - } else { - if (extract_flags & WIMLIB_EXTRACT_FLAG_DIRS_ONLY) - return 0; - } - - if ((extract_flags & WIMLIB_EXTRACT_FLAG_EMPTY_ONLY) - && (!dentry_is_regular_file(dentry) || - inode_unnamed_lte(dentry->d_inode, w->lookup_table) != NULL)) - return 0; if (extract_flags & WIMLIB_EXTRACT_FLAG_VERBOSE) { wimlib_assert(dentry->full_path_utf8); @@ -440,11 +431,42 @@ static int sort_stream_list_by_wim_position(struct list_head *stream_list) INIT_LIST_HEAD(stream_list); for (i = 0; i < num_streams; i++) - list_add(&array[i]->staging_list, stream_list); + list_add_tail(&array[i]->staging_list, stream_list); FREE(array); return 0; } +static u64 calculate_bytes_to_extract(struct list_head *stream_list, + int extract_flags) +{ + struct lookup_table_entry *lte; + struct dentry *dentry; + u64 total_size = 0; + list_for_each_entry(lte, stream_list, staging_list) { + u64 size = wim_resource_size(lte); + if (extract_flags & + (WIMLIB_EXTRACT_FLAG_SYMLINK | WIMLIB_EXTRACT_FLAG_HARDLINK)) + { + total_size += size; + } else { + list_for_each_entry(dentry, <e->dentry_list, + tmp_list) + { + dentry->d_inode->found = false; + } + list_for_each_entry(dentry, <e->dentry_list, + tmp_list) + { + if (!dentry->d_inode->found) { + dentry->d_inode->found = true; + total_size += size; + } + } + } + } + return total_size; +} + static int extract_single_image(WIMStruct *w, int image, const char *output_dir, int extract_flags) { @@ -466,8 +488,13 @@ static int extract_single_image(WIMStruct *w, int image, .num_lutimes_warnings = 0, }; - if (extract_flags & WIMLIB_EXTRACT_FLAG_SEQUENTIAL) - args.extract_flags |= WIMLIB_EXTRACT_FLAG_DIRS_ONLY; + if (extract_flags & WIMLIB_EXTRACT_FLAG_SEQUENTIAL) { + for_lookup_table_entry(w->lookup_table, lte_zero_out_refcnt, + NULL); + args.extract_flags |= WIMLIB_EXTRACT_FLAG_NO_STREAMS; + if (args.extract_flags & WIMLIB_EXTRACT_FLAG_SHOW_PROGRESS) + puts("Creating directory structure..."); + } ret = for_dentry_in_tree(root, extract_dentry, &args); if (ret != 0) @@ -479,28 +506,40 @@ static int extract_single_image(WIMStruct *w, int image, w->private = &stream_list; for_dentry_in_tree(root, dentry_add_streams_for_extraction, w); ret = sort_stream_list_by_wim_position(&stream_list); - args.extract_flags &= ~WIMLIB_EXTRACT_FLAG_DIRS_ONLY; + args.extract_flags &= ~WIMLIB_EXTRACT_FLAG_NO_STREAMS; if (ret == 0) { - args.extract_flags |= WIMLIB_EXTRACT_FLAG_SKIP_DIRS; struct lookup_table_entry *lte; struct lookup_table_entry *tmp; struct dentry *dentry; + u64 total_size; + u64 cur_size; + u64 next_size; + u64 one_percent; + unsigned cur_percent; + + total_size = calculate_bytes_to_extract(&stream_list, args.extract_flags); + one_percent = total_size / 100; + cur_size = 0; + next_size = 0; + cur_percent = 0; + puts("Extracting files..."); list_for_each_entry_safe(lte, tmp, &stream_list, staging_list) { list_del(<e->staging_list); - lte->extracted_file = NULL; list_for_each_entry(dentry, <e->dentry_list, tmp_list) { + if ((!dentry->d_inode->extracted_file) && + (args.extract_flags & WIMLIB_EXTRACT_FLAG_SHOW_PROGRESS)) + { + show_stream_op_progress(&cur_size, &next_size, + total_size, one_percent, + &cur_percent, lte, + "extracted"); + } ret = extract_dentry(dentry, &args); if (ret != 0) return ret; } - FREE(lte->extracted_file); } - args.extract_flags |= WIMLIB_EXTRACT_FLAG_EMPTY_ONLY; - ret = for_dentry_in_tree(root, extract_dentry, &args); - if (ret != 0) - return ret; - args.extract_flags &= ~(WIMLIB_EXTRACT_FLAG_SKIP_DIRS | - WIMLIB_EXTRACT_FLAG_EMPTY_ONLY); + finish_stream_op_progress(total_size, "extracted"); } else { WARNING("Falling back to non-sequential image extraction"); ret = for_dentry_in_tree(root, extract_dentry, &args); @@ -587,12 +626,13 @@ WIMLIBAPI int wimlib_extract_image(WIMStruct *w, int image, w->lookup_table = joined_tab; } - for_lookup_table_entry(w->lookup_table, lte_zero_out_refcnt, NULL); - - if (!(extract_flags & WIMLIB_EXTRACT_FLAG_SEQUENTIAL)) { + if (extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK | + WIMLIB_EXTRACT_FLAG_HARDLINK)) + { for_lookup_table_entry(w->lookup_table, lte_zero_extracted_file, NULL); + extract_flags &= ~WIMLIB_EXTRACT_FLAG_SEQUENTIAL; } if (image == WIM_ALL_IMAGES) { @@ -606,7 +646,10 @@ WIMLIBAPI int wimlib_extract_image(WIMStruct *w, int image, free_lookup_table(w->lookup_table); w->lookup_table = w_tab_save; } - if (!(extract_flags & WIMLIB_EXTRACT_FLAG_SEQUENTIAL)) { + + if (extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK | + WIMLIB_EXTRACT_FLAG_HARDLINK)) + { for_lookup_table_entry(w->lookup_table, lte_free_extracted_file, NULL); diff --git a/src/lookup_table.h b/src/lookup_table.h index 97d06ec7..4458cc7e 100644 --- a/src/lookup_table.h +++ b/src/lookup_table.h @@ -193,7 +193,10 @@ struct lookup_table_entry { * extraction mode. In these mode, all identical files are linked * together, and @extracted_file will be set to the filename of the * first extracted file containing this stream. */ - char *extracted_file; + struct { + char *extracted_file; + bool extracted; + }; /* List of lookup table entries that correspond to streams that have * been extracted to the staging directory when modifying a read-write diff --git a/src/wimlib.h b/src/wimlib.h index 1e6824b4..0618ff38 100644 --- a/src/wimlib.h +++ b/src/wimlib.h @@ -334,6 +334,9 @@ enum wim_compression_type { /** Read the WIM file sequentially while extracting the image. */ #define WIMLIB_EXTRACT_FLAG_SEQUENTIAL 0x00000010 +/** Print progress information while extracting the image. */ +#define WIMLIB_EXTRACT_FLAG_SHOW_PROGRESS 0x00000020 + /** * Possible values of the error code returned by many functions in wimlib. * diff --git a/src/wimlib_internal.h b/src/wimlib_internal.h index 6a76df0b..49d1cbbc 100644 --- a/src/wimlib_internal.h +++ b/src/wimlib_internal.h @@ -487,6 +487,14 @@ extern int inode_set_symlink(struct inode *inode, struct lookup_table *lookup_table, struct lookup_table_entry **lte_ret); +extern void show_stream_op_progress(u64 *cur_size, u64 *next_size, + u64 total_size, u64 one_percent, + unsigned *cur_percent, + const struct lookup_table_entry *cur_lte, + const char *op); + +extern void finish_stream_op_progress(u64 total_size, const char *op); + /* wim.c */ extern WIMStruct *new_wim_struct(); extern int select_wim_image(WIMStruct *w, int image); @@ -504,10 +512,8 @@ extern int open_wim_writable(WIMStruct *w, const char *path, /* Internal use only */ #define WIMLIB_EXTRACT_FLAG_MULTI_IMAGE 0x80000000 -#define WIMLIB_EXTRACT_FLAG_DIRS_ONLY 0x40000000 -#define WIMLIB_EXTRACT_FLAG_SKIP_DIRS 0x20000000 -#define WIMLIB_EXTRACT_FLAG_EMPTY_ONLY 0x10000000 -#define WIMLIB_EXTRACT_MASK_PUBLIC 0x0fffffff +#define WIMLIB_EXTRACT_FLAG_NO_STREAMS 0x40000000 +#define WIMLIB_EXTRACT_MASK_PUBLIC 0x2fffffff /* write.c */ diff --git a/src/write.c b/src/write.c index 1eb695d5..61a29962 100644 --- a/src/write.c +++ b/src/write.c @@ -650,16 +650,17 @@ static void *compressor_thread_proc(void *arg) } #endif -static void show_stream_write_progress(u64 *cur_size, u64 *next_size, - u64 total_size, u64 one_percent, - unsigned *cur_percent, - const struct lookup_table_entry *cur_lte) +void show_stream_op_progress(u64 *cur_size, u64 *next_size, + u64 total_size, u64 one_percent, + unsigned *cur_percent, + const struct lookup_table_entry *cur_lte, + const char *op) { if (*cur_size >= *next_size) { printf("\r%"PRIu64" MiB of %"PRIu64" MiB " - "(uncompressed) written (%u%% done)", + "(uncompressed) %s (%u%% done)", *cur_size >> 20, - total_size >> 20, *cur_percent); + total_size >> 20, op, *cur_percent); fflush(stdout); *next_size += one_percent; (*cur_percent)++; @@ -667,11 +668,11 @@ static void show_stream_write_progress(u64 *cur_size, u64 *next_size, *cur_size += wim_resource_size(cur_lte); } -static void finish_stream_write_progress(u64 total_size) +void finish_stream_op_progress(u64 total_size, const char *op) { printf("\r%"PRIu64" MiB of %"PRIu64" MiB " - "(uncompressed) written (100%% done)\n", - total_size >> 20, total_size >> 20); + "(uncompressed) %s (100%% done)\n", + total_size >> 20, total_size >> 20, op); fflush(stdout); } @@ -693,9 +694,9 @@ static int write_stream_list_serial(struct list_head *stream_list, list_for_each_entry(lte, stream_list, staging_list) { if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS) { - show_stream_write_progress(&cur_size, &next_size, - total_size, one_percent, - &cur_percent, lte); + show_stream_op_progress(&cur_size, &next_size, + total_size, one_percent, + &cur_percent, lte, "written"); } ret = write_wim_resource(lte, out_fp, out_ctype, <e->output_resource_entry, @@ -704,7 +705,7 @@ static int write_stream_list_serial(struct list_head *stream_list, return ret; } if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS) - finish_stream_write_progress(total_size); + finish_stream_op_progress(total_size, "written"); return 0; } @@ -1010,12 +1011,13 @@ static int main_writer_thread_proc(struct list_head *stream_list, if (msg->begin_chunk == 0) { DEBUG2("Begin chunk tab"); if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS) { - show_stream_write_progress(&cur_size, - &next_size, - total_size, - one_percent, - &cur_percent, - cur_lte); + show_stream_op_progress(&cur_size, + &next_size, + total_size, + one_percent, + &cur_percent, + cur_lte, + "written"); } // This is the first set of chunks. Leave space @@ -1101,12 +1103,13 @@ static int main_writer_thread_proc(struct list_head *stream_list, staging_list) { if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS) { - show_stream_write_progress(&cur_size, - &next_size, - total_size, - one_percent, - &cur_percent, - lte); + show_stream_op_progress(&cur_size, + &next_size, + total_size, + one_percent, + &cur_percent, + lte, + "written"); } ret = write_wim_resource(lte, @@ -1131,12 +1134,13 @@ out: if (ret == 0) { list_for_each_entry(lte, &my_resources, staging_list) { if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS) { - show_stream_write_progress(&cur_size, - &next_size, - total_size, - one_percent, - &cur_percent, - lte); + show_stream_op_progress(&cur_size, + &next_size, + total_size, + one_percent, + &cur_percent, + lte, + "written"); } ret = write_wim_resource(lte, out_fp, out_ctype, @@ -1146,7 +1150,7 @@ out: break; } if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS) - finish_stream_write_progress(total_size); + finish_stream_op_progress(total_size, "written"); } else { size_t num_available_msgs = 0; struct list_head *cur;