/*
* 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", "
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)
/* 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
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
/*
* 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 "
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;
/* 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);
}
#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;
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;
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.
*
* 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;
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;
}
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. */
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;
*
* 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;
+ }
}
/*
*
* 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;
- if ((lte->resource_entry.flags & WIM_RESHDR_FLAG_METADATA) &&
- !w->write_metadata)
- return 0;
-
ret = write_wim_resource(lte, w->out_fp,
wim_resource_compression_type(lte),
<e->output_resource_entry, 0);
- if (ret != 0)
- return ret;
- lte->out_refcnt = lte->refcnt;
- lte->part_number = w->hdr.part_number;
- return 0;
+ if (ret == 0) {
+ lte->out_refcnt = lte->refcnt;
+ lte->part_number = w->hdr.part_number;
+ }
+ return ret;
}