resource reading cleanups
authorEric Biggers <ebiggers3@gmail.com>
Sat, 30 May 2015 20:48:09 +0000 (15:48 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Fri, 5 Jun 2015 03:05:36 +0000 (22:05 -0500)
20 files changed:
Makefile.am
include/wimlib/apply.h
include/wimlib/callback.h [deleted file]
include/wimlib/ntfs_3g.h
include/wimlib/reparse.h
include/wimlib/resource.h
include/wimlib/win32.h
src/blob_table.c
src/extract.c
src/metadata_resource.c
src/mount_image.c
src/ntfs-3g_apply.c
src/ntfs-3g_capture.c
src/reparse.c
src/resource.c
src/unix_apply.c
src/verify.c
src/win32_apply.c
src/win32_capture.c
src/write.c

index 0169882..206a0c2 100644 (file)
@@ -98,7 +98,6 @@ libwim_la_SOURCES =           \
        include/wimlib/bitops.h         \
        include/wimlib/blob_table.h     \
        include/wimlib/bt_matchfinder.h \
-       include/wimlib/callback.h       \
        include/wimlib/capture.h        \
        include/wimlib/case.h           \
        include/wimlib/compiler.h       \
index e4c741b..2d706b4 100644 (file)
@@ -32,7 +32,7 @@ struct wim_features {
 };
 
 struct blob_descriptor;
-struct read_blob_list_callbacks;
+struct read_blob_callbacks;
 struct apply_operations;
 struct wim_dentry;
 
@@ -69,7 +69,7 @@ struct apply_ctx {
        unsigned long invalid_sequence;
        unsigned long num_blobs_remaining;
        struct list_head blob_list;
-       const struct read_blob_list_callbacks *saved_cbs;
+       const struct read_blob_callbacks *saved_cbs;
        struct blob_descriptor *cur_blob;
        u64 cur_blob_offset;
        struct filedes tmpfile_fd;
@@ -140,8 +140,7 @@ report_apply_error(struct apply_ctx *ctx, int error_code, const tchar *path)
                         struct wim_dentry, d_extraction_alias_node)
 
 extern int
-extract_blob_list(struct apply_ctx *ctx,
-                   const struct read_blob_list_callbacks *cbs);
+extract_blob_list(struct apply_ctx *ctx, const struct read_blob_callbacks *cbs);
 
 /*
  * Represents an extraction backend.
diff --git a/include/wimlib/callback.h b/include/wimlib/callback.h
deleted file mode 100644 (file)
index e83ff68..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef _WIMLIB_CALLBACK_H
-#define _WIMLIB_CALLBACK_H
-
-#include <stddef.h>
-
-/* Callback for processing a chunk of data.  Returns 0 on success, or an error
- * code on failure.  */
-typedef int (*consume_data_callback_t)(const void *chunk, size_t size, void *ctx);
-
-#endif
index 2641801..0ee9da2 100644 (file)
@@ -3,18 +3,18 @@
 
 #ifdef WITH_NTFS_3G
 
-#include "wimlib/callback.h"
 #include "wimlib/types.h"
 
 struct blob_descriptor;
 struct ntfs_location;
+struct read_blob_callbacks;
 
 extern void
 libntfs3g_global_init(void);
 
 extern int
 read_ntfs_attribute_prefix(const struct blob_descriptor *blob, u64 size,
-                          consume_data_callback_t cb, void *cb_ctx);
+                          const struct read_blob_callbacks *cbs);
 
 extern struct ntfs_location *
 clone_ntfs_location(const struct ntfs_location *loc);
index 43adbd5..b931835 100644 (file)
@@ -89,7 +89,7 @@ make_reparse_buffer(const struct reparse_data * restrict rpdata,
 #ifndef __WIN32__
 ssize_t
 wim_inode_readlink(const struct wim_inode * restrict inode, char * restrict buf,
-                  size_t buf_len, struct blob_descriptor *blob);
+                  size_t buf_len, const struct blob_descriptor *blob);
 
 extern int
 wim_inode_set_symlink(struct wim_inode *inode, const char *target,
index 39b32de..5cfbd45 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef _WIMLIB_RESOURCE_H
 #define _WIMLIB_RESOURCE_H
 
-#include "wimlib/callback.h"
 #include "wimlib/list.h"
 #include "wimlib/sha1.h"
 #include "wimlib/types.h"
@@ -108,15 +107,6 @@ struct wim_reshdr {
  * identifies the main entry for a solid resource.  */
 #define SOLID_RESOURCE_MAGIC_NUMBER    0x100000000ULL
 
-/* Returns true if the specified WIM resource is compressed (may be either solid
- * or non-solid)  */
-static inline bool
-resource_is_compressed(const struct wim_resource_descriptor *rdesc)
-{
-       return (rdesc->flags & (WIM_RESHDR_FLAG_COMPRESSED |
-                               WIM_RESHDR_FLAG_SOLID));
-}
-
 static inline void
 copy_reshdr(struct wim_reshdr *dest, const struct wim_reshdr *src)
 {
@@ -130,14 +120,14 @@ zero_reshdr(struct wim_reshdr *reshdr)
 }
 
 extern void
-wim_res_hdr_to_desc(const struct wim_reshdr *reshdr, WIMStruct *wim,
-                   struct wim_resource_descriptor *rdesc);
+wim_reshdr_to_desc(const struct wim_reshdr *reshdr, WIMStruct *wim,
+                  struct wim_resource_descriptor *rdesc);
 
 extern void
 get_wim_reshdr(const struct wim_reshdr_disk *disk_reshdr,
               struct wim_reshdr *reshdr);
 
-void
+extern void
 put_wim_reshdr(const struct wim_reshdr *reshdr,
               struct wim_reshdr_disk *disk_reshdr);
 
@@ -178,84 +168,80 @@ get_chunk_entry_size(u64 res_size, bool is_alt)
 
 extern int
 read_partial_wim_blob_into_buf(const struct blob_descriptor *blob,
-                              size_t size, u64 offset, void *buf);
+                              u64 offset, size_t size, void *buf);
 
 extern int
-read_full_blob_into_buf(const struct blob_descriptor *blob, void *buf);
+read_blob_into_buf(const struct blob_descriptor *blob, void *buf);
 
 extern int
-read_full_blob_into_alloc_buf(const struct blob_descriptor *blob, void **buf_ret);
+read_blob_into_alloc_buf(const struct blob_descriptor *blob, void **buf_ret);
 
 extern int
-wim_reshdr_to_data(const struct wim_reshdr *reshdr,
-                  WIMStruct *wim, void **buf_ret);
+wim_reshdr_to_data(const struct wim_reshdr *reshdr, WIMStruct *wim,
+                  void **buf_ret);
 
 extern int
 wim_reshdr_to_hash(const struct wim_reshdr *reshdr, WIMStruct *wim,
                   u8 hash[SHA1_HASH_SIZE]);
 
 extern int
-skip_wim_resource(struct wim_resource_descriptor *rdesc);
-
-/*
- * Type of callback function for beginning to read a blob.
- *
- * @blob:
- *     Blob that is about to be read.
- *
- * @ctx:
- *     User-provided context.
- *
- * Must return 0 on success, a positive error code on failure, or the special
- * value BEGIN_BLOB_STATUS_SKIP_BLOB to indicate that the blob should not be
- * read, and read_blob_list() should continue on to the next blob (without
- * calling @consume_chunk or @end_blob).
- */
-typedef int (*read_blob_list_begin_blob_t)(struct blob_descriptor *blob, void *ctx);
-
-#define BEGIN_BLOB_STATUS_SKIP_BLOB    -1
-
-/*
- * Type of callback function for finishing reading a blob.
- *
- * @blob:
- *     Blob that has been fully read, or blob that started being read but could
- *     not be fully read due to a read error.
- *
- * @status:
- *     0 if reading the blob was successful; otherwise a nonzero error code
- *     that specifies the return status.
- *
- * @ctx:
- *     User-provided context.
- */
-typedef int (*read_blob_list_end_blob_t)(struct blob_descriptor *blob,
-                                        int status,
-                                        void *ctx);
-
-
-/* Callback functions and contexts for read_blob_list().  */
-struct read_blob_list_callbacks {
-
-       /* Called when a blob is about to be read.  */
-       read_blob_list_begin_blob_t begin_blob;
-
-       /* Called when a chunk of data has been read.  */
-       consume_data_callback_t consume_chunk;
-
-       /* Called when a blob has been fully read.  A successful call to
-        * @begin_blob will always be matched by a call to @end_blob.  */
-       read_blob_list_end_blob_t end_blob;
+skip_wim_resource(const struct wim_resource_descriptor *rdesc);
+
+/* Callback functions for reading blobs  */
+struct read_blob_callbacks {
+
+       /* Called when starting to read a blob.  Must return 0 on success, or a
+        * positive wimlib error code on failure, or in the case of
+        * read_blob_list(), the special value BEGIN_BLOB_STATUS_SKIP_BLOB which
+        * indicates that the data for this blob should not be read.  */
+       int (*begin_blob)(struct blob_descriptor *blob, void *ctx);
+#define BEGIN_BLOB_STATUS_SKIP_BLOB    (-1)
+
+       /* Called when the next chunk of uncompressed data is available.  'size'
+        * is guaranteed to be nonzero.  Must return 0 on success, or a positive
+        * wimlib error code on failure.  */
+       int (*consume_chunk)(const void *chunk, size_t size, void *ctx);
+
+       /* Called when a blob has been successfully read (status=0), or when
+        * begin_blob() was successfully called but an error occurred before the
+        * blob was fully read (status != 0; in this case the implementation
+        * should do cleanup and then pass on the status).  Must return 0 on
+        * success, or a positive wimlib error code on failure.  */
+       int (*end_blob)(struct blob_descriptor *blob, int status, void *ctx);
+
+       /* Parameter passed to each of the callback functions.  */
+       void *ctx;
+};
 
-       /* Parameter passed to @begin_blob.  */
-       void *begin_blob_ctx;
+/* Call cbs->begin_blob() if present.  */
+static inline int
+call_begin_blob(struct blob_descriptor *blob,
+               const struct read_blob_callbacks *cbs)
+{
+       if (!cbs->begin_blob)
+               return 0;
+       return (*cbs->begin_blob)(blob, cbs->ctx);
+}
 
-       /* Parameter passed to @consume_chunk.  */
-       void *consume_chunk_ctx;
+/* Call cbs->consume_chunk() if present.  */
+static inline int
+call_consume_chunk(const void *chunk, size_t size,
+                  const struct read_blob_callbacks *cbs)
+{
+       if (!cbs->consume_chunk)
+               return 0;
+       return (*cbs->consume_chunk)(chunk, size, cbs->ctx);
+}
 
-       /* Parameter passed to @end_blob.  */
-       void *end_blob_ctx;
-};
+/* Call cbs->end_blob() if present.  */
+static inline int
+call_end_blob(struct blob_descriptor *blob, int status,
+             const struct read_blob_callbacks *cbs)
+{
+       if (!cbs->end_blob)
+               return status;
+       return (*cbs->end_blob)(blob, status, cbs->ctx);
+}
 
 /* Flags for read_blob_list()  */
 #define VERIFY_BLOB_HASHES             0x1
@@ -264,19 +250,22 @@ struct read_blob_list_callbacks {
 
 extern int
 read_blob_list(struct list_head *blob_list, size_t list_head_offset,
-              const struct read_blob_list_callbacks *cbs, int flags);
+              const struct read_blob_callbacks *cbs, int flags);
 
-/* Functions to extract blobs.  */
+extern int
+read_blob_with_cbs(struct blob_descriptor *blob,
+                  const struct read_blob_callbacks *cbs);
 
 extern int
-extract_blob(struct blob_descriptor *blob, u64 size,
-            consume_data_callback_t extract_chunk, void *extract_chunk_arg);
+read_blob_with_sha1(struct blob_descriptor *blob,
+                   const struct read_blob_callbacks *cbs);
 
 extern int
-extract_blob_to_fd(struct blob_descriptor *blob, struct filedes *fd, u64 size);
+extract_blob_prefix_to_fd(struct blob_descriptor *blob, u64 size,
+                         struct filedes *fd);
 
 extern int
-extract_full_blob_to_fd(struct blob_descriptor *blob, struct filedes *fd);
+extract_blob_to_fd(struct blob_descriptor *blob, struct filedes *fd);
 
 /* Miscellaneous blob functions.  */
 
index c76a7ff..96d2ebd 100644 (file)
@@ -3,20 +3,19 @@
 
 #ifdef __WIN32__
 
-#include "wimlib/callback.h"
 #include "wimlib/types.h"
 
 struct blob_descriptor;
+struct read_blob_callbacks;
 
 extern int
 read_winnt_stream_prefix(const struct blob_descriptor *blob, u64 size,
-                        consume_data_callback_t cb, void *cb_ctx);
+                        const struct read_blob_callbacks *cbs);
 
 extern int
 read_win32_encrypted_file_prefix(const struct blob_descriptor *blob,
                                 u64 size,
-                                consume_data_callback_t cb,
-                                void *cb_ctx);
+                                const struct read_blob_callbacks *cbs);
 
 extern int
 win32_global_init(int init_flags);
index 3e9f9b4..aa73cc0 100644 (file)
@@ -611,7 +611,7 @@ do_load_solid_info(WIMStruct *wim, struct wim_resource_descriptor **rdescs,
 
                rdesc = rdescs[i];
 
-               wim_res_hdr_to_desc(&reshdr, wim, rdesc);
+               wim_reshdr_to_desc(&reshdr, wim, rdesc);
 
                /* For solid resources, the uncompressed size, compression type,
                 * and chunk size are stored in the resource itself, not in the
@@ -969,7 +969,7 @@ read_blob_table(WIMStruct *wim)
                        if (!rdesc)
                                goto oom;
 
-                       wim_res_hdr_to_desc(&reshdr, wim, rdesc);
+                       wim_reshdr_to_desc(&reshdr, wim, rdesc);
 
                        blob_set_is_located_in_nonsolid_wim_resource(cur_blob, rdesc);
                }
index 533e848..efce477 100644 (file)
@@ -191,8 +191,7 @@ read_error:
 }
 
 static int
-read_blobs_from_pipe(struct apply_ctx *ctx,
-                    const struct read_blob_list_callbacks *cbs)
+read_blobs_from_pipe(struct apply_ctx *ctx, const struct read_blob_callbacks *cbs)
 {
        int ret;
        u8 hash[SHA1_HASH_SIZE];
@@ -234,24 +233,14 @@ read_blobs_from_pipe(struct apply_ctx *ctx,
                if (ret)
                        return ret;
 
-               wim_res_hdr_to_desc(&reshdr, ctx->wim, &rdesc);
+               wim_reshdr_to_desc(&reshdr, ctx->wim, &rdesc);
 
                if (!(rdesc.flags & WIM_RESHDR_FLAG_METADATA)
                    && (blob = lookup_blob(ctx->wim->blob_table, hash))
                    && (blob->out_refcnt))
                {
                        blob_set_is_located_in_nonsolid_wim_resource(blob, &rdesc);
-
-                       ret = (*cbs->begin_blob)(blob, cbs->begin_blob_ctx);
-
-                       if (!ret) {
-                               ret = extract_blob(blob, blob->size,
-                                                  cbs->consume_chunk,
-                                                  cbs->consume_chunk_ctx);
-
-                               ret = (*cbs->end_blob)(blob, ret,
-                                                      cbs->end_blob_ctx);
-                       }
+                       ret = read_blob_with_sha1(blob, cbs);
                        blob_unset_is_located_in_wim_resource(blob);
                        if (ret)
                                return ret;
@@ -315,8 +304,8 @@ begin_extract_blob_wrapper(struct blob_descriptor *blob, void *_ctx)
 
        if (unlikely(blob->out_refcnt > MAX_OPEN_FILES))
                return create_temporary_file(&ctx->tmpfile_fd, &ctx->tmpfile_name);
-       else
-               return (*ctx->saved_cbs->begin_blob)(blob, ctx->saved_cbs->begin_blob_ctx);
+
+       return call_begin_blob(blob, ctx->saved_cbs);
 }
 
 static int
@@ -391,10 +380,9 @@ extract_chunk_wrapper(const void *chunk, size_t size, void *_ctx)
                                         ctx->tmpfile_name);
                }
                return ret;
-       } else {
-               return (*ctx->saved_cbs->consume_chunk)(chunk, size,
-                                                       ctx->saved_cbs->consume_chunk_ctx);
        }
+
+       return call_consume_chunk(chunk, size, ctx->saved_cbs);
 }
 
 static int
@@ -402,7 +390,7 @@ extract_from_tmpfile(const tchar *tmpfile_name, struct apply_ctx *ctx)
 {
        struct blob_descriptor tmpfile_blob;
        struct blob_descriptor *orig_blob = ctx->cur_blob;
-       const struct read_blob_list_callbacks *cbs = ctx->saved_cbs;
+       const struct read_blob_callbacks *cbs = ctx->saved_cbs;
        int ret;
        const u32 orig_refcnt = orig_blob->out_refcnt;
 
@@ -426,7 +414,7 @@ extract_from_tmpfile(const tchar *tmpfile_name, struct apply_ctx *ctx)
                 * blob descriptor to callbacks provided by the extraction
                 * backend as opposed to the tmpfile blob descriptor, since they
                 * shouldn't actually read data from the blob other than through
-                * the read_blob_prefix() call below.  But for
+                * the read_blob_with_cbs() call below.  But for
                 * WIMLIB_EXTRACT_FLAG_WIMBOOT mode on Windows it does matter
                 * because it needs access to the original WIM resource
                 * descriptor in order to create the external backing reference.
@@ -435,17 +423,17 @@ extract_from_tmpfile(const tchar *tmpfile_name, struct apply_ctx *ctx)
                orig_blob->out_refcnt = 1;
                orig_blob->inline_blob_extraction_targets[0] = targets[i];
 
-               ret = (*cbs->begin_blob)(orig_blob, cbs->begin_blob_ctx);
+               ret = call_begin_blob(orig_blob, cbs);
                if (ret)
                        break;
 
-               /* Extra SHA-1 isn't necessary here, but it shouldn't hurt as
-                * this case is very rare anyway.  */
-               ret = extract_blob(&tmpfile_blob, tmpfile_blob.size,
-                                  cbs->consume_chunk,
-                                  cbs->consume_chunk_ctx);
+               struct read_blob_callbacks wrapper_cbs = {
+                       .consume_chunk  = cbs->consume_chunk,
+                       .ctx            = cbs->ctx,
+               };
+               ret = read_blob_with_cbs(&tmpfile_blob, &wrapper_cbs);
 
-               ret = (*cbs->end_blob)(orig_blob, ret, cbs->end_blob_ctx);
+               ret = call_end_blob(orig_blob, ret, cbs);
                if (ret)
                        break;
        }
@@ -467,10 +455,9 @@ end_extract_blob_wrapper(struct blob_descriptor *blob, int status, void *_ctx)
                tunlink(ctx->tmpfile_name);
                FREE(ctx->tmpfile_name);
                return status;
-       } else {
-               return (*ctx->saved_cbs->end_blob)(blob, status,
-                                                  ctx->saved_cbs->end_blob_ctx);
        }
+
+       return call_end_blob(blob, status, ctx->saved_cbs);
 }
 
 /*
@@ -481,8 +468,7 @@ end_extract_blob_wrapper(struct blob_descriptor *blob, int status, void *_ctx)
  *
  * This also handles sending WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS.
  *
- * This also works if the WIM is being read from a pipe, whereas attempting to
- * read blobs directly (e.g. with read_full_blob_into_buf()) will not.
+ * This also works if the WIM is being read from a pipe.
  *
  * This also will split up blobs that will need to be extracted to more than
  * MAX_OPEN_FILES locations, as measured by the 'out_refcnt' of each blob.
@@ -492,16 +478,13 @@ end_extract_blob_wrapper(struct blob_descriptor *blob, int status, void *_ctx)
  * destination file system might not support hard links).
  */
 int
-extract_blob_list(struct apply_ctx *ctx,
-                 const struct read_blob_list_callbacks *cbs)
+extract_blob_list(struct apply_ctx *ctx, const struct read_blob_callbacks *cbs)
 {
-       struct read_blob_list_callbacks wrapper_cbs = {
-               .begin_blob        = begin_extract_blob_wrapper,
-               .begin_blob_ctx    = ctx,
-               .consume_chunk     = extract_chunk_wrapper,
-               .consume_chunk_ctx = ctx,
-               .end_blob          = end_extract_blob_wrapper,
-               .end_blob_ctx      = ctx,
+       struct read_blob_callbacks wrapper_cbs = {
+               .begin_blob     = begin_extract_blob_wrapper,
+               .consume_chunk  = extract_chunk_wrapper,
+               .end_blob       = end_extract_blob_wrapper,
+               .ctx            = ctx,
        };
        ctx->saved_cbs = cbs;
        if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_FROM_PIPE) {
@@ -545,7 +528,7 @@ extract_dentry_to_stdout(struct wim_dentry *dentry,
        }
 
        filedes_init(&_stdout, STDOUT_FILENO);
-       return extract_full_blob_to_fd(blob, &_stdout);
+       return extract_blob_to_fd(blob, &_stdout);
 }
 
 static int
@@ -1975,7 +1958,7 @@ wimlib_extract_image_from_pipe_with_progress(int pipe_fd,
                metadata_rdesc = MALLOC(sizeof(struct wim_resource_descriptor));
                if (!metadata_rdesc)
                        goto out_wimlib_free;
-               wim_res_hdr_to_desc(&reshdr, pwm, metadata_rdesc);
+               wim_reshdr_to_desc(&reshdr, pwm, metadata_rdesc);
                blob_set_is_located_in_nonsolid_wim_resource(imd->metadata_blob,
                                                             metadata_rdesc);
 
index 1394ef9..a3faa9c 100644 (file)
@@ -81,7 +81,7 @@ read_metadata_resource(struct wim_image_metadata *imd)
        DEBUG("Reading metadata resource (size=%"PRIu64").", metadata_blob->size);
 
        /* Read the metadata resource into memory.  (It may be compressed.)  */
-       ret = read_full_blob_into_alloc_buf(metadata_blob, &buf);
+       ret = read_blob_into_alloc_buf(metadata_blob, &buf);
        if (ret)
                return ret;
 
index 8037a38..d9aa23c 100644 (file)
@@ -717,7 +717,7 @@ extract_blob_to_staging_dir(struct wim_inode *inode,
                filedes_init(&fd, staging_fd);
                errno = 0;
                extract_size = min(old_blob->size, size);
-               result = extract_blob_to_fd(old_blob, &fd, extract_size);
+               result = extract_blob_prefix_to_fd(old_blob, extract_size, &fd);
        } else {
                extract_size = 0;
                result = 0;
@@ -1311,9 +1311,9 @@ wimfs_getxattr(const char *path, const char *name, char *value,
               size_t size)
 {
        const struct wimfs_context *ctx = wimfs_get_context();
-       struct wim_inode *inode;
-       struct wim_inode_stream *strm;
-       struct blob_descriptor *blob;
+       const struct wim_inode *inode;
+       const struct wim_inode_stream *strm;
+       const struct blob_descriptor *blob;
 
        if (!strncmp(name, "wimfs.", 6)) {
                /* Handle some magical extended attributes.  These really should
@@ -1386,7 +1386,7 @@ wimfs_getxattr(const char *path, const char *name, char *value,
                if (size < blob->size)
                        return -ERANGE;
 
-               if (read_full_blob_into_buf(blob, value))
+               if (read_blob_into_buf(blob, value))
                        return errno ? -errno : -EIO;
        }
        return blob->size;
@@ -1669,7 +1669,7 @@ wimfs_read(const char *path, char *buf, size_t size,
 
        switch (blob->blob_location) {
        case BLOB_IN_WIM:
-               if (read_partial_wim_blob_into_buf(blob, size, offset, buf))
+               if (read_partial_wim_blob_into_buf(blob, offset, size, buf))
                        ret = errno ? -errno : -EIO;
                else
                        ret = size;
index 690c220..3a02812 100644 (file)
@@ -947,13 +947,11 @@ ntfs_3g_extract(struct list_head *dentry_list, struct apply_ctx *_ctx)
                goto out_unmount;
 
        /* Extract blobs.  */
-       struct read_blob_list_callbacks cbs = {
-               .begin_blob        = ntfs_3g_begin_extract_blob,
-               .begin_blob_ctx    = ctx,
-               .consume_chunk     = ntfs_3g_extract_chunk,
-               .consume_chunk_ctx = ctx,
-               .end_blob          = ntfs_3g_end_extract_blob,
-               .end_blob_ctx      = ctx,
+       struct read_blob_callbacks cbs = {
+               .begin_blob     = ntfs_3g_begin_extract_blob,
+               .consume_chunk  = ntfs_3g_extract_chunk,
+               .end_blob       = ntfs_3g_end_extract_blob,
+               .ctx            = ctx,
        };
        ret = extract_blob_list(&ctx->common, &cbs);
 
index ab20511..6994978 100644 (file)
@@ -106,7 +106,7 @@ open_ntfs_attr(ntfs_inode *ni, const struct ntfs_location *loc)
 
 int
 read_ntfs_attribute_prefix(const struct blob_descriptor *blob, u64 size,
-                          consume_data_callback_t cb, void *cb_ctx)
+                          const struct read_blob_callbacks *cbs)
 {
        const struct ntfs_location *loc = blob->ntfs_loc;
        ntfs_volume *vol = loc->volume->vol;
@@ -143,7 +143,7 @@ read_ntfs_attribute_prefix(const struct blob_descriptor *blob, u64 size,
                }
                pos += to_read;
                bytes_remaining -= to_read;
-               ret = cb(buf, to_read, cb_ctx);
+               ret = call_consume_chunk(buf, to_read, cbs);
                if (ret)
                        goto out_close_ntfs_attr;
        }
index 0ae053b..620684a 100644 (file)
@@ -149,6 +149,9 @@ make_reparse_buffer(const struct reparse_data * restrict rpdata,
        return 0;
 }
 
+/* UNIX version of getting and setting the data in reparse points */
+#ifndef __WIN32__
+
 /*
  * Read the reparse data from a WIM inode that is a reparse point.
  *
@@ -165,9 +168,9 @@ static int
 wim_inode_get_reparse_data(const struct wim_inode * restrict inode,
                           u8 * restrict rpbuf,
                           u16 * restrict rpbuflen_ret,
-                          struct blob_descriptor *blob_override)
+                          const struct blob_descriptor *blob_override)
 {
-       struct blob_descriptor *blob;
+       const struct blob_descriptor *blob;
        int ret;
        struct reparse_buffer_disk *rpbuf_disk;
        u16 rpdatalen;
@@ -197,7 +200,7 @@ wim_inode_get_reparse_data(const struct wim_inode * restrict inode,
        rpdatalen = blob->size;
 
        /* Read the reparse data from blob  */
-       ret = read_full_blob_into_buf(blob, rpbuf + REPARSE_DATA_OFFSET);
+       ret = read_blob_into_buf(blob, rpbuf + REPARSE_DATA_OFFSET);
        if (ret)
                return ret;
 
@@ -218,9 +221,6 @@ wim_inode_get_reparse_data(const struct wim_inode * restrict inode,
        return 0;
 }
 
-/* UNIX version of getting and setting the data in reparse points */
-#ifndef __WIN32__
-
 static const utf16lechar volume_junction_prefix[11] = {
        cpu_to_le16('\\'),
        cpu_to_le16('?'),
@@ -338,7 +338,7 @@ parse_substitute_name(const utf16lechar *substitute_name,
 ssize_t
 wim_inode_readlink(const struct wim_inode * restrict inode,
                   char * restrict buf, size_t bufsize,
-                  struct blob_descriptor *blob_override)
+                  const struct blob_descriptor *blob_override)
 {
        int ret;
        struct reparse_buffer_disk rpbuf_disk _aligned_attribute(8);
index eac8089..74c9bb8 100644 (file)
 /*
  *                         Compressed WIM resources
  *
- * A compressed resource in a WIM consists of a number of compressed chunks,
- * each of which decompresses to a fixed chunk size (given in the WIM header;
- * usually 32768) except possibly the last, which always decompresses to any
- * remaining bytes.  In addition, immediately before the chunks, a table (the
- * "chunk table") provides the offset, in bytes relative to the end of the chunk
- * table, of the start of each compressed chunk, except for the first chunk
- * which is omitted as it always has an offset of 0.  Therefore, a compressed
- * resource with N chunks will have a chunk table with N - 1 entries.
+ * A compressed resource in a WIM consists of a sequence of chunks.  Each chunk
+ * decompresses to the same size except possibly for the last, which
+ * decompresses to the remaining size.  Chunks that did not compress to less
+ * than their original size are stored uncompressed.
  *
- * Additional information:
+ * We support three variations on this resource format, independently of the
+ * compression type and chunk size which can vary as well:
  *
- * - Entries in the chunk table are 4 bytes each, except if the uncompressed
- *   size of the resource is greater than 4 GiB, in which case the entries in
- *   the chunk table are 8 bytes each.  In either case, the entries are unsigned
- *   little-endian integers.
+ * - Original resource format: immediately before the compressed chunks, the
+ *   "chunk table" provides the offset, in bytes relative to the end of the
+ *   chunk table, of the start of each compressed chunk, except for the first
+ *   chunk which is omitted as it always has an offset of 0.  Chunk table
+ *   entries are 32-bit for resources <= 4 GiB uncompressed and 64-bit for
+ *   resources > 4 GiB uncompressed.
  *
- * - The chunk table is included in the compressed size of the resource provided
- *   in the corresponding entry in the WIM's blob table.
+ * - Solid resource format (distinguished by the use of WIM_RESHDR_FLAG_SOLID
+ *   instead of WIM_RESHDR_FLAG_COMPRESSED): similar to the original format, but
+ *   the resource begins with a 16-byte header which specifies the uncompressed
+ *   size of the resource, the compression type, and the chunk size.  (In the
+ *   original format, these values were instead determined from outside the
+ *   resource itself, from the blob table and the WIM file header.) In addition,
+ *   in this format the entries in the chunk table contain compressed chunk
+ *   sizes rather than offsets.  As a consequence of this, the chunk table
+ *   entries are always 32-bit and there is an entry for chunk 0.
  *
- * - The compressed size of a chunk is never greater than the uncompressed size.
- *   From the compressor's point of view, chunks that would have compressed to a
- *   size greater than or equal to their original size are in fact stored
- *   uncompressed.  From the decompresser's point of view, chunks with
- *   compressed size equal to their uncompressed size are in fact uncompressed.
- *
- * Furthermore, wimlib supports its own "pipable" WIM format, and for this the
- * structure of compressed resources was modified to allow piped reading and
- * writing.  To make sequential writing possible, the chunk table is placed
- * after the chunks rather than before the chunks, and to make sequential
- * reading possible, each chunk is prefixed with a 4-byte header giving its
- * compressed size as a 32-bit, unsigned, little-endian integer.  Otherwise the
- * details are the same.
+ * - Pipable resource format (wimlib extension; all resources in a pipable WIM
+ *   have this format): similar to the original format, but the chunk table is
+ *   at the end of the resource rather than the beginning, and each compressed
+ *   chunk is prefixed with its compressed size as a 32-bit integer.  This
+ *   format allows a resource to be written without rewinding.
  */
 
 
@@ -86,8 +84,6 @@ struct data_range {
 };
 
 /*
- * read_compressed_wim_resource() -
- *
  * Read data from a compressed WIM resource.
  *
  * @rdesc
@@ -97,13 +93,11 @@ struct data_range {
  *     read, sorted by increasing offset.
  * @num_ranges
  *     Number of ranges in @ranges; must be at least 1.
- * @cb
- *     Callback function to feed the data being read.  Each call provides the
- *     next chunk of the requested data, uncompressed.  Each chunk will be of
- *     nonzero size and will not cross range boundaries, but otherwise will be
- *     of unspecified size.
- * @cb_ctx
- *     Parameter to pass to @cb_ctx.
+ * @cbs
+ *     Structure which provides the consume_chunk() callback to feed the data
+ *     being read.  Each call provides the next chunk of the requested data,
+ *     uncompressed.  Each chunk will be nonempty and will not cross range
+ *     boundaries but otherwise will be of unspecified size.
  *
  * Possible return values:
  *
@@ -112,19 +106,17 @@ struct data_range {
  *     WIMLIB_ERR_UNEXPECTED_END_OF_FILE (errno set to 0)
  *     WIMLIB_ERR_NOMEM                  (errno set to ENOMEM)
  *     WIMLIB_ERR_DECOMPRESSION          (errno set to EINVAL)
+ *     WIMLIB_ERR_INVALID_CHUNK_SIZE     (errno set to EINVAL)
  *
- *     or other error code returned by the @cb function.
+ *     or other error code returned by the cbs->consume_chunk() function.
  */
 static int
 read_compressed_wim_resource(const struct wim_resource_descriptor * const rdesc,
                             const struct data_range * const ranges,
                             const size_t num_ranges,
-                            const consume_data_callback_t cb,
-                            void * const cb_ctx)
+                            const struct read_blob_callbacks *cbs)
 {
        int ret;
-       int errno_save;
-
        u64 *chunk_offsets = NULL;
        u8 *ubuf = NULL;
        void *cbuf = NULL;
@@ -134,17 +126,10 @@ read_compressed_wim_resource(const struct wim_resource_descriptor * const rdesc,
        struct wimlib_decompressor *decompressor = NULL;
 
        /* Sanity checks  */
-       wimlib_assert(rdesc != NULL);
-       wimlib_assert(resource_is_compressed(rdesc));
-       wimlib_assert(cb != NULL);
        wimlib_assert(num_ranges != 0);
        for (size_t i = 0; i < num_ranges; i++) {
-               DEBUG("Range %zu/%zu: %"PRIu64"@+%"PRIu64" / %"PRIu64,
-                     i + 1, num_ranges, ranges[i].size, ranges[i].offset,
-                     rdesc->uncompressed_size);
-               wimlib_assert(ranges[i].size != 0);
-               wimlib_assert(ranges[i].offset + ranges[i].size >= ranges[i].size);
-               wimlib_assert(ranges[i].offset + ranges[i].size <= rdesc->uncompressed_size);
+               wimlib_assert(ranges[i].offset + ranges[i].size > ranges[i].offset &&
+                             ranges[i].offset + ranges[i].size <= rdesc->uncompressed_size);
        }
        for (size_t i = 0; i < num_ranges - 1; i++)
                wimlib_assert(ranges[i].offset + ranges[i].size <= ranges[i + 1].offset);
@@ -176,18 +161,18 @@ read_compressed_wim_resource(const struct wim_resource_descriptor * const rdesc,
                cur_read_offset += sizeof(struct alt_chunk_table_header_disk);
        }
 
-       if (!is_power_of_2(chunk_size)) {
+       if (unlikely(!is_power_of_2(chunk_size))) {
                ERROR("Invalid compressed resource: "
                      "expected power-of-2 chunk size (got %"PRIu32")",
                      chunk_size);
                ret = WIMLIB_ERR_INVALID_CHUNK_SIZE;
                errno = EINVAL;
-               goto out_free_memory;
+               goto out_cleanup;
        }
 
        /* Get valid decompressor.  */
-       if (ctype == rdesc->wim->decompressor_ctype &&
-           chunk_size == rdesc->wim->decompressor_max_block_size)
+       if (likely(ctype == rdesc->wim->decompressor_ctype &&
+                  chunk_size == rdesc->wim->decompressor_max_block_size))
        {
                /* Cached decompressor.  */
                decompressor = rdesc->wim->decompressor;
@@ -196,10 +181,10 @@ read_compressed_wim_resource(const struct wim_resource_descriptor * const rdesc,
        } else {
                ret = wimlib_create_decompressor(ctype, chunk_size,
                                                 &decompressor);
-               if (ret) {
+               if (unlikely(ret)) {
                        if (ret != WIMLIB_ERR_NOMEM)
                                errno = EINVAL;
-                       goto out_free_memory;
+                       goto out_cleanup;
                }
        }
 
@@ -282,14 +267,16 @@ read_compressed_wim_resource(const struct wim_resource_descriptor * const rdesc,
                        max(num_chunk_entries_to_read,
                            num_needed_chunk_offsets) * sizeof(chunk_offsets[0]);
 
-               if ((size_t)chunk_offsets_alloc_size != chunk_offsets_alloc_size)
+               if (unlikely((size_t)chunk_offsets_alloc_size != chunk_offsets_alloc_size)) {
+                       errno = ENOMEM;
                        goto oom;
+               }
 
-               if (chunk_offsets_alloc_size <= STACK_MAX) {
+               if (likely(chunk_offsets_alloc_size <= STACK_MAX)) {
                        chunk_offsets = alloca(chunk_offsets_alloc_size);
                } else {
                        chunk_offsets = MALLOC(chunk_offsets_alloc_size);
-                       if (chunk_offsets == NULL)
+                       if (unlikely(!chunk_offsets))
                                goto oom;
                        chunk_offsets_malloced = true;
                }
@@ -309,7 +296,7 @@ read_compressed_wim_resource(const struct wim_resource_descriptor * const rdesc,
 
                ret = full_pread(in_fd, chunk_table_data, chunk_table_size_to_read,
                                 file_offset_of_needed_chunk_entries);
-               if (ret)
+               if (unlikely(ret))
                        goto read_error;
 
                /* Now fill in chunk_offsets from the entries we have read in
@@ -359,7 +346,7 @@ read_compressed_wim_resource(const struct wim_resource_descriptor * const rdesc,
                ubuf = alloca(chunk_size);
        } else {
                ubuf = MALLOC(chunk_size);
-               if (ubuf == NULL)
+               if (unlikely(!ubuf))
                        goto oom;
                ubuf_malloced = true;
        }
@@ -372,7 +359,7 @@ read_compressed_wim_resource(const struct wim_resource_descriptor * const rdesc,
                cbuf = alloca(chunk_size - 1);
        } else {
                cbuf = MALLOC(chunk_size - 1);
-               if (cbuf == NULL)
+               if (unlikely(!cbuf))
                        goto oom;
                cbuf_malloced = true;
        }
@@ -400,7 +387,7 @@ read_compressed_wim_resource(const struct wim_resource_descriptor * const rdesc,
 
                        ret = full_pread(in_fd, &chunk_hdr,
                                         sizeof(chunk_hdr), cur_read_offset);
-                       if (ret)
+                       if (unlikely(ret))
                                goto read_error;
                        chunk_csize = le32_to_cpu(chunk_hdr.compressed_size);
                } else {
@@ -415,11 +402,11 @@ read_compressed_wim_resource(const struct wim_resource_descriptor * const rdesc,
                                              chunk_offsets[i - read_start_chunk];
                        }
                }
-               if (chunk_csize == 0 || chunk_csize > chunk_usize) {
+               if (unlikely(chunk_csize == 0 || chunk_csize > chunk_usize)) {
                        ERROR("Invalid chunk size in compressed resource!");
                        errno = EINVAL;
                        ret = WIMLIB_ERR_DECOMPRESSION;
-                       goto out_free_memory;
+                       goto out_cleanup;
                }
                if (rdesc->is_pipable)
                        cur_read_offset += sizeof(struct pwm_chunk_hdr);
@@ -438,7 +425,7 @@ read_compressed_wim_resource(const struct wim_resource_descriptor * const rdesc,
                                u8 dummy;
 
                                ret = full_pread(in_fd, &dummy, 1, cur_read_offset - 1);
-                               if (ret)
+                               if (unlikely(ret))
                                        goto read_error;
                        }
                } else {
@@ -456,23 +443,20 @@ read_compressed_wim_resource(const struct wim_resource_descriptor * const rdesc,
                                         read_buf,
                                         chunk_csize,
                                         cur_read_offset);
-                       if (ret)
+                       if (unlikely(ret))
                                goto read_error;
 
                        if (read_buf == cbuf) {
-                               DEBUG("Decompressing chunk %"PRIu64" "
-                                     "(csize=%"PRIu32" usize=%"PRIu32")",
-                                     i, chunk_csize, chunk_usize);
                                ret = wimlib_decompress(cbuf,
                                                        chunk_csize,
                                                        ubuf,
                                                        chunk_usize,
                                                        decompressor);
-                               if (ret) {
+                               if (unlikely(ret)) {
                                        ERROR("Failed to decompress data!");
                                        ret = WIMLIB_ERR_DECOMPRESSION;
                                        errno = EINVAL;
-                                       goto out_free_memory;
+                                       goto out_cleanup;
                                }
                        }
                        cur_read_offset += chunk_csize;
@@ -490,10 +474,9 @@ read_compressed_wim_resource(const struct wim_resource_descriptor * const rdesc,
                                end = min(cur_range_end, chunk_end_offset) - chunk_start_offset;
                                size = end - start;
 
-                               ret = (*cb)(&ubuf[start], size, cb_ctx);
-
-                               if (ret)
-                                       goto out_free_memory;
+                               ret = call_consume_chunk(&ubuf[start], size, cbs);
+                               if (unlikely(ret))
+                                       goto out_cleanup;
 
                                cur_range_pos += size;
                                if (cur_range_pos == cur_range_end) {
@@ -520,13 +503,12 @@ read_compressed_wim_resource(const struct wim_resource_descriptor * const rdesc,
                 * returns.  */
                cur_read_offset += chunk_table_size;
                ret = full_pread(in_fd, &dummy, 1, cur_read_offset - 1);
-               if (ret)
+               if (unlikely(ret))
                        goto read_error;
        }
        ret = 0;
 
-out_free_memory:
-       errno_save = errno;
+out_cleanup:
        if (decompressor) {
                wimlib_free_decompressor(rdesc->wim->decompressor);
                rdesc->wim->decompressor = decompressor;
@@ -539,26 +521,23 @@ out_free_memory:
                FREE(ubuf);
        if (cbuf_malloced)
                FREE(cbuf);
-       errno = errno_save;
        return ret;
 
 oom:
-       ERROR("Not enough memory available to read size=%"PRIu64" bytes "
-             "from compressed WIM resource!", last_offset - first_offset + 1);
-       errno = ENOMEM;
+       ERROR("Out of memory while reading compressed WIM resource");
        ret = WIMLIB_ERR_NOMEM;
-       goto out_free_memory;
+       goto out_cleanup;
 
 read_error:
-       ERROR_WITH_ERRNO("Error reading compressed WIM resource!");
-       goto out_free_memory;
+       ERROR_WITH_ERRNO("Error reading data from WIM file");
+       goto out_cleanup;
 }
 
 /* Read raw data from a file descriptor at the specified offset, feeding the
- * data it in chunks into the specified callback function.  */
+ * data in nonempty chunks into the cbs->consume_chunk() function.  */
 static int
 read_raw_file_data(struct filedes *in_fd, u64 offset, u64 size,
-                  consume_data_callback_t cb, void *cb_ctx)
+                  const struct read_blob_callbacks *cbs)
 {
        u8 buf[BUFFER_SIZE];
        size_t bytes_to_read;
@@ -567,12 +546,12 @@ read_raw_file_data(struct filedes *in_fd, u64 offset, u64 size,
        while (size) {
                bytes_to_read = min(sizeof(buf), size);
                ret = full_pread(in_fd, buf, bytes_to_read, offset);
-               if (ret) {
+               if (unlikely(ret)) {
                        ERROR_WITH_ERRNO("Read error");
                        return ret;
                }
-               ret = cb(buf, bytes_to_read, cb_ctx);
-               if (ret)
+               ret = call_consume_chunk(buf, bytes_to_read, cbs);
+               if (unlikely(ret))
                        return ret;
                size -= bytes_to_read;
                offset += bytes_to_read;
@@ -580,118 +559,83 @@ read_raw_file_data(struct filedes *in_fd, u64 offset, u64 size,
        return 0;
 }
 
-/* A consume_data_callback_t implementation that simply concatenates all chunks
- * into a buffer.  */
+/* A consume_chunk() implementation that simply concatenates all chunks into an
+ * in-memory buffer.  */
 static int
 bufferer_cb(const void *chunk, size_t size, void *_ctx)
 {
-       u8 **buf_p = _ctx;
+       void **buf_p = _ctx;
 
        *buf_p = mempcpy(*buf_p, chunk, size);
        return 0;
 }
 
 /*
- * read_partial_wim_resource()-
- *
- * Read a range of data from an uncompressed or compressed resource in a WIM
- * file.
- *
- * @rdesc
- *     Description of the WIM resource to read from.
- * @offset
- *     Offset within the uncompressed resource at which to start reading.
- * @size
- *     Number of bytes to read.
- * @cb
- *     Callback function to feed the data being read.  Each call provides the
- *     next chunk of the requested data, uncompressed.  Each chunk will be of
- *     nonzero size and will not cross range boundaries, but otherwise will be
- *     of unspecified size.
- * @cb_ctx
- *     Parameter to pass to @cb_ctx.
+ * Read @size bytes at @offset in the WIM resource described by @rdesc and feed
+ * the data into the @cbs->consume_chunk callback function.
  *
- * Return values:
- *     WIMLIB_ERR_SUCCESS (0)
- *     WIMLIB_ERR_READ                   (errno set)
- *     WIMLIB_ERR_UNEXPECTED_END_OF_FILE (errno set to 0)
- *     WIMLIB_ERR_NOMEM                  (errno set to ENOMEM)
- *     WIMLIB_ERR_DECOMPRESSION          (errno set to EINVAL)
+ * @offset and @size are assumed to have already been validated against the
+ * resource's uncompressed size.
  *
- *     or other error code returned by the @cb function.
+ * Returns 0 on success; or the first nonzero value returned by the callback
+ * function; or a nonzero wimlib error code with errno set as well.
  */
 static int
 read_partial_wim_resource(const struct wim_resource_descriptor *rdesc,
-                         u64 offset, u64 size,
-                         consume_data_callback_t cb, void *cb_ctx)
+                         const u64 offset, const u64 size,
+                         const struct read_blob_callbacks *cbs)
 {
-       /* Sanity checks.  */
-       wimlib_assert(offset + size >= offset);
-       wimlib_assert(offset + size <= rdesc->uncompressed_size);
-
-       DEBUG("Reading %"PRIu64" @ %"PRIu64" from WIM resource  "
-             "%"PRIu64" => %"PRIu64" @ %"PRIu64,
-             size, offset, rdesc->uncompressed_size,
-             rdesc->size_in_wim, rdesc->offset_in_wim);
-
-       /* Trivial case.  */
-       if (size == 0)
-               return 0;
-
-       if (resource_is_compressed(rdesc)) {
+       if (rdesc->flags & (WIM_RESHDR_FLAG_COMPRESSED |
+                           WIM_RESHDR_FLAG_SOLID))
+       {
+               /* Compressed resource  */
+               if (unlikely(!size))
+                       return 0;
                struct data_range range = {
                        .offset = offset,
                        .size = size,
                };
-               return read_compressed_wim_resource(rdesc, &range, 1,
-                                                   cb, cb_ctx);
-       } else {
-               return read_raw_file_data(&rdesc->wim->in_fd,
-                                         rdesc->offset_in_wim + offset,
-                                         size, cb, cb_ctx);
+               return read_compressed_wim_resource(rdesc, &range, 1, cbs);
        }
+
+       /* Uncompressed resource  */
+       return read_raw_file_data(&rdesc->wim->in_fd,
+                                 rdesc->offset_in_wim + offset,
+                                 size, cbs);
 }
 
 /* Read the specified range of uncompressed data from the specified blob, which
- * must be located into a WIM file, into the specified buffer.  */
+ * must be located in a WIM file, into the specified buffer.  */
 int
 read_partial_wim_blob_into_buf(const struct blob_descriptor *blob,
-                              size_t size, u64 offset, void *_buf)
+                              u64 offset, size_t size, void *buf)
 {
-       u8 *buf = _buf;
-
-       wimlib_assert(blob->blob_location == BLOB_IN_WIM);
-
+       struct read_blob_callbacks cbs = {
+               .consume_chunk  = bufferer_cb,
+               .ctx            = &buf,
+       };
        return read_partial_wim_resource(blob->rdesc,
                                         blob->offset_in_res + offset,
                                         size,
-                                        bufferer_cb,
-                                        &buf);
-}
-
-/* A consume_data_callback_t implementation that simply ignores the data
- * received.  */
-static int
-skip_chunk_cb(const void *chunk, size_t size, void *_ctx)
-{
-       return 0;
+                                        &cbs);
 }
 
 /* Skip over the data of the specified WIM resource.  */
 int
-skip_wim_resource(struct wim_resource_descriptor *rdesc)
+skip_wim_resource(const struct wim_resource_descriptor *rdesc)
 {
-       DEBUG("Skipping resource (size=%"PRIu64")", rdesc->uncompressed_size);
-       return read_partial_wim_resource(rdesc, 0, rdesc->uncompressed_size,
-                                        skip_chunk_cb, NULL);
+       struct read_blob_callbacks cbs = {
+       };
+       return read_partial_wim_resource(rdesc, 0,
+                                        rdesc->uncompressed_size, &cbs);
 }
 
 static int
 read_wim_blob_prefix(const struct blob_descriptor *blob, u64 size,
-                    consume_data_callback_t cb, void *cb_ctx)
+                    const struct read_blob_callbacks *cbs)
 {
-       return read_partial_wim_resource(blob->rdesc, blob->offset_in_res, size,
-                                        cb, cb_ctx);
+       return read_partial_wim_resource(blob->rdesc, blob->offset_in_res,
+                                        size, cbs);
 }
 
 /* This function handles reading blob data that is located in an external file,
@@ -704,21 +648,19 @@ read_wim_blob_prefix(const struct blob_descriptor *blob, u64 size,
  * encrypted), so Windows uses its own code for its equivalent case.  */
 static int
 read_file_on_disk_prefix(const struct blob_descriptor *blob, u64 size,
-                        consume_data_callback_t cb, void *cb_ctx)
+                        const struct read_blob_callbacks *cbs)
 {
        int ret;
        int raw_fd;
        struct filedes fd;
 
-       DEBUG("Reading %"PRIu64" bytes from \"%"TS"\"", size, blob->file_on_disk);
-
        raw_fd = topen(blob->file_on_disk, O_BINARY | O_RDONLY);
-       if (raw_fd < 0) {
+       if (unlikely(raw_fd < 0)) {
                ERROR_WITH_ERRNO("Can't open \"%"TS"\"", blob->file_on_disk);
                return WIMLIB_ERR_OPEN;
        }
        filedes_init(&fd, raw_fd);
-       ret = read_raw_file_data(&fd, 0, size, cb, cb_ctx);
+       ret = read_raw_file_data(&fd, 0, size, cbs);
        filedes_close(&fd);
        return ret;
 }
@@ -726,24 +668,21 @@ read_file_on_disk_prefix(const struct blob_descriptor *blob, u64 size,
 #ifdef WITH_FUSE
 static int
 read_staging_file_prefix(const struct blob_descriptor *blob, u64 size,
-                        consume_data_callback_t cb, void *cb_ctx)
+                        const struct read_blob_callbacks *cbs)
 {
        int raw_fd;
        struct filedes fd;
        int ret;
 
-       DEBUG("Reading %"PRIu64" bytes from staging file \"%s\"",
-             size, blob->staging_file_name);
-
        raw_fd = openat(blob->staging_dir_fd, blob->staging_file_name,
                        O_RDONLY | O_NOFOLLOW);
-       if (raw_fd < 0) {
+       if (unlikely(raw_fd < 0)) {
                ERROR_WITH_ERRNO("Can't open staging file \"%s\"",
                                 blob->staging_file_name);
                return WIMLIB_ERR_OPEN;
        }
        filedes_init(&fd, raw_fd);
-       ret = read_raw_file_data(&fd, 0, size, cb, cb_ctx);
+       ret = read_raw_file_data(&fd, 0, size, cbs);
        filedes_close(&fd);
        return ret;
 }
@@ -753,34 +692,32 @@ read_staging_file_prefix(const struct blob_descriptor *blob, u64 size,
  * already located in an in-memory buffer.  */
 static int
 read_buffer_prefix(const struct blob_descriptor *blob,
-                  u64 size, consume_data_callback_t cb, void *cb_ctx)
+                  u64 size, const struct read_blob_callbacks *cbs)
 {
-       return (*cb)(blob->attached_buffer, size, cb_ctx);
+       if (unlikely(!size))
+               return 0;
+       return call_consume_chunk(blob->attached_buffer, size, cbs);
 }
 
 typedef int (*read_blob_prefix_handler_t)(const struct blob_descriptor *blob,
                                          u64 size,
-                                         consume_data_callback_t cb,
-                                         void *cb_ctx);
+                                         const struct read_blob_callbacks *cbs);
 
 /*
- * read_blob_prefix()-
- *
- * Reads the first @size bytes from a generic "blob", which may be located in
- * any one of several locations, such as in a WIM file (compressed or
- * uncompressed), in an external file, or directly in an in-memory buffer.
- *
- * This function feeds the data to a callback function @cb in chunks of
- * unspecified size.
+ * Read the first @size bytes from a generic "blob", which may be located in any
+ * one of several locations, such as in a WIM resource (possibly compressed), in
+ * an external file, or directly in an in-memory buffer.  The blob data will be
+ * fed to the cbs->consume_chunk() callback function in chunks that are nonempty
+ * but otherwise are of unspecified size.
  *
  * Returns 0 on success; nonzero on error.  A nonzero value will be returned if
  * the blob data cannot be successfully read (for a number of different reasons,
- * depending on the blob location), or if @cb returned nonzero in which case
- * that error code will be returned.
+ * depending on the blob location), or if cbs->consume_chunk() returned nonzero
+ * in which case that error code will be returned.
  */
 static int
 read_blob_prefix(const struct blob_descriptor *blob, u64 size,
-                consume_data_callback_t cb, void *cb_ctx)
+                const struct read_blob_callbacks *cbs)
 {
        static const read_blob_prefix_handler_t handlers[] = {
                [BLOB_IN_WIM] = read_wim_blob_prefix,
@@ -800,37 +737,59 @@ read_blob_prefix(const struct blob_descriptor *blob, u64 size,
        wimlib_assert(blob->blob_location < ARRAY_LEN(handlers)
                      && handlers[blob->blob_location] != NULL);
        wimlib_assert(size <= blob->size);
-       return handlers[blob->blob_location](blob, size, cb, cb_ctx);
+       return handlers[blob->blob_location](blob, size, cbs);
+}
+
+/* Read the full data of the specified blob, passing the data into the specified
+ * callbacks (all of which are optional).  */
+int
+read_blob_with_cbs(struct blob_descriptor *blob,
+                  const struct read_blob_callbacks *cbs)
+{
+       int ret;
+
+       ret = call_begin_blob(blob, cbs);
+       if (unlikely(ret))
+               return ret;
+
+       ret = read_blob_prefix(blob, blob->size, cbs);
+
+       return call_end_blob(blob, ret, cbs);
 }
 
 /* Read the full uncompressed data of the specified blob into the specified
- * buffer, which must have space for at least blob->size bytes.  */
+ * buffer, which must have space for at least blob->size bytes.  The SHA-1
+ * message digest is *not* checked.  */
 int
-read_full_blob_into_buf(const struct blob_descriptor *blob, void *_buf)
+read_blob_into_buf(const struct blob_descriptor *blob, void *buf)
 {
-       u8 *buf = _buf;
-       return read_blob_prefix(blob, blob->size, bufferer_cb, &buf);
+       struct read_blob_callbacks cbs = {
+               .consume_chunk  = bufferer_cb,
+               .ctx            = &buf,
+       };
+       return read_blob_prefix(blob, blob->size, &cbs);
 }
 
 /* Retrieve the full uncompressed data of the specified blob.  A buffer large
- * enough hold the data is allocated and returned in @buf_ret.  */
+ * enough hold the data is allocated and returned in @buf_ret.  The SHA-1
+ * message digest is *not* checked.  */
 int
-read_full_blob_into_alloc_buf(const struct blob_descriptor *blob, void **buf_ret)
+read_blob_into_alloc_buf(const struct blob_descriptor *blob, void **buf_ret)
 {
        int ret;
        void *buf;
 
-       if ((size_t)blob->size != blob->size) {
+       if (unlikely((size_t)blob->size != blob->size)) {
                ERROR("Can't read %"PRIu64" byte blob into memory", blob->size);
                return WIMLIB_ERR_NOMEM;
        }
 
        buf = MALLOC(blob->size);
-       if (buf == NULL)
+       if (unlikely(!buf))
                return WIMLIB_ERR_NOMEM;
 
-       ret = read_full_blob_into_buf(blob, buf);
-       if (ret) {
+       ret = read_blob_into_buf(blob, buf);
+       if (unlikely(ret)) {
                FREE(buf);
                return ret;
        }
@@ -843,17 +802,20 @@ read_full_blob_into_alloc_buf(const struct blob_descriptor *blob, void **buf_ret
  * `wim_reshdr' and the corresponding WIM file.  A buffer large enough hold the
  * data is allocated and returned in @buf_ret.  */
 int
-wim_reshdr_to_data(const struct wim_reshdr *reshdr, WIMStruct *wim, void **buf_ret)
+wim_reshdr_to_data(const struct wim_reshdr *reshdr, WIMStruct *wim,
+                  void **buf_ret)
 {
        struct wim_resource_descriptor rdesc;
        struct blob_descriptor blob;
 
-       wim_res_hdr_to_desc(reshdr, wim, &rdesc);
+       wim_reshdr_to_desc(reshdr, wim, &rdesc);
        blob_set_is_located_in_nonsolid_wim_resource(&blob, &rdesc);
 
-       return read_full_blob_into_alloc_buf(&blob, buf_ret);
+       return read_blob_into_alloc_buf(&blob, buf_ret);
 }
 
+/* Calculate the SHA-1 message digest of the uncompressed data of the specified
+ * WIM resource.  */
 int
 wim_reshdr_to_hash(const struct wim_reshdr *reshdr, WIMStruct *wim,
                   u8 hash[SHA1_HASH_SIZE])
@@ -862,19 +824,20 @@ wim_reshdr_to_hash(const struct wim_reshdr *reshdr, WIMStruct *wim,
        struct blob_descriptor blob;
        int ret;
 
-       wim_res_hdr_to_desc(reshdr, wim, &rdesc);
+       wim_reshdr_to_desc(reshdr, wim, &rdesc);
        blob_set_is_located_in_nonsolid_wim_resource(&blob, &rdesc);
        blob.unhashed = 1;
 
        ret = sha1_blob(&blob);
-       if (ret)
+       if (unlikely(ret))
                return ret;
+
        copy_hash(hash, blob.hash);
        return 0;
 }
 
 struct blobifier_context {
-       struct read_blob_list_callbacks cbs;
+       struct read_blob_callbacks cbs;
        struct blob_descriptor *cur_blob;
        struct blob_descriptor *next_blob;
        u64 cur_blob_offset;
@@ -892,35 +855,28 @@ next_blob(struct blob_descriptor *blob, size_t list_head_offset)
        return (struct blob_descriptor*)((u8*)cur->next - list_head_offset);
 }
 
-/* A consume_data_callback_t implementation that translates raw resource data
- * into blobs, calling the begin_blob, consume_chunk, and end_blob callback
- * functions as appropriate.  */
+/* A consume_chunk() implementation that translates raw resource data into
+ * blobs, calling the begin_blob, consume_chunk, and end_blob callbacks as
+ * appropriate.  */
 static int
 blobifier_cb(const void *chunk, size_t size, void *_ctx)
 {
        struct blobifier_context *ctx = _ctx;
        int ret;
 
-       DEBUG("%zu bytes passed to blobifier", size);
-
        wimlib_assert(ctx->cur_blob != NULL);
        wimlib_assert(size <= ctx->cur_blob->size - ctx->cur_blob_offset);
 
        if (ctx->cur_blob_offset == 0) {
-
                /* Starting a new blob.  */
-               DEBUG("Begin new blob (size=%"PRIu64").", ctx->cur_blob->size);
-
-               ret = (*ctx->cbs.begin_blob)(ctx->cur_blob,
-                                            ctx->cbs.begin_blob_ctx);
+               ret = call_begin_blob(ctx->cur_blob, &ctx->cbs);
                if (ret)
                        return ret;
        }
 
-       /* Consume the chunk.  */
-       ret = (*ctx->cbs.consume_chunk)(chunk, size,
-                                       ctx->cbs.consume_chunk_ctx);
        ctx->cur_blob_offset += size;
+
+       ret = call_consume_chunk(chunk, size, &ctx->cbs);
        if (ret)
                return ret;
 
@@ -929,9 +885,7 @@ blobifier_cb(const void *chunk, size_t size, void *_ctx)
 
                ctx->cur_blob_offset = 0;
 
-               DEBUG("End blob (size=%"PRIu64").", ctx->cur_blob->size);
-               ret = (*ctx->cbs.end_blob)(ctx->cur_blob, 0,
-                                          ctx->cbs.end_blob_ctx);
+               ret = call_end_blob(ctx->cur_blob, 0, &ctx->cbs);
                if (ret)
                        return ret;
 
@@ -951,7 +905,7 @@ blobifier_cb(const void *chunk, size_t size, void *_ctx)
 struct hasher_context {
        SHA_CTX sha_ctx;
        int flags;
-       struct read_blob_list_callbacks cbs;
+       struct read_blob_callbacks cbs;
 };
 
 /* Callback for starting to read a blob while calculating its SHA-1 message
@@ -963,26 +917,21 @@ hasher_begin_blob(struct blob_descriptor *blob, void *_ctx)
 
        sha1_init(&ctx->sha_ctx);
 
-       if (ctx->cbs.begin_blob == NULL)
-               return 0;
-       else
-               return (*ctx->cbs.begin_blob)(blob, ctx->cbs.begin_blob_ctx);
+       return call_begin_blob(blob, &ctx->cbs);
 }
 
-/* A consume_data_callback_t implementation that continues calculating the SHA-1
- * message digest of the blob being read, then optionally passes the data on to
- * another consume_data_callback_t implementation.  This allows checking the
- * SHA-1 message digest of a blob being extracted, for example.  */
+/* A consume_chunk() implementation that continues calculating the SHA-1 message
+ * digest of the blob being read, then optionally passes the data on to another
+ * consume_chunk() implementation.  This allows checking the SHA-1 message
+ * digest of a blob being extracted, for example.  */
 static int
 hasher_consume_chunk(const void *chunk, size_t size, void *_ctx)
 {
        struct hasher_context *ctx = _ctx;
 
        sha1_update(&ctx->sha_ctx, chunk, size);
-       if (ctx->cbs.consume_chunk == NULL)
-               return 0;
-       else
-               return (*ctx->cbs.consume_chunk)(chunk, size, ctx->cbs.consume_chunk_ctx);
+
+       return call_consume_chunk(chunk, size, &ctx->cbs);
 }
 
 /* Callback for finishing reading a blob while calculating its SHA-1 message
@@ -994,7 +943,7 @@ hasher_end_blob(struct blob_descriptor *blob, int status, void *_ctx)
        u8 hash[SHA1_HASH_SIZE];
        int ret;
 
-       if (status) {
+       if (unlikely(status)) {
                /* Error occurred; the full blob may not have been read.  */
                ret = status;
                goto out_next_cb;
@@ -1003,90 +952,57 @@ hasher_end_blob(struct blob_descriptor *blob, int status, void *_ctx)
        /* Retrieve the final SHA-1 message digest.  */
        sha1_final(hash, &ctx->sha_ctx);
 
+       /* Set the SHA-1 message digest of the blob, or compare the calculated
+        * value with stored value.  */
        if (blob->unhashed) {
-               if (ctx->flags & COMPUTE_MISSING_BLOB_HASHES) {
-                       /* No SHA-1 message digest was previously present for the
-                        * blob.  Set it to the one just calculated.  */
-                       DEBUG("Set SHA-1 message digest for blob "
-                             "(size=%"PRIu64").", blob->size);
+               if (ctx->flags & COMPUTE_MISSING_BLOB_HASHES)
                        copy_hash(blob->hash, hash);
+       } else if ((ctx->flags & VERIFY_BLOB_HASHES) &&
+                  unlikely(!hashes_equal(hash, blob->hash)))
+       {
+               if (wimlib_print_errors) {
+                       tchar expected_hashstr[SHA1_HASH_SIZE * 2 + 1];
+                       tchar actual_hashstr[SHA1_HASH_SIZE * 2 + 1];
+                       sprint_hash(blob->hash, expected_hashstr);
+                       sprint_hash(hash, actual_hashstr);
+                       ERROR("The data is corrupted!\n"
+                             "        (Expected SHA-1=%"TS", got SHA-1=%"TS")",
+                             expected_hashstr, actual_hashstr);
                }
-       } else {
-               if (ctx->flags & VERIFY_BLOB_HASHES) {
-                       /* The blob already had a SHA-1 message digest present.
-                        * Verify that it is the same as the calculated value.
-                        */
-                       if (!hashes_equal(hash, blob->hash)) {
-                               if (wimlib_print_errors) {
-                                       tchar expected_hashstr[SHA1_HASH_SIZE * 2 + 1];
-                                       tchar actual_hashstr[SHA1_HASH_SIZE * 2 + 1];
-                                       sprint_hash(blob->hash, expected_hashstr);
-                                       sprint_hash(hash, actual_hashstr);
-                                       ERROR("The data is corrupted!\n"
-                                             "        (Expected SHA-1=%"TS",\n"
-                                             "              got SHA-1=%"TS")",
-                                             expected_hashstr, actual_hashstr);
-                               }
-                               ret = WIMLIB_ERR_INVALID_RESOURCE_HASH;
-                               errno = EINVAL;
-                               goto out_next_cb;
-                       }
-                       DEBUG("SHA-1 message digest okay for "
-                             "blob (size=%"PRIu64").", blob->size);
-               }
+               ret = WIMLIB_ERR_INVALID_RESOURCE_HASH;
+               goto out_next_cb;
        }
        ret = 0;
 out_next_cb:
-       if (ctx->cbs.end_blob == NULL)
-               return ret;
-       else
-               return (*ctx->cbs.end_blob)(blob, ret, ctx->cbs.end_blob_ctx);
-}
-
-static int
-read_full_blob_with_cbs(struct blob_descriptor *blob,
-                       const struct read_blob_list_callbacks *cbs)
-{
-       int ret;
-
-       ret = (*cbs->begin_blob)(blob, cbs->begin_blob_ctx);
-       if (ret)
-               return ret;
-
-       ret = read_blob_prefix(blob, blob->size, cbs->consume_chunk,
-                              cbs->consume_chunk_ctx);
-
-       return (*cbs->end_blob)(blob, ret, cbs->end_blob_ctx);
+       return call_end_blob(blob, ret, &ctx->cbs);
 }
 
 /* Read the full data of the specified blob, passing the data into the specified
  * callbacks (all of which are optional) and either checking or computing the
  * SHA-1 message digest of the blob.  */
-static int
-read_full_blob_with_sha1(struct blob_descriptor *blob,
-                        const struct read_blob_list_callbacks *cbs)
+int
+read_blob_with_sha1(struct blob_descriptor *blob,
+                   const struct read_blob_callbacks *cbs)
 {
        struct hasher_context hasher_ctx = {
                .flags = VERIFY_BLOB_HASHES | COMPUTE_MISSING_BLOB_HASHES,
                .cbs = *cbs,
        };
-       struct read_blob_list_callbacks hasher_cbs = {
-               .begin_blob             = hasher_begin_blob,
-               .begin_blob_ctx         = &hasher_ctx,
-               .consume_chunk          = hasher_consume_chunk,
-               .consume_chunk_ctx      = &hasher_ctx,
-               .end_blob               = hasher_end_blob,
-               .end_blob_ctx           = &hasher_ctx,
+       struct read_blob_callbacks hasher_cbs = {
+               .begin_blob     = hasher_begin_blob,
+               .consume_chunk  = hasher_consume_chunk,
+               .end_blob       = hasher_end_blob,
+               .ctx            = &hasher_ctx,
        };
-       return read_full_blob_with_cbs(blob, &hasher_cbs);
+       return read_blob_with_cbs(blob, &hasher_cbs);
 }
 
 static int
 read_blobs_in_solid_resource(struct blob_descriptor *first_blob,
                             struct blob_descriptor *last_blob,
-                            u64 blob_count,
+                            size_t blob_count,
                             size_t list_head_offset,
-                            const struct read_blob_list_callbacks *sink_cbs)
+                            const struct read_blob_callbacks *sink_cbs)
 {
        struct data_range *ranges;
        bool ranges_malloced;
@@ -1095,28 +1011,22 @@ read_blobs_in_solid_resource(struct blob_descriptor *first_blob,
        int ret;
        u64 ranges_alloc_size;
 
-       DEBUG("Reading %"PRIu64" blobs combined in same WIM resource",
-             blob_count);
-
        /* Setup data ranges array (one range per blob to read); this way
         * read_compressed_wim_resource() does not need to be aware of blobs.
         */
 
-       ranges_alloc_size = blob_count * sizeof(ranges[0]);
+       ranges_alloc_size = (u64)blob_count * sizeof(ranges[0]);
 
-       if (unlikely((size_t)ranges_alloc_size != ranges_alloc_size)) {
-               ERROR("Too many blobs in one resource!");
-               return WIMLIB_ERR_NOMEM;
-       }
-       if (likely(ranges_alloc_size <= STACK_MAX)) {
+       if (unlikely((size_t)ranges_alloc_size != ranges_alloc_size))
+               goto oom;
+
+       if (ranges_alloc_size <= STACK_MAX) {
                ranges = alloca(ranges_alloc_size);
                ranges_malloced = false;
        } else {
                ranges = MALLOC(ranges_alloc_size);
-               if (ranges == NULL) {
-                       ERROR("Too many blobs in one resource!");
-                       return WIMLIB_ERR_NOMEM;
-               }
+               if (unlikely(!ranges))
+                       goto oom;
                ranges_malloced = true;
        }
 
@@ -1136,25 +1046,26 @@ read_blobs_in_solid_resource(struct blob_descriptor *first_blob,
                .final_blob             = last_blob,
                .list_head_offset       = list_head_offset,
        };
+       struct read_blob_callbacks cbs = {
+               .consume_chunk  = blobifier_cb,
+               .ctx            = &blobifier_ctx,
+       };
 
-       ret = read_compressed_wim_resource(first_blob->rdesc,
-                                          ranges,
-                                          blob_count,
-                                          blobifier_cb,
-                                          &blobifier_ctx);
+       ret = read_compressed_wim_resource(first_blob->rdesc, ranges,
+                                          blob_count, &cbs);
 
        if (ranges_malloced)
                FREE(ranges);
 
-       if (ret) {
-               if (blobifier_ctx.cur_blob_offset != 0) {
-                       ret = (*blobifier_ctx.cbs.end_blob)
-                               (blobifier_ctx.cur_blob,
-                                ret,
-                                blobifier_ctx.cbs.end_blob_ctx);
-               }
+       if (unlikely(ret && blobifier_ctx.cur_blob_offset != 0)) {
+               ret = call_end_blob(blobifier_ctx.cur_blob, ret,
+                                   &blobifier_ctx.cbs);
        }
        return ret;
+
+oom:
+       ERROR("Too many blobs in one resource!");
+       return WIMLIB_ERR_NOMEM;
 }
 
 /*
@@ -1167,8 +1078,8 @@ read_blobs_in_solid_resource(struct blob_descriptor *first_blob,
  * @blob_list
  *     List of blobs to read.
  * @list_head_offset
- *     Offset of the `struct list_head' within each `struct blob_descriptor' that makes up
- *     the @blob_list.
+ *     Offset of the `struct list_head' within each `struct blob_descriptor'
+ *     that makes up the @blob_list.
  * @cbs
  *     Callback functions to accept the blob data.
  * @flags
@@ -1196,19 +1107,18 @@ read_blobs_in_solid_resource(struct blob_descriptor *first_blob,
  * of the callback functions.
  */
 int
-read_blob_list(struct list_head *blob_list,
-              size_t list_head_offset,
-              const struct read_blob_list_callbacks *cbs,
-              int flags)
+read_blob_list(struct list_head *blob_list, size_t list_head_offset,
+              const struct read_blob_callbacks *cbs, int flags)
 {
        int ret;
        struct list_head *cur, *next;
        struct blob_descriptor *blob;
        struct hasher_context *hasher_ctx;
-       struct read_blob_list_callbacks *sink_cbs;
+       struct read_blob_callbacks *sink_cbs;
 
        if (!(flags & BLOB_LIST_ALREADY_SORTED)) {
-               ret = sort_blob_list_by_sequential_order(blob_list, list_head_offset);
+               ret = sort_blob_list_by_sequential_order(blob_list,
+                                                        list_head_offset);
                if (ret)
                        return ret;
        }
@@ -1220,16 +1130,14 @@ read_blob_list(struct list_head *blob_list,
                        .cbs    = *cbs,
                };
                sink_cbs = alloca(sizeof(*sink_cbs));
-               *sink_cbs = (struct read_blob_list_callbacks) {
-                       .begin_blob             = hasher_begin_blob,
-                       .begin_blob_ctx         = hasher_ctx,
-                       .consume_chunk          = hasher_consume_chunk,
-                       .consume_chunk_ctx      = hasher_ctx,
-                       .end_blob               = hasher_end_blob,
-                       .end_blob_ctx           = hasher_ctx,
+               *sink_cbs = (struct read_blob_callbacks) {
+                       .begin_blob     = hasher_begin_blob,
+                       .consume_chunk  = hasher_consume_chunk,
+                       .end_blob       = hasher_end_blob,
+                       .ctx            = hasher_ctx,
                };
        } else {
-               sink_cbs = (struct read_blob_list_callbacks*)cbs;
+               sink_cbs = (struct read_blob_callbacks *)cbs;
        }
 
        for (cur = blob_list->next, next = cur->next;
@@ -1243,7 +1151,7 @@ read_blob_list(struct list_head *blob_list,
                {
                        struct blob_descriptor *blob_next, *blob_last;
                        struct list_head *next2;
-                       u64 blob_count;
+                       size_t blob_count;
 
                        /* The next blob is a proper sub-sequence of a WIM
                         * resource.  See if there are other blobs in the same
@@ -1283,80 +1191,55 @@ read_blob_list(struct list_head *blob_list,
                        }
                }
 
-               ret = read_full_blob_with_cbs(blob, sink_cbs);
-               if (ret && ret != BEGIN_BLOB_STATUS_SKIP_BLOB)
+               ret = read_blob_with_cbs(blob, sink_cbs);
+               if (unlikely(ret && ret != BEGIN_BLOB_STATUS_SKIP_BLOB))
                        return ret;
        }
        return 0;
 }
 
-/*
- * Extract the first @size bytes of the specified blob.
- *
- * If @size specifies the full uncompressed size of the blob, then the SHA-1
- * message digest of the uncompressed blob is checked while being extracted.
- *
- * The uncompressed data of the blob is passed in chunks of unspecified size to
- * the @extract_chunk function, passing it @extract_chunk_arg.
- */
-int
-extract_blob(struct blob_descriptor *blob, u64 size,
-            consume_data_callback_t extract_chunk, void *extract_chunk_arg)
-{
-       wimlib_assert(size <= blob->size);
-       if (size == blob->size) {
-               /* Do SHA-1.  */
-               struct read_blob_list_callbacks cbs = {
-                       .consume_chunk          = extract_chunk,
-                       .consume_chunk_ctx      = extract_chunk_arg,
-               };
-               return read_full_blob_with_sha1(blob, &cbs);
-       } else {
-               /* Don't do SHA-1.  */
-               return read_blob_prefix(blob, size, extract_chunk,
-                                       extract_chunk_arg);
-       }
-}
-
-/* A consume_data_callback_t implementation that writes the chunk of data to a
- * file descriptor.  */
 static int
-extract_chunk_to_fd(const void *chunk, size_t size, void *_fd_p)
+extract_chunk_to_fd(const void *chunk, size_t size, void *_fd)
 {
-       struct filedes *fd = _fd_p;
-
+       struct filedes *fd = _fd;
        int ret = full_write(fd, chunk, size);
-       if (ret) {
+       if (unlikely(ret))
                ERROR_WITH_ERRNO("Error writing to file descriptor");
-               return ret;
-       }
-       return 0;
+       return ret;
 }
 
 /* Extract the first @size bytes of the specified blob to the specified file
- * descriptor.  */
+ * descriptor.  This does *not* check the SHA-1 message digest.  */
 int
-extract_blob_to_fd(struct blob_descriptor *blob, struct filedes *fd, u64 size)
+extract_blob_prefix_to_fd(struct blob_descriptor *blob, u64 size,
+                         struct filedes *fd)
 {
-       return extract_blob(blob, size, extract_chunk_to_fd, fd);
+       struct read_blob_callbacks cbs = {
+               .consume_chunk  = extract_chunk_to_fd,
+               .ctx            = fd,
+       };
+       return read_blob_prefix(blob, size, &cbs);
 }
 
 /* Extract the full uncompressed contents of the specified blob to the specified
- * file descriptor.  */
+ * file descriptor.  This checks the SHA-1 message digest.  */
 int
-extract_full_blob_to_fd(struct blob_descriptor *blob, struct filedes *fd)
+extract_blob_to_fd(struct blob_descriptor *blob, struct filedes *fd)
 {
-       return extract_blob_to_fd(blob, fd, blob->size);
+       struct read_blob_callbacks cbs = {
+               .consume_chunk  = extract_chunk_to_fd,
+               .ctx            = fd,
+       };
+       return read_blob_with_sha1(blob, &cbs);
 }
 
 /* Calculate the SHA-1 message digest of a blob and store it in @blob->hash.  */
 int
 sha1_blob(struct blob_descriptor *blob)
 {
-       wimlib_assert(blob->unhashed);
-       struct read_blob_list_callbacks cbs = {
+       struct read_blob_callbacks cbs = {
        };
-       return read_full_blob_with_sha1(blob, &cbs);
+       return read_blob_with_sha1(blob, &cbs);
 }
 
 /*
@@ -1365,8 +1248,8 @@ sha1_blob(struct blob_descriptor *blob)
  * Note: for solid resources some fields still need to be overridden.
  */
 void
-wim_res_hdr_to_desc(const struct wim_reshdr *reshdr, WIMStruct *wim,
-                   struct wim_resource_descriptor *rdesc)
+wim_reshdr_to_desc(const struct wim_reshdr *reshdr, WIMStruct *wim,
+                  struct wim_resource_descriptor *rdesc)
 {
        rdesc->wim = wim;
        rdesc->offset_in_wim = reshdr->offset_in_wim;
@@ -1384,8 +1267,7 @@ wim_res_hdr_to_desc(const struct wim_reshdr *reshdr, WIMStruct *wim,
        }
 }
 
-/* Translates a WIM resource header from the on-disk format into an in-memory
- * format.  */
+/* Import a WIM resource header from the on-disk format.  */
 void
 get_wim_reshdr(const struct wim_reshdr_disk *disk_reshdr,
               struct wim_reshdr *reshdr)
@@ -1402,8 +1284,7 @@ get_wim_reshdr(const struct wim_reshdr_disk *disk_reshdr,
        reshdr->flags = disk_reshdr->flags;
 }
 
-/* Translates a WIM resource header from an in-memory format into the on-disk
- * format.  */
+/* Export a WIM resource header to the on-disk format.  */
 void
 put_wim_reshdr(const struct wim_reshdr *reshdr,
               struct wim_reshdr_disk *disk_reshdr)
index 3f61353..dd25362 100644 (file)
@@ -775,13 +775,11 @@ unix_extract(struct list_head *dentry_list, struct apply_ctx *_ctx)
 
        /* Extract nonempty regular files and symbolic links.  */
 
-       struct read_blob_list_callbacks cbs = {
-               .begin_blob        = unix_begin_extract_blob,
-               .begin_blob_ctx    = ctx,
-               .consume_chunk     = unix_extract_chunk,
-               .consume_chunk_ctx = ctx,
-               .end_blob          = unix_end_extract_blob,
-               .end_blob_ctx      = ctx,
+       struct read_blob_callbacks cbs = {
+               .begin_blob     = unix_begin_extract_blob,
+               .consume_chunk  = unix_extract_chunk,
+               .end_blob       = unix_end_extract_blob,
+               .ctx            = ctx,
        };
        ret = extract_blob_list(&ctx->common, &cbs);
        if (ret)
index 11efe55..1ca5be4 100644 (file)
@@ -116,9 +116,9 @@ wimlib_verify_wim(WIMStruct *wim, int verify_flags)
        union wimlib_progress_info progress;
        struct verify_blob_list_ctx ctx;
        struct blob_descriptor *blob;
-       struct read_blob_list_callbacks cbs = {
-               .end_blob = end_verify_blob,
-               .end_blob_ctx = &ctx,
+       struct read_blob_callbacks cbs = {
+               .end_blob       = end_verify_blob,
+               .ctx            = &ctx,
        };
 
        /* Check parameters  */
index b50da97..9d627db 100644 (file)
@@ -289,7 +289,7 @@ load_prepopulate_pats(struct win32_apply_ctx *ctx)
 {
        const wchar_t *path = L"\\Windows\\System32\\WimBootCompress.ini";
        struct wim_dentry *dentry;
-       struct blob_descriptor *blob;
+       const struct blob_descriptor *blob;
        int ret;
        void *buf;
        struct string_set *s;
@@ -313,7 +313,7 @@ load_prepopulate_pats(struct win32_apply_ctx *ctx)
                return WIMLIB_ERR_PATH_DOES_NOT_EXIST;
        }
 
-       ret = read_full_blob_into_alloc_buf(blob, &buf);
+       ret = read_blob_into_alloc_buf(blob, &buf);
        if (ret)
                return ret;
 
@@ -2686,13 +2686,11 @@ win32_extract(struct list_head *dentry_list, struct apply_ctx *_ctx)
        if (ret)
                goto out;
 
-       struct read_blob_list_callbacks cbs = {
-               .begin_blob        = begin_extract_blob,
-               .begin_blob_ctx    = ctx,
-               .consume_chunk     = extract_chunk,
-               .consume_chunk_ctx = ctx,
-               .end_blob          = end_extract_blob,
-               .end_blob_ctx      = ctx,
+       struct read_blob_callbacks cbs = {
+               .begin_blob     = begin_extract_blob,
+               .consume_chunk  = extract_chunk,
+               .end_blob       = end_extract_blob,
+               .ctx            = ctx,
        };
        ret = extract_blob_list(&ctx->common, &cbs);
        if (ret)
index ba9937c..9d8bbbc 100644 (file)
@@ -106,7 +106,7 @@ retry:
  * described by @blob.  */
 int
 read_winnt_stream_prefix(const struct blob_descriptor *blob, u64 size,
-                        consume_data_callback_t cb, void *cb_ctx)
+                        const struct read_blob_callbacks *cbs)
 {
        const wchar_t *path;
        HANDLE h;
@@ -147,7 +147,7 @@ read_winnt_stream_prefix(const struct blob_descriptor *blob, u64 size,
                bytes_read = iosb.Information;
 
                bytes_remaining -= bytes_read;
-               ret = (*cb)(buf, bytes_read, cb_ctx);
+               ret = call_consume_chunk(buf, bytes_read, cbs);
                if (ret)
                        break;
        }
@@ -156,8 +156,7 @@ read_winnt_stream_prefix(const struct blob_descriptor *blob, u64 size,
 }
 
 struct win32_encrypted_read_ctx {
-       consume_data_callback_t read_prefix_cb;
-       void *read_prefix_ctx;
+       const struct read_blob_callbacks *cbs;
        int wimlib_err_code;
        u64 bytes_remaining;
 };
@@ -172,7 +171,7 @@ win32_encrypted_export_cb(unsigned char *data, void *_ctx, unsigned long len)
        if (bytes_to_consume == 0)
                return ERROR_SUCCESS;
 
-       ret = (*ctx->read_prefix_cb)(data, bytes_to_consume, ctx->read_prefix_ctx);
+       ret = call_consume_chunk(data, bytes_to_consume, ctx->cbs);
        if (ret) {
                ctx->wimlib_err_code = ret;
                /* It doesn't matter what error code is returned here, as long
@@ -186,7 +185,7 @@ win32_encrypted_export_cb(unsigned char *data, void *_ctx, unsigned long len)
 int
 read_win32_encrypted_file_prefix(const struct blob_descriptor *blob,
                                 u64 size,
-                                consume_data_callback_t cb, void *cb_ctx)
+                                const struct read_blob_callbacks *cbs)
 {
        struct win32_encrypted_read_ctx export_ctx;
        DWORD err;
@@ -197,8 +196,7 @@ read_win32_encrypted_file_prefix(const struct blob_descriptor *blob,
        if (blob->file_inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
                flags |= CREATE_FOR_DIR;
 
-       export_ctx.read_prefix_cb = cb;
-       export_ctx.read_prefix_ctx = cb_ctx;
+       export_ctx.cbs = cbs;
        export_ctx.wimlib_err_code = 0;
        export_ctx.bytes_remaining = size;
 
index 4d5e716..178a88a 100644 (file)
@@ -795,7 +795,7 @@ write_blob_uncompressed(struct blob_descriptor *blob, struct filedes *out_fd)
        if (filedes_seek(out_fd, begin_offset) == -1)
                return 0;
 
-       ret = extract_full_blob_to_fd(blob, out_fd);
+       ret = extract_blob_to_fd(blob, out_fd);
        if (ret) {
                /* Error reading the uncompressed data.  */
                if (out_fd->offset == begin_offset &&
@@ -1615,13 +1615,11 @@ write_blob_list(struct list_head *blob_list,
        /* Read the list of blobs needing to be compressed, using the specified
         * callbacks to execute processing of the data.  */
 
-       struct read_blob_list_callbacks cbs = {
-               .begin_blob             = write_blob_begin_read,
-               .begin_blob_ctx         = &ctx,
-               .consume_chunk          = write_blob_process_chunk,
-               .consume_chunk_ctx      = &ctx,
-               .end_blob               = write_blob_end_read,
-               .end_blob_ctx           = &ctx,
+       struct read_blob_callbacks cbs = {
+               .begin_blob     = write_blob_begin_read,
+               .consume_chunk  = write_blob_process_chunk,
+               .end_blob       = write_blob_end_read,
+               .ctx            = &ctx,
        };
 
        ret = read_blob_list(blob_list,