Lots of changes
authorEric Biggers <ebiggers3@gmail.com>
Wed, 21 Nov 2012 08:34:34 +0000 (02:34 -0600)
committerEric Biggers <ebiggers3@gmail.com>
Wed, 21 Nov 2012 08:34:34 +0000 (02:34 -0600)
- Add progress functions
- Rename wimlib_mount() and wimlib_unmount() to wimlib_mount_image() and
  wimlib_unmount_image()
- Remove wimlib_add_image_from_ntfs_volume() and
  wimlib_apply_image_to_ntfs_volume() in favor of flags to wimlib_add_image()
  and wimlib_extract_image()
- Add progress callback functions, and make them work for NTFS apply as well as
  normal apply
- Consolidate some of the extraction code into extract_single_image().
- Make serial WIM reading work when applying to NTFS as well as in the normal
  extraction mode.
- Update documentation in wimlib.h.

21 files changed:
Makefile.am
NEWS
programs/imagex.c
src/dentry.h
src/extract.c
src/header.c
src/integrity.c
src/join.c
src/lookup_table.c
src/lookup_table.h
src/modify.c
src/mount.c
src/ntfs-apply.c
src/ntfs-capture.c
src/resource.c
src/split.c
src/wim.c
src/wimlib.h
src/wimlib_internal.h
src/write.c
src/xml.c

index 1835be1..5bcf8c1 100644 (file)
@@ -33,8 +33,6 @@ libwim_la_SOURCES =           \
        src/lzx.h               \
        src/modify.c            \
        src/mount.c             \
-       src/ntfs-apply.c        \
-       src/ntfs-capture.c      \
        src/resource.c          \
        src/rbtree.c            \
        src/rbtree.h            \
@@ -58,6 +56,12 @@ libwim_la_SOURCES =          \
        src/xpress-decomp.c     \
        src/xpress.h
 
+if WITH_NTFS_3G
+libwim_la_SOURCES += src/ntfs-apply.c  \
+                    src/ntfs-capture.c
+endif
+
+
 EXTRA_libwim_la_SOURCES = src/sha1-ssse3.asm
 libwim_la_DEPENDENCIES = $(SSSE3_SHA1_OBJ)
 STRIP_FPIC = sh $(top_srcdir)/build-aux/strip_fPIC.sh
diff --git a/NEWS b/NEWS
index 30f02db..3651a6b 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,9 @@ Version 1.1.1:
        interface changes.  The soname is now updated to 1.0.0 and will now be
        updated each release.
 
+       Progress information has been improved, and now arbitrary callback
+       functions can be used to show the progress of a WIM operation.
+
        A possible bug with changing the bootable image of a WIM was fixed.
 
 Version 1.1.0:
index 9b8af6e..883b1e0 100644 (file)
@@ -217,7 +217,7 @@ static void imagex_error_with_errno(const char *format, ...)
 static int verify_image_exists(int image, const char *image_name,
                               const char *wim_name)
 {
-       if (image == WIM_NO_IMAGE) {
+       if (image == WIMLIB_NO_IMAGE) {
                imagex_error("\"%s\" is not a valid image in `%s'!\n"
                             "       Please specify a 1-based imagex index or "
                             "image name.\n"
@@ -231,7 +231,7 @@ static int verify_image_exists(int image, const char *image_name,
 
 static int verify_image_is_single(int image)
 {
-       if (image == WIM_ALL_IMAGES) {
+       if (image == WIMLIB_ALL_IMAGES) {
                imagex_error("Cannot specify all images for this action!");
                return -1;
        }
@@ -251,15 +251,15 @@ static int verify_image_exists_and_is_single(int image, const char *image_name,
 static int get_compression_type(const char *optarg)
 {
        if (strcasecmp(optarg, "maximum") == 0 || strcasecmp(optarg, "lzx") == 0)
-               return WIM_COMPRESSION_TYPE_LZX;
+               return WIMLIB_COMPRESSION_TYPE_LZX;
        else if (strcasecmp(optarg, "fast") == 0 || strcasecmp(optarg, "xpress") == 0)
-               return WIM_COMPRESSION_TYPE_XPRESS;
+               return WIMLIB_COMPRESSION_TYPE_XPRESS;
        else if (strcasecmp(optarg, "none") == 0)
-               return WIM_COMPRESSION_TYPE_NONE;
+               return WIMLIB_COMPRESSION_TYPE_NONE;
        else {
                imagex_error("Invalid compression type `%s'! Must be "
                             "\"maximum\", \"fast\", or \"none\".", optarg);
-               return WIM_COMPRESSION_TYPE_INVALID;
+               return WIMLIB_COMPRESSION_TYPE_INVALID;
        }
 }
 
@@ -320,6 +320,134 @@ static int file_writable(const char *path)
        return ret;
 }
 
+#define TO_PERCENT(numerator, denominator) \
+       (((denominator) == 0) ? 0 : ((numerator) * 100 / (denominator)))
+
+static const char *get_data_type(int ctype)
+{
+       switch (ctype) {
+       case WIMLIB_COMPRESSION_TYPE_NONE:
+               return "uncompressed";
+       case WIMLIB_COMPRESSION_TYPE_LZX:
+               return "LZX-compressed";
+       case WIMLIB_COMPRESSION_TYPE_XPRESS:
+               return "XPRESS-compressed";
+       }
+       return NULL;
+}
+
+static int imagex_progress_func(enum wimlib_progress_msg msg,
+                               const union wimlib_progress_info *info)
+{
+       unsigned percent_done;
+       switch (msg) {
+       case WIMLIB_PROGRESS_MSG_WRITE_STREAMS:
+               percent_done = TO_PERCENT(info->write_streams.completed_bytes,
+                                         info->write_streams.total_bytes);
+               if (info->write_streams.completed_streams == 0) {
+                       const char *data_type;
+
+                       data_type = get_data_type(info->write_streams.compression_type);
+                       printf("Writing %s data using %u thread%s\n",
+                              data_type, info->write_streams.num_threads,
+                              (info->write_streams.num_threads == 1) ? "" : "s");
+               }
+               printf("\r%"PRIu64" MiB of %"PRIu64" MiB (uncompressed) "
+                      "written (%u%% done)",
+                      info->write_streams.completed_bytes >> 20,
+                      info->write_streams.total_bytes >> 20,
+                      percent_done);
+               if (info->write_streams.completed_bytes == info->write_streams.total_bytes)
+                       putchar('\n');
+               break;
+       case WIMLIB_PROGRESS_MSG_SCAN_BEGIN:
+               printf("Scanning `%s'...\n", info->scan.source);
+               break;
+       /*case WIMLIB_PROGRESS_MSG_SCAN_END:*/
+               /*break;*/
+       case WIMLIB_PROGRESS_MSG_VERIFY_INTEGRITY:
+               percent_done = TO_PERCENT(info->integrity.completed_bytes,
+                                         info->integrity.total_bytes);
+               printf("\rVerifying integrity of `%s': %"PRIu64" MiB "
+                      "of %"PRIu64" MiB (%u%%) done",
+                      info->integrity.filename,
+                      info->integrity.completed_bytes >> 20,
+                      info->integrity.total_bytes >> 20,
+                      percent_done);
+               if (info->integrity.completed_bytes == info->integrity.total_bytes)
+                       putchar('\n');
+               break;
+       case WIMLIB_PROGRESS_MSG_CALC_INTEGRITY:
+               percent_done = TO_PERCENT(info->integrity.completed_bytes,
+                                         info->integrity.total_bytes);
+               printf("\rCalculating integrity table for WIM: %"PRIu64" MiB "
+                      "of %"PRIu64" MiB (%u%%) done",
+                      info->integrity.completed_bytes >> 20,
+                      info->integrity.total_bytes >> 20,
+                      percent_done);
+               if (info->integrity.completed_bytes == info->integrity.total_bytes)
+                       putchar('\n');
+               break;
+       case WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_BEGIN:
+               /*printf("Applying image %d (%s) to `%s'\n",*/
+                      /*info->extract.image,*/
+                      /*info->extract.image_name,*/
+                      /*info->extract.target);*/
+               break;
+       /*case WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_END:*/
+               /*printf("Done applying image %d!\n",*/
+                      /*info->extract.image);*/
+               /*break;*/
+       /*case WIMLIB_PROGRESS_MSG_EXTRACT_DIR_STRUCTURE_BEGIN:*/
+               /*printf("Applying directory structure to %s\n",*/
+                      /*info->extract.target);*/
+               /*break;*/
+       case WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS:
+               percent_done = TO_PERCENT(info->extract.completed_bytes,
+                                         info->extract.total_bytes);
+               printf("\rExtracting files: "
+                      "%"PRIu64" MiB of %"PRIu64" MiB (%u%%) done",
+                      info->extract.completed_bytes >> 20,
+                      info->extract.total_bytes >> 20,
+                      percent_done);
+               if (info->extract.completed_bytes == info->extract.total_bytes)
+                       putchar('\n');
+               break;
+       case WIMLIB_PROGRESS_MSG_JOIN_STREAMS:
+               percent_done = TO_PERCENT(info->join.completed_bytes,
+                                         info->join.total_bytes);
+               printf("Writing resources from part %u of %u: "
+                      "%"PRIu64 " MiB of %"PRIu64" MiB (%u%%) written\n",
+                      (info->join.completed_parts == info->join.total_parts) ?
+                               info->join.completed_parts : info->join.completed_parts + 1,
+                      info->join.total_parts,
+                      info->join.completed_bytes >> 20,
+                      info->join.total_bytes >> 20,
+                      percent_done);
+               break;
+       case WIMLIB_PROGRESS_MSG_SPLIT_BEGIN_PART:
+               percent_done = TO_PERCENT(info->split.completed_bytes,
+                                         info->split.total_bytes);
+               printf("Writing `%s': %"PRIu64" MiB of %"PRIu64" MiB (%u%%) written\n",
+                      info->split.part_name,
+                      info->split.completed_bytes >> 20,
+                      info->split.total_bytes >> 20,
+                      percent_done);
+               break;
+       case WIMLIB_PROGRESS_MSG_SPLIT_END_PART:
+               if (info->split.completed_bytes == info->split.total_bytes) {
+                       printf("Finished writing %u split WIM parts\n",
+                              info->split.cur_part_number);
+               }
+               break;
+       default:
+               break;
+       }
+       fflush(stdout);
+       return 0;
+}
+
+
 static int open_swms_from_glob(const char *swm_glob,
                               const char *first_part,
                               int open_flags,
@@ -358,7 +486,8 @@ static int open_swms_from_glob(const char *swm_glob,
                }
                ret = wimlib_open_wim(globbuf.gl_pathv[i],
                                      open_flags | WIMLIB_OPEN_FLAG_SPLIT_OK,
-                                     &additional_swms[i - offset]);
+                                     &additional_swms[i - offset],
+                                     imagex_progress_func);
                if (ret != 0)
                        goto out_close_swms;
        }
@@ -394,17 +523,15 @@ static unsigned parse_num_threads(const char *optarg)
 static int imagex_apply(int argc, const char **argv)
 {
        int c;
-       int open_flags = WIMLIB_OPEN_FLAG_SHOW_PROGRESS |
-                        WIMLIB_OPEN_FLAG_SPLIT_OK;
+       int open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK;
        int image;
        int num_images;
        WIMStruct *w;
        int ret;
        const char *wimfile;
-       const char *dir;
+       const char *target;
        const char *image_num_or_name;
-       int extract_flags = WIMLIB_EXTRACT_FLAG_SEQUENTIAL |
-                           WIMLIB_EXTRACT_FLAG_SHOW_PROGRESS;
+       int extract_flags = WIMLIB_EXTRACT_FLAG_SEQUENTIAL;
 
        const char *swm_glob = NULL;
        WIMStruct **additional_swms = NULL;
@@ -442,13 +569,13 @@ static int imagex_apply(int argc, const char **argv)
        wimfile = argv[0];
        if (argc == 2) {
                image_num_or_name = "1";
-               dir = argv[1];
+               target = argv[1];
        } else {
                image_num_or_name = argv[1];
-               dir = argv[2];
+               target = argv[2];
        }
 
-       ret = wimlib_open_wim(wimfile, open_flags, &w);
+       ret = wimlib_open_wim(wimfile, open_flags, &w, imagex_progress_func);
        if (ret != 0)
                return ret;
 
@@ -477,30 +604,25 @@ static int imagex_apply(int argc, const char **argv)
 #ifdef WITH_NTFS_3G
        struct stat stbuf;
 
-       ret = stat(dir, &stbuf);
+       ret = stat(target, &stbuf);
        if (ret == 0) {
                if (S_ISBLK(stbuf.st_mode) || S_ISREG(stbuf.st_mode)) {
-                       const char *ntfs_device = dir;
-                       printf("Applying image %d of `%s' to NTFS filesystem on `%s'\n",
-                              image, wimfile, ntfs_device);
-                       ret = wimlib_apply_image_to_ntfs_volume(w, image,
-                                                               ntfs_device,
-                                                               extract_flags,
-                                                               additional_swms,
-                                                               num_additional_swms);
-                       goto out;
+                       extract_flags |= WIMLIB_EXTRACT_FLAG_NTFS;
+                       printf("Applying `%s' image %d to NTFS volume `%s'\n",
+                              wimfile, image, target);
                }
        } else {
                if (errno != ENOENT) {
-                       imagex_error_with_errno("Failed to stat `%s'", dir);
+                       imagex_error_with_errno("Failed to stat `%s'", target);
                        ret = -1;
                        goto out;
                }
        }
 #endif
 
-       ret = wimlib_extract_image(w, image, dir, extract_flags,
-                                  additional_swms, num_additional_swms);
+       ret = wimlib_extract_image(w, image, target, extract_flags,
+                                  additional_swms, num_additional_swms,
+                                  imagex_progress_func);
 out:
        wimlib_free(w);
        if (additional_swms) {
@@ -514,11 +636,11 @@ out:
 static int imagex_capture_or_append(int argc, const char **argv)
 {
        int c;
-       int open_flags = WIMLIB_OPEN_FLAG_SHOW_PROGRESS;
-       int add_image_flags = WIMLIB_ADD_IMAGE_FLAG_SHOW_PROGRESS;
-       int write_flags = WIMLIB_WRITE_FLAG_SHOW_PROGRESS;
-       int compression_type = WIM_COMPRESSION_TYPE_XPRESS;
-       const char *dir;
+       int open_flags = 0;
+       int add_image_flags = 0;
+       int write_flags = 0;
+       int compression_type = WIMLIB_COMPRESSION_TYPE_XPRESS;
+       const char *source;
        const char *wimfile;
        const char *name;
        const char *desc;
@@ -547,7 +669,7 @@ static int imagex_capture_or_append(int argc, const char **argv)
                        break;
                case 'x':
                        compression_type = get_compression_type(optarg);
-                       if (compression_type == WIM_COMPRESSION_TYPE_INVALID)
+                       if (compression_type == WIMLIB_COMPRESSION_TYPE_INVALID)
                                return -1;
                        break;
                case 'f':
@@ -558,7 +680,6 @@ static int imagex_capture_or_append(int argc, const char **argv)
                        break;
                case 'v':
                        add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_VERBOSE;
-                       write_flags |= WIMLIB_WRITE_FLAG_VERBOSE;
                        break;
                case 't':
                        num_threads = parse_num_threads(optarg);
@@ -579,12 +700,12 @@ static int imagex_capture_or_append(int argc, const char **argv)
                usage(cmd);
                return -1;
        }
-       dir = argv[0];
+       source = argv[0];
        wimfile = argv[1];
 
-       char dir_copy[strlen(dir) + 1];
-       memcpy(dir_copy, dir, strlen(dir) + 1);
-       default_name = basename(dir_copy);
+       char source_copy[strlen(source) + 1];
+       memcpy(source_copy, source, strlen(source) + 1);
+       default_name = basename(source_copy);
 
        name = (argc >= 3) ? argv[2] : default_name;
        desc = (argc >= 4) ? argv[3] : NULL;
@@ -596,7 +717,8 @@ static int imagex_capture_or_append(int argc, const char **argv)
        }
 
        if (cmd == APPEND)
-               ret = wimlib_open_wim(wimfile, open_flags, &w);
+               ret = wimlib_open_wim(wimfile, open_flags, &w,
+                                     imagex_progress_func);
        else
                ret = wimlib_create_new_wim(compression_type, &w);
        if (ret != 0)
@@ -605,31 +727,24 @@ static int imagex_capture_or_append(int argc, const char **argv)
 #ifdef WITH_NTFS_3G
        struct stat stbuf;
 
-       ret = stat(dir, &stbuf);
+       ret = stat(source, &stbuf);
        if (ret == 0) {
                if (S_ISBLK(stbuf.st_mode) || S_ISREG(stbuf.st_mode)) {
-                       const char *ntfs_device = dir;
-                       printf("Capturing WIM image NTFS filesystem on `%s'\n",
-                              ntfs_device);
-                       ret = wimlib_add_image_from_ntfs_volume(w, ntfs_device,
-                                                               name,
-                                                               config_str,
-                                                               config_len,
-                                                               add_image_flags);
-                       goto out_write;
+                       printf("Capturing WIM image from NTFS filesystem on `%s'\n",
+                              source);
+                       add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_NTFS;
                }
        } else {
                if (errno != ENOENT) {
-                       imagex_error_with_errno("Failed to stat `%s'", dir);
+                       imagex_error_with_errno("Failed to stat `%s'", source);
                        ret = -1;
                        goto out;
                }
        }
 #endif
-       ret = wimlib_add_image(w, dir, name, config_str, config_len,
-                              add_image_flags);
+       ret = wimlib_add_image(w, source, name, config_str, config_len,
+                              add_image_flags, imagex_progress_func);
 
-out_write:
        if (ret != 0)
                goto out;
        cur_image = wimlib_get_num_images(w);
@@ -644,10 +759,11 @@ out_write:
                        goto out;
        }
        if (cmd == APPEND) {
-               ret = wimlib_overwrite(w, write_flags, num_threads);
+               ret = wimlib_overwrite(w, write_flags, num_threads,
+                                      imagex_progress_func);
        } else {
-               ret = wimlib_write(w, wimfile, WIM_ALL_IMAGES, write_flags,
-                                  num_threads);
+               ret = wimlib_write(w, wimfile, WIMLIB_ALL_IMAGES, write_flags,
+                                  num_threads, imagex_progress_func);
        }
        if (ret == WIMLIB_ERR_REOPEN)
                ret = 0;
@@ -663,8 +779,8 @@ out:
 static int imagex_delete(int argc, const char **argv)
 {
        int c;
-       int open_flags = WIMLIB_OPEN_FLAG_SHOW_PROGRESS;
-       int write_flags = WIMLIB_WRITE_FLAG_SHOW_PROGRESS;
+       int open_flags = 0;
+       int write_flags = 0;
        const char *wimfile;
        const char *image_num_or_name;
        WIMStruct *w;
@@ -703,7 +819,8 @@ static int imagex_delete(int argc, const char **argv)
        if (ret != 0)
                return ret;
 
-       ret = wimlib_open_wim(wimfile, open_flags, &w);
+       ret = wimlib_open_wim(wimfile, open_flags, &w,
+                             imagex_progress_func);
        if (ret != 0)
                return ret;
 
@@ -719,7 +836,7 @@ static int imagex_delete(int argc, const char **argv)
                goto out;
        }
 
-       ret = wimlib_overwrite(w, write_flags, 0);
+       ret = wimlib_overwrite(w, write_flags, 0, imagex_progress_func);
        if (ret == WIMLIB_ERR_REOPEN)
                ret = 0;
        if (ret != 0) {
@@ -752,7 +869,8 @@ static int imagex_dir(int argc, const char **argv)
        }
 
        wimfile = argv[1];
-       ret = wimlib_open_wim(wimfile, WIMLIB_OPEN_FLAG_SPLIT_OK, &w);
+       ret = wimlib_open_wim(wimfile, WIMLIB_OPEN_FLAG_SPLIT_OK, &w,
+                             imagex_progress_func);
        if (ret != 0)
                return ret;
 
@@ -786,10 +904,10 @@ out:
 static int imagex_export(int argc, const char **argv)
 {
        int c;
-       int open_flags = WIMLIB_OPEN_FLAG_SHOW_PROGRESS;
+       int open_flags = 0;
        int export_flags = 0;
-       int write_flags = WIMLIB_WRITE_FLAG_SHOW_PROGRESS;
-       int compression_type;
+       int write_flags = 0;
+       int compression_type = WIMLIB_COMPRESSION_TYPE_NONE;
        bool compression_type_specified = false;
        const char *src_wimfile;
        const char *src_image_num_or_name;
@@ -818,7 +936,7 @@ static int imagex_export(int argc, const char **argv)
                        break;
                case 'x':
                        compression_type = get_compression_type(optarg);
-                       if (compression_type == WIM_COMPRESSION_TYPE_INVALID)
+                       if (compression_type == WIMLIB_COMPRESSION_TYPE_INVALID)
                                return -1;
                        compression_type_specified = true;
                        break;
@@ -850,7 +968,8 @@ static int imagex_export(int argc, const char **argv)
        dest_name             = (argc >= 4) ? argv[3] : NULL;
        dest_desc             = (argc >= 5) ? argv[4] : NULL;
        ret = wimlib_open_wim(src_wimfile,
-                             open_flags | WIMLIB_OPEN_FLAG_SPLIT_OK, &src_w);
+                             open_flags | WIMLIB_OPEN_FLAG_SPLIT_OK, &src_w,
+                             imagex_progress_func);
        if (ret != 0)
                return ret;
 
@@ -868,7 +987,8 @@ static int imagex_export(int argc, const char **argv)
                        ret = -1;
                        goto out;
                }
-               ret = wimlib_open_wim(dest_wimfile, open_flags, &dest_w);
+               ret = wimlib_open_wim(dest_wimfile, open_flags, &dest_w,
+                                     imagex_progress_func);
                if (ret != 0)
                        goto out;
 
@@ -919,16 +1039,18 @@ static int imagex_export(int argc, const char **argv)
 
        ret = wimlib_export_image(src_w, image, dest_w, dest_name, dest_desc,
                                  export_flags, additional_swms,
-                                 num_additional_swms);
+                                 num_additional_swms, imagex_progress_func);
        if (ret != 0)
                goto out;
 
 
        if (wim_is_new)
-               ret = wimlib_write(dest_w, dest_wimfile, WIM_ALL_IMAGES,
-                                  write_flags, num_threads);
+               ret = wimlib_write(dest_w, dest_wimfile, WIMLIB_ALL_IMAGES,
+                                  write_flags, num_threads,
+                                  imagex_progress_func);
        else
-               ret = wimlib_overwrite(dest_w, write_flags, num_threads);
+               ret = wimlib_overwrite(dest_w, write_flags, num_threads,
+                                      imagex_progress_func);
 out:
        if (ret == WIMLIB_ERR_REOPEN)
                ret = 0;
@@ -963,8 +1085,7 @@ static int imagex_info(int argc, const char **argv)
        FILE *fp;
        int image;
        int ret;
-       int open_flags = WIMLIB_OPEN_FLAG_SHOW_PROGRESS |
-                        WIMLIB_OPEN_FLAG_SPLIT_OK;
+       int open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK;
        int part_number;
        int total_parts;
 
@@ -1022,14 +1143,15 @@ static int imagex_info(int argc, const char **argv)
        if (check)
                open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
 
-       ret = wimlib_open_wim(wimfile, open_flags, &w);
+       ret = wimlib_open_wim(wimfile, open_flags, &w,
+                             imagex_progress_func);
        if (ret != 0)
                return ret;
 
        part_number = wimlib_get_part_number(w, &total_parts);
 
        image = wimlib_resolve_image(w, image_num_or_name);
-       if (image == WIM_NO_IMAGE && strcmp(image_num_or_name, "0") != 0) {
+       if (image == WIMLIB_NO_IMAGE && strcmp(image_num_or_name, "0") != 0) {
                imagex_error("The image `%s' does not exist",
                                                image_num_or_name);
                if (boot)
@@ -1040,7 +1162,7 @@ static int imagex_info(int argc, const char **argv)
                goto out;
        }
 
-       if (image == WIM_ALL_IMAGES && wimlib_get_num_images(w) > 1) {
+       if (image == WIMLIB_ALL_IMAGES && wimlib_get_num_images(w) > 1) {
                if (boot) {
                        imagex_error("Cannot specify the --boot flag "
                                     "without specifying a specific "
@@ -1063,14 +1185,14 @@ static int imagex_info(int argc, const char **argv)
 
                /* Read-only operations */
 
-               if (image == WIM_NO_IMAGE) {
+               if (image == WIMLIB_NO_IMAGE) {
                        imagex_error("`%s' is not a valid image",
                                     image_num_or_name);
                        ret = WIMLIB_ERR_INVALID_IMAGE;
                        goto out;
                }
 
-               if (image == WIM_ALL_IMAGES && short_header)
+               if (image == WIMLIB_ALL_IMAGES && short_header)
                        wimlib_print_wim_information(w);
 
                if (header)
@@ -1126,10 +1248,10 @@ static int imagex_info(int argc, const char **argv)
                        imagex_error("Modifying a split WIM is not supported.");
                        return -1;
                }
-               if (image == WIM_ALL_IMAGES)
+               if (image == WIMLIB_ALL_IMAGES)
                        image = 1;
 
-               if (image == WIM_NO_IMAGE && new_name) {
+               if (image == WIMLIB_NO_IMAGE && new_name) {
                        imagex_error("Cannot specify new_name (`%s') when "
                                     "using image 0", new_name);
                        return -1;
@@ -1188,13 +1310,13 @@ static int imagex_info(int argc, const char **argv)
 
                        int write_flags;
                        if (check) {
-                               write_flags = WIMLIB_WRITE_FLAG_CHECK_INTEGRITY |
-                                             WIMLIB_WRITE_FLAG_SHOW_PROGRESS;
+                               write_flags = WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
                        } else {
                                write_flags = 0;
                        }
 
-                       ret = wimlib_overwrite(w, write_flags, 1);
+                       ret = wimlib_overwrite(w, write_flags, 1,
+                                              imagex_progress_func);
                        if (ret == WIMLIB_ERR_REOPEN)
                                ret = 0;
                } else {
@@ -1212,13 +1334,15 @@ out:
 static int imagex_join(int argc, const char **argv)
 {
        int c;
-       int flags = WIMLIB_OPEN_FLAG_SPLIT_OK | WIMLIB_OPEN_FLAG_SHOW_PROGRESS;
+       int swm_open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK;
+       int wim_write_flags = 0;
        const char *output_path;
 
        for_opt(c, join_options) {
                switch (c) {
                case 'c':
-                       flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
+                       swm_open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
+                       wim_write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
                        break;
                default:
                        goto err;
@@ -1228,12 +1352,13 @@ static int imagex_join(int argc, const char **argv)
        argv += optind;
 
        if (argc < 2) {
-               imagex_error("Must specify at least one split WIM (.swm) parts "
+               imagex_error("Must specify one or more split WIM (.swm) parts "
                             "to join");
                goto err;
        }
        output_path = argv[0];
-       return wimlib_join(++argv, --argc, output_path, flags);
+       return wimlib_join(++argv, --argc, output_path, swm_open_flags,
+                          wim_write_flags, imagex_progress_func);
 err:
        usage(JOIN);
        return -1;
@@ -1244,8 +1369,7 @@ static int imagex_mount_rw_or_ro(int argc, const char **argv)
 {
        int c;
        int mount_flags = 0;
-       int open_flags = WIMLIB_OPEN_FLAG_SHOW_PROGRESS |
-                        WIMLIB_OPEN_FLAG_SPLIT_OK;
+       int open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK;
        const char *wimfile;
        const char *dir;
        WIMStruct *w;
@@ -1293,7 +1417,8 @@ static int imagex_mount_rw_or_ro(int argc, const char **argv)
 
        wimfile = argv[0];
 
-       ret = wimlib_open_wim(wimfile, open_flags, &w);
+       ret = wimlib_open_wim(wimfile, open_flags, &w,
+                             imagex_progress_func);
        if (ret != 0)
                return ret;
 
@@ -1331,8 +1456,8 @@ static int imagex_mount_rw_or_ro(int argc, const char **argv)
                        return ret;
        }
 
-       ret = wimlib_mount(w, image, dir, mount_flags, additional_swms,
-                          num_additional_swms);
+       ret = wimlib_mount_image(w, image, dir, mount_flags, additional_swms,
+                                num_additional_swms);
        if (ret != 0) {
                imagex_error("Failed to mount image %d from `%s' on `%s'",
                             image, wimfile, dir);
@@ -1355,9 +1480,8 @@ mount_usage:
 static int imagex_optimize(int argc, const char **argv)
 {
        int c;
-       int open_flags = WIMLIB_OPEN_FLAG_SHOW_PROGRESS;
-       int write_flags = WIMLIB_WRITE_FLAG_REBUILD |
-                         WIMLIB_WRITE_FLAG_SHOW_PROGRESS;
+       int open_flags = 0;
+       int write_flags = WIMLIB_WRITE_FLAG_REBUILD;
        int ret;
        WIMStruct *w;
        const char *wimfile;
@@ -1388,7 +1512,8 @@ static int imagex_optimize(int argc, const char **argv)
 
        wimfile = argv[0];
 
-       ret = wimlib_open_wim(wimfile, open_flags, &w);
+       ret = wimlib_open_wim(wimfile, open_flags, &w,
+                             imagex_progress_func);
        if (ret != 0)
                return ret;
 
@@ -1399,7 +1524,7 @@ static int imagex_optimize(int argc, const char **argv)
        else
                printf("%"PRIu64" KiB\n", old_size >> 10);
 
-       ret = wimlib_overwrite(w, write_flags, 0);
+       ret = wimlib_overwrite(w, write_flags, 0, imagex_progress_func);
 
        new_size = file_get_size(argv[0]);
        printf("`%s' optimized size: ", wimfile);
@@ -1424,14 +1549,18 @@ static int imagex_optimize(int argc, const char **argv)
 static int imagex_split(int argc, const char **argv)
 {
        int c;
-       int flags = WIMLIB_OPEN_FLAG_SHOW_PROGRESS;
+       int open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK;
+       int write_flags = 0;
        unsigned long part_size;
        char *tmp;
+       int ret;
+       WIMStruct *w;
 
        for_opt(c, split_options) {
                switch (c) {
                case 'c':
-                       flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
+                       open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
+                       write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
                        break;
                default:
                        usage(SPLIT);
@@ -1451,7 +1580,12 @@ static int imagex_split(int argc, const char **argv)
                imagex_error("The part size must be an integer or floating-point number of megabytes.");
                return -1;
        }
-       return wimlib_split(argv[0], argv[1], part_size, flags);
+       ret = wimlib_open_wim(argv[0], open_flags, &w, imagex_progress_func);
+       if (ret != 0)
+               return ret;
+       ret = wimlib_split(w, argv[1], part_size, write_flags, imagex_progress_func);
+       wimlib_free(w);
+       return ret;
 }
 
 /* Unmounts an image. */
@@ -1481,7 +1615,7 @@ static int imagex_unmount(int argc, const char **argv)
                return -1;
        }
 
-       ret = wimlib_unmount(argv[0], unmount_flags);
+       ret = wimlib_unmount_image(argv[0], unmount_flags);
        if (ret != 0)
                imagex_error("Failed to unmount `%s'", argv[0]);
        return ret;
index 2e2ba8b..afa6aaa 100644 (file)
@@ -157,6 +157,8 @@ struct dentry {
        u16 file_name_utf8_len;
 
        u8 is_extracted : 1;
+       u8 visited : 1;
+       u8 canonical : 1;
 
        /* Byte 40 */
 
@@ -253,7 +255,7 @@ struct inode {
        u8 verified : 1;
 
        /* temporary flag */
-       u8 found    : 1;
+       u8 visited    : 1;
 
        /* Number of alternate data streams associated with this inode */
        u16 num_ads;
@@ -286,7 +288,13 @@ struct inode {
        /* List of dentries that reference this inode (there should be
         * link_count of them) */
        struct list_head dentry_list;
+
        struct hlist_node hlist;
+
+       struct list_head tmp_list;
+
+       struct list_head lte_inode_list;
+
        char *extracted_file;
 
        /* Root of a red-black tree storing the children of this inode (if
@@ -319,11 +327,6 @@ struct inode {
                list_add(&(dentry)->inode_dentry_list, &(inode)->dentry_list);  \
        })
 
-static inline bool dentry_is_extracted(const struct dentry *dentry)
-{
-       return dentry->is_extracted;
-}
-
 static inline bool dentry_is_first_in_inode(const struct dentry *dentry)
 {
        return container_of(dentry->d_inode->dentry_list.next,
index 90b6ce3..a3f00cc 100644 (file)
@@ -44,6 +44,7 @@
 #include <utime.h>
 #endif
 
+
 #include <unistd.h>
 
 #include "dentry.h"
 #include "wimlib_internal.h"
 #include "xml.h"
 
+#ifdef WITH_NTFS_3G
+#include <ntfs-3g/volume.h>
+#endif
 
-static int extract_regular_file_linked(const struct dentry *dentry,
-                                      const char *output_dir,
+static int extract_regular_file_linked(struct dentry *dentry,
                                       const char *output_path,
-                                      int extract_flags,
+                                      struct apply_args *args,
                                       struct lookup_table_entry *lte)
 {
        /* This mode overrides the normal hard-link extraction and
         * 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 != NULL);
 
-       if (extract_flags & WIMLIB_EXTRACT_FLAG_HARDLINK) {
+       if (args->extract_flags & WIMLIB_EXTRACT_FLAG_HARDLINK) {
                if (link(lte->extracted_file, output_path) != 0) {
                        ERROR_WITH_ERRNO("Failed to hard link "
                                         "`%s' to `%s'",
@@ -80,14 +82,12 @@ static int extract_regular_file_linked(const struct dentry *dentry,
                const char *p2;
                size_t i;
 
-               wimlib_assert(extract_flags & WIMLIB_EXTRACT_FLAG_SYMLINK);
-
                num_path_components =
                        get_num_path_components(dentry->full_path_utf8) - 1;
                num_output_dir_path_components =
-                       get_num_path_components(output_dir);
+                       get_num_path_components(args->target);
 
-               if (extract_flags & WIMLIB_EXTRACT_FLAG_MULTI_IMAGE) {
+               if (args->extract_flags & WIMLIB_EXTRACT_FLAG_MULTI_IMAGE) {
                        num_path_components++;
                        num_output_dir_path_components--;
                }
@@ -113,15 +113,13 @@ static int extract_regular_file_linked(const struct dentry *dentry,
                                         buf, lte->extracted_file);
                        return WIMLIB_ERR_LINK;
                }
-
        }
        return 0;
 }
 
-static int extract_regular_file_unlinked(WIMStruct *w,
-                                        struct dentry *dentry,
+static int extract_regular_file_unlinked(struct dentry *dentry,
+                                        struct apply_args *args,
                                         const char *output_path,
-                                        int extract_flags,
                                         struct lookup_table_entry *lte)
 {
        /* Normal mode of extraction.  Regular files and hard links are
@@ -131,8 +129,8 @@ static int extract_regular_file_unlinked(WIMStruct *w,
        int ret;
        struct inode *inode = dentry->d_inode;
 
-       if (!((extract_flags & WIMLIB_EXTRACT_FLAG_MULTI_IMAGE)
-               && (extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK |
+       if (!((args->extract_flags & WIMLIB_EXTRACT_FLAG_MULTI_IMAGE)
+               && (args->extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK |
                                     WIMLIB_EXTRACT_FLAG_HARDLINK))))
        {
                /* If the dentry is one of a hard link set of at least 2
@@ -184,7 +182,7 @@ static int extract_regular_file_unlinked(WIMStruct *w,
                ERROR("Failed to extract resource to `%s'", output_path);
                goto out;
        }
-
+       args->progress.extract.completed_bytes += wim_resource_size(lte);
 out:
        if (close(out_fd) != 0) {
                ERROR_WITH_ERRNO("Failed to close file `%s'", output_path);
@@ -196,41 +194,38 @@ out:
 /*
  * Extracts a regular file from the WIM archive.
  */
-static int extract_regular_file(WIMStruct *w,
-                               struct dentry *dentry,
-                               const char *output_dir,
-                               const char *output_path,
-                               int extract_flags)
+static int extract_regular_file(struct dentry *dentry,
+                               struct apply_args *args,
+                               const char *output_path)
 {
        struct lookup_table_entry *lte;
        const struct inode *inode = dentry->d_inode;
 
-       lte = inode_unnamed_lte(inode, w->lookup_table);
+       lte = inode_unnamed_lte_resolved(inode);
 
-       if ((extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK |
-                             WIMLIB_EXTRACT_FLAG_HARDLINK)) && lte) {
+       if (lte && (args->extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK |
+                                          WIMLIB_EXTRACT_FLAG_HARDLINK)))
+       {
                if (lte->extracted_file) {
-                       return extract_regular_file_linked(dentry, output_dir,
-                                                          output_path,
-                                                          extract_flags, lte);
+                       return extract_regular_file_linked(dentry, output_path, args, lte);
                } else {
                        lte->extracted_file = STRDUP(output_path);
                        if (!lte->extracted_file)
                                return WIMLIB_ERR_NOMEM;
                }
        }
-
-       return extract_regular_file_unlinked(w, dentry, output_path,
-                                            extract_flags, lte);
-
+       return extract_regular_file_unlinked(dentry, args, output_path, lte);
 }
 
-static int extract_symlink(const struct dentry *dentry, const char *output_path,
-                          const WIMStruct *w)
+static int extract_symlink(struct dentry *dentry,
+                          struct apply_args *args,
+                          const char *output_path)
 {
        char target[4096];
        ssize_t ret = inode_readlink(dentry->d_inode, target,
-                                    sizeof(target), w, 0);
+                                    sizeof(target), args->w, 0);
+       struct lookup_table_entry *lte;
+
        if (ret <= 0) {
                ERROR("Could not read the symbolic link from dentry `%s'",
                      dentry->full_path_utf8);
@@ -242,6 +237,8 @@ static int extract_symlink(const struct dentry *dentry, const char *output_path,
                                 output_path, target);
                return WIMLIB_ERR_LINK;
        }
+       lte = inode_unnamed_lte_resolved(dentry->d_inode);
+       args->progress.extract.completed_bytes += wim_resource_size(lte);
        return 0;
 }
 
@@ -282,58 +279,55 @@ static int extract_directory(const char *output_path, bool is_root)
        return 0;
 }
 
-struct extract_args {
-       WIMStruct *w;
-       int extract_flags;
-       const char *output_dir;
-       unsigned num_lutimes_warnings;
-};
-
 /*
  * Extracts a file, directory, or symbolic link from the WIM archive.  For use
  * in for_dentry_in_tree().
  */
-static int extract_dentry(struct dentry *dentry, void *arg)
+static int apply_dentry_normal(struct dentry *dentry, void *arg)
 {
-       struct extract_args *args = arg;
-       WIMStruct *w = args->w;
+       struct apply_args *args = arg;
        int extract_flags = args->extract_flags;
-       size_t len = strlen(args->output_dir);
-       char output_path[len + dentry->full_path_utf8_len + 1];
+       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(dentry->d_inode, w->lookup_table) != NULL)
+               if (inode_unnamed_lte_resolved(inode))
                        return 0;
 
-       if (extract_flags & WIMLIB_EXTRACT_FLAG_VERBOSE) {
-               wimlib_assert(dentry->full_path_utf8);
+       if (extract_flags & WIMLIB_EXTRACT_FLAG_VERBOSE)
                puts(dentry->full_path_utf8);
-       }
 
-       memcpy(output_path, args->output_dir, len);
+       len = strlen(args->target);
+       char output_path[len + dentry->full_path_utf8_len + 1];
+       memcpy(output_path, args->target, len);
        memcpy(output_path + len, dentry->full_path_utf8, dentry->full_path_utf8_len);
        output_path[len + dentry->full_path_utf8_len] = '\0';
 
-
-       if (dentry_is_symlink(dentry))
-               return extract_symlink(dentry, output_path, w);
-       else if (dentry_is_directory(dentry))
-               return extract_directory(output_path, dentry_is_root(dentry));
+       if (inode_is_symlink(inode))
+               ret = extract_symlink(dentry, args, output_path);
+       else if (inode_is_directory(inode))
+               ret = extract_directory(output_path, false);
        else
-               return extract_regular_file(w, dentry, args->output_dir,
-                                           output_path, extract_flags);
+               ret = extract_regular_file(dentry, args, output_path);
+       if (ret == 0)
+               dentry->is_extracted = 1;
+       return ret;
 }
 
 /* Apply timestamp to extracted file */
-static int apply_dentry_timestamps(struct dentry *dentry, void *arg)
+static int apply_dentry_timestamps_normal(struct dentry *dentry, void *arg)
 {
-       struct extract_args *args = arg;
-       size_t len = strlen(args->output_dir);
+       struct apply_args *args = arg;
+       size_t len = strlen(args->target);
        char output_path[len + dentry->full_path_utf8_len + 1];
        const struct inode *inode = dentry->d_inode;
        int ret;
 
-       memcpy(output_path, args->output_dir, len);
+       memcpy(output_path, args->target, len);
        memcpy(output_path + len, dentry->full_path_utf8, dentry->full_path_utf8_len);
        output_path[len + dentry->full_path_utf8_len] = '\0';
 
@@ -365,26 +359,6 @@ static int apply_dentry_timestamps(struct dentry *dentry, void *arg)
        return 0;
 }
 
-
-static int dentry_add_streams_for_extraction(struct dentry *dentry,
-                                            void *wim)
-{
-       WIMStruct *w = wim;
-       struct list_head *stream_list;
-       struct lookup_table_entry *lte;
-
-       lte = inode_unnamed_lte(dentry->d_inode, w->lookup_table);
-       if (lte) {
-               if (++lte->out_refcnt == 1) {
-                       INIT_LIST_HEAD(&lte->dentry_list);
-                       stream_list = w->private;
-                       list_add_tail(&lte->staging_list, stream_list);
-               }
-               list_add_tail(&dentry->tmp_list, &lte->dentry_list);
-       }
-       return 0;
-}
-
 static int cmp_streams_by_wim_position(const void *p1, const void *p2)
 {
        const struct lookup_table_entry *lte1, *lte2;
@@ -406,15 +380,10 @@ static int sort_stream_list_by_wim_position(struct list_head *stream_list)
        size_t i;
        size_t array_size;
 
-       DEBUG("Sorting stream list by wim position");
-
        num_streams = 0;
        list_for_each(cur, stream_list)
                num_streams++;
        array_size = num_streams * sizeof(array[0]);
-
-       DEBUG("num_streams = %zu", num_streams);
-
        array = MALLOC(array_size);
        if (!array) {
                ERROR("Failed to allocate %zu bytes to sort stream entries",
@@ -436,166 +405,296 @@ static int sort_stream_list_by_wim_position(struct list_head *stream_list)
        return 0;
 }
 
-static u64 calculate_bytes_to_extract(struct list_head *stream_list,
-                                     int extract_flags)
+static void calculate_bytes_to_extract(struct list_head *stream_list,
+                                      int extract_flags,
+                                      union wimlib_progress_info *progress)
 {
        struct lookup_table_entry *lte;
-       struct dentry *dentry;
-       u64 total_size = 0;
+       struct inode *inode;
+       u64 total_bytes = 0;
+       u64 num_streams = 0;
+
+       /* For each stream to be extracted... */
        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;
+                       /* In the symlink or hard link extraction mode, each
+                        * stream will be extracted one time regardless of how
+                        * many dentries share the stream. */
+                       wimlib_assert(!(extract_flags & WIMLIB_EXTRACT_FLAG_NTFS));
+                       if (!lte->extracted_file) {
+                               num_streams++;
+                               total_bytes += wim_resource_size(lte);
+                       }
                } else {
-                       list_for_each_entry(dentry, &lte->dentry_list,
-                                           tmp_list)
+                       list_for_each_entry(inode, &lte->inode_list,
+                                           lte_inode_list)
                        {
-                               dentry->d_inode->found = false;
+                               num_streams++;
+                               total_bytes += wim_resource_size(lte);
                        }
-                       list_for_each_entry(dentry, &lte->dentry_list,
-                                           tmp_list)
-                       {
-                               if (!dentry->d_inode->found) {
-                                       dentry->d_inode->found = true;
-                                       total_size += size;
+               }
+       }
+       progress->extract.num_streams = num_streams;
+       progress->extract.total_bytes = total_bytes;
+       progress->extract.completed_bytes = 0;
+}
+
+static void maybe_add_stream_for_extraction(struct lookup_table_entry *lte,
+                                           struct list_head *stream_list)
+{
+       if (lte->out_refcnt == 0) {
+               lte->out_refcnt = 1;
+               INIT_LIST_HEAD(&lte->inode_list);
+               list_add_tail(&lte->staging_list, stream_list);
+       }
+}
+
+static void inode_find_streams_for_extraction(struct inode *inode,
+                                             struct list_head *stream_list,
+                                             int extract_flags)
+{
+       struct lookup_table_entry *lte;
+       bool inode_added = false;
+
+       lte = inode_unnamed_lte_resolved(inode);
+
+       if (lte) {
+               maybe_add_stream_for_extraction(lte, stream_list);
+               list_add_tail(&inode->lte_inode_list, &lte->inode_list);
+               inode_added = true;
+       }
+#ifdef WITH_NTFS_3G
+       if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) {
+               for (unsigned i = 0; i < inode->num_ads; i++) {
+                       if (inode->ads_entries[i].stream_name_len != 0) {
+                               lte = inode_stream_lte_resolved(inode, i + 1);
+                               if (lte) {
+                                       maybe_add_stream_for_extraction(lte,
+                                                                       stream_list);
+                                       if (!inode_added) {
+                                               list_add_tail(&inode->lte_inode_list,
+                                                             &lte->inode_list);
+                                               inode_added = true;
+                                       }
+                               }
+                       }
+               }
+       }
+#endif
+}
+
+static void find_streams_for_extraction(struct hlist_head *inode_list,
+                                       struct list_head *stream_list,
+                                       struct lookup_table *lookup_table,
+                                       int extract_flags)
+{
+       struct inode *inode;
+       struct hlist_node *cur;
+       struct dentry *dentry;
+
+       for_lookup_table_entry(lookup_table, lte_zero_out_refcnt, NULL);
+       INIT_LIST_HEAD(stream_list);
+       hlist_for_each_entry(inode, cur, inode_list, hlist) {
+               if (!inode->resolved)
+                       inode_resolve_ltes(inode, lookup_table);
+               inode_for_each_dentry(dentry, inode)
+                       dentry->is_extracted = 0;
+               inode_find_streams_for_extraction(inode, stream_list,
+                                                 extract_flags);
+       }
+}
+
+struct apply_operations {
+       int (*apply_dentry)(struct dentry *dentry, void *arg);
+       int (*apply_dentry_timestamps)(struct dentry *dentry, void *arg);
+};
+
+static const struct apply_operations normal_apply_operations = {
+       .apply_dentry = apply_dentry_normal,
+       .apply_dentry_timestamps = apply_dentry_timestamps_normal,
+};
+
+#ifdef WITH_NTFS_3G
+static const struct apply_operations ntfs_apply_operations = {
+       .apply_dentry = wim_apply_dentry_ntfs,
+       .apply_dentry_timestamps = wim_apply_dentry_timestamps,
+};
+#endif
+
+static int apply_stream_list(struct list_head *stream_list,
+                            struct apply_args *args,
+                            const struct apply_operations *ops,
+                            wimlib_progress_func_t progress_func)
+{
+       uint64_t bytes_per_progress = args->progress.extract.total_bytes / 100;
+       uint64_t next_progress = bytes_per_progress;
+       struct lookup_table_entry *lte;
+       struct inode *inode;
+       struct dentry *dentry;
+       int ret = 0;
+       list_for_each_entry(lte, stream_list, staging_list) {
+               list_for_each_entry(inode, &lte->inode_list, lte_inode_list) {
+                       inode_for_each_dentry(dentry, inode) {
+                               ret = ops->apply_dentry(dentry, args);
+                               if (ret != 0)
+                                       goto out;
+                               if (args->progress.extract.completed_bytes >= next_progress) {
+                                       progress_func(WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS,
+                                                     &args->progress);
+                                       next_progress += bytes_per_progress;
                                }
                        }
                }
        }
-       return total_size;
+out:
+       return ret;
 }
 
 static int extract_single_image(WIMStruct *w, int image,
-                               const char *output_dir, int extract_flags)
+                               const char *target, int extract_flags,
+                               wimlib_progress_func_t progress_func)
 {
        int ret;
-       struct dentry *root;
-       const char *image_name;
+       struct list_head stream_list;
+       struct hlist_head *inode_list;
+
+       struct apply_args args;
+       const struct apply_operations *ops;
+
+       args.w                    = w;
+       args.target               = target;
+       args.extract_flags        = extract_flags;
+       args.num_lutimes_warnings = 0;
+       args.target               = target;
+       args.stream_list          = &stream_list;
+
+       if (progress_func) {
+               args.progress.extract.image      = image;
+               args.progress.extract.image_name = wimlib_get_image_name(w, image);
+               args.progress.extract.target     = target;
+       }
 
-       DEBUG("Extracting image %d", image);
+#ifdef WITH_NTFS_3G
+       if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) {
+               args.vol = ntfs_mount(target, 0);
+               if (!args.vol) {
+                       ERROR_WITH_ERRNO("Failed to mount NTFS volume `%s'", target);
+                       return WIMLIB_ERR_NTFS_3G;
+               }
+       }
+#endif
+
+#ifdef WITH_NTFS_3G
+       if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS)
+               ops = &ntfs_apply_operations;
+       else
+#endif
+               ops = &normal_apply_operations;
 
        ret = select_wim_image(w, image);
        if (ret != 0)
-               return ret;
+               goto out;
 
-       root = wim_root_dentry(w);
+       inode_list = &w->image_metadata[image - 1].inode_list;
+       find_streams_for_extraction(inode_list,
+                                   &stream_list,
+                                   w->lookup_table,
+                                   extract_flags);
 
-       struct extract_args args = {
-               .w                    = w,
-               .extract_flags        = extract_flags,
-               .output_dir           = output_dir,
-               .num_lutimes_warnings = 0,
-       };
+       calculate_bytes_to_extract(&stream_list, extract_flags,
+                                  &args.progress);
 
-       image_name = wimlib_get_image_name(w, image);
-       if (!image_name)
-               image_name = "unnamed";
+       if (progress_func) {
+               progress_func(WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_BEGIN,
+                             &args.progress);
+       }
 
        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) {
-                       printf("Creating directory structure for image %d (%s)...\n",
-                              image, image_name);
-               }
-       } else {
-               if (args.extract_flags & WIMLIB_EXTRACT_FLAG_SHOW_PROGRESS) {
-                       printf("Extracting image %d (%s)...\n",
-                              image, image_name);
+               ret = sort_stream_list_by_wim_position(&stream_list);
+               if (ret != 0) {
+                       WARNING("Falling back to non-sequential extraction");
+                       extract_flags &= ~WIMLIB_EXTRACT_FLAG_SEQUENTIAL;
                }
        }
 
-       ret = for_dentry_in_tree(root, extract_dentry, &args);
+       if (progress_func) {
+               progress_func(WIMLIB_PROGRESS_MSG_EXTRACT_DIR_STRUCTURE_BEGIN,
+                             &args.progress);
+       }
+
+
+       args.extract_flags |= WIMLIB_EXTRACT_FLAG_NO_STREAMS;
+       ret = for_dentry_in_tree(wim_root_dentry(w), ops->apply_dentry, &args);
+       args.extract_flags &= ~WIMLIB_EXTRACT_FLAG_NO_STREAMS;
        if (ret != 0)
-               return ret;
+               goto out;
 
-       if (extract_flags & WIMLIB_EXTRACT_FLAG_SEQUENTIAL) {
-               struct list_head stream_list;
-               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;
-
-               INIT_LIST_HEAD(&stream_list);
-               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_NO_STREAMS;
-               if (ret != 0) {
-                       WARNING("Falling back to non-sequential image extraction");
-                       ret = for_dentry_in_tree(root, extract_dentry, &args);
-                       if (ret != 0)
-                               return ret;
-                       goto out;
-               }
+       if (progress_func) {
+               progress_func(WIMLIB_PROGRESS_MSG_EXTRACT_DIR_STRUCTURE_END,
+                             &args.progress);
+       }
 
-               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);
-                       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;
-                       }
-               }
-               finish_stream_op_progress(total_size, "extracted");
+       ret = apply_stream_list(&stream_list, &args, ops, progress_func);
+       if (ret != 0)
+               goto out;
+
+       if (progress_func)
+               progress_func(WIMLIB_PROGRESS_MSG_APPLY_TIMESTAMPS, NULL);
+
+       ret = for_dentry_in_tree_depth(wim_root_dentry(w),
+                                      ops->apply_dentry_timestamps, &args);
+       if (ret != 0)
+               goto out;
+
+       if (progress_func) {
+               progress_func(WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_END,
+                             &args.progress);
        }
 out:
-       return for_dentry_in_tree_depth(root, apply_dentry_timestamps, &args);
+#ifdef WITH_NTFS_3G
+       if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) {
+               if (ntfs_umount(args.vol, FALSE) != 0) {
+                       ERROR_WITH_ERRNO("Failed to unmount NTFS volume `%s'", args.target);
+                       if (ret == 0)
+                               ret = WIMLIB_ERR_NTFS_3G;
+               }
+       }
+#endif
+       return ret;
 }
 
 
 /* Extracts all images from the WIM to @output_dir, with the images placed in
  * subdirectories named by their image names. */
-static int extract_all_images(WIMStruct *w, const char *output_dir,
-                             int extract_flags)
+static int extract_all_images(WIMStruct *w, const char *target,
+                             int extract_flags,
+                             wimlib_progress_func_t progress_func)
 {
        size_t image_name_max_len = max(xml_get_max_image_name_len(w), 20);
-       size_t output_path_len = strlen(output_dir);
+       size_t output_path_len = strlen(target);
        char buf[output_path_len + 1 + image_name_max_len + 1];
        int ret;
        int image;
        const char *image_name;
 
-       DEBUG("Attempting to extract all images from `%s' to `%s'",
-             w->filename, output_dir);
-
-       ret = extract_directory(output_dir, true);
+       ret = extract_directory(target, true);
        if (ret != 0)
                return ret;
 
-       memcpy(buf, output_dir, output_path_len);
+       memcpy(buf, target, output_path_len);
        buf[output_path_len] = '/';
        for (image = 1; image <= w->hdr.image_count; image++) {
-
                image_name = wimlib_get_image_name(w, image);
-               if (*image_name) {
+               if (image_name && *image_name) {
                        strcpy(buf + output_path_len + 1, image_name);
                } else {
                        /* Image name is empty. Use image number instead */
                        sprintf(buf + output_path_len + 1, "%d", image);
                }
-               ret = extract_single_image(w, image, buf, extract_flags);
+               ret = extract_single_image(w, image, buf, extract_flags,
+                                          progress_func);
                if (ret != 0)
                        return ret;
        }
@@ -604,19 +703,16 @@ static int extract_all_images(WIMStruct *w, const char *output_dir,
 
 /* Extracts a single image or all images from a WIM file. */
 WIMLIBAPI int wimlib_extract_image(WIMStruct *w, int image,
-                                  const char *output_dir,
+                                  const char *target,
                                   int extract_flags,
                                   WIMStruct **additional_swms,
-                                  unsigned num_additional_swms)
+                                  unsigned num_additional_swms,
+                                  wimlib_progress_func_t progress_func)
 {
        struct lookup_table *joined_tab, *w_tab_save;
        int ret;
 
-       DEBUG("w->filename = %s, image = %d, output_dir = %s, flags = 0x%x, "
-             "num_additional_swms = %u",
-             w->filename, image, output_dir, extract_flags, num_additional_swms);
-
-       if (!w || !output_dir)
+       if (!w || !target)
                return WIMLIB_ERR_INVALID_PARAM;
 
        extract_flags &= WIMLIB_EXTRACT_MASK_PUBLIC;
@@ -625,6 +721,25 @@ WIMLIBAPI int wimlib_extract_image(WIMStruct *w, int image,
                        == (WIMLIB_EXTRACT_FLAG_SYMLINK | WIMLIB_EXTRACT_FLAG_HARDLINK))
                return WIMLIB_ERR_INVALID_PARAM;
 
+       if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) {
+#ifdef WITH_NTFS_3G
+               if ((extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK | WIMLIB_EXTRACT_FLAG_HARDLINK))) {
+                       ERROR("Cannot specify symlink or hardlink flags when applying ");
+                       ERROR("directly to a NTFS volume");
+                       return WIMLIB_ERR_INVALID_PARAM;
+               }
+               if (image == WIMLIB_ALL_IMAGES) {
+                       ERROR("Can only apply a single image when applying "
+                             "directly to a NTFS volume");
+                       return WIMLIB_ERR_INVALID_PARAM;
+               }
+#else
+               ERROR("wimlib was compiled without support for NTFS-3g, so");
+               ERROR("we cannot apply a WIM image directly to a NTFS volume");
+               return WIMLIB_ERR_UNSUPPORTED;
+#endif
+       }
+
        ret = verify_swm_set(w, additional_swms, num_additional_swms);
        if (ret != 0)
                return ret;
@@ -638,25 +753,14 @@ WIMLIBAPI int wimlib_extract_image(WIMStruct *w, int image,
                w->lookup_table = joined_tab;
        }
 
-       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) {
+       if (image == WIMLIB_ALL_IMAGES) {
                extract_flags |= WIMLIB_EXTRACT_FLAG_MULTI_IMAGE;
-               ret = extract_all_images(w, output_dir, extract_flags);
+               ret = extract_all_images(w, target, extract_flags,
+                                        progress_func);
        } else {
                extract_flags &= ~WIMLIB_EXTRACT_FLAG_MULTI_IMAGE;
-               ret = extract_single_image(w, image, output_dir, extract_flags);
-       }
-       if (num_additional_swms) {
-               free_lookup_table(w->lookup_table);
-               w->lookup_table = w_tab_save;
+               ret = extract_single_image(w, image, target, extract_flags,
+                                          progress_func);
        }
 
        if (extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK |
@@ -666,6 +770,10 @@ WIMLIBAPI int wimlib_extract_image(WIMStruct *w, int image,
                                       lte_free_extracted_file,
                                       NULL);
        }
-       return ret;
 
+       if (num_additional_swms) {
+               free_lookup_table(w->lookup_table);
+               w->lookup_table = w_tab_save;
+       }
+       return ret;
 }
index 69d4f69..2a7fe32 100644 (file)
@@ -197,14 +197,14 @@ int init_header(struct wim_header *hdr, int ctype)
 {
        memset(hdr, 0, sizeof(struct wim_header));
        switch (ctype) {
-       case WIM_COMPRESSION_TYPE_NONE:
+       case WIMLIB_COMPRESSION_TYPE_NONE:
                hdr->flags = 0;
                break;
-       case WIM_COMPRESSION_TYPE_LZX:
+       case WIMLIB_COMPRESSION_TYPE_LZX:
                hdr->flags = WIM_HDR_FLAG_COMPRESSION |
                             WIM_HDR_FLAG_COMPRESS_LZX;
                break;
-       case WIM_COMPRESSION_TYPE_XPRESS:
+       case WIMLIB_COMPRESSION_TYPE_XPRESS:
                hdr->flags = WIM_HDR_FLAG_COMPRESSION |
                             WIM_HDR_FLAG_COMPRESS_XPRESS;
                break;
index d7f81eb..67f2133 100644 (file)
@@ -222,9 +222,9 @@ out:
  *     If @old_table is non-NULL, the byte after the last byte that was checked
  *     in the old table.  Must be less than or equal to new_check_end.
  *
- * @show_progress:
- *     True if progress information is to be shown while calculating the
- *     integrity data.
+ * @progress_func:
+ *     If non-NULL, a progress function that will be called after every
+ *     calculated chunk.
  *
  * @integrity_table_ret:
  *     On success, a pointer to the calculated integrity table is written into
@@ -236,7 +236,7 @@ static int calculate_integrity_table(FILE *fp,
                                     off_t new_check_end,
                                     const struct integrity_table *old_table,
                                     off_t old_check_end,
-                                    bool show_progress,
+                                    wimlib_progress_func_t progress_func,
                                     struct integrity_table **integrity_table_ret)
 {
        int ret = 0;
@@ -272,6 +272,18 @@ static int calculate_integrity_table(FILE *fp,
        new_table->chunk_size = chunk_size;
 
        u64 offset = WIM_HEADER_DISK_SIZE;
+       union wimlib_progress_info progress;
+
+       if (progress_func) {
+               progress.integrity.total_bytes      = new_check_bytes;
+               progress.integrity.total_chunks     = new_num_chunks;
+               progress.integrity.completed_chunks = 0;
+               progress.integrity.completed_bytes  = 0;
+               progress.integrity.chunk_size       = chunk_size;
+               progress.integrity.filename         = NULL;
+               progress_func(WIMLIB_PROGRESS_MSG_CALC_INTEGRITY,
+                             &progress);
+       }
 
        for (u32 i = 0; i < new_num_chunks; i++) {
                size_t this_chunk_size;
@@ -279,18 +291,6 @@ static int calculate_integrity_table(FILE *fp,
                        this_chunk_size = new_last_chunk_size;
                else
                        this_chunk_size = chunk_size;
-               if (show_progress) {
-                       unsigned percent_done;
-                       u64 checked_bytes = offset - WIM_HEADER_DISK_SIZE;
-                       percent_done = checked_bytes * 100 / new_check_bytes;
-                       printf("\rCalculating integrity checksums for WIM: "
-                              "%"PRIu64" MiB of %"PRIu64" MiB (%u%%) done",
-                              checked_bytes >> 20,
-                              new_check_bytes >> 20,
-                              percent_done);
-                       fflush(stdout);
-               }
-
                if (old_table &&
                    ((this_chunk_size == chunk_size && i < old_num_chunks - 1) ||
                      (i == old_num_chunks - 1 && this_chunk_size == old_last_chunk_size)))
@@ -306,17 +306,17 @@ static int calculate_integrity_table(FILE *fp,
                                break;
                }
                offset += this_chunk_size;
+               if (progress_func) {
+                       progress.integrity.completed_chunks++;
+                       progress.integrity.completed_bytes += this_chunk_size;
+                       progress_func(WIMLIB_PROGRESS_MSG_CALC_INTEGRITY,
+                                     &progress);
+               }
        }
-       if (ret != 0) {
-               FREE(new_table);
-       } else {
-               printf("\rCalculating integrity checksums for WIM: "
-                      "%"PRIu64" MiB of %"PRIu64" MiB (100%%) done\n",
-                      new_check_bytes >> 20,
-                      new_check_bytes >> 20);
-               fflush(stdout);
+       if (ret == 0)
                *integrity_table_ret = new_table;
-       }
+       else
+               FREE(new_table);
        return ret;
 }
 
@@ -350,9 +350,9 @@ static int calculate_integrity_table(FILE *fp,
  *     If nonzero, the offset of the byte directly following the old lookup
  *     table in the WIM.
  *
- * @show_progress:
- *     True if progress information is to be shown while writing the integrity
- *     table.
+ * @progress_func
+ *     If non-NULL, a progress function that will be called after every
+ *     calculated chunk.
  *
  * Returns:
  *     0 on success, nonzero on failure.  The possible error codes are:
@@ -364,7 +364,7 @@ int write_integrity_table(FILE *fp,
                          struct resource_entry *integrity_res_entry,
                          off_t new_lookup_table_end,
                          off_t old_lookup_table_end,
-                         bool show_progress)
+                         wimlib_progress_func_t progress_func)
 {
        struct integrity_table *old_table;
        struct integrity_table *new_table;
@@ -397,7 +397,7 @@ int write_integrity_table(FILE *fp,
 
        ret = calculate_integrity_table(fp, new_lookup_table_end,
                                        old_table, old_lookup_table_end,
-                                       show_progress, &new_table);
+                                       progress_func, &new_table);
        if (ret != 0)
                goto out_free_old_table;
 
@@ -444,9 +444,9 @@ out_free_old_table:
  *     Number of bytes in the WIM that need to be checked (offset of end of the
  *     lookup table minus offset of end of the header).
  *
- * @show_progress:
- *     True if progress information is to be shown while checking the
- *     integrity.
+ * @progress_func
+ *     If non-NULL, a progress function that will be called after every
+ *     verified chunk.
  *
  * Returns:
  *     > 0 (WIMLIB_ERR_*) on error
@@ -454,12 +454,26 @@ out_free_old_table:
  *     were no inconsistencies.
  *     -1 (WIM_INTEGRITY_NOT_OK) if the WIM failed the integrity check.
  */
-static int verify_integrity(FILE *fp, const struct integrity_table *table,
-                           u64 bytes_to_check, bool show_progress)
+static int verify_integrity(FILE *fp, const char *filename,
+                           const struct integrity_table *table,
+                           u64 bytes_to_check,
+                           wimlib_progress_func_t progress_func)
 {
        int ret;
        u64 offset = WIM_HEADER_DISK_SIZE;
        u8 sha1_md[SHA1_HASH_SIZE];
+       union wimlib_progress_info progress;
+
+       if (progress_func) {
+               progress.integrity.total_bytes      = bytes_to_check;
+               progress.integrity.total_chunks     = table->num_entries;
+               progress.integrity.completed_chunks = 0;
+               progress.integrity.completed_bytes  = 0;
+               progress.integrity.chunk_size       = table->chunk_size;
+               progress.integrity.filename         = filename;
+               progress_func(WIMLIB_PROGRESS_MSG_VERIFY_INTEGRITY,
+                             &progress);
+       }
        for (u32 i = 0; i < table->num_entries; i++) {
                size_t this_chunk_size;
                if (i == table->num_entries - 1)
@@ -475,23 +489,14 @@ static int verify_integrity(FILE *fp, const struct integrity_table *table,
                if (!hashes_equal(sha1_md, table->sha1sums[i]))
                        return WIM_INTEGRITY_NOT_OK;
 
-               if (show_progress) {
-                       u64 checked_bytes = offset - WIM_HEADER_DISK_SIZE;
-                       unsigned percent_done = checked_bytes * 100 / bytes_to_check;
-                       printf("\rVerifying integrity of WIM: "
-                              "%"PRIu64" MiB of %"PRIu64" MiB (%u%%) done",
-                              checked_bytes >> 20,
-                              bytes_to_check >> 20,
-                              percent_done);
-                       fflush(stdout);
-               }
                offset += this_chunk_size;
+               if (progress_func) {
+                       progress.integrity.completed_chunks++;
+                       progress.integrity.completed_bytes += this_chunk_size;
+                       progress_func(WIMLIB_PROGRESS_MSG_VERIFY_INTEGRITY,
+                                     &progress);
+               }
        }
-       printf("\rVerifying integrity of WIM: "
-              "%"PRIu64" MiB of %"PRIu64" MiB (100%%) done\n",
-              bytes_to_check >> 20,
-              bytes_to_check >> 20);
-       fflush(stdout);
        return WIM_INTEGRITY_OK;
 }
 
@@ -504,9 +509,9 @@ static int verify_integrity(FILE *fp, const struct integrity_table *table,
  * @w:
  *     The WIM, opened for reading, and with the header already read.
  *
- * @show_progress:
- *     True if progress information is to be shown while checking the
- *     integrity.
+ * @progress_func
+ *     If non-NULL, a progress function that will be called after every
+ *     verified chunk.
  *
  * Returns:
  *     > 0 (WIMLIB_ERR_*) on error
@@ -516,7 +521,7 @@ static int verify_integrity(FILE *fp, const struct integrity_table *table,
  *     -2 (WIM_INTEGRITY_NONEXISTENT) if the WIM contains no integrity
  *     information.
  */
-int check_wim_integrity(WIMStruct *w, bool show_progress)
+int check_wim_integrity(WIMStruct *w, wimlib_progress_func_t progress_func)
 {
        int ret;
        u64 bytes_to_check;
@@ -542,7 +547,8 @@ int check_wim_integrity(WIMStruct *w, bool show_progress)
                                   bytes_to_check, &table);
        if (ret != 0)
                return ret;
-       ret = verify_integrity(w->fp, table, bytes_to_check, show_progress);
+       ret = verify_integrity(w->fp, w->filename, table,
+                              bytes_to_check, progress_func);
        FREE(table);
        return ret;
 }
index 222c9a9..34e5df9 100644 (file)
 #include "xml.h"
 #include <stdlib.h>
 
-static int copy_lte_to_table(struct lookup_table_entry *lte, void *table)
+static int move_lte_to_table(struct lookup_table_entry *lte,
+                            void *other_tab)
 {
-       struct lookup_table_entry *copy;
-       copy = MALLOC(sizeof(struct lookup_table_entry));
-       if (!copy)
-               return WIMLIB_ERR_NOMEM;
-       memcpy(copy, lte, sizeof(struct lookup_table_entry));
-       lookup_table_insert(table, copy);
+       hlist_del(&lte->hash_list);
+       lookup_table_insert((struct lookup_table*)other_tab, lte);
        return 0;
 }
 
 static int lookup_table_join(struct lookup_table *table,
                             struct lookup_table *new)
 {
-       return for_lookup_table_entry(new, copy_lte_to_table, table);
-}
-
-
-static int cmp_swms_by_part_number(const void *swm1, const void *swm2)
-{
-       u16 partno_1 = (*(WIMStruct**)swm1)->hdr.part_number;
-       u16 partno_2 = (*(WIMStruct**)swm2)->hdr.part_number;
-       return (int)partno_1 - (int)partno_2;
+       return for_lookup_table_entry(new, move_lte_to_table, table);
 }
 
 /*
@@ -158,7 +147,9 @@ int verify_swm_set(WIMStruct *w, WIMStruct **additional_swms,
  * Joins lookup tables from the parts of a split WIM.
  *
  * @w specifies the first part, while @additional_swms and @num_additional_swms
- * specify an array of points to the WIMStruct's for additional split WIM parts.
+ * specify an array of pointers to the WIMStruct's for additional split WIM parts.
+ *
+ * The lookup table entries are *moved* to the new table.
  *
  * On success, 0 is returned on a pointer to the joined lookup table is returned
  * in @table_ret.
@@ -178,13 +169,13 @@ int new_joined_lookup_table(WIMStruct *w,
        int ret;
        unsigned i;
 
-
        table = new_lookup_table(9001);
        if (!table)
                return WIMLIB_ERR_NOMEM;
-       ret = lookup_table_join(table, w->lookup_table);
-       if (ret != 0)
-               goto out_free_table;
+
+       if (w)
+               lookup_table_join(table, w->lookup_table);
+
        for (i = 0; i < num_additional_swms; i++) {
                ret = lookup_table_join(table, additional_swms[i]->lookup_table);
                if (ret != 0)
@@ -198,111 +189,106 @@ out_free_table:
 }
 
 
-static int join_wims(WIMStruct **swms, uint num_swms, WIMStruct *joined_wim,
-                    int write_flags)
+static int join_wims(WIMStruct **swms, unsigned num_swms,
+                    WIMStruct *joined_wim, int write_flags,
+                    wimlib_progress_func_t progress_func)
 {
-       uint i;
        int ret;
-       FILE *out_fp = joined_wim->out_fp;
-       u64 total_bytes = wim_info_get_total_bytes(swms[0]->wim_info);
+       unsigned i;
+       union wimlib_progress_info progress;
+       u64 total_bytes = 0;
+       u64 part_bytes;
+       u64 swm_part_sizes[num_swms];
 
-       swms[0]->write_metadata = false;
+       /* Calculate total size of the streams in the split WIM parts. */
+       for (i = 0; i < num_swms; i++) {
+               part_bytes = lookup_table_total_stream_size(swms[i]->lookup_table);
+               swm_part_sizes[i] = part_bytes;
+               total_bytes += part_bytes;
+       }
+
+       if (progress_func) {
+               progress.join.total_bytes        = total_bytes;
+               progress.join.total_parts        = swms[0]->hdr.total_parts;
+               progress.join.completed_bytes    = 0;
+               progress.join.completed_parts    = 0;
+               progress_func(WIMLIB_PROGRESS_MSG_JOIN_STREAMS, &progress);
+       }
+
+       /* Write the resources (streams and metadata resources) from each SWM
+        * part */
+       swms[0]->write_metadata = true;
        for (i = 0; i < num_swms; i++) {
-               if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS) {
-                       off_t cur_offset = ftello(out_fp);
-                       printf("Writing resources from part %u of %u "
-                              "(%"PRIu64" of %"PRIu64" bytes, %.0f%% done)\n",
-                              i + 1, num_swms, cur_offset, total_bytes,
-                              (double)cur_offset / total_bytes * 100.0);
-               }
                swms[i]->fp = fopen(swms[i]->filename, "rb");
                if (!swms[i]->fp) {
                        ERROR_WITH_ERRNO("Failed to reopen `%s'",
                                         swms[i]->filename);
                        return WIMLIB_ERR_OPEN;
                }
-               swms[i]->out_fp = out_fp;
+               swms[i]->out_fp = joined_wim->out_fp;
                swms[i]->hdr.part_number = 1;
                ret = for_lookup_table_entry(swms[i]->lookup_table,
                                             copy_resource, swms[i]);
-               if (ret != 0)
-                       return ret;
-               if (i != 0) {
-                       fclose(swms[i]->fp);
-                       swms[i]->fp = NULL;
-               }
-       }
-       swms[0]->write_metadata = true;
-       if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS)
-               printf("Writing %d metadata resources\n",
-                       swms[0]->hdr.image_count);
+               swms[i]->out_fp = NULL;
+               fclose(swms[i]->fp);
+               swms[i]->fp = NULL;
 
-       for (i = 0; i < swms[0]->hdr.image_count; i++) {
-               ret = copy_resource(swms[0]->image_metadata[i].metadata_lte,
-                                   swms[0]);
                if (ret != 0)
                        return ret;
-       }
 
-       off_t lookup_table_offset = ftello(out_fp);
-
-       if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS)
-               printf("Writing lookup tables, XML data, and header\n");
-       /* Now write the lookup table for the joined wim.  Since the lookup
-        * table has no header, we can just concatenate the lookup tables of all
-        * the SWM parts. */
-       for (i = 0; i < num_swms; i++) {
-               ret = for_lookup_table_entry(swms[i]->lookup_table,
-                                            write_lookup_table_entry,
-                                            out_fp);
-               if (ret != 0)
-                       return ret;
+               if (progress_func) {
+                       progress.join.completed_bytes += swm_part_sizes[i];
+                       progress.join.completed_parts++;
+                       progress_func(WIMLIB_PROGRESS_MSG_JOIN_STREAMS, &progress);
+               }
        }
-       off_t xml_data_offset = ftello(out_fp);
 
-       if (lookup_table_offset == -1 || xml_data_offset == -1) {
-               ERROR_WITH_ERRNO("Failed to get file offset");
-               return WIMLIB_ERR_WRITE;
-       }
-       swms[0]->hdr.lookup_table_res_entry.offset = lookup_table_offset;
-       swms[0]->hdr.lookup_table_res_entry.size =
-                                       xml_data_offset - lookup_table_offset;
-       swms[0]->hdr.lookup_table_res_entry.original_size =
-                                       xml_data_offset - lookup_table_offset;
-       swms[0]->hdr.lookup_table_res_entry.flags =
-                                       WIM_RESHDR_FLAG_METADATA;
-
-
-       /* finish_write is called on the first swm, not the joined_wim, because
-        * the first swm is the one that has the image metadata and XML data
-        * attached to it.  */
-       swms[0]->hdr.flags &= ~WIM_HDR_FLAG_SPANNED;
-       swms[0]->hdr.total_parts = 1;
-       return finish_write(swms[0], WIM_ALL_IMAGES,
-                           write_flags | WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE);
+       joined_wim->hdr.image_count = swms[0]->hdr.image_count;
+       for (i = 0; i < num_swms; i++)
+               lookup_table_join(joined_wim->lookup_table, swms[i]->lookup_table);
+
+       free_wim_info(joined_wim->wim_info);
+       joined_wim->wim_info = swms[0]->wim_info;
+       ret = finish_write(joined_wim, WIMLIB_ALL_IMAGES, write_flags, progress_func);
+       joined_wim->wim_info = NULL;
+       return ret;
 }
 
+static int cmp_swms_by_part_number(const void *swm1, const void *swm2)
+{
+       u16 partno_1 = (*(const WIMStruct**)swm1)->hdr.part_number;
+       u16 partno_2 = (*(const WIMStruct**)swm2)->hdr.part_number;
+       return (int)partno_1 - (int)partno_2;
+}
 
+/*
+ * Join a set of split WIMs into a stand-alone WIM.
+ */
 WIMLIBAPI int wimlib_join(const char **swm_names, unsigned num_swms,
-                         const char *output_path, int flags)
+                         const char *output_path, int swm_open_flags,
+                         int wim_write_flags,
+                         wimlib_progress_func_t progress_func)
 {
        int ret;
-       int write_flags = 0;
        WIMStruct *joined_wim = NULL;
-       WIMStruct *swms[num_swms];
+       unsigned i;
+
+       swm_open_flags |= WIMLIB_OPEN_FLAG_SPLIT_OK;
+       wim_write_flags &= WIMLIB_WRITE_MASK_PUBLIC;
 
-       if (num_swms < 1)
+       if (num_swms < 1 || num_swms > 0xffff)
                return WIMLIB_ERR_INVALID_PARAM;
 
+       WIMStruct *swms[num_swms];
        ZERO_ARRAY(swms);
 
-       for (unsigned i = 0; i < num_swms; i++) {
-               ret = wimlib_open_wim(swm_names[i],
-                                     flags | WIMLIB_OPEN_FLAG_SPLIT_OK, &swms[i]);
+       for (i = 0; i < num_swms; i++) {
+               ret = wimlib_open_wim(swm_names[i], swm_open_flags, &swms[i],
+                                     progress_func);
                if (ret != 0)
                        goto out;
 
-               /* don't open all the parts at the same time, in case there are
+               /* Don't open all the parts at the same time, in case there are
                 * a lot of them */
                fclose(swms[i]->fp);
                swms[i]->fp = NULL;
@@ -314,29 +300,19 @@ WIMLIBAPI int wimlib_join(const char **swm_names, unsigned num_swms,
        if (ret != 0)
                goto out;
 
-       joined_wim = new_wim_struct();
-       if (!joined_wim) {
-               ret = WIMLIB_ERR_NOMEM;
+       ret = wimlib_create_new_wim(wimlib_get_compression_type(swms[0]),
+                                   &joined_wim);
+       if (ret != 0)
                goto out;
-       }
 
-       if (flags & WIMLIB_OPEN_FLAG_CHECK_INTEGRITY)
-               write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
-       if (flags & WIMLIB_OPEN_FLAG_SHOW_PROGRESS)
-               write_flags |= WIMLIB_WRITE_FLAG_SHOW_PROGRESS;
-
-       ret = begin_write(joined_wim, output_path, write_flags);
+       ret = begin_write(joined_wim, output_path, wim_write_flags);
        if (ret != 0)
                goto out;
-       ret = join_wims(swms, num_swms, joined_wim, write_flags);
+       ret = join_wims(swms, num_swms, joined_wim, wim_write_flags,
+                       progress_func);
 out:
-       /* out_fp is the same in all the swms and joined_wim.  And it was
-        * already closed in the call to finish_write(). */
-       for (unsigned i = 0; i < num_swms; i++) {
-               swms[i]->out_fp = NULL;
+       for (i = 0; i < num_swms; i++)
                wimlib_free(swms[i]);
-       }
-       joined_wim->out_fp = NULL;
        wimlib_free(joined_wim);
        return ret;
 }
index d1be89b..364f469 100644 (file)
@@ -626,7 +626,7 @@ out:
 }
 #endif
 
-static void inode_resolve_ltes(struct inode *inode, struct lookup_table *table)
+void inode_resolve_ltes(struct inode *inode, struct lookup_table *table)
 {
        struct lookup_table_entry *lte;
 
@@ -704,7 +704,7 @@ int dentry_unresolve_ltes(struct dentry *dentry, void *ignore)
  */
 struct lookup_table_entry *
 inode_unnamed_lte(const struct inode *inode,
-                  const struct lookup_table *table)
+                 const struct lookup_table *table)
 {
        if (inode->resolved)
                return inode_unnamed_lte_resolved(inode);
@@ -712,3 +712,16 @@ inode_unnamed_lte(const struct inode *inode,
                return inode_unnamed_lte_unresolved(inode, table);
 }
 
+static int lte_add_stream_size(struct lookup_table_entry *lte,
+                              void *total_bytes_p)
+{
+       *(u64*)total_bytes_p += lte->resource_entry.size;
+       return 0;
+}
+
+u64 lookup_table_total_stream_size(struct lookup_table *table)
+{
+       u64 total_size = 0;
+       for_lookup_table_entry(table, lte_add_stream_size, &total_size);
+       return total_size;
+}
index 4458cc7..592116b 100644 (file)
@@ -185,24 +185,22 @@ struct lookup_table_entry {
                struct resource_entry output_resource_entry;
 
                struct list_head msg_list;
-               struct list_head dentry_list;
+               struct list_head inode_list;
        };
 
-       union {
-               /* This field is used for the special hardlink or symlink image
-                * 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.  */
-               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
-                * mounted WIM. */
-               struct list_head staging_list;
-       };
+       /* List of lookup table entries that correspond to streams that have
+        * been extracted to the staging directory when modifying a read-write
+        * mounted WIM.
+        *
+        * This field is also used to make other lists of lookup table entries.
+        * */
+       struct list_head staging_list;
+
+       /* This field is used for the special hardlink or symlink image
+        * 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;
 };
 
 static inline u64 wim_resource_size(const struct lookup_table_entry *lte)
@@ -230,7 +228,7 @@ wim_resource_compression_type(const struct lookup_table_entry *lte)
 {
        if (!(lte->resource_entry.flags & WIM_RESHDR_FLAG_COMPRESSED)
            || lte->resource_location != RESOURCE_IN_WIM)
-               return WIM_COMPRESSION_TYPE_NONE;
+               return WIMLIB_COMPRESSION_TYPE_NONE;
        return wimlib_get_compression_type(lte->wim);
 }
 
@@ -286,6 +284,9 @@ extern int write_lookup_table_entry(struct lookup_table_entry *lte, void *__out)
 
 extern void free_lookup_table_entry(struct lookup_table_entry *lte);
 
+extern void inode_resolve_ltes(struct inode *inode,
+                              struct lookup_table *table);
+
 extern int dentry_resolve_ltes(struct dentry *dentry, void *__table);
 extern int dentry_unresolve_ltes(struct dentry *dentry, void *ignore);
 
@@ -418,5 +419,7 @@ extern struct lookup_table_entry *
 inode_unnamed_lte(const struct inode *inode,
                  const struct lookup_table *table);
 
+extern u64 lookup_table_total_stream_size(struct lookup_table *table);
+
 
 #endif
index 3180c50..a8ce13c 100644 (file)
@@ -482,9 +482,10 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
                                  WIMStruct *dest_wim,
                                  const char *dest_name,
                                  const char *dest_description,
-                                 int flags,
+                                 int export_flags,
                                  WIMStruct **additional_swms,
-                                 unsigned num_additional_swms)
+                                 unsigned num_additional_swms,
+                                 wimlib_progress_func_t progress_func)
 {
        int i;
        int ret;
@@ -502,12 +503,12 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
                return WIMLIB_ERR_SPLIT_UNSUPPORTED;
        }
 
-       if (src_image == WIM_ALL_IMAGES) {
+       if (src_image == WIMLIB_ALL_IMAGES) {
                if (src_wim->hdr.image_count > 1) {
 
                        /* multi-image export. */
 
-                       if ((flags & WIMLIB_EXPORT_FLAG_BOOT) &&
+                       if ((export_flags & WIMLIB_EXPORT_FLAG_BOOT) &&
                              (src_wim->hdr.boot_idx == 0))
                        {
                                /* Specifying the boot flag on a multi-image
@@ -527,16 +528,17 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
                                return WIMLIB_ERR_INVALID_PARAM;
                        }
                        for (i = 1; i <= src_wim->hdr.image_count; i++) {
-                               int export_flags = flags;
+                               int new_flags = export_flags;
 
                                if (i != src_wim->hdr.boot_idx)
-                                       export_flags &= ~WIMLIB_EXPORT_FLAG_BOOT;
+                                       new_flags &= ~WIMLIB_EXPORT_FLAG_BOOT;
 
                                ret = wimlib_export_image(src_wim, i, dest_wim,
                                                          NULL, NULL,
-                                                         export_flags,
+                                                         new_flags,
                                                          additional_swms,
-                                                         num_additional_swms);
+                                                         num_additional_swms,
+                                                         progress_func);
                                if (ret != 0)
                                        return ret;
                        }
@@ -624,9 +626,9 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
        for_dentry_in_tree(root, add_lte_to_dest_wim, &wims);
        wimlib_assert(list_empty(&wims.lte_list_head));
 
-       if (flags & WIMLIB_EXPORT_FLAG_BOOT) {
+       if (export_flags & WIMLIB_EXPORT_FLAG_BOOT) {
                DEBUG("Setting boot_idx to %d", dest_wim->hdr.image_count);
-               dest_wim->hdr.boot_idx = dest_wim->hdr.image_count;
+               wimlib_set_boot_idx(dest_wim, dest_wim->hdr.image_count);
        }
        ret = 0;
        goto out;
@@ -661,7 +663,7 @@ WIMLIBAPI int wimlib_delete_image(WIMStruct *w, int image)
                return WIMLIB_ERR_SPLIT_UNSUPPORTED;
        }
 
-       if (image == WIM_ALL_IMAGES) {
+       if (image == WIMLIB_ALL_IMAGES) {
                for (i = w->hdr.image_count; i >= 1; i--) {
                        ret = wimlib_delete_image(w, i);
                        if (ret != 0)
@@ -699,7 +701,7 @@ WIMLIBAPI int wimlib_delete_image(WIMStruct *w, int image)
        else if (w->hdr.boot_idx > image)
                w->hdr.boot_idx--;
 
-       w->current_image = WIM_NO_IMAGE;
+       w->current_image = WIMLIB_NO_IMAGE;
 
        /* Remove the image from the XML information. */
        xml_delete_image(&w->wim_info, image);
@@ -942,30 +944,18 @@ bool exclude_path(const char *path, const struct capture_config *config,
 
 }
 
-
-
-/*
- * Adds an image to the WIM, delegating the capture of the dentry tree and
- * security data to the function @capture_tree passed as a parameter.
- * Currently, @capture_tree may be build_dentry_tree() for capturing a "regular"
- * directory tree on disk, or build_dentry_tree_ntfs() for capturing a WIM image
- * directory from a NTFS volume using libntfs-3g.
- *
- * The @capture_tree function is also expected to create lookup table entries
- * for all the file streams it captures and insert them into @lookup_table,
- * being careful to look for identical entries that already exist and simply
- * increment the reference count for them rather than duplicating the entry.
- */
-int do_add_image(WIMStruct *w, const char *dir, const char *name,
-                const char *config_str, size_t config_len,
-                int flags,
-                int (*capture_tree)(struct dentry **, const char *,
-                                    struct lookup_table *,
-                                    struct wim_security_data *,
-                                    const struct capture_config *,
-                                    int, void *),
-                void *extra_arg)
+WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *source,
+                              const char *name, const char *config_str,
+                              size_t config_len, int add_image_flags,
+                              wimlib_progress_func_t progress_func)
 {
+       int (*capture_tree)(struct dentry **, const char *,
+                           struct lookup_table *,
+                           struct wim_security_data *,
+                           const struct capture_config *,
+                           int, void *);
+       void *extra_arg;
+
        struct dentry *root_dentry = NULL;
        struct wim_security_data *sd;
        struct capture_config config;
@@ -973,13 +963,31 @@ int do_add_image(WIMStruct *w, const char *dir, const char *name,
        struct hlist_head inode_list;
        int ret;
 
+       if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_NTFS) {
+#ifdef WITH_NTFS_3G
+               if (add_image_flags & (WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE)) {
+                       ERROR("Cannot dereference files when capturing directly from NTFS");
+                       return WIMLIB_ERR_INVALID_PARAM;
+               }
+               capture_tree = build_dentry_tree_ntfs;
+               extra_arg = &w->ntfs_vol;
+#else
+               ERROR("wimlib was compiled without support for NTFS-3g, so");
+               ERROR("we cannot capture a WIM image directly from a NTFS volume");
+               return WIMLIB_ERR_UNSUPPORTED;
+#endif
+       } else {
+               capture_tree = build_dentry_tree;
+               extra_arg = NULL;
+       }
+
        DEBUG("Adding dentry tree from directory or NTFS volume `%s'.", dir);
 
        if (!name || !*name) {
                ERROR("Must specify a non-empty string for the image name");
                return WIMLIB_ERR_INVALID_PARAM;
        }
-       if (!dir) {
+       if (!source) {
                ERROR("Must specify the name of a directory or NTFS volume");
                return WIMLIB_ERR_INVALID_PARAM;
        }
@@ -1001,7 +1009,7 @@ int do_add_image(WIMStruct *w, const char *dir, const char *name,
                config_str = default_config;
                config_len = strlen(default_config);
        }
-       ret = init_capture_config(config_str, config_len, dir, &config);
+       ret = init_capture_config(config_str, config_len, source, &config);
        if (ret != 0)
                return ret;
        print_capture_config(&config);
@@ -1016,20 +1024,29 @@ int do_add_image(WIMStruct *w, const char *dir, const char *name,
        sd->total_length = 8;
        sd->refcnt = 1;
 
-       DEBUG("Building dentry tree.");
-       if (flags & WIMLIB_ADD_IMAGE_FLAG_SHOW_PROGRESS) {
-               printf("Scanning `%s'...\n", dir);
+       if (progress_func) {
+               union wimlib_progress_info progress;
+               progress.scan.source = source;
+               progress_func(WIMLIB_PROGRESS_MSG_SCAN_BEGIN, &progress);
        }
-       ret = (*capture_tree)(&root_dentry, dir, w->lookup_table, sd,
-                             &config, flags | WIMLIB_ADD_IMAGE_FLAG_ROOT,
+
+       DEBUG("Building dentry tree.");
+       ret = (*capture_tree)(&root_dentry, source, w->lookup_table, sd,
+                             &config, add_image_flags | WIMLIB_ADD_IMAGE_FLAG_ROOT,
                              extra_arg);
        destroy_capture_config(&config);
 
        if (ret != 0) {
-               ERROR("Failed to build dentry tree for `%s'", dir);
+               ERROR("Failed to build dentry tree for `%s'", source);
                goto out_free_security_data;
        }
 
+       if (progress_func) {
+               union wimlib_progress_info progress;
+               progress.scan.source = source;
+               progress_func(WIMLIB_PROGRESS_MSG_SCAN_END, &progress);
+       }
+
        DEBUG("Calculating full paths of dentries.");
        ret = for_dentry_in_tree(root_dentry, calculate_dentry_full_path, NULL);
        if (ret != 0)
@@ -1059,9 +1076,8 @@ int do_add_image(WIMStruct *w, const char *dir, const char *name,
        if (ret != 0)
                goto out_destroy_imd;
 
-       if (flags & WIMLIB_ADD_IMAGE_FLAG_BOOT)
-               w->hdr.boot_idx = w->hdr.image_count;
-
+       if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_BOOT)
+               wimlib_set_boot_idx(w, w->hdr.image_count);
        return 0;
 out_destroy_imd:
        destroy_image_metadata(&w->image_metadata[w->hdr.image_count - 1],
@@ -1076,14 +1092,3 @@ out_destroy_config:
        destroy_capture_config(&config);
        return ret;
 }
-
-/*
- * Adds an image to a WIM file from a directory tree on disk.
- */
-WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *dir,
-                              const char *name, const char *config_str,
-                              size_t config_len, int flags)
-{
-       return do_add_image(w, dir, name, config_str, config_len, flags,
-                           build_dentry_tree, NULL);
-}
index 15d7444..67a6edd 100644 (file)
@@ -896,7 +896,7 @@ static int rebuild_wim(struct wimfs_context *ctx, bool check_integrity)
 
        xml_update_image_info(w, w->current_image);
 
-       ret = wimlib_overwrite(w, check_integrity, 0);
+       ret = wimlib_overwrite(w, check_integrity, 0, NULL);
        if (ret != 0) {
                ERROR("Failed to commit changes");
                return ret;
@@ -1853,10 +1853,10 @@ static struct fuse_operations wimfs_operations = {
 };
 
 
-/* Mounts a WIM file. */
-WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir,
-                          int flags, WIMStruct **additional_swms,
-                          unsigned num_additional_swms)
+/* Mounts an image from a WIM file. */
+WIMLIBAPI int wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
+                                int mount_flags, WIMStruct **additional_swms,
+                                unsigned num_additional_swms)
 {
        int argc = 0;
        char *argv[16];
@@ -1867,7 +1867,7 @@ WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir,
        struct wimfs_context ctx;
 
        DEBUG("Mount: wim = %p, image = %d, dir = %s, flags = %d, ",
-             wim, image, dir, flags);
+             wim, image, dir, mount_flags);
 
        if (!wim || !dir)
                return WIMLIB_ERR_INVALID_PARAM;
@@ -1876,7 +1876,7 @@ WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir,
        if (ret != 0)
                return ret;
 
-       if ((flags & WIMLIB_MOUNT_FLAG_READWRITE) && (wim->hdr.total_parts != 1)) {
+       if ((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) && (wim->hdr.total_parts != 1)) {
                ERROR("Cannot mount a split WIM read-write");
                return WIMLIB_ERR_SPLIT_UNSUPPORTED;
        }
@@ -1914,10 +1914,10 @@ WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir,
                goto out;
        }
 
-       if (!(flags & (WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
+       if (!(mount_flags & (WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
                       WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR |
                       WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)))
-               flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR;
+               mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR;
 
 
        DEBUG("Initializing struct wimfs_context");
@@ -1947,10 +1947,10 @@ WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir,
        argv[argc++] = dir_copy;
 
        /* disable multi-threaded operation for read-write mounts */
-       if (flags & WIMLIB_MOUNT_FLAG_READWRITE)
+       if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)
                argv[argc++] = "-s";
 
-       if (flags & WIMLIB_MOUNT_FLAG_DEBUG)
+       if (mount_flags & WIMLIB_MOUNT_FLAG_DEBUG)
                argv[argc++] = "-d";
 
        /*
@@ -1962,7 +1962,7 @@ WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir,
        char optstring[256] = "use_ino,subtype=wimfs,attr_timeout=0";
        argv[argc++] = "-o";
        argv[argc++] = optstring;
-       if ((flags & WIMLIB_MOUNT_FLAG_READWRITE)) {
+       if ((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)) {
                /* Read-write mount.  Make the staging directory */
                ret = make_staging_dir(&ctx);
                if (ret != 0)
@@ -1987,7 +1987,7 @@ WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir,
 #endif
 
        /* Mark dentry tree as modified if read-write mount. */
-       if (flags & WIMLIB_MOUNT_FLAG_READWRITE) {
+       if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
                imd->modified = true;
                imd->has_been_mounted_rw = true;
        }
@@ -2002,7 +2002,7 @@ WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir,
 
        /* Finish initializing the filesystem context. */
        ctx.wim = wim;
-       ctx.mount_flags = flags;
+       ctx.mount_flags = mount_flags;
 
        DEBUG("Calling fuse_main()");
 
@@ -2029,9 +2029,9 @@ out:
 
 /*
  * Unmounts the WIM file that was previously mounted on @dir by using
- * wimlib_mount().
+ * wimlib_mount_image().
  */
-WIMLIBAPI int wimlib_unmount(const char *dir, int flags)
+WIMLIBAPI int wimlib_unmount_image(const char *dir, int unmount_flags)
 {
        pid_t pid;
        int status;
@@ -2057,8 +2057,8 @@ WIMLIBAPI int wimlib_unmount(const char *dir, int flags)
 
        /* Send a message to the filesystem daemon saying whether to commit or
         * not. */
-       msg[0] = (flags & WIMLIB_UNMOUNT_FLAG_COMMIT) ? 1 : 0;
-       msg[1] = (flags & WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY) ? 1 : 0;
+       msg[0] = (unmount_flags & WIMLIB_UNMOUNT_FLAG_COMMIT) ? 1 : 0;
+       msg[1] = (unmount_flags & WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY) ? 1 : 0;
 
        DEBUG("Sending message: %scommit, %scheck",
                        (msg[0] ? "" : "don't "),
@@ -2208,14 +2208,14 @@ static inline int mount_unsupported_error()
        return WIMLIB_ERR_UNSUPPORTED;
 }
 
-WIMLIBAPI int wimlib_unmount(const char *dir, int flags)
+WIMLIBAPI int wimlib_unmount_image(const char *dir, int unmount_flags)
 {
        return mount_unsupported_error();
 }
 
-WIMLIBAPI int wimlib_mount(WIMStruct *wim_p, int image, const char *dir,
-                          int flags, WIMStruct **additional_swms,
-                          unsigned num_additional_swms)
+WIMLIBAPI int wimlib_mount_image(WIMStruct *wim_p, int image, const char *dir,
+                                int mount_flags, WIMStruct **additional_swms,
+                                unsigned num_additional_swms)
 {
        return mount_unsupported_error();
 }
index 32d9810..61199b8 100644 (file)
 
 #include "config.h"
 
-#ifdef WITH_NTFS_3G
+
 #include <ntfs-3g/endians.h>
 #include <ntfs-3g/types.h>
-#endif
 
 #include "wimlib_internal.h"
-
-
-#ifdef WITH_NTFS_3G
 #include "dentry.h"
 #include "lookup_table.h"
 #include "io.h"
 #include <stdlib.h>
 #include <unistd.h>
 
-struct ntfs_apply_args {
-       ntfs_volume *vol;
-       int extract_flags;
-       WIMStruct *w;
-};
-
 /*
  * Extracts a WIM resource to a NTFS attribute.
  */
@@ -98,12 +88,11 @@ extract_wim_resource_to_ntfs_attr(const struct lookup_table_entry *lte,
  *
  * @ni:             The NTFS inode for the file.
  * @inode:   The WIM dentry that has an inode containing the streams.
- * @w:      The WIMStruct for the WIM containing the image we are applying.
  *
  * Returns 0 on success, nonzero on failure.
  */
 static int write_ntfs_data_streams(ntfs_inode *ni, const struct dentry *dentry,
-                                  WIMStruct *w)
+                                  struct apply_args *args)
 {
        int ret = 0;
        unsigned stream_idx = 0;
@@ -120,7 +109,7 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct dentry *dentry,
                struct lookup_table_entry *lte;
                ntfs_attr *na;
 
-               lte = inode_stream_lte(inode, stream_idx, w->lookup_table);
+               lte = inode_stream_lte_resolved(inode, stream_idx);
 
                if (stream_name_len) {
                        /* Create an empty named stream. */
@@ -151,6 +140,7 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct dentry *dentry,
                        ret = extract_wim_resource_to_ntfs_attr(lte, na);
                        if (ret != 0)
                                break;
+                       args->progress.extract.completed_bytes += wim_resource_size(lte);
                        ntfs_attr_close(na);
                }
                if (stream_idx == inode->num_ads)
@@ -281,14 +271,12 @@ apply_file_attributes_and_security_data(ntfs_inode *ni,
 }
 
 static int apply_reparse_data(ntfs_inode *ni, const struct dentry *dentry,
-                             const WIMStruct *w)
+                             struct apply_args *args)
 {
        struct lookup_table_entry *lte;
        int ret = 0;
 
-       wimlib_assert(dentry->d_inode->attributes & FILE_ATTRIBUTE_REPARSE_POINT);
-
-       lte = inode_unnamed_lte(dentry->d_inode, w->lookup_table);
+       lte = inode_unnamed_lte_resolved(dentry->d_inode);
 
        DEBUG("Applying reparse data to `%s'", dentry->full_path_utf8);
 
@@ -321,11 +309,12 @@ static int apply_reparse_data(ntfs_inode *ni, const struct dentry *dentry,
                                 dentry->full_path_utf8);
                return WIMLIB_ERR_NTFS_3G;
        }
+       args->progress.extract.completed_bytes += wim_resource_size(lte);
        return 0;
 }
 
 static int do_wim_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni,
-                                   WIMStruct *w);
+                                   struct apply_args *args);
 
 /*
  * If @dentry is part of a hard link group, search for hard-linked dentries in
@@ -337,7 +326,7 @@ static int do_wim_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni,
  */
 static int preapply_dentry_with_dos_name(struct dentry *dentry,
                                         ntfs_inode **dir_ni_p,
-                                        WIMStruct *w)
+                                        struct apply_args *args)
 {
        struct dentry *other;
        struct dentry *dentry_with_dos_name;
@@ -357,7 +346,7 @@ static int preapply_dentry_with_dos_name(struct dentry *dentry,
                }
        }
        /* If there's a dentry with a DOS name, extract it first */
-       if (dentry_with_dos_name && !dentry_is_extracted(dentry)) {
+       if (dentry_with_dos_name && !dentry_with_dos_name->is_extracted) {
                char *p;
                const char *dir_name;
                char orig;
@@ -367,7 +356,7 @@ static int preapply_dentry_with_dos_name(struct dentry *dentry,
                DEBUG("pre-applying DOS name `%s'",
                      dentry_with_dos_name->full_path_utf8);
                ret = do_wim_apply_dentry_ntfs(dentry_with_dos_name,
-                                              *dir_ni_p, w);
+                                              *dir_ni_p, args);
                if (ret != 0)
                        return ret;
                p = dentry->full_path_utf8 + dentry->full_path_utf8_len;
@@ -395,12 +384,11 @@ static int preapply_dentry_with_dos_name(struct dentry *dentry,
  *
  * @dentry:  The WIM dentry to apply
  * @dir_ni:  The NTFS inode for the parent directory
- * @w:      The WIMStruct for the WIM containing the image we are applying.
  *
  * @return:  0 on success; nonzero on failure.
  */
 static int do_wim_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni,
-                                   WIMStruct *w)
+                                   struct apply_args *args)
 {
        int ret = 0;
        mode_t type;
@@ -417,7 +405,7 @@ static int do_wim_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni,
                 * (if there is one) before this dentry */
                if (dentry->short_name_len == 0) {
                        ret = preapply_dentry_with_dos_name(dentry,
-                                                           &dir_ni, w);
+                                                           &dir_ni, args);
                        if (ret != 0)
                                return ret;
                }
@@ -467,18 +455,19 @@ static int do_wim_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni,
         * */
        if (!(inode->attributes & (FILE_ATTRIBUTE_REPARSE_POINT |
                                   FILE_ATTRIBUTE_DIRECTORY))) {
-               ret = write_ntfs_data_streams(ni, dentry, w);
+               ret = write_ntfs_data_streams(ni, dentry, args);
                if (ret != 0)
                        goto out_close_dir_ni;
        }
 
 
-       ret = apply_file_attributes_and_security_data(ni, dir_ni, dentry, w);
+       ret = apply_file_attributes_and_security_data(ni, dir_ni,
+                                                     dentry, args->w);
        if (ret != 0)
                goto out_close_dir_ni;
 
        if (inode->attributes & FILE_ATTR_REPARSE_POINT) {
-               ret = apply_reparse_data(ni, dentry, w);
+               ret = apply_reparse_data(ni, dentry, args);
                if (ret != 0)
                        goto out_close_dir_ni;
        }
@@ -593,9 +582,9 @@ static int wim_apply_root_dentry_ntfs(const struct dentry *dentry,
 }
 
 /* Applies a WIM dentry to the NTFS volume */
-static int wim_apply_dentry_ntfs(struct dentry *dentry, void *arg)
+int wim_apply_dentry_ntfs(struct dentry *dentry, void *arg)
 {
-       struct ntfs_apply_args *args = arg;
+       struct apply_args *args = arg;
        ntfs_volume *vol             = args->vol;
        int extract_flags            = args->extract_flags;
        WIMStruct *w                 = args->w;
@@ -604,10 +593,12 @@ static int wim_apply_dentry_ntfs(struct dentry *dentry, void *arg)
        char orig;
        const char *dir_name;
 
-       if (dentry_is_extracted(dentry))
+       if (dentry->is_extracted)
                return 0;
 
-       wimlib_assert(dentry->full_path_utf8);
+       if (extract_flags & WIMLIB_EXTRACT_FLAG_NO_STREAMS)
+               if (inode_unnamed_lte_resolved(dentry->d_inode))
+                       return 0;
 
        DEBUG("Applying dentry `%s' to NTFS", dentry->full_path_utf8);
 
@@ -633,19 +624,18 @@ static int wim_apply_dentry_ntfs(struct dentry *dentry, void *arg)
                                 dir_name);
                return WIMLIB_ERR_NTFS_3G;
        }
-       return do_wim_apply_dentry_ntfs(dentry, dir_ni, w);
+       return do_wim_apply_dentry_ntfs(dentry, dir_ni, arg);
 }
 
-static int wim_apply_dentry_timestamps(struct dentry *dentry, void *arg)
+int wim_apply_dentry_timestamps(struct dentry *dentry, void *arg)
 {
-       struct ntfs_apply_args *args = arg;
-       ntfs_volume *vol             = args->vol;
+       struct apply_args *args = arg;
+       ntfs_volume *vol = args->vol;
        u8 *p;
        u8 buf[24];
        ntfs_inode *ni;
        int ret = 0;
 
-
        DEBUG("Setting timestamps on `%s'", dentry->full_path_utf8);
 
        ni = ntfs_pathname_to_inode(vol, NULL, dentry->full_path_utf8);
@@ -674,126 +664,3 @@ static int wim_apply_dentry_timestamps(struct dentry *dentry, void *arg)
        }
        return ret;
 }
-
-static int dentry_set_unextracted(struct dentry *dentry, void *ignore)
-{
-       dentry->is_extracted = false;
-       return 0;
-}
-
-static int do_wim_apply_image_ntfs(WIMStruct *w, const char *device, int extract_flags)
-{
-       ntfs_volume *vol;
-       int ret;
-       struct dentry *root;
-       struct ntfs_apply_args args;
-
-       DEBUG("Mounting NTFS volume `%s'", device);
-       vol = ntfs_mount(device, 0);
-       if (!vol) {
-               ERROR_WITH_ERRNO("Failed to mount NTFS volume `%s'", device);
-               return WIMLIB_ERR_NTFS_3G;
-       }
-       args.vol = vol;
-       args.extract_flags = extract_flags;
-       args.w = w;
-       root = wim_root_dentry(w);
-
-       for_dentry_in_tree(root, dentry_set_unextracted, NULL);
-       ret = for_dentry_in_tree(root, wim_apply_dentry_ntfs, &args);
-       if (ret != 0)
-               goto out;
-
-       if (extract_flags & WIMLIB_EXTRACT_FLAG_VERBOSE)
-               printf("Setting timestamps of extracted files on NTFS "
-                      "volume `%s'\n", device);
-       ret = for_dentry_in_tree_depth(root, wim_apply_dentry_timestamps,
-                                      &args);
-
-       if (ret == 0 && (extract_flags & WIMLIB_EXTRACT_FLAG_VERBOSE))
-               printf("Finished applying image %d of %s to NTFS "
-                      "volume `%s'\n",
-                      w->current_image,
-                      w->filename ? w->filename : "WIM",
-                      device);
-out:
-       DEBUG("Unmounting NTFS volume `%s'", device);
-       if (ntfs_umount(vol, FALSE) != 0) {
-               ERROR_WITH_ERRNO("Failed to unmount NTFS volume `%s'", device);
-               if (ret == 0)
-                       ret = WIMLIB_ERR_NTFS_3G;
-       }
-       return ret;
-}
-
-
-/*
- * API entry point for applying a WIM image to a NTFS volume.
- *
- * Please note that this is a NTFS *volume* and not a directory.  The intention
- * is that the volume contain an empty filesystem, and the WIM image contain a
- * full filesystem to be applied to the volume.
- */
-WIMLIBAPI int wimlib_apply_image_to_ntfs_volume(WIMStruct *w, int image,
-                                               const char *device, int flags,
-                                               WIMStruct **additional_swms,
-                                               unsigned num_additional_swms)
-{
-       struct lookup_table *joined_tab, *w_tab_save;
-       int ret;
-
-       DEBUG("w->filename = %s, image = %d, device = %s, flags = 0x%x, "
-             "num_additional_swms = %u",
-             w->filename, image, device, flags, num_additional_swms);
-
-       if (!w || !device)
-               return WIMLIB_ERR_INVALID_PARAM;
-       if (image == WIM_ALL_IMAGES) {
-               ERROR("Can only apply a single image when applying "
-                     "directly to a NTFS volume");
-               return WIMLIB_ERR_INVALID_PARAM;
-       }
-       if (flags & (WIMLIB_EXTRACT_FLAG_SYMLINK | WIMLIB_EXTRACT_FLAG_HARDLINK)) {
-               ERROR("Cannot specify symlink or hardlink flags when applying ");
-               ERROR("directly to a NTFS volume");
-               return WIMLIB_ERR_INVALID_PARAM;
-       }
-
-       ret = verify_swm_set(w, additional_swms, num_additional_swms);
-       if (ret != 0)
-               return ret;
-
-       if (num_additional_swms) {
-               ret = new_joined_lookup_table(w, additional_swms,
-                                             num_additional_swms, &joined_tab);
-               if (ret != 0)
-                       return ret;
-               w_tab_save = w->lookup_table;
-               w->lookup_table = joined_tab;
-       }
-
-       ret = select_wim_image(w, image);
-       if (ret != 0)
-               goto out;
-
-       ret = do_wim_apply_image_ntfs(w, device, flags);
-
-out:
-       if (num_additional_swms) {
-               free_lookup_table(w->lookup_table);
-               w->lookup_table = w_tab_save;
-       }
-       return ret;
-}
-
-#else /* WITH_NTFS_3G */
-WIMLIBAPI int wimlib_apply_image_to_ntfs_volume(WIMStruct *w, int image,
-                                               const char *device, int flags,
-                                               WIMStruct **additional_swms,
-                                               unsigned num_additional_swms)
-{
-       ERROR("wimlib was compiled without support for NTFS-3g, so");
-       ERROR("we cannot apply a WIM image directly to a NTFS volume");
-       return WIMLIB_ERR_UNSUPPORTED;
-}
-#endif /* WITH_NTFS_3G */
index fb670dc..c4770a5 100644 (file)
 
 #include "config.h"
 
-#ifdef WITH_NTFS_3G
 #include <ntfs-3g/endians.h>
 #include <ntfs-3g/types.h>
-#endif
 
 #include "wimlib_internal.h"
 
 
-#ifdef WITH_NTFS_3G
 #include "dentry.h"
 #include "lookup_table.h"
 #include "io.h"
@@ -646,13 +643,13 @@ static int build_dentry_tree_ntfs_recursive(struct dentry **root_p,
        return ret;
 }
 
-static int build_dentry_tree_ntfs(struct dentry **root_p,
-                                 const char *device,
-                                 struct lookup_table *lookup_table,
-                                 struct wim_security_data *sd,
-                                 const struct capture_config *config,
-                                 int flags,
-                                 void *extra_arg)
+int build_dentry_tree_ntfs(struct dentry **root_p,
+                          const char *device,
+                          struct lookup_table *lookup_table,
+                          struct wim_security_data *sd,
+                          const struct capture_config *config,
+                          int flags,
+                          void *extra_arg)
 {
        ntfs_volume *vol;
        ntfs_inode *root_ni;
@@ -721,34 +718,3 @@ out:
        }
        return ret;
 }
-
-
-
-WIMLIBAPI int wimlib_add_image_from_ntfs_volume(WIMStruct *w,
-                                               const char *device,
-                                               const char *name,
-                                               const char *config_str,
-                                               size_t config_len,
-                                               int flags)
-{
-       if (flags & (WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE)) {
-               ERROR("Cannot dereference files when capturing directly from NTFS");
-               return WIMLIB_ERR_INVALID_PARAM;
-       }
-       return do_add_image(w, device, name, config_str, config_len, flags,
-                           build_dentry_tree_ntfs, &w->ntfs_vol);
-}
-
-#else /* WITH_NTFS_3G */
-WIMLIBAPI int wimlib_add_image_from_ntfs_volume(WIMStruct *w,
-                                               const char *device,
-                                               const char *name,
-                                               const char *config_str,
-                                               size_t config_len,
-                                               int flags)
-{
-       ERROR("wimlib was compiled without support for NTFS-3g, so");
-       ERROR("we cannot capture a WIM image directly from a NTFS volume");
-       return WIMLIB_ERR_UNSUPPORTED;
-}
-#endif /* WITH_NTFS_3G */
index c29ed4f..86a2be6 100644 (file)
@@ -83,7 +83,7 @@ static int read_compressed_resource(FILE *fp, u64 resource_compressed_size,
 
        int (*decompress)(const void *, uint, void *, uint);
        /* Set the appropriate decompress function. */
-       if (resource_ctype == WIM_COMPRESSION_TYPE_LZX)
+       if (resource_ctype == WIMLIB_COMPRESSION_TYPE_LZX)
                decompress = lzx_decompress;
        else
                decompress = xpress_decompress;
@@ -518,12 +518,12 @@ int read_wim_resource(const struct lookup_table_entry *lte, u8 buf[],
 
                ctype = wim_resource_compression_type(lte);
 
-               wimlib_assert(ctype != WIM_COMPRESSION_TYPE_NONE ||
+               wimlib_assert(ctype != WIMLIB_COMPRESSION_TYPE_NONE ||
                              (lte->resource_entry.original_size ==
                               lte->resource_entry.size));
 
                if ((flags & WIMLIB_RESOURCE_FLAG_RAW)
-                   || ctype == WIM_COMPRESSION_TYPE_NONE)
+                   || ctype == WIMLIB_COMPRESSION_TYPE_NONE)
                        ret = read_uncompressed_resource(fp,
                                                         lte->resource_entry.offset + offset,
                                                         size, buf);
@@ -694,9 +694,6 @@ int extract_full_wim_resource_to_fd(const struct lookup_table_entry *lte, int fd
  *
  * The output_resource_entry, out_refcnt, and part_number fields of @lte are
  * updated.
- *
- * Metadata resources are not copied (they are handled elsewhere for joining and
- * splitting).
  */
 int copy_resource(struct lookup_table_entry *lte, void *wim)
 {
@@ -744,15 +741,14 @@ int read_metadata_resource(WIMStruct *w, struct image_metadata *imd)
        struct inode_table inode_tab;
        const struct lookup_table_entry *metadata_lte;
        u64 metadata_len;
-       u64 metadata_offset;
        struct hlist_head inode_list;
 
        metadata_lte = imd->metadata_lte;
        metadata_len = wim_resource_size(metadata_lte);
-       metadata_offset = metadata_lte->resource_entry.offset;
 
        DEBUG("Reading metadata resource: length = %"PRIu64", "
-             "offset = %"PRIu64"", metadata_len, metadata_offset);
+             "offset = %"PRIu64"", metadata_len,
+             metadata_lte->resource_entry.offset);
 
        /* There is no way the metadata resource could possibly be less than (8
         * + WIM_DENTRY_DISK_SIZE) bytes, where the 8 is for security data (with
index df384f8..091fa3f 100644 (file)
@@ -33,25 +33,22 @@ struct split_args {
        char *swm_base_name;
        size_t swm_base_name_len;
        const char *swm_suffix;
-       struct list_head *lte_list;
-       int    part_number;
+       struct list_head lte_list;
+       int    cur_part_number;
        int    write_flags;
        long   size_remaining;
        size_t part_size;
-       u64    total_bytes;
-       u64    total_bytes_written;
+       wimlib_progress_func_t progress_func;
+       union wimlib_progress_info progress;
 };
 
 static int finish_swm(WIMStruct *w, struct list_head *lte_list,
-                     int write_flags)
+                     int write_flags, wimlib_progress_func_t progress_func)
 {
        off_t lookup_table_offset = ftello(w->out_fp);
        int ret;
        struct lookup_table_entry *lte;
 
-       DEBUG("Writing lookup table for SWM (offset %"PRIu64")",
-                       lookup_table_offset);
-
        list_for_each_entry(lte, lte_list, staging_list) {
                ret = write_lookup_table_entry(lte, w->out_fp);
                if (ret != 0)
@@ -68,8 +65,9 @@ static int finish_swm(WIMStruct *w, struct list_head *lte_list,
        w->hdr.lookup_table_res_entry.original_size =
                                xml_data_offset - lookup_table_offset;
        w->hdr.lookup_table_res_entry.flags = WIM_RESHDR_FLAG_METADATA;
-       return finish_write(w, WIM_ALL_IMAGES,
-                           write_flags | WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE);
+       return finish_write(w, WIMLIB_ALL_IMAGES,
+                           write_flags | WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE,
+                           progress_func);
 }
 
 static int copy_resource_to_swm(struct lookup_table_entry *lte, void *__args)
@@ -88,24 +86,29 @@ static int copy_resource_to_swm(struct lookup_table_entry *lte, void *__args)
                /* No space for this resource.  Finish the previous swm and
                 * start a new one. */
 
-               ret = finish_swm(w, args->lte_list, args->write_flags);
+               ret = finish_swm(w, &args->lte_list, args->write_flags,
+                                args->progress_func);
                if (ret != 0)
                        return ret;
-               INIT_LIST_HEAD(args->lte_list);
+
+               if (args->progress_func) {
+                       args->progress_func(WIMLIB_PROGRESS_MSG_SPLIT_END_PART,
+                                           &args->progress);
+               }
+
+               INIT_LIST_HEAD(&args->lte_list);
+               args->cur_part_number++;
 
                sprintf(args->swm_base_name + args->swm_base_name_len, "%d%s",
-                       ++args->part_number, args->swm_suffix);
+                       args->cur_part_number, args->swm_suffix);
 
-               w->hdr.part_number = args->part_number;
+               w->hdr.part_number = args->cur_part_number;
 
-               if (args->write_flags & WIMLIB_OPEN_FLAG_SHOW_PROGRESS)
-                       printf("Writing `%s' (%"PRIu64" of %"PRIu64" bytes, "
-                              "%.0f%% done)\n",
-                              args->swm_base_name,
-                              args->total_bytes_written,
-                              args->total_bytes,
-                              (double)args->total_bytes_written /
-                                  (double)args->total_bytes * 100.0);
+               if (args->progress_func) {
+                       args->progress.split.cur_part_number = args->cur_part_number;
+                       args->progress_func(WIMLIB_PROGRESS_MSG_SPLIT_BEGIN_PART,
+                                           &args->progress);
+               }
 
                ret = begin_write(w, args->swm_base_name, args->write_flags);
                if (ret != 0)
@@ -113,119 +116,120 @@ static int copy_resource_to_swm(struct lookup_table_entry *lte, void *__args)
                args->size_remaining = args->part_size;
        }
        args->size_remaining -= lte->resource_entry.size;
-       args->total_bytes_written += lte->resource_entry.size;
-       list_add(&lte->staging_list, args->lte_list);
+       args->progress.split.completed_bytes += lte->resource_entry.size;
+       list_add(&lte->staging_list, &args->lte_list);
        return copy_resource(lte, w);
 }
 
 /* Splits the WIM file @wimfile into multiple parts prefixed by @swm_name with
  * size at most @part_size. */
-WIMLIBAPI int wimlib_split(const char *wimfile, const char *swm_name,
-                          size_t part_size, int flags)
+WIMLIBAPI int wimlib_split(WIMStruct *w, const char *swm_name,
+                          size_t part_size, int write_flags,
+                          wimlib_progress_func_t progress_func)
 {
        int ret;
-       WIMStruct *w;
-       int write_flags = 0;
-       size_t swm_name_len = strlen(swm_name);
+       struct wim_header hdr_save;
+       struct split_args args;
+       const char *swm_suffix;
+       size_t swm_name_len;
        size_t swm_base_name_len;
-       char name[swm_name_len + 20];
-       char *swm_suffix;
 
-       long size_remaining = part_size;
-       u64 total_bytes_written = 0;
-       u64 total_bytes;
+       if (!w || !swm_name || part_size == 0)
+               return WIMLIB_ERR_INVALID_PARAM;
 
-       ret = wimlib_open_wim(wimfile, flags, &w);
-       if (ret != 0)
-               return ret;
+       if (w->hdr.total_parts != 1)
+               return WIMLIB_ERR_SPLIT_UNSUPPORTED;
 
-       total_bytes = wim_info_get_total_bytes(w->wim_info);
+       write_flags &= WIMLIB_WRITE_MASK_PUBLIC;
 
-       if (flags & WIMLIB_OPEN_FLAG_CHECK_INTEGRITY)
-               write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
-       if (flags & WIMLIB_OPEN_FLAG_SHOW_PROGRESS)
-               write_flags |= WIMLIB_WRITE_FLAG_SHOW_PROGRESS;
+       swm_name_len = strlen(swm_name);
+       char swm_base_name[swm_name_len + 20];
 
+       memcpy(&hdr_save, &w->hdr, sizeof(struct wim_header));
        w->hdr.flags |= WIM_HDR_FLAG_SPANNED;
        w->hdr.boot_idx = 0;
        randomize_byte_array(w->hdr.guid, WIM_GID_LEN);
        ret = begin_write(w, swm_name, write_flags);
        if (ret != 0)
-               return ret;
+               goto out;
+
+       memcpy(swm_base_name, swm_name, swm_name_len + 1);
 
        swm_suffix = strchr(swm_name, '.');
-       memcpy(name, swm_name, swm_name_len + 1);
        if (swm_suffix) {
                swm_base_name_len = swm_suffix - swm_name;
        } else {
                swm_base_name_len = swm_name_len;
-               name[sizeof(name) - 1] = '\0';
-               swm_suffix = &name[sizeof(name) - 1];
+               swm_base_name[sizeof(swm_base_name) - 1] = '\0';
+               swm_suffix = &swm_base_name[sizeof(swm_base_name) - 1];
        }
 
-       if (write_flags & WIMLIB_OPEN_FLAG_SHOW_PROGRESS)
-               printf("Writing `%s' (%.2f %% done)\n",
-                       swm_name,
-                       (double)total_bytes_written /
-                               (double)total_bytes * 100.0);
+       args.w                              = w;
+       args.swm_base_name                  = swm_base_name;
+       args.swm_base_name_len              = swm_base_name_len;
+       args.swm_suffix                     = swm_suffix;
+       INIT_LIST_HEAD(&args.lte_list);
+       args.cur_part_number                = 1;
+       args.write_flags                    = write_flags;
+       args.size_remaining                 = part_size;
+       args.part_size                      = part_size;
+       args.progress_func                  = progress_func;
+       args.progress.split.total_bytes     = lookup_table_total_stream_size(w->lookup_table);
+       args.progress.split.cur_part_number = 1;
+       args.progress.split.completed_bytes = 0;
+       args.progress.split.part_name       = swm_base_name;
+
+       if (progress_func) {
+               progress_func(WIMLIB_PROGRESS_MSG_SPLIT_BEGIN_PART,
+                             &args.progress);
+       }
 
        w->write_metadata = true;
-       LIST_HEAD(lte_list);
        for (int i = 0; i < w->hdr.image_count; i++) {
                struct lookup_table_entry *metadata_lte;
-
-               DEBUG("Writing metadata resource %d", i);
-
                metadata_lte = w->image_metadata[i].metadata_lte;
                ret = copy_resource(metadata_lte, w);
                if (ret != 0)
-                       return ret;
-               size_remaining -= metadata_lte->resource_entry.size;
-               total_bytes_written += metadata_lte->resource_entry.size;
-               list_add(&metadata_lte->staging_list, &lte_list);
+                       goto out;
+               args.size_remaining -= metadata_lte->resource_entry.size;
+               args.progress.split.completed_bytes += metadata_lte->resource_entry.size;
+               list_add(&metadata_lte->staging_list, &args.lte_list);
        }
        w->write_metadata = false;
 
-       struct split_args args = {
-               .w                 = w,
-               .swm_base_name     = name,
-               .swm_base_name_len = swm_base_name_len,
-               .swm_suffix        = swm_suffix,
-               .lte_list          = &lte_list,
-               .part_number       = 1,
-               .write_flags       = write_flags,
-               .size_remaining    = size_remaining,
-               .part_size         = part_size,
-               .total_bytes        = total_bytes,
-               .total_bytes_written = total_bytes_written,
-       };
-
-       ret = for_lookup_table_entry(w->lookup_table, copy_resource_to_swm, &args);
+       ret = for_lookup_table_entry(w->lookup_table,
+                                    copy_resource_to_swm, &args);
        if (ret != 0)
-               return ret;
+               goto out;
 
-       ret = finish_swm(w, &lte_list, write_flags);
+       ret = finish_swm(w, &args.lte_list, write_flags, progress_func);
        if (ret != 0)
-               return ret;
+               goto out;
 
+       if (progress_func) {
+               progress_func(WIMLIB_PROGRESS_MSG_SPLIT_END_PART,
+                             &args.progress);
+       }
 
        /* The swms are all ready now, except the total_parts and part_number
         * fields in their headers are wrong (we don't know the total parts
         * until they are all written).  Fix them. */
-       int total_parts = args.part_number;
+       int total_parts = args.cur_part_number;
        for (int i = 1; i <= total_parts; i++) {
-               const char *p;
+               const char *part_name;
                if (i == 1) {
-                       p = swm_name;
+                       part_name = swm_name;
                } else {
-                       sprintf(name + swm_base_name_len, "%d", i);
-                       p = strcat(name, swm_suffix);
+                       sprintf(swm_base_name + swm_base_name_len, "%d%s",
+                               i, swm_suffix);
+                       part_name = swm_base_name;
                }
 
-               FILE *fp = fopen(p, "r+b");
+               FILE *fp = fopen(part_name, "r+b");
                if (!fp) {
-                       ERROR_WITH_ERRNO("Failed to open `%s'", p);
-                       return WIMLIB_ERR_OPEN;
+                       ERROR_WITH_ERRNO("Failed to open `%s'", part_name);
+                       ret = WIMLIB_ERR_OPEN;
+                       goto out;
                }
                u8 buf[4];
                put_u16(&buf[0], i);
@@ -235,12 +239,12 @@ WIMLIBAPI int wimlib_split(const char *wimfile, const char *swm_name,
                                fwrite(buf, 1, sizeof(buf), fp) != sizeof(buf)
                                || fclose(fp) != 0) {
                        ERROR_WITH_ERRNO("Error overwriting header of `%s'",
-                                        name);
-                       return WIMLIB_ERR_WRITE;
+                                        part_name);
+                       ret = WIMLIB_ERR_WRITE;
+                       break;
                }
        }
-       if (write_flags & WIMLIB_OPEN_FLAG_SHOW_PROGRESS)
-               puts("Done!");
-       wimlib_free(w);
-       return 0;
+out:
+       memcpy(&w->hdr, &hdr_save, sizeof(struct wim_header));
+       return ret;
 }
index f40915f..9dd9718 100644 (file)
--- a/src/wim.c
+++ b/src/wim.c
@@ -74,7 +74,7 @@ WIMStruct *new_wim_struct()
 }
 
 /*
- * Calls a function on images in the WIM.  If @image is WIM_ALL_IMAGES, @visitor
+ * Calls a function on images in the WIM.  If @image is WIMLIB_ALL_IMAGES, @visitor
  * is called on the WIM once for each image, with each image selected as the
  * current image in turn.  If @image is a certain image, @visitor is called on
  * the WIM only once, with that image selected.
@@ -86,7 +86,7 @@ int for_image(WIMStruct *w, int image, int (*visitor)(WIMStruct *))
        int end;
        int i;
 
-       if (image == WIM_ALL_IMAGES) {
+       if (image == WIMLIB_ALL_IMAGES) {
                start = 1;
                end = w->hdr.image_count;
        } else if (image >= 1 && image <= w->hdr.image_count) {
@@ -153,13 +153,13 @@ int wim_hdr_flags_compression_type(int wim_hdr_flags)
 {
        if (wim_hdr_flags & WIM_HDR_FLAG_COMPRESSION) {
                if (wim_hdr_flags & WIM_HDR_FLAG_COMPRESS_LZX)
-                       return WIM_COMPRESSION_TYPE_LZX;
+                       return WIMLIB_COMPRESSION_TYPE_LZX;
                else if (wim_hdr_flags & WIM_HDR_FLAG_COMPRESS_XPRESS)
-                       return WIM_COMPRESSION_TYPE_XPRESS;
+                       return WIMLIB_COMPRESSION_TYPE_XPRESS;
                else
-                       return WIM_COMPRESSION_TYPE_INVALID;
+                       return WIMLIB_COMPRESSION_TYPE_INVALID;
        } else {
-               return WIM_COMPRESSION_TYPE_NONE;
+               return WIMLIB_COMPRESSION_TYPE_NONE;
        }
 }
 
@@ -219,7 +219,7 @@ int select_wim_image(WIMStruct *w, int image)
 
        /* If a valid image is currently selected, it can be freed if it is not
         * modified.  */
-       if (w->current_image != WIM_NO_IMAGE) {
+       if (w->current_image != WIMLIB_NO_IMAGE) {
                imd = wim_get_current_image_metadata(w);
                if (!imd->modified) {
                        DEBUG("Freeing image %u", w->current_image);
@@ -254,11 +254,11 @@ WIMLIBAPI int wimlib_get_compression_type(const WIMStruct *w)
 WIMLIBAPI const char *wimlib_get_compression_type_string(int ctype)
 {
        switch (ctype) {
-               case WIM_COMPRESSION_TYPE_NONE:
+               case WIMLIB_COMPRESSION_TYPE_NONE:
                        return "None";
-               case WIM_COMPRESSION_TYPE_LZX:
+               case WIMLIB_COMPRESSION_TYPE_LZX:
                        return "LZX";
-               case WIM_COMPRESSION_TYPE_XPRESS:
+               case WIMLIB_COMPRESSION_TYPE_XPRESS:
                        return "XPRESS";
                default:
                        return "Invalid";
@@ -277,15 +277,15 @@ WIMLIBAPI int wimlib_resolve_image(WIMStruct *w, const char *image_name_or_num)
        int i;
 
        if (!image_name_or_num)
-               return WIM_NO_IMAGE;
+               return WIMLIB_NO_IMAGE;
 
        if (strcmp(image_name_or_num, "all") == 0
            || strcmp(image_name_or_num, "*") == 0)
-               return WIM_ALL_IMAGES;
+               return WIMLIB_ALL_IMAGES;
        image = strtol(image_name_or_num, &p, 10);
        if (p != image_name_or_num && *p == '\0') {
                if (image < 1 || image > w->hdr.image_count)
-                       return WIM_NO_IMAGE;
+                       return WIMLIB_NO_IMAGE;
                return image;
        } else {
                for (i = 1; i <= w->hdr.image_count; i++) {
@@ -293,7 +293,7 @@ WIMLIBAPI int wimlib_resolve_image(WIMStruct *w, const char *image_name_or_num)
                                   wimlib_get_image_name(w, i)) == 0)
                                return i;
                }
-               return WIM_NO_IMAGE;
+               return WIMLIB_NO_IMAGE;
        }
 }
 
@@ -332,7 +332,7 @@ WIMLIBAPI void wimlib_print_available_images(const WIMStruct *w, int image)
        int last;
        int i;
        int n;
-       if (image == WIM_ALL_IMAGES) {
+       if (image == WIMLIB_ALL_IMAGES) {
                n = printf("Available Images:\n");
                first = 1;
                last = w->hdr.image_count;
@@ -353,8 +353,8 @@ WIMLIBAPI void wimlib_print_available_images(const WIMStruct *w, int image)
 }
 
 
-/* Prints the metadata for the specified image, which may be WIM_ALL_IMAGES, but
- * not WIM_NO_IMAGE. */
+/* Prints the metadata for the specified image, which may be WIMLIB_ALL_IMAGES, but
+ * not WIMLIB_NO_IMAGE. */
 WIMLIBAPI int wimlib_print_metadata(WIMStruct *w, int image)
 {
        if (!w)
@@ -463,7 +463,8 @@ int open_wim_writable(WIMStruct *w, const char *path,
  * Begins the reading of a WIM file; opens the file and reads its header and
  * lookup table, and optionally checks the integrity.
  */
-static int begin_read(WIMStruct *w, const char *in_wim_path, int open_flags)
+static int begin_read(WIMStruct *w, const char *in_wim_path, int open_flags,
+                     wimlib_progress_func_t progress_func)
 {
        int ret;
        uint xml_num_images;
@@ -495,7 +496,7 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int open_flags)
                w->hdr.boot_idx = 0;
        }
 
-       if (wimlib_get_compression_type(w) == WIM_COMPRESSION_TYPE_INVALID) {
+       if (wimlib_get_compression_type(w) == WIMLIB_COMPRESSION_TYPE_INVALID) {
                ERROR("Invalid compression type (WIM header flags = %x)",
                      w->hdr.flags);
                ret = WIMLIB_ERR_INVALID_COMPRESSION_TYPE;
@@ -503,8 +504,7 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int open_flags)
        }
 
        if (open_flags & WIMLIB_OPEN_FLAG_CHECK_INTEGRITY) {
-               ret = check_wim_integrity(w,
-                                         (open_flags & WIMLIB_OPEN_FLAG_SHOW_PROGRESS) != 0);
+               ret = check_wim_integrity(w, progress_func);
                if (ret == WIM_INTEGRITY_NONEXISTENT) {
                        WARNING("No integrity information for `%s'; skipping "
                                "integrity check.", w->filename);
@@ -566,7 +566,7 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int open_flags)
        qsort(w->image_metadata, w->current_image,
              sizeof(struct image_metadata), sort_image_metadata_by_position);
 
-       w->current_image = WIM_NO_IMAGE;
+       w->current_image = WIMLIB_NO_IMAGE;
 
        /* Read the XML data. */
        ret = read_xml_data(w->fp, &w->hdr.xml_res_entry,
@@ -600,7 +600,7 @@ out_free_xml_data:
 out_free_image_metadata:
        /*FREE(w->image_metadata);*/
        /*w->image_metadata = NULL;*/
-       /*w->current_image = WIM_NO_IMAGE;*/
+       /*w->current_image = WIMLIB_NO_IMAGE;*/
 out_free_lookup_table:
        /*free_lookup_table(w->lookup_table);*/
        /*w->lookup_table = NULL;*/
@@ -616,7 +616,8 @@ out:
  * Opens a WIM file and creates a WIMStruct for it.
  */
 WIMLIBAPI int wimlib_open_wim(const char *wim_file, int open_flags,
-                             WIMStruct **w_ret)
+                             WIMStruct **w_ret,
+                             wimlib_progress_func_t progress_func)
 {
        WIMStruct *w;
        int ret;
@@ -628,7 +629,7 @@ WIMLIBAPI int wimlib_open_wim(const char *wim_file, int open_flags,
                return WIMLIB_ERR_NOMEM;
        }
 
-       ret = begin_read(w, wim_file, open_flags);
+       ret = begin_read(w, wim_file, open_flags, progress_func);
        if (ret == 0) {
                *w_ret = w;
        } else {
index 0618ff3..ed1e449 100644 (file)
  *
  * To add an image to a WIM file from a directory tree on your filesystem, call
  * wimlib_add_image().  This can be done with a ::WIMStruct gotten from
- * wimlib_open_wim() or from wimlib_create_new_wim().  Alternatively, if you
- * want to capture a WIM image directly from a NTFS volume while preserving
- * NTFS-specific data such as security descriptors, call
- * wimlib_add_image_from_ntfs_volume() instead.
+ * wimlib_open_wim() or from wimlib_create_new_wim().  Alternatively, you can
+ * capture a WIM directory from a NTFS volume if you provide the
+ * ::WIMLIB_ADD_IMAGE_FLAG_NTFS flag, provided that wimlib was not compiled with
+ * the <code>--without-ntfs-3g</code> flag.
  *
- * To extract an image from a WIM file, call wimlib_extract_image().
- * Alternatively, if you want to apply a WIM image directly to a NTFS volume
- * while setting NTFS-specific data such as security descriptors, call
- * wimlib_apply_image_to_ntfs_volume().
- *
- * The NTFS functions will fail if wimlib was compiled with the
- * <code>--without-ntfs-3g</code> flag.
+ * To extract an image from a WIM file, call wimlib_extract_image().  You may
+ * extract an image to a directory or directly to a NTFS volume, the latter of
+ * which will preserve NTFS-specific data such as security descriptors.
  *
  * wimlib supports mounting WIM files either read-only or read-write.  Mounting
- * is done using wimlib_mount() and unmounting is done using wimlib_unmount().
- * Mounting can be done without root privileges because it is implemented using
- * FUSE (Filesystem in Userspace).  If wimlib is compiled with the
- * <code>--without-fuse</code> flag, these functions will be available but will
- * fail.
+ * is done using wimlib_mount_image() and unmounting is done using
+ * wimlib_unmount_image().  Mounting can be done without root privileges because
+ * it is implemented using FUSE (Filesystem in Userspace).  If wimlib is
+ * compiled with the <code>--without-fuse</code> flag, these functions will be
+ * available but will fail.
  *
  * After creating or modifying a WIM file, you can write it to a file using
  * wimlib_write().  Alternatively,  if the WIM was originally read from a file,
  *
  * Please not: merely by calling wimlib_add_image() or many of the other
  * functions in this library that operate on ::WIMStruct's, you are @b not
- * modifing the WIM file on disk.  Changes are not saved until you explicitly
+ * modifying the WIM file on disk.  Changes are not saved until you explicitly
  * call wimlib_write() or wimlib_overwrite().
  *
  * After you are done with the WIM file, use wimlib_free() to free all memory
  * associated with a ::WIMStruct and close all files associated with it.
  *
+ * A number of functions take a pointer to a progress function of type
+ * ::wimlib_progress_func_t.  This function will be called periodically during
+ * the WIM operation(s) to report on the progress of the operation (e.g. how
+ * many bytes have been written so far).
+ *
  * To see an example of how to use wimlib, see the file @c programs/imagex.c in
  * wimlib's source tree.
  *
- * wimlib supports custom memory allocators; use wimlib_set_memory_allocator()
- * for this.  However, if wimlib calls into @c libntfs-3g, the custom memory
- * allocator may not be used.
- *
  * \section imagex imagex
  *
  * wimlib comes with the <b>imagex</b> program, which is documented in man pages.
 #include <stdio.h>
 #include <stddef.h>
 #include <stdbool.h>
+#include <inttypes.h>
 
-#ifndef _WIMLIB_INTERNAL_H
 /**
  * Opaque structure that represents a WIM file.
  */
 typedef struct WIMStruct WIMStruct;
-#endif
 
 /**
  * Specifies the compression type of a WIM file.
  */
-
-enum wim_compression_type {
+enum wimlib_compression_type {
        /** An invalid compression type. */
-       WIM_COMPRESSION_TYPE_INVALID = -1,
+       WIMLIB_COMPRESSION_TYPE_INVALID = -1,
 
        /** The WIM does not include any compressed resources. */
-       WIM_COMPRESSION_TYPE_NONE = 0,
+       WIMLIB_COMPRESSION_TYPE_NONE = 0,
 
        /** Compressed resources in the WIM use LZX compression. */
-       WIM_COMPRESSION_TYPE_LZX = 1,
+       WIMLIB_COMPRESSION_TYPE_LZX = 1,
 
        /** Compressed resources in the WIM use XPRESS compression. */
-       WIM_COMPRESSION_TYPE_XPRESS = 2,
+       WIMLIB_COMPRESSION_TYPE_XPRESS = 2,
+};
+
+enum wimlib_progress_msg {
+       WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_BEGIN,
+       WIMLIB_PROGRESS_MSG_EXTRACT_DIR_STRUCTURE_BEGIN,
+       WIMLIB_PROGRESS_MSG_EXTRACT_DIR_STRUCTURE_END,
+       WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS,
+       WIMLIB_PROGRESS_MSG_APPLY_TIMESTAMPS,
+       WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_END,
+
+       WIMLIB_PROGRESS_MSG_SCAN_BEGIN,
+       WIMLIB_PROGRESS_MSG_SCAN_END,
+
+       WIMLIB_PROGRESS_MSG_WRITE_STREAMS,
+       WIMLIB_PROGRESS_MSG_WRITE_METADATA_BEGIN,
+       WIMLIB_PROGRESS_MSG_WRITE_METADATA_END,
+       WIMLIB_PROGRESS_MSG_RENAME,
+
+       WIMLIB_PROGRESS_MSG_VERIFY_INTEGRITY,
+
+       WIMLIB_PROGRESS_MSG_CALC_INTEGRITY,
+
+       WIMLIB_PROGRESS_MSG_JOIN_STREAMS,
+
+       WIMLIB_PROGRESS_MSG_SPLIT_BEGIN_PART,
+       WIMLIB_PROGRESS_MSG_SPLIT_END_PART,
+};
+
+union wimlib_progress_info {
+       struct {
+               uint64_t total_bytes;
+               uint64_t total_streams;
+               uint64_t completed_bytes;
+               uint64_t completed_streams;
+               unsigned num_threads;
+               int      compression_type;
+       } write_streams;
+       struct {
+               const char *source;
+       } scan;
+       struct {
+               int image;
+               const char *image_name;
+               const char *target;
+               uint64_t total_bytes;
+               uint64_t completed_bytes;
+               uint64_t num_streams;
+       } extract;
+       struct {
+               const char *from;
+               const char *to;
+       } rename;
+       struct {
+               uint64_t total_bytes;
+               uint64_t completed_bytes;
+               uint32_t completed_chunks;
+               uint32_t total_chunks;
+               uint32_t chunk_size;
+               const char *filename;
+       } integrity;
+       struct {
+               uint64_t total_bytes;
+               uint64_t completed_bytes;
+               unsigned completed_parts;
+               unsigned total_parts;
+               const char *filename;
+       } join;
+       struct {
+               uint64_t completed_bytes;
+               unsigned cur_part_number;
+               const char *part_name;
+               uint64_t total_bytes;
+       } split;
 };
 
+/** A user-supplied function that will be called periodically during certain WIM
+ * operations.  The first argument specifies the type of operation that is being
+ * performed or is about to be started or has been completed.  The second
+ * argument is a pointer to one of a number of structures depending on the first
+ * argument.  It may be @c NULL for some message types.
+ *
+ * The return value
+ * is currently ignored, but it may do something in the future.  (Set it to 0
+ * for now.)
+ */
+typedef int (*wimlib_progress_func_t)(enum wimlib_progress_msg msg_type,
+                                     const union wimlib_progress_info *info);
+
+/*****************************
+ * WIMLIB_ADD_IMAGE_FLAG_*   *
+ *****************************/
+
+/** Directly capture a NTFS volume, not a generic directory. */
+#define WIMLIB_ADD_IMAGE_FLAG_NTFS                     0x00000001
+
+/** Follow symlinks; archive and dump the files they point to.  Cannot be used
+ * with ::WIMLIB_ADD_IMAGE_FLAG_NTFS. */
+#define WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE              0x00000002
+
+/** Print the name of each file or directory as it is scanned to be included in
+ * the WIM image. */
+#define WIMLIB_ADD_IMAGE_FLAG_VERBOSE                  0x00000004
+
+/** Mark the image being added as the bootable image of the WIM. */
+#define WIMLIB_ADD_IMAGE_FLAG_BOOT                     0x00000008
+
+/******************************
+ * WIMLIB_EXPORT_FLAG_* *
+ ******************************/
+
+/** See documentation for wimlib_export_image(). */
+#define WIMLIB_EXPORT_FLAG_BOOT                                0x00000001
+
+/******************************
+ * WIMLIB_EXTRACT_FLAG_*      *
+ ******************************/
+
+/** Apply the image directly to a NTFS volume, not a generic directory. */
+#define WIMLIB_EXTRACT_FLAG_NTFS                       0x00000001
+
+/** When identical files are extracted from the WIM, always hard link them
+ * together.  Not valid with ::WIMLIB_EXTRACT_FLAG_NTFS. */
+#define WIMLIB_EXTRACT_FLAG_HARDLINK                   0x00000002
+
+/** When identical files are extracted from the WIM, always symlink them
+ * together.  Not valid with ::WIMLIB_EXTRACT_FLAG_NTFS. */
+#define WIMLIB_EXTRACT_FLAG_SYMLINK                    0x00000004
+
+/** Print the name of each file as it is extracted from the WIM image. */
+#define WIMLIB_EXTRACT_FLAG_VERBOSE                    0x00000008
+
+/** Read the WIM file sequentially while extracting the image. */
+#define WIMLIB_EXTRACT_FLAG_SEQUENTIAL                 0x00000010
+
+/******************************
+ * WIMLIB_MOUNT_FLAG_*        *
+ ******************************/
+
 /** Mount the WIM read-write. */
-#define WIMLIB_MOUNT_FLAG_READWRITE            0x00000001
+#define WIMLIB_MOUNT_FLAG_READWRITE                    0x00000001
 
 /** For debugging only. (This passes the @c -d flag to @c fuse_main()).*/
-#define WIMLIB_MOUNT_FLAG_DEBUG                        0x00000002
+#define WIMLIB_MOUNT_FLAG_DEBUG                                0x00000002
 
 /** Do not allow accessing alternate data streams. */
-#define WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE                0x00000010
+#define WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE                0x00000004
 
 /** Access alternate data streams through extended file attributes.  This is the
  * default mode. */
-#define WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR       0x00000020
+#define WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR       0x00000008
 
 /** Access alternate data streams by specifying the file name, a colon, then the
  * alternate file stream name. */
-#define WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS     0x00000040
+#define WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS     0x00000010
+
+/******************************
+ * WIMLIB_OPEN_FLAG_*         *
+ ******************************/
+
+/** See documentation for wimlib_open_wim(). */
+#define WIMLIB_OPEN_FLAG_CHECK_INTEGRITY               0x00000001
+
+/** See documentation for wimlib_open_wim(). */
+#define WIMLIB_OPEN_FLAG_SPLIT_OK                      0x00000002
+
+/******************************
+ * WIMLIB_UNMOUNT_FLAG_*      *
+ ******************************/
 
 /** Include an integrity table in the new WIM being written during the unmount.
  * Ignored for read-only mounts. */
-#define WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY    0x00000001
+#define WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY            0x00000001
 
 /** Unless this flag is given, changes to a mounted WIM are discarded.  Ignored
  * for read-only mounts. */
-#define WIMLIB_UNMOUNT_FLAG_COMMIT             0x00000002
-
-/** Include an integrity table in the new WIM file. */
-#define WIMLIB_WRITE_FLAG_CHECK_INTEGRITY      0x00000001
-
-/** Print progress information when writing streams and when writing the
- * integrity table. */
-#define WIMLIB_WRITE_FLAG_SHOW_PROGRESS                0x00000002
+#define WIMLIB_UNMOUNT_FLAG_COMMIT                     0x00000002
 
-/** Print file paths as we write then */
-#define WIMLIB_WRITE_FLAG_VERBOSE              0x00000004
+/******************************
+ * WIMLIB_WRITE_FLAG_*        *
+ ******************************/
 
-/** Call fsync() when the WIM file is closed */
-#define WIMLIB_WRITE_FLAG_FSYNC                        0x00000008
+/** Include an integrity table in the new WIM file. */
+#define WIMLIB_WRITE_FLAG_CHECK_INTEGRITY              0x00000001
 
 /** Re-build the entire WIM file rather than appending data to it, if possible.
  * (Applies to wimlib_overwrite(), not wimlib_write()). */
-#define WIMLIB_WRITE_FLAG_REBUILD              0x00000010
+#define WIMLIB_WRITE_FLAG_REBUILD                      0x00000002
 
 /** Do not copy compressed resources between WIMs if the compression type is the
  * same.  Instead, recompress them. */
-#define WIMLIB_WRITE_FLAG_RECOMPRESS           0x00000020
+#define WIMLIB_WRITE_FLAG_RECOMPRESS                   0x00000004
+
+/** Call fsync() when the WIM file is closed */
+#define WIMLIB_WRITE_FLAG_FSYNC                                0x00000008
 
 /** Specifying this flag overrides the default behavior of wimlib_overwrite()
  * after one or more calls to wimlib_delete_image(), which is to rebuild the
@@ -291,51 +433,7 @@ enum wim_compression_type {
  * particular, all streams will be left alone, even if they are no longer
  * references.  This is probably not what you want, because almost no space will
  * be spaced by deleting an image in this way. */
-#define WIMLIB_WRITE_FLAG_SOFT_DELETE          0x00000040
-
-/** Mark the image being added as the bootable image of the WIM. */
-#define WIMLIB_ADD_IMAGE_FLAG_BOOT             0x00000001
-
-/** Print the name of each file or directory as it is scanned to be included in
- * the WIM image. */
-#define WIMLIB_ADD_IMAGE_FLAG_VERBOSE          0x00000002
-
-/** Follow symlinks; archive and dump the files they point to. */
-#define WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE      0x00000004
-
-/** Show progress information when scanning a directory tree */
-#define WIMLIB_ADD_IMAGE_FLAG_SHOW_PROGRESS    0x00000008
-
-/** See documentation for wimlib_export_image(). */
-#define WIMLIB_EXPORT_FLAG_BOOT                        0x00000001
-
-/** Verify the integrity of the WIM if an integrity table is present. */
-#define WIMLIB_OPEN_FLAG_CHECK_INTEGRITY       0x00000001
-
-/** Print progress information when verifying integrity table. */
-#define WIMLIB_OPEN_FLAG_SHOW_PROGRESS         0x00000002
-
-/** If this flag is not given, an error is issued if the WIM is part of a split
- * WIM.  */
-#define WIMLIB_OPEN_FLAG_SPLIT_OK              0x00000004
-
-
-/** When identical files are extracted from the WIM, always hard link them
- * together. */
-#define WIMLIB_EXTRACT_FLAG_HARDLINK           0x00000001
-
-/** When identical files are extracted from the WIM, always symlink them
- * together. */
-#define WIMLIB_EXTRACT_FLAG_SYMLINK            0x00000002
-
-/** Print the name of each file as it is extracted from the WIM image. */
-#define WIMLIB_EXTRACT_FLAG_VERBOSE            0x00000008
-
-/** 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
+#define WIMLIB_WRITE_FLAG_SOFT_DELETE                  0x00000010
 
 /**
  * Possible values of the error code returned by many functions in wimlib.
@@ -394,11 +492,10 @@ enum wimlib_error_code {
 
 
 /** Used to indicate that no WIM image is currently selected. */
-#define WIM_NO_IMAGE   0
+#define WIMLIB_NO_IMAGE                0
 
 /** Used to specify all images in the WIM. */
-#define WIM_ALL_IMAGES (-1)
-
+#define WIMLIB_ALL_IMAGES      (-1)
 
 /**
  * Adds an image to a WIM file from a directory tree on disk.
@@ -410,6 +507,9 @@ enum wimlib_error_code {
  * permanently, and instead references to their paths saved.  The files are then
  * read on-demand if wimlib_write() or wimlib_overwrite() is called.
  *
+ * Please note that @b no changes are committed to the underlying WIM file (if
+ * any) until wimlib_write() or wimlib_overwrite() is called.
+ *
  * @param wim
  *     Pointer to the ::WIMStruct for a WIM file to which the image will be
  *     added.
@@ -426,7 +526,7 @@ enum wimlib_error_code {
  *     Length of the string @a config in bytes.  Ignored if @a config is @c
  *     NULL.
  *
- * @param flags
+ * @param add_image_flags
  *     Bitwise OR of flags prefixed with WIMLIB_ADD_IMAGE_FLAG.  If
  *     ::WIMLIB_ADD_IMAGE_FLAG_BOOT is specified, the image in @a wim that is
  *     marked as bootable is changed to the one being added.  If
@@ -434,9 +534,11 @@ enum wimlib_error_code {
  *     printed as it is scanned or captured.  If
  *     ::WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE is specified, the files or
  *     directories pointed to by symbolic links are archived rather than the
- *     symbolic links themselves.  If ::WIMLIB_ADD_IMAGE_FLAG_SHOW_PROGRESS is
- *     specified, progress information will be printed (distinct from the
- *     verbose information).
+ *     symbolic links themselves.
+ *
+ * @param progress_func
+ *     If non-NULL, a function that will be called periodically with the
+ *     progress of the current operation.
  *
  * @return 0 on success; nonzero on error.  On error, changes to @a wim are
  * discarded so that it appears to be in the same state as when this function
@@ -456,8 +558,8 @@ enum wimlib_error_code {
  * @retval ::WIMLIB_ERR_READ
  *     Failed to read a file in the directory tree rooted at @a dir.
  * @retval ::WIMLIB_ERR_SPECIAL_FILE
- *     The directory tree rooted at @dir contains a special file that is not a
- *     directory, regular file, or symbolic link.
+ *     The directory tree rooted at @a dir contains a special file that is not
+ *     directory, regular file, or symbolic link.
  * @retval ::WIMLIB_ERR_STAT
  *     Failed obtain the metadata for a file or directory in the directory tree
  *     rooted at @a dir.
@@ -467,42 +569,16 @@ enum wimlib_error_code {
  */
 extern int wimlib_add_image(WIMStruct *wim, const char *dir,
                            const char *name, const char *config,
-                           size_t config_len, int flags);
-
-/**
- * This function is similar to wimlib_add_image(), except instead of capturing
- * the WIM image from a directory, it is captured from a NTFS volume specified
- * by @a device.  NTFS-3g errors are reported as ::WIMLIB_ERR_NTFS_3G.
- * ::WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE may not be specified because we capture
- * the reparse points exactly as they are.
- */
-extern int wimlib_add_image_from_ntfs_volume(WIMStruct *wim, const char *device,
-                                            const char *name,
-                                            const char *config,
-                                            size_t config_len,
-                                            int flags);
-
-/**
- * This function is similar to wimlib_extract_image(), except that @a image may
- * not be ::WIM_ALL_IMAGES, and @a device specifies the name of a file or block
- * device containing a NTFS volume to apply the image to.  NTFS-3g errors are
- * reported as ::WIMLIB_ERR_NTFS_3G, and ::WIMLIB_EXTRACT_FLAG_HARDLINK or
- * ::WIMLIB_EXTRACT_FLAG_SYMLINK may not be specified because in the NTFS
- * apply mode we apply the reparse points and hard links exactly as they are in
- * the WIM.
- */
-extern int wimlib_apply_image_to_ntfs_volume(WIMStruct *wim, int image,
-                                            const char *device, int flags,
-                                            WIMStruct **additional_swms,
-                                            unsigned num_additional_swms);
+                           size_t config_len, int add_image_flags,
+                           wimlib_progress_func_t progress_func);
 
 /**
  * Creates a WIMStruct for a new WIM file.
  *
  * @param ctype
  *     The type of compression to be used in the new WIM file.  Must be
- *     ::WIM_COMPRESSION_TYPE_NONE, ::WIM_COMPRESSION_TYPE_LZX, or
- *     ::WIM_COMPRESSION_TYPE_XPRESS.
+ *     ::WIMLIB_COMPRESSION_TYPE_NONE, ::WIMLIB_COMPRESSION_TYPE_LZX, or
+ *     ::WIMLIB_COMPRESSION_TYPE_XPRESS.
  * @param wim_ret
  *     On success, a pointer to an opaque ::WIMStruct for the new WIM file is
  *     written to the memory location pointed to by this paramater.  The
@@ -510,8 +586,8 @@ extern int wimlib_apply_image_to_ntfs_volume(WIMStruct *wim, int image,
  *     it.
  * @return 0 on success; nonzero on error.
  * @retval ::WIMLIB_ERR_INVALID_COMPRESSION_TYPE
- *     @a ctype was not ::WIM_COMPRESSION_TYPE_NONE,
- *     ::WIM_COMPRESSION_TYPE_LZX, or ::WIM_COMPRESSION_TYPE_XPRESS.
+ *     @a ctype was not ::WIMLIB_COMPRESSION_TYPE_NONE,
+ *     ::WIMLIB_COMPRESSION_TYPE_LZX, or ::WIMLIB_COMPRESSION_TYPE_XPRESS.
  * @retval ::WIMLIB_ERR_NOMEM
  *     Failed to allocate needed memory.
  */
@@ -524,15 +600,18 @@ extern int wimlib_create_new_wim(int ctype, WIMStruct **wim_ret);
  * lookup table of the WIM if they are not referenced by any other images in the
  * WIM.
  *
+ * Please note that @b no changes are committed to the underlying WIM file (if
+ * any) until wimlib_write() or wimlib_overwrite() is called.
+ *
  * @param wim
  *     Pointer to the ::WIMStruct for the WIM file that contains the image(s)
  *     being deleted.
  * @param image
- *     The number of the image to delete, or ::WIM_ALL_IMAGES to delete all
+ *     The number of the image to delete, or ::WIMLIB_ALL_IMAGES to delete all
  *     images.
  * @return 0 on success; nonzero on failure.  On failure, @a wim is guaranteed
  * to be left unmodified only if @a image specified a single image.  If instead
- * @a image was ::WIM_ALL_IMAGES and @a wim contained more than one image, it's
+ * @a image was ::WIMLIB_ALL_IMAGES and @a wim contained more than one image, it's
  * possible for some but not all of the images to have been deleted when a
  * failure status is returned.
  *
@@ -542,7 +621,7 @@ extern int wimlib_create_new_wim(int ctype, WIMStruct **wim_ret);
  *     A directory entry in the metadata resource for @a image in the WIM is
  *     invalid.
  * @retval ::WIMLIB_ERR_INVALID_IMAGE
- *     @a image does not exist in the WIM and is not ::WIM_ALL_IMAGES.
+ *     @a image does not exist in the WIM and is not ::WIMLIB_ALL_IMAGES.
  * @retval ::WIMLIB_ERR_INVALID_RESOURCE_SIZE
  *     The metadata resource for @a image in the WIM is invalid.
  * @retval ::WIMLIB_ERR_INVALID_SECURITY_DATA
@@ -562,10 +641,10 @@ extern int wimlib_delete_image(WIMStruct *wim, int image);
  *
  * The destination image is made to share the same dentry tree and security data
  * structure as the source image.  This places some restrictions on additional
- * functions that may be called.  wimlib_mount() may not be called on either the
- * source image or the destination image without an intervening call to a
- * function that un-shares the images, such as wimlib_free() on @a dest_wim, or
- * wimlib_delete_image() on either the source or destination image.
+ * functions that may be called.  wimlib_mount_image() may not be called on
+ * either the source image or the destination image without an intervening call
+ * to a function that un-shares the images, such as wimlib_free() on @a
+ * dest_wim, or wimlib_delete_image() on either the source or destination image.
  * Furthermore, you may not call wimlib_free() or wimlib_overwrite() on @a
  * src_wim before any calls to functions such as wimlib_write() on @a dest_wim
  * because @a dest_wim will have references back to @a src_wim.
@@ -581,30 +660,33 @@ extern int wimlib_delete_image(WIMStruct *wim, int image);
  * Regardless of whether this function succeeds or fails, no user-visible
  * changes are made to @a src_wim.
  *
+ * Please note that @b no changes are committed to the underlying WIM file (if
+ * any) until wimlib_write() or wimlib_overwrite() is called.
+ *
  * @param src_wim
  *     Pointer to the ::WIMStruct for a stand-alone WIM or part 1 of a split
  *     WIM that contains the image(s) being exported.
  * @param src_image
  *     The image to export from @a src_wim.  Can be the number of an image, or
- *     ::WIM_ALL_IMAGES to export all images.
+ *     ::WIMLIB_ALL_IMAGES to export all images.
  * @param dest_wim
  *     Pointer to the ::WIMStruct for a WIM file that will receive the images
  *     being exported.
  * @param dest_name
  *     The name to give the exported image in the new WIM file.  If left @c NULL,
  *     the name from @a src_wim is used.  This parameter must be left @c NULL
- *     if @a src_image is ::WIM_ALL_IMAGES and @a src_wim contains more than one
+ *     if @a src_image is ::WIMLIB_ALL_IMAGES and @a src_wim contains more than one
  *     image; in that case, the names are all taken from the @a src_wim.
  * @param dest_description
  *     The description to give the exported image in the new WIM file.  If left
  *     @c NULL, the description from the @a src_wim is used.  This parameter must
- *     be left @c NULL if @a src_image is ::WIM_ALL_IMAGES and @a src_wim contains
+ *     be left @c NULL if @a src_image is ::WIMLIB_ALL_IMAGES and @a src_wim contains
  *     more than one image; in that case, the descriptions are all taken from
  *     @a src_wim.
- * @param flags
+ * @param export_flags
  *     ::WIMLIB_EXPORT_FLAG_BOOT if the image being exported is to be made
  *     bootable, or 0 if which image is marked as bootable in the destination
- *     WIM is to be left unchanged.  If @a src_image is ::WIM_ALL_IMAGES and
+ *     WIM is to be left unchanged.  If @a src_image is ::WIMLIB_ALL_IMAGES and
  *     there are multiple images in @a src_wim, specifying
  *     ::WIMLIB_EXPORT_FLAG_BOOT is valid only if one of the exported images is
  *     currently marked as bootable in @a src_wim; if that is the case, then
@@ -619,6 +701,9 @@ extern int wimlib_delete_image(WIMStruct *wim, int image);
  *     Number of additional WIM parts provided in the @a additional_swms array.
  *     This number should be one less than the total number of parts in the
  *     split WIM.  Set to 0 if the WIM is a standalone WIM.
+ * @param progress_func
+ *     If non-NULL, a function that will be called periodically with the
+ *     progress of the current operation.
  *
  * @return 0 on success; nonzero on error.
  * @retval ::WIMLIB_ERR_DECOMPRESSION
@@ -634,10 +719,10 @@ extern int wimlib_delete_image(WIMStruct *wim, int image);
  *     @a src_image does not exist in @a src_wim.
  * @retval ::WIMLIB_ERR_INVALID_PARAM
  *     ::WIMLIB_EXPORT_FLAG_BOOT was specified in @a flags, @a src_image was
- *     ::WIM_ALL_IMAGES, @a src_wim contains multiple images, and no images in
+ *     ::WIMLIB_ALL_IMAGES, @a src_wim contains multiple images, and no images in
  *     @a src_wim are marked as bootable; or @a dest_name and/or @a
  *     dest_description were non-<code>NULL</code>, @a src_image was
- *     ::WIM_ALL_IMAGES, and @a src_wim contains multiple images; or @a src_wim
+ *     ::WIMLIB_ALL_IMAGES, and @a src_wim contains multiple images; or @a src_wim
  *     or @a dest_wim was @c NULL.
  * @retval ::WIMLIB_ERR_INVALID_RESOURCE_SIZE
  *     The metadata resource for @a src_image in @a src_wim is invalid.
@@ -658,9 +743,10 @@ extern int wimlib_delete_image(WIMStruct *wim, int image);
  */
 extern int wimlib_export_image(WIMStruct *src_wim, int src_image,
                               WIMStruct *dest_wim, const char *dest_name,
-                              const char *dest_description, int flags,
+                              const char *dest_description, int export_flags,
                               WIMStruct **additional_swms,
-                              unsigned num_additional_swms);
+                              unsigned num_additional_swms,
+                              wimlib_progress_func_t progress_func);
 
 /**
  * Extracts an image, or all images, from a standalone or split WIM file.
@@ -669,26 +755,41 @@ extern int wimlib_export_image(WIMStruct *src_wim, int src_image,
  *     Pointer to the ::WIMStruct for a standalone WIM file, or part 1 of a
  *     split WIM.
  * @param image
- *     The image to extract.  Can be the number of an image, or ::WIM_ALL_IMAGES
- *     to specify that all images are to be extracted.
- * @param output_dir
- *     Directory to extract the WIM image(s) to.  It is created if it does not
- *     already exist.
- * @param flags
- *     Bitwise or of the flags prefixed with WIMLIB_EXTRACT_FLAG.
- *
- *     One or none of ::WIMLIB_EXTRACT_FLAG_HARDLINK or
- *     ::WIMLIB_EXTRACT_FLAG_SYMLINK may be specified.  These flags cause
- *     extracted files that are identical to be hardlinked or symlinked
- *     together, depending on the flag.  These flags override the hard link
- *     groups that are specified in the WIM file itself.  If ::WIM_ALL_IMAGES
- *     is provided as the @a image parameter, files may be hardlinked or
- *     symlinked across images if a file is found to occur in more than one
- *     image.
+ *     The image to extract.  Can be the number of an image, or ::WIMLIB_ALL_IMAGES
+ *     to specify that all images are to be extracted.  ::WIMLIB_ALL_IMAGES cannot
+ *     be used if ::WIMLIB_EXTRACT_FLAG_NTFS is specified in @a extract_flags.
+ * @param target
+ *     Directory to extract the WIM image(s) to (created if it does not already
+ *     exist); or, with ::WIMLIB_EXTRACT_FLAG_NTFS in @a extract_flags, the
+ *     name of the NTFS volume to extract the image to.
+ * @param extract_flags
+ *     Bitwise OR of the flags prefixed with WIMLIB_EXTRACT_FLAG.
+ *
+ *     If ::WIMLIB_EXTRACT_FLAG_NTFS is specified, @a target is interpreted as
+ *     a NTFS volume to extract the image to.  The volume will be opened using
+ *     NTFS-3g and the image will be extracted to the root of the NTFS volume.
+ *     Otherwise, @a target is interpreted as a directory to extract the
+ *     image(s) to.
+ *
+ *     If ::WIMLIB_EXTRACT_FLAG_NTFS is not specified, one or none of
+ *     ::WIMLIB_EXTRACT_FLAG_HARDLINK or ::WIMLIB_EXTRACT_FLAG_SYMLINK may be
+ *     specified.  These flags cause extracted files that are identical to be
+ *     hardlinked or symlinked together, depending on the flag.  These flags
+ *     override the hard link groups that are specified in the WIM file itself.
+ *     If ::WIMLIB_ALL_IMAGES is provided as the @a image parameter, files may be
+ *     hardlinked or symlinked across images if a file is found to occur in
+ *     more than one image.
  *
  *     You may also specify the flag ::WIMLIB_EXTRACT_FLAG_VERBOSE to cause
  *     informational messages to be printed during the extraction, including
  *     the name of each extracted file or directory.
+ *     
+ *     If ::WIMLIB_EXTRACT_FLAG_SEQUENTIAL is specified, streams are read from
+ *     the WIM sequentially, if possible.  If ::WIMLIB_ALL_IMAGES is specified,
+ *     each image is considered separately with regards to the sequential
+ *     order.  It is also possible for alternate data streams to break the
+ *     sequential order (this only applies if ::WIMLIB_EXTRACT_FLAG_NTFS is
+ *     specified).
  * @param additional_swms
  *     Array of pointers to the ::WIMStruct for each additional part in the
  *     split WIM.  Ignored if @a num_additional_swms is 0.  The pointers do not
@@ -700,6 +801,10 @@ extern int wimlib_export_image(WIMStruct *src_wim, int src_image,
  *     This number should be one less than the total number of parts in the
  *     split WIM.  Set to 0 if the WIM is a standalone WIM.
  *
+ * @param progress_func
+ *     If non-NULL, a function that will be called periodically with the
+ *     progress of the current operation.
+ *
  * @return 0 on success; nonzero on error.
  * @retval ::WIMLIB_ERR_DECOMPRESSION
  *     Could not decompress a resource (file or metadata) for @a image in @a
@@ -734,9 +839,10 @@ extern int wimlib_export_image(WIMStruct *src_wim, int src_image,
  *     Failed to write a file being extracted.
  */
 extern int wimlib_extract_image(WIMStruct *wim, int image,
-                               const char *output_dir, int flags,
+                               const char *target, int extract_flags,
                                WIMStruct **additional_swms,
-                               unsigned num_additional_swms);
+                               unsigned num_additional_swms,
+                               wimlib_progress_func_t progress_func);
 
 /**
  * Extracts the XML data for a WIM file to a file stream.  Every WIM file
@@ -784,8 +890,8 @@ extern int wimlib_get_boot_idx(const WIMStruct *wim);
  *     Pointer to the ::WIMStruct for a WIM file
  *
  * @return
- *     ::WIM_COMPRESSION_TYPE_NONE, ::WIM_COMPRESSION_TYPE_LZX, or
- *     ::WIM_COMPRESSION_TYPE_XPRESS.
+ *     ::WIMLIB_COMPRESSION_TYPE_NONE, ::WIMLIB_COMPRESSION_TYPE_LZX, or
+ *     ::WIMLIB_COMPRESSION_TYPE_XPRESS.
  */
 extern int wimlib_get_compression_type(const WIMStruct *wim);
 
@@ -793,8 +899,8 @@ extern int wimlib_get_compression_type(const WIMStruct *wim);
  * Converts a compression type enumeration value into a string.
  *
  * @param ctype
- *     ::WIM_COMPRESSION_TYPE_NONE, ::WIM_COMPRESSION_TYPE_LZX,
- *     ::WIM_COMPRESSION_TYPE_XPRESS, or another value.
+ *     ::WIMLIB_COMPRESSION_TYPE_NONE, ::WIMLIB_COMPRESSION_TYPE_LZX,
+ *     ::WIMLIB_COMPRESSION_TYPE_XPRESS, or another value.
  *
  * @return
  *     A statically allocated string: "None", "LZX", "XPRESS", or "Invalid",
@@ -903,55 +1009,57 @@ extern bool wimlib_has_integrity_table(const WIMStruct *wim);
 extern bool wimlib_image_name_in_use(const WIMStruct *wim, const char *name);
 
 /**
- * Joins a set of split WIMs into a one-part WIM.
+ * Joins a set of split WIMs into a stand-alone one-part WIM.
  *
  * @param swms
  *     An array of strings that give the filenames of all parts of the split
  *     WIM.
  * @param num_swms
  *     Number of filenames in @a swms.
+ * @param swm_open_flags
+ *     Open flags to use when opening the split WIM pats.
+ * @param wim_write_flags
+ *     Write flags to use when writing the joined WIM.
  * @param output_path
  *     The path to write the one-part WIM to.
- * @param flags
- *     ::WIMLIB_OPEN_FLAG_CHECK_INTEGRITY to check the split WIMs' integrity
- *     tables (if present) when opening them, and include an integrity table in
- *     the output WIM.
+ * @param progress_func
+ *     If non-NULL, a function that will be called periodically with the
+ *     progress of the current operation.
  *
  * @return 0 on success; nonzero on error.  This function may return any value
- * returned by wimlib_open_wim() except ::WIMLIB_ERR_SPLIT_UNSUPPORTED, as well
- * as the following error codes:
+ * returned by wimlib_open_wim() and wimlib_write() except
+ * ::WIMLIB_ERR_SPLIT_UNSUPPORTED, as well as the following error code:
  *
  * @retval ::WIMLIB_ERR_SPLIT_INVALID
  *     The split WIMs do not form a valid WIM because they do not include all
  *     the parts of the original WIM, there are duplicate parts, or not all the
  *     parts have the same GUID and compression type.
- * @retval ::WIMLIB_ERR_WRITE
- *     An error occurred when trying to write data to the new WIM at @a output_path.
  *
  * Note that this function merely copies the resources, so it will not check to
- * see if the resources, including the metadata resources, are valid or not.
- *
- * Also, after this function is called, the only function that may be called on
- * the ::WIMStruct's in the @a swms array is wimlib_free().
+ * see if the resources, including the metadata resources, are valid or not
+ * (unless ::WIMLIB_WRITE_FLAG_RECOMPRESS is specified).
  */
 extern int wimlib_join(const char **swms, unsigned num_swms,
-                      const char *output_path, int flags);
+                      const char *output_path, int swm_open_flags,
+                      int wim_write_flags,
+                      wimlib_progress_func_t progress_func);
 
 /**
  * Mounts an image in a WIM file on a directory read-only or read-write.
  *
- * A daemon will be forked to service the filesystem.
+ * A daemon will be forked to service the filesystem.  In other words, this
+ * function returns @b before the image is unmounted.
  *
  * If the mount is read-write, modifications to the WIM are staged in a staging
  * directory.
  *
- * wimlib_mount() may be called from multiple threads without intervening calls
- * to wimlib_unmount(), provided that different ::WIMStruct's are used.  (This
+ * wimlib_mount_image() may be called from multiple threads without intervening calls
+ * to wimlib_unmount_image(), provided that different ::WIMStruct's are used.  (This
  * was not the case for versions of this library 1.0.3 and earlier.)
  *
- * wimlib_mount() cannot be used on an image that was exported with
+ * wimlib_mount_image() cannot be used on an image that was exported with
  * wimlib_export_image() while the dentry trees for both images are still in
- * memory.  In addition, wimlib_mount() may not be used to mount an image that
+ * memory.  In addition, wimlib_mount_image() may not be used to mount an image that
  * has just been added with wimlib_add_image() or
  * wimlib_add_image_from_ntfs_volume(), unless the WIM has been written and read
  * into a new ::WIMStruct.
@@ -963,11 +1071,12 @@ extern int wimlib_join(const char **swms, unsigned num_swms,
  *     existing, single image.
  * @param dir
  *     The path to an existing directory to mount the image on.
- * @param flags
+ * @param mount_flags
  *     Bitwise OR of the flags prefixed with WIMLIB_MOUNT_FLAG.  If
- *     ::WIMLIB_MOUNT_FLAG_READWRITE is not given, the WIM is mounted
- *     read-only.  The interface to the WIM named data streams is specified by
- *     exactly one of ::WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE,
+ *     ::WIMLIB_MOUNT_FLAG_READWRITE is given, the WIM is mounted read-write
+ *     rather than the default of read-only.  The interface to the WIM named
+ *     data streams is specified by exactly one of
+ *     ::WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE,
  *     ::WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR, or
  *     ::WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS.  The default interface is
  *     the XATTR interface.
@@ -1001,8 +1110,8 @@ extern int wimlib_join(const char **swms, unsigned num_swms,
  * @retval ::WIMLIB_ERR_INVALID_SECURITY_DATA
  *     The security data for @a image in @a wim is invalid.
  * @retval ::WIMLIB_ERR_MKDIR
- *     ::WIMLIB_MOUNT_FLAG_READWRITE was specified in @a flags, but the staging
- *     directory could not be created.
+ *     ::WIMLIB_MOUNT_FLAG_READWRITE was specified in @a mount_flags, but the
+ *     staging directory could not be created.
  * @retval ::WIMLIB_ERR_NOMEM
  *     Failed to allocate needed memory.
  * @retval ::WIMLIB_ERR_NOTDIR
@@ -1019,30 +1128,34 @@ extern int wimlib_join(const char **swms, unsigned num_swms,
  *     The WIM is a split WIM and a read-write mount was requested.  We only
  *     support mounting a split WIM read-only.
  */
-extern int wimlib_mount(WIMStruct *wim, int image, const char *dir, int flags,
-                       WIMStruct **additional_swms,
-                       unsigned num_additional_swms);
+extern int wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
+                             int mount_flags, WIMStruct **additional_swms,
+                             unsigned num_additional_swms);
 
 /**
  * Opens a WIM file and creates a ::WIMStruct for it.
  *
  * @param wim_file
  *     The path to the WIM file to open.
- * @param flags
- *     Bitwise OR of ::WIMLIB_OPEN_FLAG_CHECK_INTEGRITY and/or
- *     ::WIMLIB_OPEN_FLAG_SHOW_PROGRESS.
- *     If ::WIMLIB_OPEN_FLAG_CHECK_INTEGRITY is given, the integrity table
- *     of the WIM, if it exists, is checked, and the function will fail with an
+ * @param open_flags
+ *     Bitwise OR of flags ::WIMLIB_OPEN_FLAG_CHECK_INTEGRITY and/or
+ *     ::WIMLIB_OPEN_FLAG_SPLIT_OK.
+ *
+ *     If ::WIMLIB_OPEN_FLAG_CHECK_INTEGRITY is given, the integrity table of
+ *     the WIM, if it exists, is checked, and this function will fail with an
  *     ::WIMLIB_ERR_INTEGRITY status if any of the computed SHA1 message
  *     digests of the WIM do not exactly match the corresponding message
  *     digests given in the integrity table.
- *     If ::WIMLIB_OPEN_FLAG_SHOW_PROGRESS is given, progress information will
- *     be shown if the integrity of the WIM is checked.
+ *
  *     If ::WIMLIB_OPEN_FLAG_SPLIT_OK is given, no error will be issued if the
  *     WIM is part of a split WIM; otherwise ::WIMLIB_ERR_SPLIT_UNSUPPORTED is
  *     returned.  (This flag may be removed in the future, in which case no
  *     error will be issued when opening a split WIM.)
  *
+ * @param progress_func
+ *     If non-NULL, a function that will be called periodically with the
+ *     progress of the current operation.
+ *
  * @param wim_ret
  *     On success, a pointer to an opaque ::WIMStruct for the opened WIM file
  *     is written to the memory location pointed to by this parameter.  The
@@ -1060,7 +1173,7 @@ extern int wimlib_mount(WIMStruct *wim, int image, const char *dir, int flags,
  *     in the WIM header, or the number of &lt;IMAGE&gt; elements in the XML
  *     data for the WIM did not match the image count given in the WIM header.
  * @retval ::WIMLIB_ERR_INTEGRITY
- *     ::WIMLIB_OPEN_FLAG_CHECK_INTEGRITY was specified in @a flags and @a
+ *     ::WIMLIB_OPEN_FLAG_CHECK_INTEGRITY was specified in @a open_flags and @a
  *     wim_file contains an integrity table, but the SHA1 message digest for a
  *     chunk of the WIM does not match the corresponding message digest given
  *     in the integrity table.
@@ -1072,7 +1185,7 @@ extern int wimlib_mount(WIMStruct *wim, int image, const char *dir, int flags,
  * @retval ::WIMLIB_ERR_INVALID_HEADER_SIZE
  *     The length field of the WIM header is not 208.
  * @retval ::WIMLIB_ERR_INVALID_INTEGRITY_TABLE
- *     ::WIMLIB_OPEN_FLAG_CHECK_INTEGRITY was specified in @a flags and @a
+ *     ::WIMLIB_OPEN_FLAG_CHECK_INTEGRITY was specified in @a open_flags and @a
  *     wim_file contains an integrity table, but the integrity table is
  *     invalid.
  * @retval ::WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY
@@ -1089,15 +1202,16 @@ extern int wimlib_mount(WIMStruct *wim, int image, const char *dir, int flags,
  *     data from @a wim_file.
  * @retval ::WIMLIB_ERR_SPLIT_UNSUPPORTED
  *     @a wim_file is a split WIM, but ::WIMLIB_OPEN_FLAG_SPLIT_OK was not
- *     givin in @a flags.
+ *     givin in @a open_flags.
  * @retval ::WIMLIB_ERR_UNKNOWN_VERSION
  *     A number other than 0x10d00 is written in the version field of the WIM
  *     header of @a wim_file.
  * @retval ::WIMLIB_ERR_XML
  *     The XML data for @a wim_file is invalid.
  */
-extern int wimlib_open_wim(const char *wim_file, int flags,
-                          WIMStruct **wim_ret);
+extern int wimlib_open_wim(const char *wim_file, int open_flags,
+                          WIMStruct **wim_ret,
+                          wimlib_progress_func_t progress_func);
 
 /**
  * Overwrites the file that the WIM was originally read from, with changes made.
@@ -1128,17 +1242,21 @@ extern int wimlib_open_wim(const char *wim_file, int flags,
  * termination of the program will result in the temporary file being orphaned.
  * In the direct append mode, the WIM is truncated to the original length on
  * failure, while abnormal termination of the program will result in extra data
- * appended to the original WIM, but it will still be a valid WIM.
+ * appended to the original WIM, but it should still be a valid WIM.
  *
  * @param wim
  *     Pointer to the ::WIMStruct for the WIM file to write.  There may have
  *     been in-memory changes made to it, which are then reflected in the
  *     output file.
  * @param write_flags
- *     Bitwise OR of ::WIMLIB_WRITE_FLAG_CHECK_INTEGRITY and/or
- *     ::WIMLIB_WRITE_FLAG_SHOW_PROGRESS.
+ *     Bitwise OR of the flags ::WIMLIB_WRITE_FLAG_CHECK_INTEGRITY,
+ *     ::WIMLIB_WRITE_FLAG_REBUILD, ::WIMLIB_WRITE_FLAG_RECOMPRESS, and/or
+ *     ::WIMLIB_WRITE_FLAG_SOFT_DELETE.
  * @param num_threads
  *     Number of threads to use for compression (see wimlib_write()).
+ * @param progress_func
+ *     If non-NULL, a function that will be called periodically with the
+ *     progress of the current operation.
  *
  * @return 0 on success; nonzero on error.  This function may return any value
  * returned by wimlib_write() as well as the following error codes:
@@ -1155,14 +1273,8 @@ extern int wimlib_open_wim(const char *wim_file, int flags,
  *     before calling wimlib_free().
  */
 extern int wimlib_overwrite(WIMStruct *wim, int write_flags,
-                           unsigned num_threads);
-
-/**
- * This function is deprecated; call wimlib_overwrite() instead.
- * (wimlib_overwrite() no longer rebuilds the full WIM unless it has to or is
- * specified explicitly with ::WIMLIB_WRITE_FLAG_REBUILD)
- */
-extern int wimlib_overwrite_xml_and_header(WIMStruct *wim, int write_flags);
+                           unsigned num_threads,
+                           wimlib_progress_func_t progress_func);
 
 /**
  * Prints information about one image, or all images, contained in a WIM.
@@ -1171,7 +1283,7 @@ extern int wimlib_overwrite_xml_and_header(WIMStruct *wim, int write_flags);
  *     Pointer to the ::WIMStruct for a WIM file.
  * @param image
  *     The image about which to print information.  Can be the number of an
- *     image, or ::WIM_ALL_IMAGES to print information about all images in the
+ *     image, or ::WIMLIB_ALL_IMAGES to print information about all images in the
  *     WIM.
  *
  * @return This function has no return value.  No error checking is done when
@@ -1188,7 +1300,7 @@ extern void wimlib_print_available_images(const WIMStruct *wim, int image);
  *     Pointer to the ::WIMStruct for a WIM file.
  * @param image
  *     Which image to print files for.  Can be the number of an image, or
- *     ::WIM_ALL_IMAGES to print the files contained in all images.
+ *     ::WIMLIB_ALL_IMAGES to print the files contained in all images.
  *
  * @return 0 on success; nonzero on error.
  * @retval ::WIMLIB_ERR_DECOMPRESSION
@@ -1199,7 +1311,7 @@ extern void wimlib_print_available_images(const WIMStruct *wim, int image);
  *     images is invaled.
  * @retval ::WIMLIB_ERR_INVALID_IMAGE
  *     @a image does not specify a valid image in @a wim, and is not
- *     ::WIM_ALL_IMAGES.
+ *     ::WIMLIB_ALL_IMAGES.
  * @retval ::WIMLIB_ERR_INVALID_PARAM
  *     @a wim was @c NULL.
  * @retval ::WIMLIB_ERR_INVALID_RESOURCE_SIZE
@@ -1252,7 +1364,7 @@ extern void wimlib_print_lookup_table(WIMStruct *wim);
  *     Pointer to the ::WIMStruct for a WIM file.
  * @param image
  *     Which image to print the metadata for.  Can be the number of an image,
- *     or ::WIM_ALL_IMAGES to print the metadata for all images in the WIM.
+ *     or ::WIMLIB_ALL_IMAGES to print the metadata for all images in the WIM.
  *
  * @return 0 on success; nonzero on error.
  * @retval ::WIMLIB_ERR_DECOMPRESSION
@@ -1263,7 +1375,7 @@ extern void wimlib_print_lookup_table(WIMStruct *wim);
  *     images is invaled.
  * @retval ::WIMLIB_ERR_INVALID_IMAGE
  *     @a image does not specify a valid image in @a wim, and is not
- *     ::WIM_ALL_IMAGES.
+ *     ::WIMLIB_ALL_IMAGES.
  * @retval ::WIMLIB_ERR_INVALID_PARAM
  *     @a wim was @c NULL.
  * @retval ::WIMLIB_ERR_INVALID_RESOURCE_SIZE
@@ -1305,12 +1417,12 @@ extern void wimlib_print_wim_information(const WIMStruct *wim);
  *     taken to be a string specifying the image number.  Otherwise, it is
  *     taken to be the name of an image, as specified in the XML data for the
  *     WIM file.  It also may be the keyword "all" or the string "*", both of
- *     which will resolve to ::WIM_ALL_IMAGES.
+ *     which will resolve to ::WIMLIB_ALL_IMAGES.
  *
  * @return
  *     If the string resolved to a single existing image, the number of that
  *     image, counting starting at 1, is returned.  If the keyword "all" was
- *     specified, ::WIM_ALL_IMAGES is returned.  Otherwise, ::WIM_NO_IMAGE is
+ *     specified, ::WIMLIB_ALL_IMAGES is returned.  Otherwise, ::WIMLIB_NO_IMAGE is
  *     returned.
  */
 extern int wimlib_resolve_image(WIMStruct *wim, const char *image_name_or_num);
@@ -1465,38 +1577,44 @@ extern int wimlib_set_print_errors(bool show_messages);
 /**
  * Splits a WIM into multiple parts.
  *
- * @param wimfile
- *     Name of the WIM file to split.  It must be a standalone, one-part WIM.
+ * @param wim
+ *     The ::WIMStruct for the WIM to split.  It must be a standalone, one-part
+ *     WIM.
  * @param swm_name
  *     Name of the SWM file to create.  This will be the name of the first
  *     part.  The other parts will have the same name with 2, 3, 4, ..., etc.
- *     appended.
+ *     appended before the suffix.
  * @param part_size
  *     The maximum size per part, in bytes.  It is not guaranteed that this
  *     will really be the maximum size per part, because some file resources in
  *     the WIM may be larger than this size, and the WIM file format provides
  *     no way to split up file resources among multiple WIMs.
- * @param flags
- *     Bitwise OR of ::WIMLIB_OPEN_FLAG_CHECK_INTEGRITY and/or
- *     ::WIMLIB_OPEN_FLAG_SHOW_PROGRESS.
+ * @param write_flags
+ *     Bitwise OR of the flags ::WIMLIB_WRITE_FLAG_CHECK_INTEGRITY and/or
+ *     ::WIMLIB_WRITE_FLAG_RECOMPRESS.
+ * @param progress_func
+ *     If non-NULL, a function that will be called periodically with the
+ *     progress of the current operation.
  *
  * @return 0 on success; nonzero on error.  This function may return any value
- * returned by wimlib_open_wim() as well as the following error codes:
- *
- * @retval ::WIMLIB_ERR_WRITE
- *     An error occurred when trying to write data to one of the split WIMs.
+ * returned by wimlib_write() as well as the following error codes:
  *
+ * @retval ::WIMLIB_ERR_SPLIT_UNSUPPORTED:
+ *     @a wim is not part 1 of a stand-alone WIM.
+ * @retval ::WIMLIB_ERR_INVALID_PARAM
+ *     @a w was @c NULL, @a swm_name was @c NULL, or @a part_size was 0.
  */
-extern int wimlib_split(const char *wimfile, const char *swm_name,
-                       size_t part_size, int flags);
+extern int wimlib_split(WIMStruct *wim, const char *swm_name,
+                       size_t part_size, int write_flags,
+                       wimlib_progress_func_t progress_func);
 
 /**
- * Unmounts a WIM image that was mounted using wimlib_mount().
+ * Unmounts a WIM image that was mounted using wimlib_mount_image().
  *
  * Blocks until it is known whether the mount succeeded or failed.
  *
- * To perform this operation, the process calling wimlib_unmount() communicates
- * with the process that had called wimlib_mount().
+ * To perform this operation, the process calling wimlib_unmount_image()
+ * communicates with the process that had called wimlib_mount_image().
  *
  * There is currently a design problem with this function because it is hard to
  * know whether the filesystem daemon is still working or whether it has
@@ -1508,8 +1626,8 @@ extern int wimlib_split(const char *wimfile, const char *swm_name,
  *
  * @param dir
  *     The directory that the WIM image was mounted on.
- * @param flags
- *     Bitwise OR of the flags ::WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY or
+ * @param unmount_flags
+ *     Bitwise OR of the flags ::WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY and/or
  *     ::WIMLIB_UNMOUNT_FLAG_COMMIT.  Neither of these flags affect read-only
  *     mounts.
  *
@@ -1546,33 +1664,33 @@ extern int wimlib_split(const char *wimfile, const char *swm_name,
  *     WIM file, or the filesystem daemon was unable to flush changes that had
  *     been made to files in the staging directory.
  */
-extern int wimlib_unmount(const char *dir, int flags);
+extern int wimlib_unmount_image(const char *dir, int unmount_flags);
 
 /**
- * Writes the WIM to a file.
+ * Writes a standalone WIM to a file.
  *
  * @param wim
- *     Pointer to the ::WIMStruct for a WIM file.  There may have been
- *     in-memory changes made to it, which are then reflected in the output
- *     file.
+ *     Pointer to the ::WIMStruct for a WIM.  There may have been in-memory
+ *     changes made to it, which are then reflected in the output file.
  * @param path
  *     The path to the file to write the WIM to.
  * @param image
- *     The image inside the WIM to write.  Use ::WIM_ALL_IMAGES to include all
+ *     The image inside the WIM to write.  Use ::WIMLIB_ALL_IMAGES to include all
  *     images.
  * @param write_flags
- *     Bitwise OR of ::WIMLIB_WRITE_FLAG_CHECK_INTEGRITY and/or
- *     ::WIMLIB_WRITE_FLAG_SHOW_PROGRESS.  If
- *     ::WIMLIB_WRITE_FLAG_CHECK_INTEGRITY is given, an integrity table is
- *     included in the WIM being written.  If ::WIMLIB_WRITE_FLAG_SHOW_PROGRESS
- *     is given, the progress of the calculation of the integrity table is
- *     shown.
+ *     Bitwise OR of the flags ::WIMLIB_WRITE_FLAG_CHECK_INTEGRITY,
+ *     ::WIMLIB_WRITE_FLAG_RECOMPRESS, ::WIMLIB_WRITE_FLAG_FSYNC, and/or
+ *     ::WIMLIB_WRITE_FLAG_SOFT_DELETE.
  * @param num_threads
  *     Number of threads to use for compressing data.  Autodetected if set to
- *     0.  Note: if no data compression needs to be done, no threads will be
- *     created regardless of this parameter (e.g. if writing an uncompressed
- *     WIM, or exporting an image from a compressed WIM to another WIM of the
- *     same compression type).
+ *     0.  Note: if no data compression needs to be done, no additional threads
+ *     will be created regardless of this parameter (e.g. if writing an
+ *     uncompressed WIM, or exporting an image from a compressed WIM to another
+ *     WIM of the same compression type without ::WIMLIB_WRITE_FLAG_RECOMPRESS
+ *     specified in @a write_flags).
+ * @param progress_func
+ *     If non-NULL, a function that will be called periodically with the
+ *     progress of the current operation.
  *
  * @return 0 on success; nonzero on error.
  * @retval ::WIMLIB_ERR_DECOMPRESSION
@@ -1582,7 +1700,7 @@ extern int wimlib_unmount(const char *dir, int flags);
  *     invalid.
  * @retval ::WIMLIB_ERR_INVALID_IMAGE
  *     @a image does not specify a single existing image in @a wim, and is not
- *     ::WIM_ALL_IMAGES.
+ *     ::WIMLIB_ALL_IMAGES.
  * @retval ::WIMLIB_ERR_INVALID_RESOURCE_HASH
  *     A file that had previously been scanned for inclusion in the WIM by the
  *     wimlib_add_image() or wimlib_add_image_from_ntfs_volume() functions was
@@ -1612,9 +1730,7 @@ extern int wimlib_unmount(const char *dir, int flags);
  *     path.
  */
 extern int wimlib_write(WIMStruct *wim, const char *path, int image,
-                       int write_flags, unsigned num_threads);
-
-
+                       int write_flags, unsigned num_threads,
+                       wimlib_progress_func_t progress_func);
 
 #endif /* _WIMLIB_H */
-
index 49d1cbb..8782995 100644 (file)
@@ -39,6 +39,8 @@ struct stat;
 struct dentry;
 struct inode;
 
+#include "wimlib.h"
+
 #define WIM_MAGIC_LEN  8
 #define WIM_GID_LEN    16
 #define WIM_UNUSED_LEN 60
@@ -387,14 +389,14 @@ struct inode_table {
        struct hlist_head extra_inodes;
 };
 
-int init_inode_table(struct inode_table *table, size_t capacity);
+extern int init_inode_table(struct inode_table *table, size_t capacity);
 static inline void destroy_inode_table(struct inode_table *table)
 {
        FREE(table->array);
 }
-int inode_table_insert(struct dentry *dentry, void *__table);
-u64 assign_inode_numbers(struct hlist_head *inode_list);
-int fix_inodes(struct inode_table *table, struct hlist_head *inode_list);
+extern int inode_table_insert(struct dentry *dentry, void *__table);
+extern u64 assign_inode_numbers(struct hlist_head *inode_list);
+extern int fix_inodes(struct inode_table *table, struct hlist_head *inode_list);
 
 
 /* header.c */
@@ -407,8 +409,10 @@ extern int write_integrity_table(FILE *out,
                                 struct resource_entry *integrity_res_entry,
                                 off_t new_lookup_table_end,
                                 off_t old_lookup_table_end,
-                                bool show_progress);
-extern int check_wim_integrity(WIMStruct *w, bool show_progress);
+                                wimlib_progress_func_t progress_func);
+
+extern int check_wim_integrity(WIMStruct *w,
+                              wimlib_progress_func_t progress_func);
 
 /* join.c */
 
@@ -434,7 +438,35 @@ extern int do_add_image(WIMStruct *w, const char *dir, const char *name,
                                     struct wim_security_data *,
                                     const struct capture_config *,
                                     int, void *),
-                       void *extra_arg);
+                       void *extra_arg,
+                       wimlib_progress_func_t progress_func);
+
+/* ntfs-apply.c */
+
+struct apply_args {
+       WIMStruct *w;
+       const char *target;
+       int extract_flags;
+       unsigned num_lutimes_warnings;
+       struct list_head *stream_list;
+       union wimlib_progress_info progress;
+#ifdef WITH_NTFS_3G
+       struct _ntfs_volume *vol;
+#endif
+       struct list_head empty_files;
+};
+
+extern int wim_apply_dentry_ntfs(struct dentry *dentry, void *arg);
+extern int wim_apply_dentry_timestamps(struct dentry *dentry, void *arg);
+
+/* ntfs-capture.c */
+int build_dentry_tree_ntfs(struct dentry **root_p,
+                          const char *device,
+                          struct lookup_table *lookup_table,
+                          struct wim_security_data *sd,
+                          const struct capture_config *config,
+                          int flags,
+                          void *extra_arg);
 
 /* resource.c */
 extern const u8 *get_resource_entry(const u8 *p, struct resource_entry *entry);
@@ -487,14 +519,6 @@ 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);
@@ -513,15 +537,14 @@ extern int open_wim_writable(WIMStruct *w, const char *path,
 /* Internal use only */
 #define WIMLIB_EXTRACT_FLAG_MULTI_IMAGE                0x80000000
 #define WIMLIB_EXTRACT_FLAG_NO_STREAMS         0x40000000
-#define WIMLIB_EXTRACT_MASK_PUBLIC             0x2fffffff
+#define WIMLIB_EXTRACT_MASK_PUBLIC             0x3fffffff
 
 
 /* write.c */
 extern int begin_write(WIMStruct *w, const char *path, int write_flags);
-extern int finish_write(WIMStruct *w, int image, int write_flags);
-
 
-#include "wimlib.h"
+extern int finish_write(WIMStruct *w, int image, int write_flags,
+                       wimlib_progress_func_t progress_func);
 
 #endif /* _WIMLIB_INTERNAL_H */
 
index 61a2996..a08bc85 100644 (file)
@@ -158,7 +158,7 @@ typedef int (*compress_func_t)(const void *, unsigned, void *, unsigned *);
 
 compress_func_t get_compress_func(int out_ctype)
 {
-       if (out_ctype == WIM_COMPRESSION_TYPE_LZX)
+       if (out_ctype == WIMLIB_COMPRESSION_TYPE_LZX)
                return lzx_compress;
        else
                return xpress_compress;
@@ -358,7 +358,7 @@ int write_wim_resource(struct lookup_table_entry *lte,
        struct chunk_table *chunk_tab = NULL;
        bool raw;
        off_t file_offset;
-       compress_func_t compress;
+       compress_func_t compress = NULL;
 #ifdef WITH_NTFS_3G
        ntfs_inode *ni = NULL;
 #endif
@@ -382,7 +382,7 @@ int write_wim_resource(struct lookup_table_entry *lte,
        /* Are the compression types the same?  If so, do a raw copy (copy
         * without decompressing and recompressing the data). */
        raw = (wim_resource_compression_type(lte) == out_ctype
-              && out_ctype != WIM_COMPRESSION_TYPE_NONE
+              && out_ctype != WIMLIB_COMPRESSION_TYPE_NONE
               && !(flags & WIMLIB_RESOURCE_FLAG_RECOMPRESS));
 
        if (raw) {
@@ -402,7 +402,7 @@ int write_wim_resource(struct lookup_table_entry *lte,
 
        /* If we are writing a compressed resource and not doing a raw copy, we
         * need to initialize the chunk table */
-       if (out_ctype != WIM_COMPRESSION_TYPE_NONE && !raw) {
+       if (out_ctype != WIMLIB_COMPRESSION_TYPE_NONE && !raw) {
                ret = begin_wim_resource_chunk_tab(lte, out_fp, file_offset,
                                                   &chunk_tab);
                if (ret != 0)
@@ -452,7 +452,7 @@ int write_wim_resource(struct lookup_table_entry *lte,
        /* Raw copy:  The new compressed size is the same as the old compressed
         * size
         *
-        * Using WIM_COMPRESSION_TYPE_NONE:  The new compressed size is the
+        * Using WIMLIB_COMPRESSION_TYPE_NONE:  The new compressed size is the
         * original size
         *
         * Using a different compression type:  Call
@@ -462,7 +462,7 @@ int write_wim_resource(struct lookup_table_entry *lte,
        if (raw) {
                new_compressed_size = old_compressed_size;
        } else {
-               if (out_ctype == WIM_COMPRESSION_TYPE_NONE)
+               if (out_ctype == WIMLIB_COMPRESSION_TYPE_NONE)
                        new_compressed_size = original_size;
                else {
                        ret = finish_wim_resource_chunk_tab(chunk_tab, out_fp,
@@ -494,7 +494,7 @@ int write_wim_resource(struct lookup_table_entry *lte,
        }
 
        if (!raw && new_compressed_size >= original_size &&
-           out_ctype != WIM_COMPRESSION_TYPE_NONE)
+           out_ctype != WIMLIB_COMPRESSION_TYPE_NONE)
        {
                /* Oops!  We compressed the resource to larger than the original
                 * size.  Write the resource uncompressed instead. */
@@ -504,7 +504,7 @@ int write_wim_resource(struct lookup_table_entry *lte,
                        ret = WIMLIB_ERR_WRITE;
                        goto out_fclose;
                }
-               ret = write_wim_resource(lte, out_fp, WIM_COMPRESSION_TYPE_NONE,
+               ret = write_wim_resource(lte, out_fp, WIMLIB_COMPRESSION_TYPE_NONE,
                                         out_res_entry, flags);
                if (ret != 0)
                        goto out_fclose;
@@ -519,7 +519,7 @@ int write_wim_resource(struct lookup_table_entry *lte,
                        out_res_entry->offset        = file_offset;
                        out_res_entry->flags         = lte->resource_entry.flags
                                                        & ~WIM_RESHDR_FLAG_COMPRESSED;
-                       if (out_ctype != WIM_COMPRESSION_TYPE_NONE)
+                       if (out_ctype != WIMLIB_COMPRESSION_TYPE_NONE)
                                out_res_entry->flags |= WIM_RESHDR_FLAG_COMPRESSED;
                }
        }
@@ -647,68 +647,61 @@ static void *compressor_thread_proc(void *arg)
                shared_queue_put(compressed_res_queue, msg);
        }
        DEBUG("Compressor thread terminating");
+       return NULL;
 }
 #endif
 
-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) %s (%u%% done)",
-                      *cur_size >> 20,
-                      total_size >> 20, op, *cur_percent);
-               fflush(stdout);
-               *next_size += one_percent;
-               (*cur_percent)++;
-       }
-       *cur_size += wim_resource_size(cur_lte);
-}
-
-void finish_stream_op_progress(u64 total_size, const char *op)
-{
-       printf("\r%"PRIu64" MiB of %"PRIu64" MiB "
-              "(uncompressed) %s (100%% done)\n",
-              total_size >> 20, total_size >> 20, op);
-       fflush(stdout);
-}
-
-static int write_stream_list_serial(struct list_head *stream_list,
-                                   FILE *out_fp, int out_ctype,
-                                   int write_flags, u64 total_size)
+static int do_write_stream_list(struct list_head *my_resources,
+                               FILE *out_fp,
+                               int out_ctype,
+                               wimlib_progress_func_t progress_func,
+                               union wimlib_progress_info *progress,
+                               int write_resource_flags)
 {
-       struct lookup_table_entry *lte;
        int ret;
+       struct lookup_table_entry *lte, *tmp;
 
-       u64 one_percent = total_size / 100;
-       u64 cur_size = 0;
-       u64 next_size = 0;
-       unsigned cur_percent = 0;
-       int write_resource_flags = 0;
-
-       if (write_flags & WIMLIB_WRITE_FLAG_RECOMPRESS)
-               write_resource_flags |= WIMLIB_RESOURCE_FLAG_RECOMPRESS;
-
-       list_for_each_entry(lte, stream_list, staging_list) {
-               if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS) {
-                       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,
+       list_for_each_entry_safe(lte, tmp, my_resources, staging_list) {
+               ret = write_wim_resource(lte,
+                                        out_fp,
+                                        out_ctype,
                                         &lte->output_resource_entry,
                                         write_resource_flags);
                if (ret != 0)
                        return ret;
+               list_del(&lte->staging_list);
+               progress->write_streams.completed_bytes +=
+                       wim_resource_size(lte);
+               progress->write_streams.completed_streams++;
+               if (progress_func) {
+                       progress_func(WIMLIB_PROGRESS_MSG_WRITE_STREAMS,
+                                     progress);
+               }
        }
-       if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS)
-               finish_stream_op_progress(total_size, "written");
        return 0;
 }
 
+static int write_stream_list_serial(struct list_head *stream_list,
+                                   FILE *out_fp,
+                                   int out_ctype,
+                                   int write_flags,
+                                   wimlib_progress_func_t progress_func,
+                                   union wimlib_progress_info *progress)
+{
+       int write_resource_flags;
+
+       if (write_flags & WIMLIB_WRITE_FLAG_RECOMPRESS)
+               write_resource_flags = WIMLIB_RESOURCE_FLAG_RECOMPRESS;
+       else
+               write_resource_flags = 0;
+       progress->write_streams.num_threads = 1;
+       if (progress_func)
+               progress_func(WIMLIB_PROGRESS_MSG_WRITE_STREAMS, progress);
+       return do_write_stream_list(stream_list, out_fp,
+                                   out_ctype, progress_func,
+                                   progress, write_resource_flags);
+}
+
 #ifdef ENABLE_MULTITHREADED_COMPRESSION
 static int write_wim_chunks(struct message *msg, FILE *out_fp,
                            struct chunk_table *chunk_tab)
@@ -751,7 +744,8 @@ static int main_writer_thread_proc(struct list_head *stream_list,
                                   struct shared_queue *compressed_res_queue,
                                   size_t queue_size,
                                   int write_flags,
-                                  u64 total_size)
+                                  wimlib_progress_func_t progress_func,
+                                  union wimlib_progress_info *progress)
 {
        int ret;
 
@@ -800,14 +794,8 @@ static int main_writer_thread_proc(struct list_head *stream_list,
 
        struct lookup_table_entry *cur_lte = next_lte;
        struct chunk_table *cur_chunk_tab = NULL;
-       struct lookup_table_entry *lte;
        struct message *msg;
 
-       u64 one_percent = total_size / 100;
-       u64 cur_size = 0;
-       u64 next_size = 0;
-       unsigned cur_percent = 0;
-
 #ifdef WITH_NTFS_3G
        ntfs_inode *ni = NULL;
 #endif
@@ -1010,15 +998,6 @@ static int main_writer_thread_proc(struct list_head *stream_list,
                        DEBUG2("Complete msg (begin_chunk=%"PRIu64")", msg->begin_chunk);
                        if (msg->begin_chunk == 0) {
                                DEBUG2("Begin chunk tab");
-                               if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS) {
-                                       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
                                // for the chunk table in the output file.
@@ -1059,6 +1038,14 @@ static int main_writer_thread_proc(struct list_head *stream_list,
                                if (ret != 0)
                                        goto out;
 
+                               progress->write_streams.completed_bytes +=
+                                               wim_resource_size(cur_lte);
+                               progress->write_streams.completed_streams++;
+
+                               if (progress_func) {
+                                       progress_func(WIMLIB_PROGRESS_MSG_WRITE_STREAMS,
+                                                     progress);
+                               }
 
                                cur_lte->output_resource_entry.size =
                                        res_csize;
@@ -1096,31 +1083,14 @@ static int main_writer_thread_proc(struct list_head *stream_list,
                                // to be compressed because the desired
                                // compression type is the same as the previous
                                // compression type).
-                               struct lookup_table_entry *tmp;
-                               list_for_each_entry_safe(lte,
-                                                        tmp,
-                                                        &my_resources,
-                                                        staging_list)
-                               {
-                                       if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS) {
-                                               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,
-                                                                0);
-                                       list_del(&lte->staging_list);
-                                       if (ret != 0)
-                                               goto out;
-                               }
+                               ret = do_write_stream_list(&my_resources,
+                                                          out_fp,
+                                                          out_ctype,
+                                                          progress_func,
+                                                          progress,
+                                                          0);
+                               if (ret != 0)
+                                       goto out;
                        }
                }
        }
@@ -1132,25 +1102,9 @@ out:
        end_wim_resource_read(cur_lte);
 #endif
        if (ret == 0) {
-               list_for_each_entry(lte, &my_resources, staging_list) {
-                       if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS) {
-                               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,
-                                                0);
-                       if (ret != 0)
-                               break;
-               }
-               if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS)
-                       finish_stream_op_progress(total_size, "written");
+               ret = do_write_stream_list(&my_resources, out_fp,
+                                          out_ctype, progress_func,
+                                          progress, 0);
        } else {
                size_t num_available_msgs = 0;
                struct list_head *cur;
@@ -1165,8 +1119,6 @@ out:
                }
        }
 
-       DEBUG("Freeing messages");
-
        for (size_t i = 0; i < ARRAY_LEN(msgs); i++) {
                for (size_t j = 0; j < MAX_CHUNKS_PER_MSG; j++) {
                        FREE(msgs[i].compressed_chunks[j]);
@@ -1180,22 +1132,13 @@ out:
 }
 
 
-static const char *get_data_type(int ctype)
-{
-       switch (ctype) {
-       case WIM_COMPRESSION_TYPE_NONE:
-               return "uncompressed";
-       case WIM_COMPRESSION_TYPE_LZX:
-               return "LZX-compressed";
-       case WIM_COMPRESSION_TYPE_XPRESS:
-               return "XPRESS-compressed";
-       }
-}
-
 static int write_stream_list_parallel(struct list_head *stream_list,
-                                     FILE *out_fp, int out_ctype,
-                                     int write_flags, u64 total_size,
-                                     unsigned num_threads)
+                                     FILE *out_fp,
+                                     int out_ctype,
+                                     int write_flags,
+                                     unsigned num_threads,
+                                     wimlib_progress_func_t progress_func,
+                                     union wimlib_progress_info *progress)
 {
        int ret;
        struct shared_queue res_to_compress_queue;
@@ -1212,6 +1155,7 @@ static int write_stream_list_parallel(struct list_head *stream_list,
                }
        }
 
+       progress->write_streams.num_threads = num_threads;
        wimlib_assert(stream_list->next != stream_list);
 
        static const double MESSAGES_PER_THREAD = 2.0;
@@ -1247,10 +1191,8 @@ static int write_stream_list_parallel(struct list_head *stream_list,
                }
        }
 
-       if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS) {
-               printf("Writing %s data using %u threads...\n",
-                      get_data_type(out_ctype), num_threads);
-       }
+       if (progress_func)
+               progress_func(WIMLIB_PROGRESS_MSG_WRITE_STREAMS, progress);
 
        ret = main_writer_thread_proc(stream_list,
                                      out_fp,
@@ -1259,8 +1201,8 @@ static int write_stream_list_parallel(struct list_head *stream_list,
                                      &compressed_res_queue,
                                      queue_size,
                                      write_flags,
-                                     total_size);
-
+                                     progress_func,
+                                     progress);
 out_join:
        for (unsigned i = 0; i < num_threads; i++)
                shared_queue_put(&res_to_compress_queue, NULL);
@@ -1279,8 +1221,13 @@ out_destroy_res_to_compress_queue:
                return ret;
 out_serial:
        WARNING("Falling back to single-threaded compression");
-       return write_stream_list_serial(stream_list, out_fp,
-                                       out_ctype, write_flags, total_size);
+       return write_stream_list_serial(stream_list,
+                                       out_fp,
+                                       out_ctype,
+                                       write_flags,
+                                       progress_func,
+                                       progress);
+
 }
 #endif
 
@@ -1290,61 +1237,62 @@ out_serial:
  */
 static int write_stream_list(struct list_head *stream_list, FILE *out_fp,
                             int out_ctype, int write_flags,
-                            unsigned num_threads)
+                            unsigned num_threads,
+                            wimlib_progress_func_t progress_func)
 {
        struct lookup_table_entry *lte;
        size_t num_streams = 0;
-       u64 total_size = 0;
+       u64 total_bytes = 0;
        bool compression_needed = false;
+       union wimlib_progress_info progress;
+       int ret;
 
        list_for_each_entry(lte, stream_list, staging_list) {
                num_streams++;
-               total_size += wim_resource_size(lte);
+               total_bytes += wim_resource_size(lte);
                if (!compression_needed
                    &&
-                   (out_ctype != WIM_COMPRESSION_TYPE_NONE
+                   (out_ctype != WIMLIB_COMPRESSION_TYPE_NONE
                       && (lte->resource_location != RESOURCE_IN_WIM
                           || wimlib_get_compression_type(lte->wim) != out_ctype
                           || (write_flags & WIMLIB_WRITE_FLAG_REBUILD)))
                    && wim_resource_size(lte) != 0)
                        compression_needed = true;
        }
+       progress.write_streams.total_bytes       = total_bytes;
+       progress.write_streams.total_streams     = num_streams;
+       progress.write_streams.completed_bytes   = 0;
+       progress.write_streams.completed_streams = 0;
+       progress.write_streams.num_threads       = num_threads;
+       progress.write_streams.compression_type  = out_ctype;
 
        if (num_streams == 0) {
-               if (write_flags & WIMLIB_WRITE_FLAG_VERBOSE)
-                       printf("No streams to write\n");
-               return 0;
-       }
-
-       if (write_flags & WIMLIB_WRITE_FLAG_VERBOSE) {
-               printf("Preparing to write %zu streams "
-                      "(%"PRIu64" total bytes uncompressed)\n",
-                      num_streams, total_size);
-               printf("Using compression type %s\n",
-                      wimlib_get_compression_type_string(out_ctype));
+               ret = 0;
+               goto out;
        }
 
 #ifdef ENABLE_MULTITHREADED_COMPRESSION
-       if (compression_needed && total_size >= 1000000 && num_threads != 1) {
-               return write_stream_list_parallel(stream_list, out_fp,
-                                                 out_ctype, write_flags,
-                                                 total_size, num_threads);
+       if (compression_needed && total_bytes >= 1000000 && num_threads != 1) {
+               ret = write_stream_list_parallel(stream_list,
+                                                out_fp,
+                                                out_ctype,
+                                                write_flags,
+                                                num_threads,
+                                                progress_func,
+                                                &progress);
        }
        else
 #endif
        {
-               if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS) {
-                       const char *reason = "";
-                       if (!compression_needed)
-                               reason = " (no compression needed)";
-                       printf("Writing %s data using 1 thread%s\n",
-                              get_data_type(out_ctype), reason);
-               }
-
-               return write_stream_list_serial(stream_list, out_fp,
-                                               out_ctype, write_flags,
-                                               total_size);
+               ret = write_stream_list_serial(stream_list,
+                                              out_fp,
+                                              out_ctype,
+                                              write_flags,
+                                              progress_func,
+                                              &progress);
        }
+out:
+       return ret;
 }
 
 
@@ -1369,7 +1317,8 @@ static int find_streams_to_write(WIMStruct *w)
 }
 
 static int write_wim_streams(WIMStruct *w, int image, int write_flags,
-                            unsigned num_threads)
+                            unsigned num_threads,
+                            wimlib_progress_func_t progress_func)
 {
 
        for_lookup_table_entry(w->lookup_table, lte_zero_out_refcnt, NULL);
@@ -1378,7 +1327,7 @@ static int write_wim_streams(WIMStruct *w, int image, int write_flags,
        for_image(w, image, find_streams_to_write);
        return write_stream_list(&stream_list, w->out_fp,
                                 wimlib_get_compression_type(w), write_flags,
-                                num_threads);
+                                num_threads, progress_func);
 }
 
 /*
@@ -1410,7 +1359,8 @@ static int write_wim_streams(WIMStruct *w, int image, int write_flags,
  *             fsync() the output file before closing it.
  *
  */
-int finish_write(WIMStruct *w, int image, int write_flags)
+int finish_write(WIMStruct *w, int image, int write_flags,
+                wimlib_progress_func_t progress_func)
 {
        int ret;
        struct wim_header hdr;
@@ -1462,7 +1412,6 @@ int finish_write(WIMStruct *w, int image, int write_flags)
 
                off_t old_lookup_table_end;
                off_t new_lookup_table_end;
-               bool show_progress;
                if (write_flags & WIMLIB_WRITE_FLAG_REUSE_INTEGRITY_TABLE) {
                        old_lookup_table_end = w->hdr.lookup_table_res_entry.offset +
                                               w->hdr.lookup_table_res_entry.size;
@@ -1471,13 +1420,12 @@ int finish_write(WIMStruct *w, int image, int write_flags)
                }
                new_lookup_table_end = hdr.lookup_table_res_entry.offset +
                                       hdr.lookup_table_res_entry.size;
-               show_progress = ((write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS) != 0);
 
                ret = write_integrity_table(out,
                                            &hdr.integrity,
                                            new_lookup_table_end,
                                            old_lookup_table_end,
-                                           show_progress);
+                                           progress_func);
                if (ret != 0)
                        goto out;
        } else {
@@ -1492,7 +1440,7 @@ int finish_write(WIMStruct *w, int image, int write_flags)
         * marked as bootable.  This is not well documented...
         */
        if (hdr.boot_idx == 0 || !w->image_metadata
-                       || (image != WIM_ALL_IMAGES && image != hdr.boot_idx)) {
+                       || (image != WIMLIB_ALL_IMAGES && image != hdr.boot_idx)) {
                memset(&hdr.boot_metadata_res_entry, 0,
                       sizeof(struct resource_entry));
        } else {
@@ -1503,7 +1451,7 @@ int finish_write(WIMStruct *w, int image, int write_flags)
        }
 
        /* Set image count and boot index correctly for single image writes */
-       if (image != WIM_ALL_IMAGES) {
+       if (image != WIMLIB_ALL_IMAGES) {
                hdr.image_count = 1;
                if (hdr.boot_idx == image)
                        hdr.boot_idx = 1;
@@ -1567,7 +1515,8 @@ int begin_write(WIMStruct *w, const char *path, int write_flags)
 
 /* Writes a stand-alone WIM to a file.  */
 WIMLIBAPI int wimlib_write(WIMStruct *w, const char *path,
-                          int image, int write_flags, unsigned num_threads)
+                          int image, int write_flags, unsigned num_threads,
+                          wimlib_progress_func_t progress_func)
 {
        int ret;
 
@@ -1576,7 +1525,7 @@ WIMLIBAPI int wimlib_write(WIMStruct *w, const char *path,
 
        write_flags &= WIMLIB_WRITE_MASK_PUBLIC;
 
-       if (image != WIM_ALL_IMAGES &&
+       if (image != WIMLIB_ALL_IMAGES &&
             (image < 1 || image > w->hdr.image_count))
                return WIMLIB_ERR_INVALID_IMAGE;
 
@@ -1585,29 +1534,26 @@ WIMLIBAPI int wimlib_write(WIMStruct *w, const char *path,
                return WIMLIB_ERR_SPLIT_UNSUPPORTED;
        }
 
-       if (image == WIM_ALL_IMAGES)
-               DEBUG("Writing all images to `%s'.", path);
-       else
-               DEBUG("Writing image %d to `%s'.", image, path);
-
        ret = begin_write(w, path, write_flags);
        if (ret != 0)
                goto out;
 
-       ret = write_wim_streams(w, image, write_flags, num_threads);
+       ret = write_wim_streams(w, image, write_flags, num_threads,
+                               progress_func);
        if (ret != 0)
                goto out;
 
-       if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS)
-               printf("Writing image metadata...\n");
+       if (progress_func)
+               progress_func(WIMLIB_PROGRESS_MSG_WRITE_METADATA_BEGIN, NULL);
 
        ret = for_image(w, image, write_metadata_resource);
        if (ret != 0)
                goto out;
 
-       ret = finish_write(w, image, write_flags);
-       if (ret == 0 && (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS))
-               printf("Successfully wrote `%s'\n", path);
+       if (progress_func)
+               progress_func(WIMLIB_PROGRESS_MSG_WRITE_METADATA_END, NULL);
+
+       ret = finish_write(w, image, write_flags, progress_func);
 out:
        close_wim_writable(w);
        return ret;
@@ -1705,6 +1651,7 @@ static int find_new_streams(struct lookup_table_entry *lte, void *arg)
  */
 static int overwrite_wim_inplace(WIMStruct *w, int write_flags,
                                 unsigned num_threads,
+                                wimlib_progress_func_t progress_func,
                                 int modified_image_idx)
 {
        int ret;
@@ -1781,7 +1728,8 @@ static int overwrite_wim_inplace(WIMStruct *w, int write_flags,
                      old_wim_end);
                ret = write_stream_list(&stream_list, w->out_fp,
                                        wimlib_get_compression_type(w),
-                                       write_flags, num_threads);
+                                       write_flags, num_threads,
+                                       progress_func);
                if (ret != 0)
                        goto out_ftruncate;
        } else {
@@ -1795,7 +1743,8 @@ static int overwrite_wim_inplace(WIMStruct *w, int write_flags,
                        goto out_ftruncate;
        }
        write_flags |= WIMLIB_WRITE_FLAG_REUSE_INTEGRITY_TABLE;
-       ret = finish_write(w, WIM_ALL_IMAGES, write_flags);
+       ret = finish_write(w, WIMLIB_ALL_IMAGES, write_flags,
+                          progress_func);
 out_ftruncate:
        close_wim_writable(w);
        if (ret != 0) {
@@ -1807,12 +1756,13 @@ out_ftruncate:
 }
 
 static int overwrite_wim_via_tmpfile(WIMStruct *w, int write_flags,
-                                    unsigned num_threads)
+                                    unsigned num_threads,
+                                    wimlib_progress_func_t progress_func)
 {
        size_t wim_name_len;
        int ret;
 
-       DEBUG("Overwrining `%s' via a temporary file", w->filename);
+       DEBUG("Overwriting `%s' via a temporary file", w->filename);
 
        /* Write the WIM to a temporary file in the same directory as the
         * original WIM. */
@@ -1822,9 +1772,9 @@ static int overwrite_wim_via_tmpfile(WIMStruct *w, int write_flags,
        randomize_char_array_with_alnum(tmpfile + wim_name_len, 9);
        tmpfile[wim_name_len + 9] = '\0';
 
-       ret = wimlib_write(w, tmpfile, WIM_ALL_IMAGES,
+       ret = wimlib_write(w, tmpfile, WIMLIB_ALL_IMAGES,
                           write_flags | WIMLIB_WRITE_FLAG_FSYNC,
-                          num_threads);
+                          num_threads, progress_func);
        if (ret != 0) {
                ERROR("Failed to write the WIM file `%s'", tmpfile);
                goto err;
@@ -1846,8 +1796,12 @@ static int overwrite_wim_via_tmpfile(WIMStruct *w, int write_flags,
                goto err;
        }
 
-       if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS)
-               printf("Successfully renamed `%s' to `%s'\n", tmpfile, w->filename);
+       if (progress_func) {
+               union wimlib_progress_info progress;
+               progress.rename.from = tmpfile;
+               progress.rename.to = w->filename;
+               progress_func(WIMLIB_PROGRESS_MSG_RENAME, &progress);
+       }
 
        /* Re-open the WIM read-only. */
        w->fp = fopen(w->filename, "rb");
@@ -1868,7 +1822,8 @@ err:
  * Writes a WIM file to the original file that it was read from, overwriting it.
  */
 WIMLIBAPI int wimlib_overwrite(WIMStruct *w, int write_flags,
-                              unsigned num_threads)
+                              unsigned num_threads,
+                              wimlib_progress_func_t progress_func)
 {
        if (!w)
                return WIMLIB_ERR_INVALID_PARAM;
@@ -1895,14 +1850,10 @@ WIMLIBAPI int wimlib_overwrite(WIMStruct *w, int write_flags,
                        ;
                if (i == w->hdr.image_count) {
                        return overwrite_wim_inplace(w, write_flags, num_threads,
+                                                    progress_func,
                                                     modified_image_idx);
                }
        }
-       return overwrite_wim_via_tmpfile(w, write_flags, num_threads);
-}
-
-/* Deprecated */
-WIMLIBAPI int wimlib_overwrite_xml_and_header(WIMStruct *wim, int write_flags)
-{
-       return wimlib_overwrite(wim, write_flags, 1);
+       return overwrite_wim_via_tmpfile(w, write_flags, num_threads,
+                                        progress_func);
 }
index f9e93fc..09f567e 100644 (file)
--- a/src/xml.c
+++ b/src/xml.c
@@ -1299,7 +1299,7 @@ int write_xml_data(const struct wim_info *wim_info, int image, FILE *out,
        size_t bytes_written;
        off_t start_offset, end_offset;
 
-       wimlib_assert(image == WIM_ALL_IMAGES ||
+       wimlib_assert(image == WIMLIB_ALL_IMAGES ||
                        (wim_info != NULL && image >= 1 &&
                         image <= wim_info->num_images));
 
@@ -1353,7 +1353,7 @@ int write_xml_data(const struct wim_info *wim_info, int image, FILE *out,
        if (wim_info != NULL) {
                DEBUG("Writing %d <IMAGE> elements", (int)wim_info->num_images);
                for (int i = 1; i <= (int)wim_info->num_images; i++) {
-                       if (image != WIM_ALL_IMAGES && i != image)
+                       if (image != WIMLIB_ALL_IMAGES && i != image)
                                continue;
                        DEBUG("Writing <IMAGE> element for image %d", i);
                        ret = xml_write_image_info(writer, &wim_info->images[i - 1]);