* instead either symlinks or hardlinks *all* identical files in
* the WIM, even if they are in a different image (in the case
* of a multi-image extraction) */
-
- wimlib_assert(lte->file_on_disk);
-
+ wimlib_assert(lte->extracted_file);
if (extract_flags & WIMLIB_EXTRACT_FLAG_HARDLINK) {
- if (link(lte->file_on_disk, output_path) != 0) {
+ if (link(lte->extracted_file, output_path) != 0) {
ERROR_WITH_ERRNO("Failed to hard link "
"`%s' to `%s'",
- output_path, lte->file_on_disk);
+ output_path, lte->extracted_file);
return WIMLIB_ERR_LINK;
}
} else {
int num_path_components;
int num_output_dir_path_components;
- size_t file_on_disk_len;
+ size_t extracted_file_len;
char *p;
const char *p2;
size_t i;
num_path_components++;
num_output_dir_path_components--;
}
- file_on_disk_len = strlen(lte->file_on_disk);
+ extracted_file_len = strlen(lte->extracted_file);
- char buf[file_on_disk_len + 3 * num_path_components + 1];
+ char buf[extracted_file_len + 3 * num_path_components + 1];
p = &buf[0];
for (i = 0; i < num_path_components; i++) {
*p++ = '.';
*p++ = '/';
}
- p2 = lte->file_on_disk;
+ p2 = lte->extracted_file;
while (*p2 == '/')
p2++;
while (num_output_dir_path_components--)
if (symlink(buf, output_path) != 0) {
ERROR_WITH_ERRNO("Failed to symlink `%s' to "
"`%s'",
- buf, lte->file_on_disk);
+ buf, lte->extracted_file);
return WIMLIB_ERR_LINK;
}
int ret;
const struct list_head *head = &dentry->link_group_list;
- if (head->next != head) {
+ if (head->next != head &&
+ !(extract_flags & WIMLIB_EXTRACT_FLAG_MULTI_IMAGE))
+ {
/* This dentry is one of a hard link set of at least 2 dentries.
* If one of the other dentries has already been extracted, make
* a hard link to the file corresponding to this
goto done;
}
- if (extract_flags & WIMLIB_EXTRACT_FLAG_MULTI_IMAGE) {
- /* Mark the lookup table entry to indicate this file has been
- * extracted. */
- lte->out_refcnt++;
- FREE(lte->file_on_disk);
- lte->file_on_disk = STRDUP(output_path);
- if (!lte->file_on_disk)
- ret = WIMLIB_ERR_NOMEM;
- }
done:
if (close(out_fd) != 0) {
ERROR_WITH_ERRNO("Failed to close file `%s'", output_path);
if ((extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK |
WIMLIB_EXTRACT_FLAG_HARDLINK)) && lte) {
- if (lte->out_refcnt++ != 0)
+ if (++lte->out_refcnt != 1)
return extract_regular_file_linked(dentry, output_dir,
output_path,
extract_flags, lte);
- lte->file_on_disk = STRDUP(output_path);
- if (!lte->file_on_disk)
+ lte->extracted_file = STRDUP(output_path);
+ if (!lte->extracted_file)
return WIMLIB_ERR_NOMEM;
}
char *file_on_disk;
char *staging_file_name;
u8 *attached_buffer;
+ };
+ union {
struct lookup_table_entry *next_lte_in_swm;
+ FILE *file_on_disk_fp;
};
- FILE *file_on_disk_fp;
#ifdef WITH_FUSE
/* File descriptors table for this data stream */
u16 num_opened_fds;
* output_resource_entry is the struct resource_entry for the position of the
* file resource when written to the output file. */
u32 out_refcnt;
- struct resource_entry output_resource_entry;
+ union {
+ struct resource_entry output_resource_entry;
+ char *extracted_file;
+ };
/* Circular linked list of streams that share the same lookup table
* entry
dest_lte = new_lookup_table_entry();
if (!dest_lte)
return WIMLIB_ERR_NOMEM;
+ dest_lte->resource_location = RESOURCE_IN_WIM;
dest_lte->wim = src_wim;
memcpy(&dest_lte->resource_entry,
&src_lte->resource_entry,
wimlib_assert(lte);
wimlib_assert(lte->num_opened_fds);
- if (lte->staging_file_name) {
+ if (lte->resource_location == RESOURCE_IN_STAGING_FILE) {
+ wimlib_assert(lte->staging_file_name);
wimlib_assert(fd->staging_fd != -1);
if (close(fd->staging_fd) != 0)
return -errno;
}
if (--lte->num_opened_fds == 0 && lte->refcnt == 0) {
- if (lte->staging_file_name)
+ if (lte->resource_location == RESOURCE_IN_STAGING_FILE) {
+ wimlib_assert(lte->staging_file_name);
unlink(lte->staging_file_name);
+ }
free_lookup_table_entry(lte);
}
wimlib_assert(lte->fds[fd->idx] == fd);
/* Use the size of the unnamed (default) file stream. */
lte = dentry_first_lte_resolved(dentry);
if (lte) {
- if (lte->staging_file_name) {
+ if (lte->resource_location == RESOURCE_IN_STAGING_FILE) {
+ wimlib_assert(lte->staging_file_name);
struct stat native_stat;
if (stat(lte->staging_file_name, &native_stat) != 0) {
DEBUG("Failed to stat `%s': %m",
{
for (u16 i = 0, j = 0; j < lte->num_opened_fds; i++) {
if (lte->fds[i] && lte->fds[i]->staging_fd != -1) {
+ wimlib_assert(lte->resource_location == RESOURCE_IN_STAGING_FILE);
+ wimlib_assert(lte->staging_file_name);
if (close(lte->fds[i]->staging_fd) != 0) {
ERROR_WITH_ERRNO("Failed close file `%s'",
lte->staging_file_name);
u8 hash[SHA1_HASH_SIZE];
struct stat stbuf;
+ wimlib_assert(lte->resource_location == RESOURCE_IN_STAGING_FILE);
wimlib_assert(lte->staging_file_name);
ret = sha1sum(lte->staging_file_name, hash);
if (ret != 0)
return ret;
-
lookup_table_unlink(table, lte);
duplicate_lte = __lookup_resource(table, hash);
ERROR_WITH_ERRNO("Failed to stat `%s'", lte->staging_file_name);
return WIMLIB_ERR_STAT;
}
+ wimlib_assert(<e->file_on_disk == <e->staging_file_name);
+ lte->resource_location = RESOURCE_IN_FILE_ON_DISK;
copy_hash(lte->hash, hash);
lte->resource_entry.original_size = stbuf.st_size;
+ lte->resource_entry.size = stbuf.st_size;
lookup_table_insert(table, lte);
}
if (ret != 0)
return ret;
}
- if (lte->staging_file_name) {
+ if (lte->resource_location == RESOURCE_IN_STAGING_FILE) {
fd->staging_fd = open(lte->staging_file_name, fi->flags);
if (fd->staging_fd == -1) {
close_wimlib_fd(fd);
wimlib_assert(fd->lte);
- if (fd->lte->staging_file_name) {
+ if (fd->lte->resource_location == RESOURCE_IN_STAGING_FILE) {
/* Read from staging file */
+ wimlib_assert(fd->lte->staging_file_name);
wimlib_assert(fd->staging_fd != -1);
ssize_t ret;
const u8 *out_chunk;
unsigned out_chunk_size;
- if (out_ctype == WIM_COMPRESSION_TYPE_NONE) {
- wimlib_assert(chunk_tab == NULL);
+ if (!chunk_tab) {
out_chunk = chunk;
out_chunk_size = chunk_size;
} else {
int ret;
unsigned compressed_chunk_len;
- wimlib_assert(chunk_tab != NULL);
-
ret = compress_chunk(chunk, chunk_size, compressed_chunk,
&out_chunk_size, out_ctype);
if (ret == 0) {
return WIMLIB_ERR_WRITE;
}
- raw = (wim_resource_compression_type(lte) == out_ctype);
+ raw = (wim_resource_compression_type(lte) == out_ctype
+ && out_ctype != WIM_COMPRESSION_TYPE_NONE);
if (raw)
bytes_remaining = old_compressed_size;
else
goto out;
}
}
+ SHA_CTX ctx;
+ if (!raw)
+ sha1_init(&ctx);
do {
u64 to_read = min(bytes_remaining, WIM_CHUNK_SIZE);
ret = __read_wim_resource(lte, buf, to_read, offset, raw);
if (ret != 0)
goto out_fclose;
+ if (!raw)
+ sha1_update(&ctx, buf, to_read);
ret = write_wim_resource_chunk(buf, to_read, out_fp,
out_ctype, chunk_tab);
if (ret != 0)
new_compressed_size = old_compressed_size;
}
+ if (!raw) {
+ u8 md[SHA1_HASH_SIZE];
+ sha1_final(md, &ctx);
+ if (!hashes_equal(md, lte->hash)) {
+ ERROR("WIM resource has incorrect hash!");
+ if (lte->resource_location == RESOURCE_IN_FILE_ON_DISK) {
+ ERROR("We were reading it from `%s'; maybe it changed "
+ "while we were reading it.",
+ lte->file_on_disk);
+ }
+ ret = WIMLIB_ERR_INTEGRITY;
+ goto out_fclose;
+ }
+ }
+
if (new_compressed_size > original_size) {
/* Oops! We compressed the resource to larger than the original
* size. Write the resource uncompressed instead. */
out_res_entry->flags = 0;
else
out_res_entry->flags = WIM_RESHDR_FLAG_COMPRESSED;
+ if (lte->resource_entry.flags & WIM_RESHDR_FLAG_METADATA)
+ out_res_entry->flags |= WIM_RESHDR_FLAG_METADATA;
}
out_fclose:
if (lte->resource_location == RESOURCE_IN_FILE_ON_DISK
}
static int write_wim_resource_from_buffer(const u8 *buf, u64 buf_size,
+ u8 buf_hash[SHA1_HASH_SIZE],
FILE *out_fp, int out_ctype,
struct resource_entry *out_res_entry)
{
struct lookup_table_entry lte;
- lte.resource_entry.flags = 0;
+ lte.resource_entry.flags = 0;
lte.resource_entry.original_size = buf_size;
- lte.resource_entry.size = buf_size;
- lte.resource_entry.offset = 0;
- lte.resource_location = RESOURCE_IN_ATTACHED_BUFFER;
- lte.attached_buffer = (u8*)buf;
+ lte.resource_entry.size = buf_size;
+ lte.resource_entry.offset = 0;
+ lte.resource_location = RESOURCE_IN_ATTACHED_BUFFER;
+ lte.attached_buffer = (u8*)buf;
+ copy_hash(lte.hash, buf_hash);
return write_wim_resource(<e, out_fp, out_ctype, out_res_entry);
}
!w->write_metadata)
return 0;
- ret = write_wim_resource(lte, w->out_fp, wimlib_get_compression_type(w),
+ ret = write_wim_resource(lte, w->out_fp,
+ wim_resource_compression_type(lte),
<e->output_resource_entry);
if (ret != 0)
return ret;
lte = wim_metadata_lookup_table_entry(w);
ret = write_wim_resource_from_buffer(buf, metadata_original_size,
- out, metadata_ctype,
+ hash, out, metadata_ctype,
<e->output_resource_entry);
- FREE(buf);
- if (ret != 0)
- return ret;
- lte->out_refcnt++;
- lte->output_resource_entry.flags |= WIM_RESHDR_FLAG_METADATA;
lookup_table_unlink(w->lookup_table, lte);
copy_hash(lte->hash, hash);
lookup_table_insert(w->lookup_table, lte);
+ lte->out_refcnt++;
+ lte->output_resource_entry.flags |= WIM_RESHDR_FLAG_METADATA;
+ FREE(buf);
+ if (ret != 0)
+ return ret;
+
return 0;
}
* Steve Reid's public domain code, or based on Intel's SSSE3 SHA1 code.
*/
-#ifdef WITH_LIBCRYPTO
+#ifndef WITH_LIBCRYPTO
-#define sha1_init SHA1_Init
-#define sha1_update SHA1_Update
-#define sha1_final SHA1_Final
-#else /* WITH_LIBCRYPTO */
-
-typedef struct {
- u32 state[5];
- u32 count[2];
- u8 buffer[64];
-} SHA_CTX;
+/* Initialize new context */
+void sha1_init(SHA_CTX* context)
+{
+ /* SHA1 initialization constants */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xEFCDAB89;
+ context->state[2] = 0x98BADCFE;
+ context->state[3] = 0x10325476;
+ context->state[4] = 0xC3D2E1F0;
+ context->count[0] = context->count[1] = 0;
+}
#ifdef ENABLE_SSSE3_SHA1
extern void sha1_update_intel(int *hash, const char* input, size_t num_blocks);
-static inline void sha1_update(SHA_CTX *context, const void *data, size_t len)
+void sha1_update(SHA_CTX *context, const u8 data[], size_t len)
{
sha1_update_intel((int*)&context->state, data, len / 64);
size_t j = (context->count[0] >> 3) & 63;
if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
context->count[1] += (len >> 29);
}
-
#include <stdlib.h>
void ssse3_not_found()
{
"to use wimlib on this CPU.\n");
abort();
}
-#endif
-
-/* Initialize new context */
-static void sha1_init(SHA_CTX* context)
-{
- /* SHA1 initialization constants */
- context->state[0] = 0x67452301;
- context->state[1] = 0xEFCDAB89;
- context->state[2] = 0x98BADCFE;
- context->state[3] = 0x10325476;
- context->state[4] = 0xC3D2E1F0;
- context->count[0] = context->count[1] = 0;
-}
-
-#ifndef ENABLE_SSSE3_SHA1
+#else /* ENABLE_SSSE3_SHA1 */
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
state[4] += e;
}
-/* Run your data through this. */
-static void sha1_update(SHA_CTX* context, const u8* data, const size_t len)
+void sha1_update(SHA_CTX* context, const u8 data[], const size_t len)
{
size_t i, j;
}
memcpy(&context->buffer[j], &data[i], len - i);
}
-#endif
+
+#endif /* !ENABLE_SSSE3_SHA1 */
/* Add padding and return the message digest. */
-static void sha1_final(u8 *md, SHA_CTX* context)
+void sha1_final(u8 md[SHA1_HASH_SIZE], SHA_CTX* context)
{
u32 i;
u8 finalcount[8];
}
}
-void sha1_buffer(const void *buffer, size_t len, void *md)
+void sha1_buffer(const u8 buffer[], size_t len, u8 md[SHA1_HASH_SIZE])
{
SHA_CTX ctx;
sha1_init(&ctx);
sha1_final(md, &ctx);
}
-#endif /* WITH_LIBCRYPTO */
+#endif /* !WITH_LIBCRYPTO */
-static int sha1_stream(FILE *fp, void *md)
+static int sha1_stream(FILE *fp, u8 md[SHA1_HASH_SIZE])
{
char buf[BUFFER_SIZE];
size_t bytes_read;
/* Calculates the SHA1 message digest given the name of a file. @md must point
* to a buffer of length 20 bytes into which the message digest is written.
*/
-int sha1sum(const char *filename, void *md)
+int sha1sum(const char *filename, u8 md[SHA1_HASH_SIZE])
{
FILE *fp;
int ret;
print_byte_field(hash, SHA1_HASH_SIZE);
}
-extern int sha1sum(const char *filename, void *md);
#ifdef WITH_LIBCRYPTO
+
#include <openssl/sha.h>
-static inline void sha1_buffer(const void *buffer, size_t len, void *md)
-{
- SHA1(buffer, len, md);
-}
-#else
-extern void sha1_buffer(const void *buffer, size_t len, void *md);
-#endif
+#define sha1_buffer SHA1
+#define sha1_init SHA1_Init
+#define sha1_update SHA1_Update
+#define sha1_final SHA1_Final
+
+#else /* WITH_LIBCRYPTO */
+
+typedef struct {
+ u32 state[5];
+ u32 count[2];
+ u8 buffer[64];
+} SHA_CTX;
+
+extern void sha1_buffer(const u8 buffer[], size_t len, u8 hash[SHA1_HASH_SIZE]);
+extern void sha1_init(SHA_CTX *ctx);
+extern void sha1_update(SHA_CTX *ctx, const u8 data[], size_t len);
+extern void sha1_final(u8 hash[SHA1_HASH_SIZE], SHA_CTX *ctx);
+
+#endif /* !WITH_LIBCRYPTO */
+
+extern int sha1sum(const char *filename, u8 hash[SHA1_HASH_SIZE]);
+
+
#endif /* _WIMLIB_SHA1_H */
lookup_table_offset);
while (lte_chain_head != NULL) {
+ print_lookup_table_entry(lte_chain_head);
+
ret = write_lookup_table_entry(lte_chain_head, w->out_fp);
if (ret != 0)
return ret;
struct lookup_table_entry *prev = lte_chain_head;
- lte_chain_head = prev->next_lte_in_swm;
+ lte_chain_head = lte_chain_head->next_lte_in_swm;
prev->next_lte_in_swm = NULL;
}
off_t xml_data_offset = ftello(w->out_fp);
w->write_metadata = true;
for (int i = 0; i < w->hdr.image_count; i++) {
-
struct lookup_table_entry *metadata_lte;
+ DEBUG("Writing metadata resource %d", i);
+
metadata_lte = w->image_metadata[i].metadata_lte;
ret = copy_resource(metadata_lte, w);
if (ret != 0)
extern void randomize_char_array_with_alnum(char p[], size_t n);
-extern int sha1sum(const char *filename, void *buf);
-
extern const char *path_next_part(const char *path,
size_t *first_part_len_ret);
int extract_flags;
int add_flags;
int write_flags;
+ bool write_metadata;
};
/* The currently selected image, indexed starting at 1. If not 0,
* subtract 1 from this to get the index of the current image in the
* image_metadata array. */
int current_image;
-
- bool write_metadata;
} WIMStruct;