Fix sequential extraction, and include progress info
authorEric Biggers <ebiggers3@gmail.com>
Tue, 20 Nov 2012 17:12:05 +0000 (11:12 -0600)
committerEric Biggers <ebiggers3@gmail.com>
Tue, 20 Nov 2012 17:12:05 +0000 (11:12 -0600)
programs/imagex.c
src/dentry.h
src/extract.c
src/lookup_table.h
src/wimlib.h
src/wimlib_internal.h
src/write.c

index f9a3d767cbc91669e5046cdd178db469b849a681..9b8af6e047d3caf16baaa544e9faefd4d55421f0 100644 (file)
@@ -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;
index 68f118d8a2bdc3cc14e0d44840a53a0084a315c6..2e2ba8bf23d128529a4b5b2702f76cdfc539f87a 100644 (file)
@@ -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;
 
index 145ea78ada5a0cfeea3d9c2c5bef8a1450031778..8f445980118d0b6c8d4113ddbf3d99870ae08b40 100644 (file)
@@ -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, &lte->dentry_list,
+                                           tmp_list)
+                       {
+                               dentry->d_inode->found = false;
+                       }
+                       list_for_each_entry(dentry, &lte->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(&lte->staging_list);
-                               lte->extracted_file = NULL;
                                list_for_each_entry(dentry, &lte->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);
index 97d06ec76969d022359ddef792f201e432bc68ed..4458cc7ef1a146c1c59d9e100f710a84a5288ccb 100644 (file)
@@ -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
index 1e6824b4394f8401e9c7267f07980c27702b7117..0618ff3801114645820b0584e99afeb6eb9dca88 100644 (file)
@@ -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.
  *
index 6a76df0b8cc66da8e138df39a6a5d127ad38ce7f..49d1cbbc9751eb6c226a4fc764510963b795387b 100644 (file)
@@ -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 */
index 1eb695d5edca2dbd03a1404e3c7e3b6585f0a0e2..61a29962f6916521bc1ca255ccb7b39bc2162cb0 100644 (file)
@@ -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,
                                         &lte->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;