]> wimlib.net Git - wimlib/blobdiff - src/resource.c
Update progress functions
[wimlib] / src / resource.c
index c7312df839d75ca7c2cc4f47274ee90b7995ec75..7631dd492309283bb7d8fa72a569004f64ae619d 100644 (file)
@@ -562,6 +562,28 @@ read_error:
        goto out_free_memory;
 }
 
+static int
+fill_zeroes(u64 size, consume_data_callback_t cb, void *cb_ctx)
+{
+       if (unlikely(size)) {
+               u8 buf[min(size, BUFFER_SIZE)];
+
+               memset(buf, 0, sizeof(buf));
+
+               do {
+                       size_t len;
+                       int ret;
+
+                       len = min(size, BUFFER_SIZE);
+                       ret = cb(buf, len, cb_ctx);
+                       if (ret)
+                               return ret;
+                       size -= len;
+               } while (size);
+       }
+       return 0;
+}
+
 /* Read raw data from a file descriptor at the specified offset, feeding the
  * data it in chunks into the specified callback function.  */
 static int
@@ -654,11 +676,37 @@ read_partial_wim_resource(const struct wim_resource_spec *rspec,
                return read_compressed_wim_resource(rspec, &range, 1,
                                                    cb, cb_ctx);
        } else {
-               return read_raw_file_data(&rspec->wim->in_fd,
-                                         rspec->offset_in_wim + offset,
-                                         size,
-                                         cb,
-                                         cb_ctx);
+               /* Reading uncompressed resource.  For completeness, handle the
+                * weird case where size_in_wim < uncompressed_size.  */
+
+               u64 read_size;
+               u64 zeroes_size;
+               int ret;
+
+               if (likely(offset + size <= rspec->size_in_wim) ||
+                   rspec->is_pipable)
+               {
+                       read_size = size;
+                       zeroes_size = 0;
+               } else {
+                       if (offset >= rspec->size_in_wim) {
+                               read_size = 0;
+                               zeroes_size = size;
+                       } else {
+                               read_size = rspec->size_in_wim - offset;
+                               zeroes_size = offset + size - rspec->size_in_wim;
+                       }
+               }
+
+               ret = read_raw_file_data(&rspec->wim->in_fd,
+                                        rspec->offset_in_wim + offset,
+                                        read_size,
+                                        cb,
+                                        cb_ctx);
+               if (ret)
+                       return ret;
+
+               return fill_zeroes(zeroes_size, cb, cb_ctx);
        }
 }
 
@@ -710,7 +758,6 @@ read_wim_stream_prefix(const struct wim_lookup_table_entry *lte, u64 size,
                                         cb, cb_ctx);
 }
 
-#ifndef __WIN32__
 /* This function handles reading stream data that is located in an external
  * file,  such as a file that has been added to the WIM image through execution
  * of a wimlib_add_command.
@@ -731,7 +778,7 @@ read_file_on_disk_prefix(const struct wim_lookup_table_entry *lte, u64 size,
 
        DEBUG("Reading %"PRIu64" bytes from \"%"TS"\"", size, lte->file_on_disk);
 
-       raw_fd = open(lte->file_on_disk, O_BINARY | O_RDONLY);
+       raw_fd = topen(lte->file_on_disk, O_BINARY | O_RDONLY);
        if (raw_fd < 0) {
                ERROR_WITH_ERRNO("Can't open \"%"TS"\"", lte->file_on_disk);
                return WIMLIB_ERR_OPEN;
@@ -741,7 +788,6 @@ read_file_on_disk_prefix(const struct wim_lookup_table_entry *lte, u64 size,
        filedes_close(&fd);
        return ret;
 }
-#endif /* !__WIN32__ */
 
 /* This function handles the trivial case of reading stream data that is, in
  * fact, already located in an in-memory buffer.  */
@@ -779,11 +825,7 @@ read_stream_prefix(const struct wim_lookup_table_entry *lte, u64 size,
 {
        static const read_stream_prefix_handler_t handlers[] = {
                [RESOURCE_IN_WIM]             = read_wim_stream_prefix,
-       #ifdef __WIN32__
-               [RESOURCE_IN_FILE_ON_DISK]    = read_win32_file_prefix,
-       #else
                [RESOURCE_IN_FILE_ON_DISK]    = read_file_on_disk_prefix,
-       #endif
                [RESOURCE_IN_ATTACHED_BUFFER] = read_buffer_prefix,
        #ifdef WITH_FUSE
                [RESOURCE_IN_STAGING_FILE]    = read_file_on_disk_prefix,
@@ -792,6 +834,7 @@ read_stream_prefix(const struct wim_lookup_table_entry *lte, u64 size,
                [RESOURCE_IN_NTFS_VOLUME]     = read_ntfs_file_prefix,
        #endif
        #ifdef __WIN32__
+               [RESOURCE_IN_WINNT_FILE_ON_DISK] = read_winnt_file_prefix,
                [RESOURCE_WIN32_ENCRYPTED]    = read_win32_encrypted_file_prefix,
        #endif
        };
@@ -878,6 +921,34 @@ wim_reshdr_to_data(const struct wim_reshdr *reshdr, WIMStruct *wim, void **buf_r
        return wim_resource_spec_to_data(&rspec, buf_ret);
 }
 
+int
+wim_reshdr_to_hash(const struct wim_reshdr *reshdr, WIMStruct *wim,
+                  u8 hash[SHA1_HASH_SIZE])
+{
+       struct wim_resource_spec rspec;
+       int ret;
+       struct wim_lookup_table_entry *lte;
+
+       wim_res_hdr_to_spec(reshdr, wim, &rspec);
+
+       lte = new_lookup_table_entry();
+       if (lte == NULL)
+               return WIMLIB_ERR_NOMEM;
+
+       lte_bind_wim_resource_spec(lte, &rspec);
+       lte->flags = rspec.flags;
+       lte->size = rspec.uncompressed_size;
+       lte->offset_in_res = 0;
+       lte->unhashed = 1;
+
+       ret = sha1_stream(lte);
+
+       lte_unbind_wim_resource_spec(lte);
+       copy_hash(hash, lte->hash);
+       free_lookup_table_entry(lte);
+       return ret;
+}
+
 struct streamifier_context {
        struct read_stream_list_callbacks cbs;
        struct wim_lookup_table_entry *cur_stream;
@@ -912,10 +983,17 @@ streamifier_cb(const void *chunk, size_t size, void *_ctx)
        wimlib_assert(size <= ctx->cur_stream->size - ctx->cur_stream_offset);
 
        if (ctx->cur_stream_offset == 0) {
+               u32 flags;
+
                /* Starting a new stream.  */
                DEBUG("Begin new stream (size=%"PRIu64").",
                      ctx->cur_stream->size);
-               ret = (*ctx->cbs.begin_stream)(ctx->cur_stream, true,
+
+               flags = BEGIN_STREAM_FLAG_PARTIAL_RESOURCE;
+               if (size == ctx->cur_stream->size)
+                       flags |= BEGIN_STREAM_FLAG_WHOLE_STREAM;
+               ret = (*ctx->cbs.begin_stream)(ctx->cur_stream,
+                                              flags,
                                               ctx->cbs.begin_stream_ctx);
                if (ret)
                        return ret;
@@ -924,9 +1002,9 @@ streamifier_cb(const void *chunk, size_t size, void *_ctx)
        /* Consume the chunk.  */
        ret = (*ctx->cbs.consume_chunk)(chunk, size,
                                        ctx->cbs.consume_chunk_ctx);
+       ctx->cur_stream_offset += size;
        if (ret)
                return ret;
-       ctx->cur_stream_offset += size;
 
        if (ctx->cur_stream_offset == ctx->cur_stream->size) {
                /* Finished reading all the data for a stream.  */
@@ -961,7 +1039,7 @@ struct hasher_context {
 /* Callback for starting to read a stream while calculating its SHA1 message
  * digest.  */
 static int
-hasher_begin_stream(struct wim_lookup_table_entry *lte, bool is_partial_res,
+hasher_begin_stream(struct wim_lookup_table_entry *lte, u32 flags,
                    void *_ctx)
 {
        struct hasher_context *ctx = _ctx;
@@ -971,7 +1049,7 @@ hasher_begin_stream(struct wim_lookup_table_entry *lte, bool is_partial_res,
        if (ctx->cbs.begin_stream == NULL)
                return 0;
        else
-               return (*ctx->cbs.begin_stream)(lte, is_partial_res,
+               return (*ctx->cbs.begin_stream)(lte, flags,
                                                ctx->cbs.begin_stream_ctx);
 }
 
@@ -991,6 +1069,13 @@ hasher_consume_chunk(const void *chunk, size_t size, void *_ctx)
                return (*ctx->cbs.consume_chunk)(chunk, size, ctx->cbs.consume_chunk_ctx);
 }
 
+static void
+get_sha1_string(const u8 md[SHA1_HASH_SIZE], tchar *str)
+{
+       for (size_t i = 0; i < SHA1_HASH_SIZE; i++)
+               str += tsprintf(str, T("%02x"), md[i]);
+}
+
 /* Callback for finishing reading a stream while calculating its SHA1 message
  * digest.  */
 static int
@@ -1023,9 +1108,14 @@ hasher_end_stream(struct wim_lookup_table_entry *lte, int status, void *_ctx)
                         * that it is the same as the calculated value.  */
                        if (!hashes_equal(hash, lte->hash)) {
                                if (wimlib_print_errors) {
-                                       ERROR("Invalid SHA1 message digest "
-                                             "on the following WIM stream:");
-                                       print_lookup_table_entry(lte, stderr);
+                                       tchar expected_hashstr[SHA1_HASH_SIZE * 2 + 1];
+                                       tchar actual_hashstr[SHA1_HASH_SIZE * 2 + 1];
+                                       get_sha1_string(lte->hash, expected_hashstr);
+                                       get_sha1_string(hash, actual_hashstr);
+                                       ERROR("The stream is corrupted!\n"
+                                             "        (Expected SHA1=%"TS",\n"
+                                             "              got SHA1=%"TS")",
+                                             expected_hashstr, actual_hashstr);
                                }
                                ret = WIMLIB_ERR_INVALID_RESOURCE_HASH;
                                errno = EINVAL;
@@ -1049,7 +1139,7 @@ read_full_stream_with_cbs(struct wim_lookup_table_entry *lte,
 {
        int ret;
 
-       ret = (*cbs->begin_stream)(lte, false, cbs->begin_stream_ctx);
+       ret = (*cbs->begin_stream)(lte, 0, cbs->begin_stream_ctx);
        if (ret)
                return ret;
 
@@ -1077,7 +1167,6 @@ read_full_stream_with_sha1(struct wim_lookup_table_entry *lte,
                .consume_chunk_ctx      = &hasher_ctx,
                .end_stream             = hasher_end_stream,
                .end_stream_ctx         = &hasher_ctx,
-
        };
        return read_full_stream_with_cbs(lte, &hasher_cbs);
 }