]> wimlib.net Git - wimlib/blobdiff - src/resource.c
win32_read_file: Use UTF16-LE name
[wimlib] / src / resource.c
index 66360130229ea6931f906ed09ca5f9197c782635..ee2b2941c8448ed13821855e9cb5a65669f49e68 100644 (file)
@@ -1,11 +1,11 @@
 /*
  * resource.c
  *
- * Read uncompressed and compressed metadata and file resources.
+ * Read uncompressed and compressed metadata and file resources from a WIM file.
  */
 
 /*
- * Copyright (C) 2012 Eric Biggers
+ * Copyright (C) 2012, 2013 Eric Biggers
  *
  * This file is part of wimlib, a library for working with WIM files.
  *
  * wimlib; if not, see http://www.gnu.org/licenses/.
  */
 
-#include "config.h"
-
-#include <stdlib.h>
-#include <stdarg.h>
-
-#include "dentry.h"
-
 #include "wimlib_internal.h"
+#include "dentry.h"
 #include "lookup_table.h"
 #include "buffer_io.h"
 #include "lzx.h"
 #include "xpress.h"
 #include "sha1.h"
-#include <unistd.h>
+
+#ifdef __WIN32__
+#  include "win32.h"
+#endif
+
 #include <errno.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
 
 #ifdef WITH_NTFS_3G
-#include <time.h>
-#include <ntfs-3g/attrib.h>
-#include <ntfs-3g/inode.h>
-#include <ntfs-3g/dir.h>
+#  include <time.h>
+#  include <ntfs-3g/attrib.h>
+#  include <ntfs-3g/inode.h>
+#  include <ntfs-3g/dir.h>
 #endif
 
+#if defined(__WIN32__) && !defined(INVALID_HANDLE_VALUE)
+#  define INVALID_HANDLE_VALUE ((HANDLE)(-1))
+#endif
 
 /*
  * Reads all or part of a compressed resource into an in-memory buffer.
  *
  * Returns zero on success, nonzero on failure.
  */
-static int read_compressed_resource(FILE *fp, u64 resource_compressed_size,
-                                   u64 resource_uncompressed_size,
-                                   u64 resource_offset, int resource_ctype,
-                                   u64 len, u64 offset, u8  contents_ret[])
+static int
+read_compressed_resource(FILE *fp, u64 resource_compressed_size,
+                        u64 resource_uncompressed_size,
+                        u64 resource_offset, int resource_ctype,
+                        u64 len, u64 offset, void *contents_ret)
 {
 
        DEBUG2("comp size = %"PRIu64", uncomp size = %"PRIu64", "
@@ -211,7 +216,7 @@ static int read_compressed_resource(FILE *fp, u64 resource_compressed_size,
 
        /* Pointer to current position in the output buffer for uncompressed
         * data. */
-       u8 *out_p = (u8*)contents_ret;
+       u8 *out_p = contents_ret;
 
        /* Buffer for compressed data.  While most compressed chunks will have a
         * size much less than WIM_CHUNK_SIZE, WIM_CHUNK_SIZE - 1 is the maximum
@@ -283,9 +288,9 @@ static int read_compressed_resource(FILE *fp, u64 resource_compressed_size,
                bool is_partial_chunk = (partial_chunk_size !=
                                                uncompressed_chunk_size);
 
-               DEBUG2("start_offset = %u, end_offset = %u", start_offset,
-                                       end_offset);
-               DEBUG2("partial_chunk_size = %u", partial_chunk_size);
+               DEBUG2("start_offset = %"PRIu64", end_offset = %"PRIu64"",
+                      start_offset, end_offset);
+               DEBUG2("partial_chunk_size = %"PRIu64"", partial_chunk_size);
 
                /* This is undocumented, but chunks can be uncompressed.  This
                 * appears to always be the case when the compressed chunk size
@@ -353,8 +358,8 @@ err:
 /*
  * Reads uncompressed data from an open file stream.
  */
-int read_uncompressed_resource(FILE *fp, u64 offset, u64 len,
-                              u8 contents_ret[])
+int
+read_uncompressed_resource(FILE *fp, u64 offset, u64 len, void *contents_ret)
 {
        if (fseeko(fp, offset, SEEK_SET) != 0) {
                ERROR("Failed to seek to byte %"PRIu64" of input file "
@@ -375,13 +380,11 @@ int read_uncompressed_resource(FILE *fp, u64 offset, u64 len,
        return 0;
 }
 
-
-
-
 /* Reads the contents of a struct resource_entry, as represented in the on-disk
  * format, from the memory pointed to by @p, and fills in the fields of @entry.
  * A pointer to the byte after the memory read at @p is returned. */
-const u8 *get_resource_entry(const u8 *p, struct resource_entry *entry)
+const u8 *
+get_resource_entry(const u8 *p, struct resource_entry *entry)
 {
        u64 size;
        u8 flags;
@@ -411,7 +414,8 @@ const u8 *get_resource_entry(const u8 *p, struct resource_entry *entry)
 /* Copies the struct resource_entry @entry to the memory pointed to by @p in the
  * on-disk format.  A pointer to the byte after the memory written at @p is
  * returned. */
-u8 *put_resource_entry(u8 *p, const struct resource_entry *entry)
+u8 *
+put_resource_entry(u8 *p, const struct resource_entry *entry)
 {
        p = put_u56(p, entry->size);
        p = put_u8(p, entry->flags);
@@ -421,7 +425,8 @@ u8 *put_resource_entry(u8 *p, const struct resource_entry *entry)
 }
 
 #ifdef WITH_FUSE
-static FILE *wim_get_fp(WIMStruct *w)
+static FILE *
+wim_get_fp(WIMStruct *w)
 {
        pthread_mutex_lock(&w->fp_tab_mutex);
        FILE *fp;
@@ -444,7 +449,8 @@ out:
        return fp;
 }
 
-static int wim_release_fp(WIMStruct *w, FILE *fp)
+static int
+wim_release_fp(WIMStruct *w, FILE *fp)
 {
        int ret = 0;
        FILE **fp_tab;
@@ -471,7 +477,7 @@ out:
        pthread_mutex_unlock(&w->fp_tab_mutex);
        return ret;
 }
-#endif
+#endif /* !WITH_FUSE */
 
 /*
  * Reads some data from the resource corresponding to a WIM lookup table entry.
@@ -483,8 +489,9 @@ out:
  *
  * Returns zero on success, nonzero on failure.
  */
-int read_wim_resource(const struct lookup_table_entry *lte, u8 buf[],
-                     size_t size, u64 offset, int flags)
+int
+read_wim_resource(const struct wim_lookup_table_entry *lte, void *buf,
+                 size_t size, u64 offset, int flags)
 {
        int ctype;
        int ret = 0;
@@ -546,8 +553,8 @@ int read_wim_resource(const struct lookup_table_entry *lte, u8 buf[],
        case RESOURCE_IN_FILE_ON_DISK:
                /* The resource is in some file on the external filesystem and
                 * needs to be read uncompressed */
-               wimlib_assert(lte->file_on_disk);
-               wimlib_assert(&lte->file_on_disk == &lte->staging_file_name);
+               wimlib_assert(lte->file_on_disk != NULL);
+               BUILD_BUG_ON(&lte->file_on_disk != &lte->staging_file_name);
                /* Use existing file pointer if available; otherwise open one
                 * temporarily */
                if (lte->file_on_disk_fp) {
@@ -565,6 +572,14 @@ int read_wim_resource(const struct lookup_table_entry *lte, u8 buf[],
                if (fp != lte->file_on_disk_fp)
                        fclose(fp);
                break;
+#ifdef __WIN32__
+       case RESOURCE_WIN32:
+               wimlib_assert(lte->win32_file_on_disk_fp != INVALID_HANDLE_VALUE);
+               ret = win32_read_file(lte->win32_file_on_disk,
+                                     lte->win32_file_on_disk_fp, offset, size,
+                                     buf);
+               break;
+#endif
        case RESOURCE_IN_ATTACHED_BUFFER:
                /* The resource is directly attached uncompressed in an
                 * in-memory buffer. */
@@ -580,7 +595,7 @@ int read_wim_resource(const struct lookup_table_entry *lte, u8 buf[],
                if (ntfs_attr_pread(lte->attr, offset, size, buf) != size) {
                        ERROR_WITH_ERRNO("Error reading NTFS attribute "
                                         "at `%s'",
-                                        lte->ntfs_loc->path_utf8);
+                                        lte->ntfs_loc->path);
                        ret = WIMLIB_ERR_NTFS_3G;
                }
                break;
@@ -603,62 +618,100 @@ int read_wim_resource(const struct lookup_table_entry *lte, u8 buf[],
  *
  * Returns 0 on success; nonzero on failure.
  */
-int read_full_wim_resource(const struct lookup_table_entry *lte, u8 buf[],
-                          int flags)
+int
+read_full_wim_resource(const struct wim_lookup_table_entry *lte,
+                      void *buf, int flags)
 {
        return read_wim_resource(lte, buf, wim_resource_size(lte), 0, flags);
 }
 
-/*
- * Extracts the first @size bytes of the WIM resource specified by @lte to the
- * open file descriptor @fd.
+/* Extracts the first @size bytes of a WIM resource to somewhere.  In the
+ * process, the SHA1 message digest of the resource is checked if the full
+ * resource is being extracted.
  *
- * Returns 0 on success; nonzero on failure.
- */
-int extract_wim_resource_to_fd(const struct lookup_table_entry *lte, int fd,
-                              u64 size)
+ * @extract_chunk is a function that is called to extract each chunk of the
+ * resource. */
+int
+extract_wim_resource(const struct wim_lookup_table_entry *lte,
+                    u64 size,
+                    extract_chunk_func_t extract_chunk,
+                    void *extract_chunk_arg)
 {
        u64 bytes_remaining = size;
        u8 buf[min(WIM_CHUNK_SIZE, bytes_remaining)];
        u64 offset = 0;
        int ret = 0;
        u8 hash[SHA1_HASH_SIZE];
-
+       bool check_hash = (size == wim_resource_size(lte));
        SHA_CTX ctx;
-       sha1_init(&ctx);
+
+       if (check_hash)
+               sha1_init(&ctx);
 
        while (bytes_remaining) {
-               u64 to_read = min(bytes_remaining, WIM_CHUNK_SIZE);
+               u64 to_read = min(bytes_remaining, sizeof(buf));
                ret = read_wim_resource(lte, buf, to_read, offset, 0);
                if (ret != 0)
-                       break;
-               sha1_update(&ctx, buf, to_read);
-               if (full_write(fd, buf, to_read) < to_read) {
+                       return ret;
+               if (check_hash)
+                       sha1_update(&ctx, buf, to_read);
+               ret = extract_chunk(buf, to_read, offset, extract_chunk_arg);
+               if (ret != 0) {
                        ERROR_WITH_ERRNO("Error extracting WIM resource");
-                       return WIMLIB_ERR_WRITE;
+                       return ret;
                }
                bytes_remaining -= to_read;
                offset += to_read;
        }
-       sha1_final(hash, &ctx);
-       if (!hashes_equal(hash, lte->hash)) {
-               ERROR("Invalid checksum on a WIM resource "
-                     "(detected when extracting to external file)");
-               ERROR("The following WIM resource is invalid:");
-               print_lookup_table_entry(lte);
-               return WIMLIB_ERR_INVALID_RESOURCE_HASH;
+       if (check_hash) {
+               sha1_final(hash, &ctx);
+               if (!hashes_equal(hash, lte->hash)) {
+               #ifdef ENABLE_ERROR_MESSAGES
+                       ERROR("Invalid checksum on the following WIM resource:");
+                       print_lookup_table_entry(lte, stderr);
+               #endif
+                       return WIMLIB_ERR_INVALID_RESOURCE_HASH;
+               }
        }
        return 0;
 }
 
-/*
- * Extracts the WIM resource specified by @lte to the open file descriptor @fd.
+/* Write @n bytes from @buf to the file descriptor @fd, retrying on internupt
+ * and on short writes.
  *
- * Returns 0 on success; nonzero on failure.
- */
-int extract_full_wim_resource_to_fd(const struct lookup_table_entry *lte, int fd)
+ * Returns short count and set errno on failure. */
+static ssize_t
+full_write(int fd, const void *buf, size_t n)
 {
-       return extract_wim_resource_to_fd(lte, fd, wim_resource_size(lte));
+       const void *p = buf;
+       ssize_t ret;
+       ssize_t total = 0;
+
+       while (total != n) {
+               ret = write(fd, p, n);
+               if (ret < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       else
+                               break;
+               }
+               total += ret;
+               p += ret;
+       }
+       return total;
+}
+
+int
+extract_wim_chunk_to_fd(const void *buf, size_t len, u64 offset, void *arg)
+{
+       int fd = *(int*)arg;
+       ssize_t ret = full_write(fd, buf, len);
+       if (ret < len) {
+               ERROR_WITH_ERRNO("Error writing to file descriptor");
+               return WIMLIB_ERR_WRITE;
+       } else {
+               return 0;
+       }
 }
 
 /*
@@ -668,8 +721,11 @@ int extract_full_wim_resource_to_fd(const struct lookup_table_entry *lte, int fd
  *
  * The output_resource_entry, out_refcnt, and part_number fields of @lte are
  * updated.
+ *
+ * (This function is confusing and should be refactored somehow.)
  */
-int copy_resource(struct lookup_table_entry *lte, void *wim)
+int
+copy_resource(struct wim_lookup_table_entry *lte, void *wim)
 {
        WIMStruct *w = wim;
        int ret;