X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fresource.c;h=d3380caf66a7380fa9d9b7b5344539b9663f6d51;hb=720db87557918105b17b51b03f264ddb9b89d2b9;hp=66360130229ea6931f906ed09ca5f9197c782635;hpb=c6e063fcb2b1ffa76df62ab902a38bf5f604d2e2;p=wimlib diff --git a/src/resource.c b/src/resource.c index 66360130..d3380caf 100644 --- a/src/resource.c +++ b/src/resource.c @@ -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. * @@ -22,29 +22,33 @@ * wimlib; if not, see http://www.gnu.org/licenses/. */ -#include "config.h" - -#include -#include - -#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 + +#ifdef __WIN32__ +# include "win32.h" +#endif + #include +#include +#include +#include #ifdef WITH_NTFS_3G -#include -#include -#include -#include +# include +# include +# include +# include #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. @@ -64,10 +68,11 @@ * * 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", " @@ -75,7 +80,7 @@ static int read_compressed_resource(FILE *fp, u64 resource_compressed_size, resource_compressed_size, resource_uncompressed_size, resource_offset); - DEBUG2("resource_ctype = %s, len = %"PRIu64", offset = %"PRIu64"", + DEBUG2("resource_ctype = %"TS", len = %"PRIu64", offset = %"PRIu64"", wimlib_get_compression_type_string(resource_ctype), len, offset); /* Trivial case */ if (len == 0) @@ -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; @@ -435,16 +440,17 @@ static FILE *wim_get_fp(WIMStruct *w) goto out; } } - DEBUG("Opening extra file descriptor to `%s'", w->filename); - fp = fopen(w->filename, "rb"); + DEBUG("Opening extra file descriptor to `%"TS"'", w->filename); + fp = tfopen(w->filename, T("rb")); if (!fp) - ERROR_WITH_ERRNO("Failed to open `%s'", w->filename); + ERROR_WITH_ERRNO("Failed to open `%"TS"'", w->filename); out: pthread_mutex_unlock(&w->fp_tab_mutex); 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,17 +553,17 @@ 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(<e->file_on_disk == <e->staging_file_name); + wimlib_assert(lte->file_on_disk != NULL); + BUILD_BUG_ON(<e->file_on_disk != <e->staging_file_name); /* Use existing file pointer if available; otherwise open one * temporarily */ if (lte->file_on_disk_fp) { fp = lte->file_on_disk_fp; } else { - fp = fopen(lte->file_on_disk, "rb"); + fp = tfopen(lte->file_on_disk, T("rb")); if (!fp) { ERROR_WITH_ERRNO("Failed to open the file " - "`%s'", lte->file_on_disk); + "`%"TS"'", lte->file_on_disk); ret = WIMLIB_ERR_OPEN; break; } @@ -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->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. */ @@ -579,8 +594,8 @@ int read_wim_resource(const struct lookup_table_entry *lte, u8 buf[], offset += 8; if (ntfs_attr_pread(lte->attr, offset, size, buf) != size) { ERROR_WITH_ERRNO("Error reading NTFS attribute " - "at `%s'", - lte->ntfs_loc->path_utf8); + "at `%"TS"'", + 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;