]> wimlib.net Git - wimlib/blobdiff - src/resource.c
resource.c: Don't manually align buffer for uncompressed data
[wimlib] / src / resource.c
index b45db5973a9e261dfb316e0c355dbee04ce5f130..13c1581fc866ff48e51fef709ef75887c0109c3c 100644 (file)
@@ -7,27 +7,26 @@
 /*
  * Copyright (C) 2012, 2013 Eric Biggers
  *
- * This file is part of wimlib, a library for working with WIM files.
+ * This file is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option) any
+ * later version.
  *
- * wimlib is free software; you can redistribute it and/or modify it under the
- * terms of the GNU General Public License as published by the Free Software
- * Foundation; either version 3 of the License, or (at your option) any later
- * version.
+ * This file is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
  *
- * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
- * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * wimlib; if not, see http://www.gnu.org/licenses/.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this file; if not, see http://www.gnu.org/licenses/.
  */
 
 #ifdef HAVE_CONFIG_H
 #  include "config.h"
 #endif
 
-#include "wimlib.h"
 #include "wimlib/assert.h"
+#include "wimlib/bitops.h"
 #include "wimlib/endianness.h"
 #include "wimlib/error.h"
 #include "wimlib/file_io.h"
@@ -37,7 +36,7 @@
 #include "wimlib/wim.h"
 
 #ifdef __WIN32__
-/* for read_win32_file_prefix(), read_win32_encrypted_file_prefix() */
+/* for read_winnt_file_prefix(), read_win32_encrypted_file_prefix() */
 #  include "wimlib/win32.h"
 #endif
 
@@ -169,9 +168,9 @@ read_compressed_wim_resource(const struct wim_resource_spec * const rspec,
        struct filedes * const in_fd = &rspec->wim->in_fd;
 
        /* Determine if we're reading a pipable resource from a pipe or not.  */
-       const bool is_pipe_read = !filedes_is_seekable(in_fd);
+       const bool is_pipe_read = (rspec->is_pipable && !filedes_is_seekable(in_fd));
 
-       /* Determine if the chunk table is in an altenate format.  */
+       /* Determine if the chunk table is in an alternate format.  */
        const bool alt_chunk_table = (rspec->flags & WIM_RESHDR_FLAG_PACKED_STREAMS)
                                        && !is_pipe_read;
 
@@ -193,6 +192,7 @@ read_compressed_wim_resource(const struct wim_resource_spec * const rspec,
                      "expected power-of-2 chunk size (got %"PRIu32")",
                      chunk_size);
                ret = WIMLIB_ERR_INVALID_CHUNK_SIZE;
+               errno = EINVAL;
                goto out_free_memory;
        }
 
@@ -205,13 +205,16 @@ read_compressed_wim_resource(const struct wim_resource_spec * const rspec,
                rspec->wim->decompressor_ctype = WIMLIB_COMPRESSION_TYPE_NONE;
                rspec->wim->decompressor = NULL;
        } else {
-               ret = wimlib_create_decompressor(ctype, chunk_size, NULL,
+               ret = wimlib_create_decompressor(ctype, chunk_size,
                                                 &decompressor);
-               if (ret)
+               if (ret) {
+                       if (ret != WIMLIB_ERR_NOMEM)
+                               errno = EINVAL;
                        goto out_free_memory;
+               }
        }
 
-       const u32 chunk_order = bsr32(chunk_size);
+       const u32 chunk_order = fls32(chunk_size);
 
        /* Calculate the total number of chunks the resource is divided into.  */
        const u64 num_chunks = (rspec->uncompressed_size + chunk_size - 1) >> chunk_order;
@@ -323,8 +326,8 @@ read_compressed_wim_resource(const struct wim_resource_spec * const rspec,
                /* Now fill in chunk_offsets from the entries we have read in
                 * chunk_tab_data.  We break aliasing rules here to avoid having
                 * to allocate yet another array.  */
-               typedef le64 __attribute__((may_alias)) aliased_le64_t;
-               typedef le32 __attribute__((may_alias)) aliased_le32_t;
+               typedef le64 _may_alias_attribute aliased_le64_t;
+               typedef le32 _may_alias_attribute aliased_le32_t;
                u64 * chunk_offsets_p = chunk_offsets;
 
                if (alt_chunk_table) {
@@ -562,6 +565,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 +679,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 +761,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 +781,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 +791,34 @@ read_file_on_disk_prefix(const struct wim_lookup_table_entry *lte, u64 size,
        filedes_close(&fd);
        return ret;
 }
-#endif /* !__WIN32__ */
+
+#ifdef WITH_FUSE
+static int
+read_staging_file_prefix(const struct wim_lookup_table_entry *lte, u64 size,
+                        consume_data_callback_t cb, void *cb_ctx)
+{
+       int raw_fd;
+       struct filedes fd;
+       int ret;
+
+       wimlib_assert(size <= lte->size);
+
+       DEBUG("Reading %"PRIu64" bytes from staging file \"%s\"",
+             size, lte->staging_file_name);
+
+       raw_fd = openat(lte->staging_dir_fd, lte->staging_file_name,
+                       O_RDONLY | O_NOFOLLOW);
+       if (raw_fd < 0) {
+               ERROR_WITH_ERRNO("Can't open staging file \"%s\"",
+                                lte->staging_file_name);
+               return WIMLIB_ERR_OPEN;
+       }
+       filedes_init(&fd, raw_fd);
+       ret = read_raw_file_data(&fd, 0, size, cb, cb_ctx);
+       filedes_close(&fd);
+       return ret;
+}
+#endif
 
 /* This function handles the trivial case of reading stream data that is, in
  * fact, already located in an in-memory buffer.  */
@@ -779,19 +856,16 @@ 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,
+               [RESOURCE_IN_STAGING_FILE]    = read_staging_file_prefix,
        #endif
        #ifdef WITH_NTFS_3G
                [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
        };
@@ -940,10 +1014,12 @@ 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) {
+
                /* Starting a new stream.  */
                DEBUG("Begin new stream (size=%"PRIu64").",
                      ctx->cur_stream->size);
-               ret = (*ctx->cbs.begin_stream)(ctx->cur_stream, true,
+
+               ret = (*ctx->cbs.begin_stream)(ctx->cur_stream,
                                               ctx->cbs.begin_stream_ctx);
                if (ret)
                        return ret;
@@ -952,9 +1028,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.  */
@@ -989,8 +1065,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,
-                   void *_ctx)
+hasher_begin_stream(struct wim_lookup_table_entry *lte, void *_ctx)
 {
        struct hasher_context *ctx = _ctx;
 
@@ -999,8 +1074,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,
-                                               ctx->cbs.begin_stream_ctx);
+               return (*ctx->cbs.begin_stream)(lte, ctx->cbs.begin_stream_ctx);
 }
 
 /* A consume_data_callback_t implementation that continues calculating the SHA1
@@ -1019,13 +1093,6 @@ 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
@@ -1060,8 +1127,8 @@ hasher_end_stream(struct wim_lookup_table_entry *lte, int status, void *_ctx)
                                if (wimlib_print_errors) {
                                        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);
+                                       sprint_hash(lte->hash, expected_hashstr);
+                                       sprint_hash(hash, actual_hashstr);
                                        ERROR("The stream is corrupted!\n"
                                              "        (Expected SHA1=%"TS",\n"
                                              "              got SHA1=%"TS")",
@@ -1089,7 +1156,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, cbs->begin_stream_ctx);
        if (ret)
                return ret;
 
@@ -1117,7 +1184,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);
 }
@@ -1361,7 +1427,7 @@ extract_stream(struct wim_lookup_table_entry *lte, u64 size,
 
 /* A consume_data_callback_t implementation that writes the chunk of data to a
  * file descriptor.  */
-int
+static int
 extract_chunk_to_fd(const void *chunk, size_t size, void *_fd_p)
 {
        struct filedes *fd = _fd_p;