]> wimlib.net Git - wimlib/commitdiff
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 1835be1cc9f704580ce9f8d9e6e1a53617d0a150..5bcf8c1fc415843a069d9907883c5999200bafc3 100644 (file)
@@ -33,8 +33,6 @@ libwim_la_SOURCES =           \
        src/lzx.h               \
        src/modify.c            \
        src/mount.c             \
        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            \
        src/resource.c          \
        src/rbtree.c            \
        src/rbtree.h            \
@@ -58,6 +56,12 @@ libwim_la_SOURCES =          \
        src/xpress-decomp.c     \
        src/xpress.h
 
        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
 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 30f02dbfd477140d7f9a5a9519b208066ace001c..3651a6bb49db1f3703db65c1f9d81213372faab3 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.
 
        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:
        A possible bug with changing the bootable image of a WIM was fixed.
 
 Version 1.1.0:
index 9b8af6e047d3caf16baaa544e9faefd4d55421f0..883b1e0527a55fc34f957995aec314790671582d 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)
 {
 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"
                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)
 {
 
 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;
        }
                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)
 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)
        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)
        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);
        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;
 }
 
        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,
 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,
                }
                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;
        }
                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;
 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;
        int image;
        int num_images;
        WIMStruct *w;
        int ret;
        const char *wimfile;
-       const char *dir;
+       const char *target;
        const char *image_num_or_name;
        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;
 
        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";
        wimfile = argv[0];
        if (argc == 2) {
                image_num_or_name = "1";
-               dir = argv[1];
+               target = argv[1];
        } else {
                image_num_or_name = 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;
 
        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;
 
 #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)) {
        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) {
                }
        } 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 = -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) {
 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;
 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;
        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);
                        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':
                                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;
                        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);
                        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;
        }
                usage(cmd);
                return -1;
        }
-       dir = argv[0];
+       source = argv[0];
        wimfile = argv[1];
 
        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;
 
        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)
        }
 
        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)
        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;
 
 #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)) {
        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) {
                }
        } 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 = -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);
        if (ret != 0)
                goto out;
        cur_image = wimlib_get_num_images(w);
@@ -644,10 +759,11 @@ out_write:
                        goto out;
        }
        if (cmd == APPEND) {
                        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 {
        } 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;
        }
        if (ret == WIMLIB_ERR_REOPEN)
                ret = 0;
@@ -663,8 +779,8 @@ out:
 static int imagex_delete(int argc, const char **argv)
 {
        int c;
 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;
        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;
 
        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;
 
        if (ret != 0)
                return ret;
 
@@ -719,7 +836,7 @@ static int imagex_delete(int argc, const char **argv)
                goto out;
        }
 
                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) {
        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];
        }
 
        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;
 
        if (ret != 0)
                return ret;
 
@@ -786,10 +904,10 @@ out:
 static int imagex_export(int argc, const char **argv)
 {
        int c;
 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 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;
        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);
                        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;
                                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,
        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;
 
        if (ret != 0)
                return ret;
 
@@ -868,7 +987,8 @@ static int imagex_export(int argc, const char **argv)
                        ret = -1;
                        goto out;
                }
                        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;
 
                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,
 
        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)
        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
        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;
 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;
        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;
 
        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;
 
        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 (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)
                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;
        }
 
                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 "
                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 */
 
 
                /* 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;
                }
 
                        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)
                        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;
                }
                        imagex_error("Modifying a split WIM is not supported.");
                        return -1;
                }
-               if (image == WIM_ALL_IMAGES)
+               if (image == WIMLIB_ALL_IMAGES)
                        image = 1;
 
                        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;
                        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) {
 
                        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;
                        }
 
                        } 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 {
                        if (ret == WIMLIB_ERR_REOPEN)
                                ret = 0;
                } else {
@@ -1212,13 +1334,15 @@ out:
 static int imagex_join(int argc, const char **argv)
 {
        int c;
 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':
        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;
                        break;
                default:
                        goto err;
@@ -1228,12 +1352,13 @@ static int imagex_join(int argc, const char **argv)
        argv += optind;
 
        if (argc < 2) {
        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];
                             "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;
 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 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;
        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];
 
 
        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;
 
        if (ret != 0)
                return ret;
 
@@ -1331,8 +1456,8 @@ static int imagex_mount_rw_or_ro(int argc, const char **argv)
                        return ret;
        }
 
                        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);
        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;
 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;
        int ret;
        WIMStruct *w;
        const char *wimfile;
@@ -1388,7 +1512,8 @@ static int imagex_optimize(int argc, const char **argv)
 
        wimfile = argv[0];
 
 
        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;
 
        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);
 
        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);
 
        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;
 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;
        unsigned long part_size;
        char *tmp;
+       int ret;
+       WIMStruct *w;
 
        for_opt(c, split_options) {
                switch (c) {
                case 'c':
 
        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);
                        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;
        }
                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. */
 }
 
 /* Unmounts an image. */
@@ -1481,7 +1615,7 @@ static int imagex_unmount(int argc, const char **argv)
                return -1;
        }
 
                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;
        if (ret != 0)
                imagex_error("Failed to unmount `%s'", argv[0]);
        return ret;
index 2e2ba8bf23d128529a4b5b2702f76cdfc539f87a..afa6aaa4f5747e0cdbb6b017ea40cd899af3f290 100644 (file)
@@ -157,6 +157,8 @@ struct dentry {
        u16 file_name_utf8_len;
 
        u8 is_extracted : 1;
        u16 file_name_utf8_len;
 
        u8 is_extracted : 1;
+       u8 visited : 1;
+       u8 canonical : 1;
 
        /* Byte 40 */
 
 
        /* Byte 40 */
 
@@ -253,7 +255,7 @@ struct inode {
        u8 verified : 1;
 
        /* temporary flag */
        u8 verified : 1;
 
        /* temporary flag */
-       u8 found    : 1;
+       u8 visited    : 1;
 
        /* Number of alternate data streams associated with this inode */
        u16 num_ads;
 
        /* 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;
        /* List of dentries that reference this inode (there should be
         * link_count of them) */
        struct list_head dentry_list;
+
        struct hlist_node hlist;
        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
        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);  \
        })
 
                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,
 static inline bool dentry_is_first_in_inode(const struct dentry *dentry)
 {
        return container_of(dentry->d_inode->dentry_list.next,
index 90b6ce39eca37c69e36b420a6a775c65c21c8eab..a3f00cc845f8eb4c561e2842969b5fb564fc05ba 100644 (file)
@@ -44,6 +44,7 @@
 #include <utime.h>
 #endif
 
 #include <utime.h>
 #endif
 
+
 #include <unistd.h>
 
 #include "dentry.h"
 #include <unistd.h>
 
 #include "dentry.h"
 #include "wimlib_internal.h"
 #include "xml.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,
                                       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) */
                                       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'",
                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;
 
                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 =
                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--;
                }
                        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;
                }
                                         buf, lte->extracted_file);
                        return WIMLIB_ERR_LINK;
                }
-
        }
        return 0;
 }
 
        }
        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,
                                         const char *output_path,
-                                        int extract_flags,
                                         struct lookup_table_entry *lte)
 {
        /* Normal mode of extraction.  Regular files and hard links are
                                         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;
 
        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
                                     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;
        }
                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);
 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.
  */
 /*
  * 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;
 
 {
        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) {
                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;
                }
        }
                } 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,
 {
        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);
        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;
        }
                                 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;
 }
 
        return 0;
 }
 
@@ -282,58 +279,55 @@ static int extract_directory(const char *output_path, bool is_root)
        return 0;
 }
 
        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().
  */
 /*
  * 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;
        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 (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;
 
                        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);
                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';
 
        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
        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 */
 }
 
 /* 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;
 
        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';
 
        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;
 }
 
        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;
 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;
 
        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]);
        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",
        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;
 }
 
        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 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) {
        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))
                {
                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 {
                } 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,
 }
 
 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;
 {
        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)
 
        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) {
 
        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)
        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:
        }
 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. */
 }
 
 
 /* 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 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;
 
        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;
 
        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++) {
        buf[output_path_len] = '/';
        for (image = 1; image <= w->hdr.image_count; image++) {
-
                image_name = wimlib_get_image_name(w, 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);
                }
                        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;
        }
                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,
 
 /* 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,
                                   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;
 
 {
        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;
                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;
 
                        == (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;
        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;
        }
 
                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;
                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;
        } 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 |
        }
 
        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);
        }
                                       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 69d4f695dbbdf0a4be057ecf404abb8904dbf100..2a7fe32b5fbaac0318b83d6937b5c2349dcd0d91 100644 (file)
@@ -197,14 +197,14 @@ int init_header(struct wim_header *hdr, int ctype)
 {
        memset(hdr, 0, sizeof(struct wim_header));
        switch (ctype) {
 {
        memset(hdr, 0, sizeof(struct wim_header));
        switch (ctype) {
-       case WIM_COMPRESSION_TYPE_NONE:
+       case WIMLIB_COMPRESSION_TYPE_NONE:
                hdr->flags = 0;
                break;
                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;
                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;
                hdr->flags = WIM_HDR_FLAG_COMPRESSION |
                             WIM_HDR_FLAG_COMPRESS_XPRESS;
                break;
index d7f81eb60a436aafaaf96ce9d5237bfb1b23ec00..67f2133041f63434c04d542839821a2dd7fc2dfa 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.
  *
  *     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
  *
  * @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,
                                     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;
                                     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;
        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;
 
        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;
                        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)))
                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;
                                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;
                *integrity_table_ret = new_table;
-       }
+       else
+               FREE(new_table);
        return ret;
 }
 
        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.
  *
  *     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:
  *
  * 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,
                          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;
 {
        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,
 
        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;
 
        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).
  *
  *     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
  *
  * 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.
  */
  *     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];
 {
        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)
        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 (!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;
                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;
 }
 
        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.
  *
  * @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
  *
  * 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.
  */
  *     -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;
 {
        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;
                                   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;
 }
        FREE(table);
        return ret;
 }
index 222c9a9a8e81411405d08f25be93c847018dc45c..34e5df91ab4e694b8585fdc5d9a820b149110cf6 100644 (file)
 #include "xml.h"
 #include <stdlib.h>
 
 #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 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
  * 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.
  *
  * 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;
 
        int ret;
        unsigned i;
 
-
        table = new_lookup_table(9001);
        if (!table)
                return WIMLIB_ERR_NOMEM;
        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)
        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;
        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++) {
        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]->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]);
                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;
                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,
 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 ret;
-       int write_flags = 0;
        WIMStruct *joined_wim = NULL;
        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;
 
                return WIMLIB_ERR_INVALID_PARAM;
 
+       WIMStruct *swms[num_swms];
        ZERO_ARRAY(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;
 
                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;
                 * 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;
 
        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;
                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;
        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:
-       /* 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]);
                wimlib_free(swms[i]);
-       }
-       joined_wim->out_fp = NULL;
        wimlib_free(joined_wim);
        return ret;
 }
        wimlib_free(joined_wim);
        return ret;
 }
index d1be89b81228fa321e85f39fdd644b0c34ffe06c..364f469ed08ab7a89426d72f6d41df8868385023 100644 (file)
@@ -626,7 +626,7 @@ out:
 }
 #endif
 
 }
 #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;
 
 {
        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,
  */
 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);
 {
        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);
 }
 
                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 4458cc7ef1a146c1c59d9e100f710a84a5288ccb..592116bcf55d60ef082f9bd5d48caac7bc218edb 100644 (file)
@@ -185,24 +185,22 @@ struct lookup_table_entry {
                struct resource_entry output_resource_entry;
 
                struct list_head msg_list;
                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)
 };
 
 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)
 {
        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);
 }
 
        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 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);
 
 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);
 
 inode_unnamed_lte(const struct inode *inode,
                  const struct lookup_table *table);
 
+extern u64 lookup_table_total_stream_size(struct lookup_table *table);
+
 
 #endif
 
 #endif
index 3180c507a71116f88a23a1b7682673d6dbec281f..a8ce13caabb08b8b31737f26387eacd7a46287db 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,
                                  WIMStruct *dest_wim,
                                  const char *dest_name,
                                  const char *dest_description,
-                                 int flags,
+                                 int export_flags,
                                  WIMStruct **additional_swms,
                                  WIMStruct **additional_swms,
-                                 unsigned num_additional_swms)
+                                 unsigned num_additional_swms,
+                                 wimlib_progress_func_t progress_func)
 {
        int i;
        int ret;
 {
        int i;
        int ret;
@@ -502,12 +503,12 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
                return WIMLIB_ERR_SPLIT_UNSUPPORTED;
        }
 
                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 (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
                              (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++) {
                                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)
 
                                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,
 
                                ret = wimlib_export_image(src_wim, i, dest_wim,
                                                          NULL, NULL,
-                                                         export_flags,
+                                                         new_flags,
                                                          additional_swms,
                                                          additional_swms,
-                                                         num_additional_swms);
+                                                         num_additional_swms,
+                                                         progress_func);
                                if (ret != 0)
                                        return ret;
                        }
                                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));
 
        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);
                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;
        }
        ret = 0;
        goto out;
@@ -661,7 +663,7 @@ WIMLIBAPI int wimlib_delete_image(WIMStruct *w, int image)
                return WIMLIB_ERR_SPLIT_UNSUPPORTED;
        }
 
                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)
                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--;
 
        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);
 
        /* 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;
        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;
 
        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;
        }
        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;
        }
                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);
        }
                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);
        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;
 
        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) {
                              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;
        }
 
                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)
        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 (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],
        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;
 }
        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 15d7444ed3036dc182712bed85fde61feaefc77e..67a6eddbe97433caed27554932216999624a737f 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);
 
 
        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;
        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];
 {
        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, ",
        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;
 
        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 (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;
        }
                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;
        }
 
                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)))
                       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");
 
 
        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 */
        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";
 
                argv[argc++] = "-s";
 
-       if (flags & WIMLIB_MOUNT_FLAG_DEBUG)
+       if (mount_flags & WIMLIB_MOUNT_FLAG_DEBUG)
                argv[argc++] = "-d";
 
        /*
                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;
        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)
                /* 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. */
 #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;
        }
                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;
 
        /* Finish initializing the filesystem context. */
        ctx.wim = wim;
-       ctx.mount_flags = flags;
+       ctx.mount_flags = mount_flags;
 
        DEBUG("Calling fuse_main()");
 
 
        DEBUG("Calling fuse_main()");
 
@@ -2029,9 +2029,9 @@ out:
 
 /*
  * Unmounts the WIM file that was previously mounted on @dir by using
 
 /*
  * 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;
 {
        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. */
 
        /* 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 "),
 
        DEBUG("Sending message: %scommit, %scheck",
                        (msg[0] ? "" : "don't "),
@@ -2208,14 +2208,14 @@ static inline int mount_unsupported_error()
        return WIMLIB_ERR_UNSUPPORTED;
 }
 
        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();
 }
 
 {
        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();
 }
 {
        return mount_unsupported_error();
 }
index 32d981082da0a9e0edb4754904fe09f62561f296..61199b81ac3c154220f8738c1de13a78f5e7f018 100644 (file)
 
 #include "config.h"
 
 
 #include "config.h"
 
-#ifdef WITH_NTFS_3G
+
 #include <ntfs-3g/endians.h>
 #include <ntfs-3g/types.h>
 #include <ntfs-3g/endians.h>
 #include <ntfs-3g/types.h>
-#endif
 
 #include "wimlib_internal.h"
 
 #include "wimlib_internal.h"
-
-
-#ifdef WITH_NTFS_3G
 #include "dentry.h"
 #include "lookup_table.h"
 #include "io.h"
 #include "dentry.h"
 #include "lookup_table.h"
 #include "io.h"
 #include <stdlib.h>
 #include <unistd.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.
  */
 /*
  * 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.
  *
  * @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,
  *
  * 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;
 {
        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;
 
                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. */
 
                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;
                        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)
                        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,
 }
 
 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;
 
 {
        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);
 
 
        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;
        }
                                 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,
        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
 
 /*
  * 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,
  */
 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;
 {
        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 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;
                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,
                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;
                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
  *
  * @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,
  *
  * @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;
 {
        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,
                 * (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;
                }
                        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))) {
         * */
        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;
        }
 
 
                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) {
        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;
        }
                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 */
 }
 
 /* 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;
        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;
 
        char orig;
        const char *dir_name;
 
-       if (dentry_is_extracted(dentry))
+       if (dentry->is_extracted)
                return 0;
 
                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);
 
 
        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;
        }
                                 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;
 
        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);
        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;
 }
        }
        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 fb670dc0183845e08f8e2349bc1c8b4cc6434295..c4770a5dc3ae22ca4b20f478e6aa8b491a6bb79d 100644 (file)
 
 #include "config.h"
 
 
 #include "config.h"
 
-#ifdef WITH_NTFS_3G
 #include <ntfs-3g/endians.h>
 #include <ntfs-3g/types.h>
 #include <ntfs-3g/endians.h>
 #include <ntfs-3g/types.h>
-#endif
 
 #include "wimlib_internal.h"
 
 
 
 #include "wimlib_internal.h"
 
 
-#ifdef WITH_NTFS_3G
 #include "dentry.h"
 #include "lookup_table.h"
 #include "io.h"
 #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;
 }
 
        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;
 {
        ntfs_volume *vol;
        ntfs_inode *root_ni;
@@ -721,34 +718,3 @@ out:
        }
        return ret;
 }
        }
        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 c29ed4fb76d54985100304c592cec514d3d18452..86a2be6a18922c720f1f5b2e4b3be95bb0d25a19 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. */
 
        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;
                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);
 
 
                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)
                              (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);
                        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.
  *
  * 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)
 {
  */
 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;
        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);
        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", "
 
        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
 
        /* 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 df384f82d30fdd0bddc10083f5a17e66a3ed7da7..091fa3fecf124585a4364fd051ea83ace5830724 100644 (file)
@@ -33,25 +33,22 @@ struct split_args {
        char *swm_base_name;
        size_t swm_base_name_len;
        const char *swm_suffix;
        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;
        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,
 };
 
 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;
 
 {
        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)
        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;
        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)
 }
 
 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. */
 
                /* 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;
                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",
 
                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)
 
                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->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. */
        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;
 {
        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;
        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)
        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, '.');
 
        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;
        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;
 
        w->write_metadata = true;
-       LIST_HEAD(lte_list);
        for (int i = 0; i < w->hdr.image_count; i++) {
                struct lookup_table_entry *metadata_lte;
        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)
                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;
 
        }
        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)
        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)
        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. */
 
        /* 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++) {
        for (int i = 1; i <= total_parts; i++) {
-               const char *p;
+               const char *part_name;
                if (i == 1) {
                if (i == 1) {
-                       p = swm_name;
+                       part_name = swm_name;
                } else {
                } 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) {
                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);
                }
                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'",
                                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 f40915fde0cbb2e2f4eaff4a42d8a80fb0b2a7fb..9dd9718d9500e03f574e175d33dd1b488ae12184 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.
  * 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;
 
        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) {
                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)
 {
        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)
                else if (wim_hdr_flags & WIM_HDR_FLAG_COMPRESS_XPRESS)
-                       return WIM_COMPRESSION_TYPE_XPRESS;
+                       return WIMLIB_COMPRESSION_TYPE_XPRESS;
                else
                else
-                       return WIM_COMPRESSION_TYPE_INVALID;
+                       return WIMLIB_COMPRESSION_TYPE_INVALID;
        } else {
        } 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 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);
                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) {
 WIMLIBAPI const char *wimlib_get_compression_type_string(int ctype)
 {
        switch (ctype) {
-               case WIM_COMPRESSION_TYPE_NONE:
+               case WIMLIB_COMPRESSION_TYPE_NONE:
                        return "None";
                        return "None";
-               case WIM_COMPRESSION_TYPE_LZX:
+               case WIMLIB_COMPRESSION_TYPE_LZX:
                        return "LZX";
                        return "LZX";
-               case WIM_COMPRESSION_TYPE_XPRESS:
+               case WIMLIB_COMPRESSION_TYPE_XPRESS:
                        return "XPRESS";
                default:
                        return "Invalid";
                        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)
        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)
 
        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)
        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++) {
                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;
                }
                                   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;
        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;
                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)
 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.
  */
  * 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;
 {
        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;
        }
 
                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;
                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) {
        }
 
        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);
                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);
 
        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,
 
        /* 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;*/
 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;*/
 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,
  * 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;
 {
        WIMStruct *w;
        int ret;
@@ -628,7 +629,7 @@ WIMLIBAPI int wimlib_open_wim(const char *wim_file, int open_flags,
                return WIMLIB_ERR_NOMEM;
        }
 
                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 {
        if (ret == 0) {
                *w_ret = w;
        } else {
index 0618ff3801114645820b0584e99afeb6eb9dca88..ed1e44948b425185eb8d6a349f739cda8203f916 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
  *
  * 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
  *
  * 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,
  *
  * 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
  *
  * 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.
  *
  * 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.
  *
  * 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.
  * \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 <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;
 /**
  * Opaque structure that represents a WIM file.
  */
 typedef struct WIMStruct WIMStruct;
-#endif
 
 /**
  * Specifies the compression type of a WIM file.
  */
 
 /**
  * Specifies the compression type of a WIM file.
  */
-
-enum wim_compression_type {
+enum wimlib_compression_type {
        /** An invalid compression type. */
        /** An invalid compression type. */
-       WIM_COMPRESSION_TYPE_INVALID = -1,
+       WIMLIB_COMPRESSION_TYPE_INVALID = -1,
 
        /** The WIM does not include any compressed resources. */
 
        /** 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. */
 
        /** 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. */
 
        /** 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. */
 /** 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()).*/
 
 /** 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. */
 
 /** 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. */
 
 /** 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. */
 
 /** 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. */
 
 /** 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. */
 
 /** 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()). */
 
 /** 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. */
 
 /** 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
 
 /** 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. */
  * 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.
 
 /**
  * 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. */
 
 
 /** 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. */
 
 /** 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.
 
 /**
  * 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.
  *
  * 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.
  * @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.
  *
  *     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
  *     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
  *     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
  *
  * @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
  * @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.
  * @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,
  */
 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
 
 /**
  * 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
  * @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
  *     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.
  */
  * @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.
  *
  * 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
  * @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
  *     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.
  *
  * 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 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
  * @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
  *
  * 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.
  * 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.
  *
  * 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
  * @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
  * @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
  *     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.
  *     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
  *     ::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
  *     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.
  *     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
  *
  * @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
  *     @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
  *     @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.
  *     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,
  */
 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,
                               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.
 
 /**
  * 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
  *     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.
  *
  *     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
  * @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.
  *
  *     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
  * @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,
  *     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,
                                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
 
 /**
  * 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
  *     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);
 
  */
 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
  * 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",
  *
  * @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);
 
 /**
 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 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 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
  *
  * @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_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
  *
  * 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,
  */
 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.
  *
 
 /**
  * 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.
  *
  *
  * 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.)
  *
  * 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
  * 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.
  * 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.
  *     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
  *     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.
  *     ::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
  * @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
  * @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.
  */
  *     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.
 
 /**
  * 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.
  *     ::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.)
  *
  *     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
  * @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
  *     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.
  *     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
  * @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
  *     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
  *     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.
  */
  * @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.
 
 /**
  * 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
  * 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
  *
  * @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 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:
  *
  * @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,
  *     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.
 
 /**
  * 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
  *     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
  *     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
  *     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
  *
  * @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
  *     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
  * @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,
  *     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
  *
  * @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
  *     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
  * @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
  *     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
  *
  * @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);
  *     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.
  *
 /**
  * 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.
  * @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 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
  *
  * @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.
  *
  *
  * 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
  *
  * 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 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.
  *
  *     ::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.
  */
  *     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
  *
  * @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
  * @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
  *     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
  * @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
  *
  * @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
  *     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
  * @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,
  *     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 */
 
 #endif /* _WIMLIB_H */
-
index 49d1cbbc9751eb6c226a4fc764510963b795387b..87829957e3fbfdc7b8212a9b1cdd9c0cab313d6b 100644 (file)
@@ -39,6 +39,8 @@ struct stat;
 struct dentry;
 struct inode;
 
 struct dentry;
 struct inode;
 
+#include "wimlib.h"
+
 #define WIM_MAGIC_LEN  8
 #define WIM_GID_LEN    16
 #define WIM_UNUSED_LEN 60
 #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;
 };
 
        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);
 }
 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 */
 
 
 /* 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,
                                 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 */
 
 
 /* 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 *),
                                     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);
 
 /* 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);
 
                             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);
 /* 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
 /* 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);
 
 
 /* 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 */
 
 
 #endif /* _WIMLIB_INTERNAL_H */
 
index 61a29962f6916521bc1ca255ccb7b39bc2162cb0..a08bc8503a6c5a57f908ab7f535787205fe3fded 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)
 {
 
 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;
                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;
        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
 #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
        /* 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) {
               && !(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 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)
                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
         *
        /* 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
         * 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 (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,
                        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 &&
        }
 
        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. */
        {
                /* 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 = 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;
                                         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;
                        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;
                }
        }
                                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");
                shared_queue_put(compressed_res_queue, msg);
        }
        DEBUG("Compressor thread terminating");
+       return NULL;
 }
 #endif
 
 }
 #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;
        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;
                                         &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;
 }
 
        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)
 #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,
                                   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;
 
 {
        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 *cur_lte = next_lte;
        struct chunk_table *cur_chunk_tab = NULL;
-       struct lookup_table_entry *lte;
        struct message *msg;
 
        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
 #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");
                        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.
 
                                // 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;
 
                                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;
 
                                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).
                                // 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) {
        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;
        } 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]);
        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,
 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;
 {
        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;
        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,
 
        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,
                                      &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);
 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 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
 
 }
 #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,
  */
 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;
 {
        struct lookup_table_entry *lte;
        size_t num_streams = 0;
-       u64 total_size = 0;
+       u64 total_bytes = 0;
        bool compression_needed = false;
        bool compression_needed = false;
+       union wimlib_progress_info progress;
+       int ret;
 
        list_for_each_entry(lte, stream_list, staging_list) {
                num_streams++;
 
        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
                    &&
                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;
        }
                       && (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 (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
        }
 
 #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
        {
        }
        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,
 }
 
 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);
 {
 
        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,
        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.
  *
  */
  *             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;
 {
        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;
 
                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;
                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;
                }
                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,
 
                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 {
                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
         * 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 {
                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 */
        }
 
        /* 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;
                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,
 
 /* 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;
 
 {
        int ret;
 
@@ -1576,7 +1525,7 @@ WIMLIBAPI int wimlib_write(WIMStruct *w, const char *path,
 
        write_flags &= WIMLIB_WRITE_MASK_PUBLIC;
 
 
        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;
 
             (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;
        }
 
                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 = 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 (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 = 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;
 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,
  */
 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;
                                 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),
                      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 {
                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;
                        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) {
 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,
 }
 
 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;
 
 {
        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. */
 
        /* 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';
 
        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,
                           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;
        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;
        }
 
                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");
 
        /* 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,
  * 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;
 {
        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,
                        ;
                if (i == w->hdr.image_count) {
                        return overwrite_wim_inplace(w, write_flags, num_threads,
+                                                    progress_func,
                                                     modified_image_idx);
                }
        }
                                                     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 f9e93fc36c1b6d6fedcdfc2ca3a4f192fb118384..09f567e368a8933502354847ae8e5016ac3e4519 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;
 
        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));
 
                        (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 (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]);
                                continue;
                        DEBUG("Writing <IMAGE> element for image %d", i);
                        ret = xml_write_image_info(writer, &wim_info->images[i - 1]);