From: Eric Biggers Date: Mon, 20 Aug 2012 22:27:14 +0000 (-0500) Subject: Various fixes X-Git-Tag: v1.0.0~114 X-Git-Url: https://wimlib.net/git/?p=wimlib;a=commitdiff_plain;h=b1c4e6a269ae4c969060e33685db12f76a204a58 Various fixes --- diff --git a/src/dentry.c b/src/dentry.c index 98d117b9..2f0cabd3 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -412,13 +412,12 @@ struct file_attr_flag file_attr_flags[] = { * NULL if the resource entry for the dentry is not to be printed. */ int print_dentry(struct dentry *dentry, void *lookup_table) { - struct lookup_table_entry *lte; - unsigned i; + const u8 *hash; printf("[DENTRY]\n"); printf("Length = %"PRIu64"\n", dentry->length); printf("Attributes = 0x%x\n", dentry->attributes); - for (i = 0; i < ARRAY_LEN(file_attr_flags); i++) + for (unsigned i = 0; i < ARRAY_LEN(file_attr_flags); i++) if (file_attr_flags[i].flag & dentry->attributes) printf(" FILE_ATTRIBUTE_%s is set\n", file_attr_flags[i].name); @@ -429,9 +428,12 @@ int print_dentry(struct dentry *dentry, void *lookup_table) printf("Creation Time = 0x%"PRIx64"\n", dentry->creation_time); printf("Last Access Time = 0x%"PRIx64"\n", dentry->last_access_time); printf("Last Write Time = 0x%"PRIx64"\n", dentry->last_write_time); - printf("Hash = 0x"); - print_hash(dentry->hash); - putchar('\n'); + hash = dentry_stream_hash(dentry, 0); + if (hash) { + printf("Hash = 0x"); + print_hash(hash); + putchar('\n'); + } printf("Reparse Tag = 0x%"PRIx32"\n", dentry->reparse_tag); printf("Hard Link Group = 0x%"PRIx64"\n", dentry->hard_link); printf("Number of Alternate Data Streams = %hu\n", dentry->num_ads); @@ -446,25 +448,20 @@ int print_dentry(struct dentry *dentry, void *lookup_table) puts("\""); printf("Short Name Length = %hu\n", dentry->short_name_len); printf("Full Path (UTF-8) = \"%s\"\n", dentry->full_path_utf8); - if (lookup_table && (lte = __lookup_resource(lookup_table, dentry->hash))) - print_lookup_table_entry(lte, NULL); - else - putchar('\n'); + print_lookup_table_entry(dentry_stream_lte(dentry, 0, lookup_table)); for (u16 i = 0; i < dentry->num_ads; i++) { printf("[Alternate Stream Entry %u]\n", i); printf("Name = \"%s\"\n", dentry->ads_entries[i].stream_name_utf8); printf("Name Length (UTF-16) = %u\n", dentry->ads_entries[i].stream_name_len); - printf("Hash = 0x"); - print_hash(dentry->ads_entries[i].hash); - if (lookup_table && - (lte = __lookup_resource(lookup_table, - dentry->ads_entries[i].hash))) - { - print_lookup_table_entry(lte, NULL); - } else { + hash = dentry_stream_hash(dentry, i + 1); + if (hash) { + printf("Hash = 0x"); + print_hash(hash); putchar('\n'); } + print_lookup_table_entry(dentry_stream_lte(dentry, i + 1, + lookup_table)); } return 0; } @@ -830,7 +827,7 @@ static int read_ads_entries(const u8 *p, struct dentry *dentry, DEBUG2("ADS length = %"PRIu64, length); p += 8; /* Unused */ - p = get_bytes(p, WIM_HASH_SIZE, (u8*)cur_entry->hash); + p = get_bytes(p, SHA1_HASH_SIZE, (u8*)cur_entry->hash); p = get_u16(p, &cur_entry->stream_name_len); DEBUG2("Stream name length = %u", cur_entry->stream_name_len); @@ -946,7 +943,7 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, p = get_u64(p, &dentry->last_access_time); p = get_u64(p, &dentry->last_write_time); - p = get_bytes(p, WIM_HASH_SIZE, dentry->hash); + p = get_bytes(p, SHA1_HASH_SIZE, dentry->hash); /* * I don't know what's going on here. It seems like M$ screwed up the @@ -1111,7 +1108,7 @@ static u8 *write_dentry(const struct dentry *dentry, u8 *p) hash = dentry->lte->hash; else hash = dentry->hash; - p = put_bytes(p, WIM_HASH_SIZE, hash); + p = put_bytes(p, SHA1_HASH_SIZE, hash); if (dentry->attributes & FILE_ATTRIBUTE_REPARSE_POINT) { p = put_zeroes(p, 4); p = put_u32(p, dentry->reparse_tag); @@ -1141,7 +1138,11 @@ static u8 *write_dentry(const struct dentry *dentry, u8 *p) for (u16 i = 0; i < dentry->num_ads; i++) { p = put_u64(p, ads_entry_length(&dentry->ads_entries[i])); p = put_u64(p, 0); /* Unused */ - p = put_bytes(p, WIM_HASH_SIZE, dentry->ads_entries[i].hash); + if (dentry->resolved && dentry->ads_entries[i].lte) + hash = dentry->ads_entries[i].lte->hash; + else + hash = dentry->ads_entries[i].hash; + p = put_bytes(p, SHA1_HASH_SIZE, hash); p = put_u16(p, dentry->ads_entries[i].stream_name_len); p = put_bytes(p, dentry->ads_entries[i].stream_name_len, (u8*)dentry->ads_entries[i].stream_name); diff --git a/src/dentry.h b/src/dentry.h index f8f05235..db6481b1 100644 --- a/src/dentry.h +++ b/src/dentry.h @@ -4,6 +4,7 @@ #include "util.h" #include "config.h" #include "list.h" +#include "sha1.h" #include @@ -16,10 +17,6 @@ typedef struct WIMStruct WIMStruct; #define WIM_ADS_ENTRY_DISK_SIZE 38 -#ifndef WIM_HASH_SIZE -#define WIM_HASH_SIZE 20 -#endif - /* * Reparse tags documented at * http://msdn.microsoft.com/en-us/library/dd541667(v=prot.10).aspx @@ -58,7 +55,7 @@ struct lookup_table_entry; struct ads_entry { union { /* SHA-1 message digest of stream contents */ - u8 hash[WIM_HASH_SIZE]; + u8 hash[SHA1_HASH_SIZE]; /* The corresponding lookup table entry (only for resolved * streams) */ @@ -155,7 +152,7 @@ struct dentry { * opposed to the alternate file streams, which may have their own * lookup table entries. */ union { - u8 hash[WIM_HASH_SIZE]; + u8 hash[SHA1_HASH_SIZE]; struct lookup_table_entry *lte; }; @@ -241,31 +238,6 @@ struct dentry { char *extracted_file; }; -/* Return hash of the "unnamed" (default) data stream. */ -static inline const u8 *dentry_hash(const struct dentry *dentry) -{ - wimlib_assert(!dentry->resolved); - /* If there are alternate data streams, the dentry hash field is zeroed - * out, and we need to find the hash in the un-named data stream (should - * be the first one, but check them in order just in case, and fall back - * to the dentry hash field if we can't find an unnamed data stream). */ - for (u16 i = 0; i < dentry->num_ads; i++) - if (dentry->ads_entries[i].stream_name_len == 0) - return dentry->ads_entries[i].hash; - return dentry->hash; -} - -/* Return lte for the "unnamed" (default) data stream. Only for resolved - * dentries */ -static inline struct lookup_table_entry * -dentry_lte(const struct dentry *dentry) -{ - wimlib_assert(dentry->resolved); - for (u16 i = 0; i < dentry->num_ads; i++) - if (dentry->ads_entries[i].stream_name_len == 0) - return dentry->ads_entries[i].lte; - return dentry->lte; -} /* Return the number of dentries in the hard link group */ static inline size_t dentry_link_group_size(const struct dentry *dentry) diff --git a/src/extract.c b/src/extract.c index 1648adea..8c3aedb9 100644 --- a/src/extract.c +++ b/src/extract.c @@ -209,7 +209,7 @@ static int extract_regular_file(WIMStruct *w, { struct lookup_table_entry *lte; - lte = __lookup_resource(w->lookup_table, dentry_hash(dentry)); + lte = dentry_first_lte(dentry, w->lookup_table); if ((extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK | WIMLIB_EXTRACT_FLAG_HARDLINK)) && lte) { diff --git a/src/hardlink.c b/src/hardlink.c index ba4f2e16..b32309fd 100644 --- a/src/hardlink.c +++ b/src/hardlink.c @@ -220,9 +220,8 @@ static bool dentries_have_same_ads(const struct dentry *d1, if (strcmp(d1->ads_entries[i].stream_name_utf8, d2->ads_entries[i].stream_name_utf8) != 0) return false; - if (memcmp(d1->ads_entries[i].hash, - d2->ads_entries[i].hash, - WIM_HASH_SIZE) != 0) + if (!hashes_equal(d1->ads_entries[i].hash, + d2->ads_entries[i].hash)) return false; } return true; @@ -247,7 +246,7 @@ static int share_dentry_ads(struct dentry *owner, struct dentry *user) mismatch_type = "security ID"; goto mismatch; } - if (memcmp(owner->hash, user->hash, WIM_HASH_SIZE) != 0) { + if (!hashes_equal(owner->hash, user->hash)) { mismatch_type = "main file resource"; goto mismatch; } diff --git a/src/integrity.c b/src/integrity.c index 55d950a6..e3107161 100644 --- a/src/integrity.c +++ b/src/integrity.c @@ -50,7 +50,7 @@ static int verify_integrity(FILE *fp, u64 num_bytes, u32 chunk_size, int *status) { char *chunk_buf; - u8 resblock[WIM_HASH_SIZE]; + u8 resblock[SHA1_HASH_SIZE]; u64 bytes_remaining; size_t bytes_to_read; uint percent_done; @@ -85,11 +85,11 @@ static int verify_integrity(FILE *fp, u64 num_bytes, u32 chunk_size, goto verify_integrity_error; } sha1_buffer(chunk_buf, bytes_to_read, resblock); - if (memcmp(resblock, sha1sums, WIM_HASH_SIZE) != 0) { + if (!hashes_equal(resblock, sha1sums)) { *status = WIM_INTEGRITY_NOT_OK; goto verify_integrity_done; } - sha1sums += WIM_HASH_SIZE; + sha1sums += SHA1_HASH_SIZE; bytes_remaining -= bytes_to_read; } *status = WIM_INTEGRITY_OK; @@ -181,7 +181,7 @@ int check_wim_integrity(WIMStruct *w, int show_progress, int *status) integrity_table_size, num_entries, chunk_size); - expected_size = num_entries * WIM_HASH_SIZE + 12; + expected_size = num_entries * SHA1_HASH_SIZE + 12; if (integrity_table_size != expected_size) { ERROR("Integrity table is %u bytes, but expected %"PRIu64" " @@ -264,7 +264,7 @@ int write_integrity_table(FILE *out, u64 end_header_offset, bytes_to_check = end_lookup_table_offset - end_header_offset; num_entries = bytes_to_check / INTEGRITY_CHUNK_SIZE + (bytes_to_check % INTEGRITY_CHUNK_SIZE != 0); - integrity_table_size = num_entries * WIM_HASH_SIZE + 3 * sizeof(u32); + integrity_table_size = num_entries * SHA1_HASH_SIZE + 3 * sizeof(u32); DEBUG("integrity table size = %u", integrity_table_size); @@ -321,7 +321,7 @@ int write_integrity_table(FILE *out, u64 end_header_offset, goto err2; } sha1_buffer(chunk_buf, bytes_read, p); - p += WIM_HASH_SIZE; + p += SHA1_HASH_SIZE; bytes_remaining -= bytes_read; } if (show_progress) diff --git a/src/lookup_table.c b/src/lookup_table.c index 2ccb0ef8..a4099472 100644 --- a/src/lookup_table.c +++ b/src/lookup_table.c @@ -219,7 +219,7 @@ int read_lookup_table(FILE *fp, u64 offset, u64 size, p = get_resource_entry(buf, &cur_entry->resource_entry); p = get_u16(p, &cur_entry->part_number); p = get_u32(p, &cur_entry->refcnt); - p = get_bytes(p, WIM_HASH_SIZE, cur_entry->hash); + p = get_bytes(p, SHA1_HASH_SIZE, cur_entry->hash); lookup_table_insert(table, cur_entry); } DEBUG("Done reading lookup table."); @@ -258,7 +258,7 @@ int write_lookup_table_entry(struct lookup_table_entry *lte, void *__out) p = put_resource_entry(buf, <e->output_resource_entry); p = put_u16(p, lte->part_number); p = put_u32(p, lte->out_refcnt); - p = put_bytes(p, WIM_HASH_SIZE, lte->hash); + p = put_bytes(p, SHA1_HASH_SIZE, lte->hash); if (fwrite(buf, 1, sizeof(buf), out) != sizeof(buf)) { ERROR_WITH_ERRNO("Failed to write lookup table entry"); return WIMLIB_ERR_WRITE; @@ -274,8 +274,12 @@ int zero_out_refcnts(struct lookup_table_entry *entry, void *ignore) return 0; } -int print_lookup_table_entry(struct lookup_table_entry *lte, void *ignore) +void print_lookup_table_entry(struct lookup_table_entry *lte) { + if (!lte) { + putchar('\n'); + return; + } printf("Offset = %"PRIu64" bytes\n", lte->resource_entry.offset); printf("Size = %"PRIu64" bytes\n", @@ -301,6 +305,12 @@ int print_lookup_table_entry(struct lookup_table_entry *lte, void *ignore) if (lte->file_on_disk && !lte->is_symlink) printf("File on Disk = `%s'\n", lte->file_on_disk); putchar('\n'); +} + +static int do_print_lookup_table_entry(struct lookup_table_entry *lte, + void *ignore) +{ + print_lookup_table_entry(lte); return 0; } @@ -310,7 +320,7 @@ int print_lookup_table_entry(struct lookup_table_entry *lte, void *ignore) WIMLIBAPI void wimlib_print_lookup_table(WIMStruct *w) { for_lookup_table_entry(w->lookup_table, - print_lookup_table_entry, + do_print_lookup_table_entry, NULL); } @@ -326,7 +336,7 @@ __lookup_resource(const struct lookup_table *table, const u8 hash[]) i = *(size_t*)hash % table->capacity; hlist_for_each_entry(lte, pos, &table->array[i], hash_list) - if (memcmp(hash, lte->hash, WIM_HASH_SIZE) == 0) + if (hashes_equal(hash, lte->hash)) return lte; return NULL; } @@ -398,7 +408,8 @@ int dentry_resolve_ltes(struct dentry *dentry, void *__table) struct lookup_table *table = __table; struct lookup_table_entry *lte; - wimlib_assert(!dentry->resolved); + if (dentry->resolved) + return 0; /* Resolve the default file stream */ lte = __lookup_resource(table, dentry->hash); @@ -427,3 +438,13 @@ int dentry_resolve_ltes(struct dentry *dentry, void *__table) } return 0; } + +struct lookup_table_entry * +dentry_first_lte(const struct dentry *dentry, const struct lookup_table *table) +{ + if (dentry->resolved) + return dentry_first_lte_resolved(dentry); + else + return dentry_first_lte_unresolved(dentry, table); +} + diff --git a/src/lookup_table.h b/src/lookup_table.h index 87198143..6facf65a 100644 --- a/src/lookup_table.h +++ b/src/lookup_table.h @@ -2,6 +2,7 @@ #define _WIMLIB_LOOKUP_TABLE_H #include "wimlib_internal.h" #include "dentry.h" +#include "sha1.h" #include /* Size of each lookup table entry in the WIM file. */ @@ -23,7 +24,6 @@ struct lookup_table { struct wimlib_fd; - /* * An entry in the lookup table in the WIM file. * @@ -56,7 +56,7 @@ struct lookup_table_entry { union { /* SHA1 hash of the file resource pointed to by this lookup * table entry */ - u8 hash[WIM_HASH_SIZE]; + u8 hash[SHA1_HASH_SIZE]; /* First 4 or 8 bytes of the SHA1 hash, used for inserting the * entry into the hash table. Since the SHA1 hashes can be @@ -125,6 +125,7 @@ struct lookup_table_entry { struct list_head staging_list; }; + extern struct lookup_table *new_lookup_table(size_t capacity); extern void lookup_table_insert(struct lookup_table *table, @@ -138,6 +139,7 @@ static inline void lookup_table_unlink(struct lookup_table *table, table->num_entries--; } + extern struct lookup_table_entry * lookup_table_decrement_refcnt(struct lookup_table* table, const u8 hash[]); @@ -162,7 +164,7 @@ extern int lookup_resource(WIMStruct *w, const char *path, extern int zero_out_refcnts(struct lookup_table_entry *entry, void *ignore); -extern int print_lookup_table_entry(struct lookup_table_entry *entry, void *ignore); +extern void print_lookup_table_entry(struct lookup_table_entry *entry); extern int read_lookup_table(FILE *fp, u64 offset, u64 size, struct lookup_table **table_ret); @@ -195,4 +197,118 @@ static inline struct resource_entry* wim_metadata_resource_entry(WIMStruct *w) w->current_image - 1].metadata_lte->resource_entry; } +static inline struct lookup_table_entry * +dentry_stream_lte_resolved(const struct dentry *dentry, unsigned stream_idx) +{ + wimlib_assert(dentry->resolved); + wimlib_assert(stream_idx <= dentry->num_ads); + if (stream_idx == 0) + return dentry->lte; + else + return dentry->ads_entries[stream_idx - 1].lte; +} + +static inline struct lookup_table_entry * +dentry_stream_lte_unresolved(const struct dentry *dentry, unsigned stream_idx, + const struct lookup_table *table) +{ + wimlib_assert(!dentry->resolved); + wimlib_assert(stream_idx <= dentry->num_ads); + if (!table) + return NULL; + if (stream_idx == 0) + return __lookup_resource(table, dentry->hash); + else + return __lookup_resource(table, + dentry->ads_entries[ + stream_idx - 1].hash); +} +/* + * Returns the lookup table entry for stream @stream_idx of the dentry, where + * stream_idx = 0 means the default un-named file stream, and stream_idx >= 1 + * corresponds to an alternate data stream. + * + * This works for both resolved and un-resolved dentries. + */ +static inline struct lookup_table_entry * +dentry_stream_lte(const struct dentry *dentry, unsigned stream_idx, + const struct lookup_table *table) +{ + if (dentry->resolved) + return dentry_stream_lte_resolved(dentry, stream_idx); + else + return dentry_stream_lte_unresolved(dentry, stream_idx, table); +} + + +static inline const u8 *dentry_stream_hash_unresolved(const struct dentry *dentry, + unsigned stream_idx) +{ + wimlib_assert(!dentry->resolved); + wimlib_assert(stream_idx <= dentry->num_ads); + if (stream_idx == 0) + return dentry->hash; + else + return dentry->ads_entries[stream_idx - 1].hash; +} + +static inline const u8 *dentry_stream_hash_resolved(const struct dentry *dentry, + unsigned stream_idx) +{ + struct lookup_table_entry *lte; + lte = dentry_stream_lte_resolved(dentry, stream_idx); + if (lte) + return lte->hash; + else + return NULL; +} + +/* + * Returns the hash for stream @stream_idx of the dentry, where stream_idx = 0 + * means the default un-named file stream, and stream_idx >= 1 corresponds to an + * alternate data stream. + * + * This works for both resolved and un-resolved dentries. + */ +static inline const u8 *dentry_stream_hash(const struct dentry *dentry, + unsigned stream_idx) +{ + if (dentry->resolved) + return dentry_stream_hash_resolved(dentry, stream_idx); + else + return dentry_stream_hash_unresolved(dentry, stream_idx); +} + +static inline struct lookup_table_entry * +dentry_first_lte_resolved(const struct dentry *dentry) +{ + struct lookup_table_entry *lte; + wimlib_assert(dentry->resolved); + + for (unsigned i = 0; i <= dentry->num_ads; i++) { + lte = dentry_stream_lte_resolved(dentry, i); + if (lte) + return lte; + } + return NULL; +} + +static inline struct lookup_table_entry * +dentry_first_lte_unresolved(const struct dentry *dentry, + const struct lookup_table *table) +{ + struct lookup_table_entry *lte; + wimlib_assert(!dentry->resolved); + + for (unsigned i = 0; i <= dentry->num_ads; i++) { + lte = dentry_stream_lte_unresolved(dentry, i, table); + if (lte) + return lte; + } + return NULL; +} + +extern struct lookup_table_entry * +dentry_first_lte(const struct dentry *dentry, const struct lookup_table *table); + #endif diff --git a/src/modify.c b/src/modify.c index 5250ff6e..f4aadf9a 100644 --- a/src/modify.c +++ b/src/modify.c @@ -78,7 +78,7 @@ static int build_dentry_tree(struct dentry *root, const char *root_disk_path, { DEBUG("%s", root_disk_path); struct stat root_stbuf; - int ret; + int ret = 0; int (*stat_fn)(const char *restrict, struct stat *restrict); if (add_flags & WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE) @@ -98,8 +98,14 @@ static int build_dentry_tree(struct dentry *root, const char *root_disk_path, ERROR("`%s' is not a directory", root_disk_path); return WIMLIB_ERR_NOTDIR; } + if (!S_ISREG(root_stbuf.st_mode) && !S_ISDIR(root_stbuf.st_mode) + && !S_ISLNK(root_stbuf.st_mode)) { + ERROR("`%s' is not a regular file, directory, or symbolic link."); + return WIMLIB_ERR_SPECIAL_FILE; + } stbuf_to_dentry(&root_stbuf, root); add_flags &= ~WIMLIB_ADD_IMAGE_FLAG_ROOT; + root->resolved = true; if (dentry_is_directory(root)) { /* Open the directory on disk */ @@ -141,32 +147,37 @@ static int build_dentry_tree(struct dentry *root, const char *root_disk_path, /* Archiving a symbolic link */ size_t symlink_buf_len; char deref_name_buf[4096]; - ssize_t ret = readlink(root_disk_path, deref_name_buf, - sizeof(deref_name_buf) - 1); - if (ret == -1) { + ssize_t deref_name_len; + + deref_name_len = readlink(root_disk_path, deref_name_buf, + sizeof(deref_name_buf) - 1); + if (deref_name_len == -1) { ERROR_WITH_ERRNO("Failed to read target of " "symbolic link `%s'", root_disk_path); - return WIMLIB_ERR_STAT; + return WIMLIB_ERR_READLINK; } - deref_name_buf[ret] = '\0'; + deref_name_buf[deref_name_len] = '\0'; DEBUG("Read symlink `%s'", deref_name_buf); ret = dentry_set_symlink(root, deref_name_buf, lookup_table, NULL); } else { /* Regular file */ struct lookup_table_entry *lte; + u8 hash[SHA1_HASH_SIZE]; /* For each regular file, we must check to see if the file is in * the lookup table already; if it is, we increment its refcnt; * otherwise, we create a new lookup table entry and insert it. * */ - ret = sha1sum(root_disk_path, root->hash); + ret = sha1sum(root_disk_path, hash); if (ret != 0) return ret; - lte = __lookup_resource(lookup_table, root->hash); + lte = __lookup_resource(lookup_table, hash); if (lte) { lte->refcnt++; + DEBUG("Add lte reference %u for `%s'", lte->refcnt, + root_disk_path); } else { char *file_on_disk = STRDUP(root_disk_path); if (!file_on_disk) { @@ -181,9 +192,10 @@ static int build_dentry_tree(struct dentry *root, const char *root_disk_path, lte->file_on_disk = file_on_disk; lte->resource_entry.original_size = root_stbuf.st_size; lte->resource_entry.size = root_stbuf.st_size; - memcpy(lte->hash, root->hash, WIM_HASH_SIZE); + copy_hash(lte->hash, hash); lookup_table_insert(lookup_table, lte); } + root->lte = lte; } return ret; } @@ -201,40 +213,39 @@ struct wim_pair { * entry is created that references the location of the file resource in the * source WIM file through the other_wim_fp field of the lookup table entry. */ -static int add_lookup_table_entry_to_dest_wim(struct dentry *dentry, void *arg) +static int add_lte_to_dest_wim(struct dentry *dentry, void *arg) { WIMStruct *src_wim, *dest_wim; - struct lookup_table_entry *src_table_entry; - struct lookup_table_entry *dest_table_entry; src_wim = ((struct wim_pair*)arg)->src_wim; dest_wim = ((struct wim_pair*)arg)->dest_wim; - if (dentry_is_directory(dentry)) - return 0; - - /* XXX ADS */ - src_table_entry = __lookup_resource(src_wim->lookup_table, dentry->hash); - if (!src_table_entry) - return 0; - - /* XXX ADS */ - dest_table_entry = __lookup_resource(dest_wim->lookup_table, dentry->hash); - if (dest_table_entry) { - dest_table_entry->refcnt++; - } else { - dest_table_entry = new_lookup_table_entry(); - if (!dest_table_entry) - return WIMLIB_ERR_NOMEM; - dest_table_entry->other_wim_fp = src_wim->fp; - dest_table_entry->other_wim_ctype = - wimlib_get_compression_type(src_wim); - dest_table_entry->refcnt = 1; - memcpy(&dest_table_entry->resource_entry, - &src_table_entry->resource_entry, - sizeof(struct resource_entry)); - memcpy(dest_table_entry->hash, dentry->hash, WIM_HASH_SIZE); - lookup_table_insert(dest_wim->lookup_table, dest_table_entry); + wimlib_assert(!dentry->resolved); + + for (unsigned i = 0; i < (unsigned)dentry->num_ads + 1; i++) { + struct lookup_table_entry *src_lte, *dest_lte; + src_lte = dentry_stream_lte_unresolved(dentry, i, + src_wim->lookup_table); + if (!src_lte) + continue; + dest_lte = dentry_stream_lte_unresolved(dentry, i, + dest_wim->lookup_table); + if (dest_lte) { + dest_lte->refcnt++; + } else { + dest_lte = new_lookup_table_entry(); + if (!dest_lte) + return WIMLIB_ERR_NOMEM; + dest_lte->other_wim_fp = src_wim->fp; + dest_lte->other_wim_ctype = + wimlib_get_compression_type(src_wim); + memcpy(&dest_lte->resource_entry, + &src_lte->resource_entry, + sizeof(struct resource_entry)); + copy_hash(dest_lte->hash, + dentry_stream_hash_unresolved(dentry, i)); + lookup_table_insert(dest_wim->lookup_table, dest_lte); + } } return 0; } @@ -283,7 +294,7 @@ static int add_new_dentry_tree(WIMStruct *w, struct dentry *root_dentry) goto out_free_security_data; metadata_lte->resource_entry.flags = WIM_RESHDR_FLAG_METADATA; - randomize_byte_array(metadata_lte->hash, WIM_HASH_SIZE); + random_hash(metadata_lte->hash); lookup_table_insert(w->lookup_table, metadata_lte); new_imd = &imd[w->hdr.image_count]; @@ -391,7 +402,7 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim, /* Cleaning up here on failure would be hard. For example, we could - * fail to allocate memory in add_lookup_table_entry_to_dest_wim(), + * fail to allocate memory in add_lte_to_dest_wim(), * leaving the lookup table entries in the destination WIM in an * inconsistent state. Until these issues can be resolved, * wimlib_export_image() is documented as leaving dest_wim is an @@ -400,7 +411,7 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim, for_dentry_in_tree(root, increment_dentry_refcnt, NULL); wims.src_wim = src_wim; wims.dest_wim = dest_wim; - ret = for_dentry_in_tree(root, add_lookup_table_entry_to_dest_wim, &wims); + ret = for_dentry_in_tree(root, add_lte_to_dest_wim, &wims); if (ret != 0) return ret; ret = add_new_dentry_tree(dest_wim, root); @@ -514,12 +525,6 @@ WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *dir, root_dentry = new_dentry(""); if (!root_dentry) return WIMLIB_ERR_NOMEM; - ret = calculate_dentry_full_path(root_dentry, NULL); - - if (ret != 0) - goto out_free_dentry_tree; - - root_dentry->attributes |= FILE_ATTRIBUTE_DIRECTORY; DEBUG("Building dentry tree."); ret = build_dentry_tree(root_dentry, dir, w->lookup_table, @@ -530,7 +535,7 @@ WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *dir, goto out_free_dentry_tree; } - DEBUG("Recalculating full paths of dentries."); + DEBUG("Calculating full paths of dentries."); ret = for_dentry_in_tree(root_dentry, calculate_dentry_full_path, NULL); if (ret != 0) goto out_free_dentry_tree; diff --git a/src/mount.c b/src/mount.c index 25b6bcd5..adfb7d66 100644 --- a/src/mount.c +++ b/src/mount.c @@ -203,11 +203,15 @@ int dentry_to_stbuf(const struct dentry *dentry, struct stat *stbuf) stbuf->st_gid = getgid(); /* Use the size of the unnamed (default) file stream. */ - if ((lte = dentry_lte(dentry))) { + lte = dentry_first_lte_resolved(dentry); + if (lte) { if (lte->staging_file_name) { struct stat native_stat; - if (stat(lte->staging_file_name, &native_stat) != 0) + if (stat(lte->staging_file_name, &native_stat) != 0) { + DEBUG("Failed to stat `%s': %m", + lte->staging_file_name); return -errno; + } stbuf->st_size = native_stat.st_size; } else { stbuf->st_size = lte->resource_entry.original_size; @@ -239,7 +243,7 @@ static int create_staging_file(char **name_ret, int open_flags) int fd; int errno_save; - name_len = staging_dir_name_len + 1 + WIM_HASH_SIZE; + name_len = staging_dir_name_len + 1 + SHA1_HASH_SIZE; name = MALLOC(name_len + 1); if (!name) { errno = ENOMEM; @@ -251,7 +255,7 @@ static int create_staging_file(char **name_ret, int open_flags) memcpy(name, staging_dir_name, staging_dir_name_len); name[staging_dir_name_len] = '/'; randomize_char_array_with_alnum(name + staging_dir_name_len + 1, - WIM_HASH_SIZE); + SHA1_HASH_SIZE); name[name_len] = '\0'; @@ -482,7 +486,7 @@ static int extract_resource_to_staging_dir(struct dentry *dentry, } new_lte->resource_entry.original_size = size; new_lte->refcnt = link_group_size; - randomize_byte_array(new_lte->hash, WIM_HASH_SIZE); + random_hash(new_lte->hash); new_lte->staging_file_name = staging_file_name; lookup_table_insert(w->lookup_table, new_lte); @@ -773,14 +777,14 @@ static int calculate_sha1sum_of_staging_file(struct lookup_table_entry *lte, { struct lookup_table_entry *duplicate_lte; int ret; - u8 hash[WIM_HASH_SIZE]; + u8 hash[SHA1_HASH_SIZE]; ret = sha1sum(lte->staging_file_name, hash); if (ret != 0) return ret; lookup_table_unlink(table, lte); - memcpy(lte->hash, hash, WIM_HASH_SIZE); + copy_hash(lte->hash, hash); duplicate_lte = __lookup_resource(table, hash); @@ -1432,8 +1436,7 @@ static int wimfs_symlink(const char *to, const char *from) dentry->ads_entries[1].lte_group_list.type = STREAM_TYPE_ADS; list_add(&dentry->ads_entries[1].lte_group_list.list, <e->lte_group_list); - dentry->ads_entries[1].lte = lte; - dentry->resolved = true; + wimlib_assert(dentry->resolved); link_dentry(dentry, dentry_parent); return 0; @@ -1595,7 +1598,7 @@ static int check_lte_refcnt(struct lookup_table_entry *lte, void *ignore) ERROR("The following lookup table entry has a reference count " "of %u, but", lte->refcnt); ERROR("We found %u references to it", lte_group_size); - print_lookup_table_entry(lte, NULL); + print_lookup_table_entry(lte); #endif return WIMLIB_ERR_INVALID_DENTRY; } diff --git a/src/resource.c b/src/resource.c index 6608529c..3797f62f 100644 --- a/src/resource.c +++ b/src/resource.c @@ -1043,12 +1043,11 @@ int write_metadata_resource(WIMStruct *w) u64 subdir_offset; struct dentry *root; struct lookup_table_entry *lte; - struct resource_entry *res_entry; off_t metadata_offset; u64 metadata_original_size; u64 metadata_compressed_size; int metadata_ctype; - u8 hash[WIM_HASH_SIZE]; + u8 hash[SHA1_HASH_SIZE]; DEBUG("Writing metadata resource for image %d", w->current_image); @@ -1098,28 +1097,23 @@ int write_metadata_resource(WIMStruct *w) /* Update the lookup table entry, including the hash and output resource * entry fields, for this image's metadata resource. */ lte = wim_metadata_lookup_table_entry(w); - res_entry = <e->output_resource_entry; lte->out_refcnt++; - if (memcmp(hash, lte->hash, WIM_HASH_SIZE) != 0) { + if (!hashes_equal(hash, lte->hash)) { lookup_table_unlink(w->lookup_table, lte); - memcpy(lte->hash, hash, WIM_HASH_SIZE); + copy_hash(lte->hash, hash); lookup_table_insert(w->lookup_table, lte); } - res_entry->original_size = metadata_original_size; - res_entry->offset = metadata_offset; - res_entry->size = metadata_compressed_size; - res_entry->flags = WIM_RESHDR_FLAG_METADATA; + lte->output_resource_entry.original_size = metadata_original_size; + lte->output_resource_entry.offset = metadata_offset; + lte->output_resource_entry.size = metadata_compressed_size; + lte->output_resource_entry.flags = WIM_RESHDR_FLAG_METADATA; if (metadata_ctype != WIM_COMPRESSION_TYPE_NONE) - res_entry->flags |= WIM_RESHDR_FLAG_COMPRESSED; + lte->output_resource_entry.flags |= WIM_RESHDR_FLAG_COMPRESSED; return 0; } -static int write_file_resource(WIMStruct *w, const u8 hash[]) +static int write_file_resource(WIMStruct *w, struct lookup_table_entry *lte) { - /* Get the lookup entry for the file resource. */ - struct lookup_table_entry *lte; - - lte = __lookup_resource(w->lookup_table, hash); if (!lte) return 0; @@ -1213,12 +1207,13 @@ static int write_file_resource(WIMStruct *w, const u8 hash[]) } /* - * Writes a dentry's resources to the output file. + * Writes a dentry's resources, including the main file resource as well as all + * alternate data streams, to the output file. * - * @dentry: The dentry for the file resource. + * @dentry: The dentry for the file. * @wim_p: A pointer to the WIMStruct. The fields of interest to this * function are the input and output file streams and the lookup - * table, and the alternate data streams. + * table. * * @return zero on success, nonzero on failure. */ @@ -1226,16 +1221,11 @@ int write_dentry_resources(struct dentry *dentry, void *wim_p) { WIMStruct *w = wim_p; int ret; + struct lookup_table_entry *lte; - /* Directories don't need file resources. */ - if (dentry_is_directory(dentry)) - return 0; - - ret = write_file_resource(w, dentry->hash); - if (ret != 0) - return ret; - for (u16 i = 0; i < dentry->num_ads; i++) { - ret = write_file_resource(w, dentry->ads_entries[i].hash); + for (unsigned i = 0; i <= dentry->num_ads; i++) { + lte = dentry_stream_lte(dentry, i, w->lookup_table); + ret = write_file_resource(w, lte); if (ret != 0) return ret; } diff --git a/src/sha1.h b/src/sha1.h index 69398ceb..f668116b 100644 --- a/src/sha1.h +++ b/src/sha1.h @@ -5,6 +5,7 @@ #include #include #include "string.h" +#include "util.h" #define SHA1_HASH_SIZE 20 @@ -15,6 +16,28 @@ static inline bool is_empty_file_hash(const u8 hash[SHA1_HASH_SIZE]) return memcmp(hash, empty_file_sha1sum, SHA1_HASH_SIZE) == 0; } +static inline void copy_hash(u8 dest[SHA1_HASH_SIZE], + const u8 src[SHA1_HASH_SIZE]) +{ + memcpy(dest, src, SHA1_HASH_SIZE); +} + +static inline void random_hash(u8 hash[SHA1_HASH_SIZE]) +{ + randomize_byte_array(hash, SHA1_HASH_SIZE); +} + +static inline bool hashes_equal(const u8 h1[SHA1_HASH_SIZE], + const u8 h2[SHA1_HASH_SIZE]) +{ + return memcmp(h1, h2, SHA1_HASH_SIZE) == 0; +} + +/* Prints a hash code field. */ +static inline void print_hash(const u8 hash[]) +{ + print_byte_field(hash, SHA1_HASH_SIZE); +} extern int sha1sum(const char *filename, void *md); diff --git a/src/symlink.c b/src/symlink.c index f16d8c22..03f78370 100644 --- a/src/symlink.c +++ b/src/symlink.c @@ -145,31 +145,6 @@ out: return buf; } -static const struct lookup_table_entry * -dentry_first_lte(const struct dentry *dentry, const struct lookup_table *table) -{ - const struct lookup_table_entry *lte; - if (dentry->resolved) { - if (dentry->lte) - return dentry->lte; - for (u16 i = 0; i < dentry->num_ads; i++) - if (dentry->ads_entries[i].lte) - return dentry->ads_entries[i].lte; - } else { - const u8 *hash = dentry->hash; - u16 i = 0; - while (1) { - if ((lte = __lookup_resource(table, hash))) - break; - if (i == dentry->num_ads) - return NULL; - hash = dentry->ads_entries[i].hash; - i++; - } - } - return NULL; -} - /* Get the symlink target from a dentry that's already checked to be either a * "real" symlink or a junction point. */ ssize_t dentry_readlink(const struct dentry *dentry, char *buf, size_t buf_len, @@ -193,7 +168,6 @@ ssize_t dentry_readlink(const struct dentry *dentry, char *buf, size_t buf_len, if (lte->is_symlink && lte->symlink_buf) { res_buf = lte->symlink_buf; } else { - res_buf = __res_buf; if (read_full_resource(w->fp, res_entry->size, res_entry->original_size, res_entry->offset, @@ -207,22 +181,36 @@ ssize_t dentry_readlink(const struct dentry *dentry, char *buf, size_t buf_len, } static int dentry_set_symlink_buf(struct dentry *dentry, - const u8 symlink_buf_hash[]) + struct lookup_table_entry *lte) { struct ads_entry *ads_entries; ads_entries = CALLOC(2, sizeof(struct ads_entry)); if (!ads_entries) return WIMLIB_ERR_NOMEM; - memcpy(ads_entries[1].hash, symlink_buf_hash, WIM_HASH_SIZE); + wimlib_assert(dentry->num_ads == 0); - wimlib_assert(!dentry->ads_entries); + wimlib_assert(dentry->ads_entries == NULL); + + ads_entries[1].lte = lte; + /*dentry_free_ads_entries(dentry);*/ dentry->num_ads = 2; dentry->ads_entries = ads_entries; return 0; } +/* + * Sets @dentry to be a symbolic link pointing to @target. + * + * A lookup table entry for the symbolic link data buffer is created and + * inserted into @lookup_table, unless there is an existing lookup table entry + * for the exact same data, in which its reference count is incremented. + * + * The lookup table entry is returned in @lte_ret. + * + * On failure @dentry and @lookup_table are not modified. + */ int dentry_set_symlink(struct dentry *dentry, const char *target, struct lookup_table *lookup_table, struct lookup_table_entry **lte_ret) @@ -231,7 +219,7 @@ int dentry_set_symlink(struct dentry *dentry, const char *target, int ret; size_t symlink_buf_len; struct lookup_table_entry *lte = NULL, *existing_lte; - u8 symlink_buf_hash[WIM_HASH_SIZE]; + u8 symlink_buf_hash[SHA1_HASH_SIZE]; void *symlink_buf; symlink_buf = make_symlink_reparse_data_buf(target, &symlink_buf_len); @@ -239,14 +227,13 @@ int dentry_set_symlink(struct dentry *dentry, const char *target, return WIMLIB_ERR_NOMEM; DEBUG("Made symlink reparse data buf (len = %zu, name len = %zu)", - symlink_buf_len, ret); + symlink_buf_len, symlink_buf_len); sha1_buffer(symlink_buf, symlink_buf_len, symlink_buf_hash); existing_lte = __lookup_resource(lookup_table, symlink_buf_hash); if (existing_lte) { - existing_lte->refcnt++; lte = existing_lte; } else { DEBUG("Creating new lookup table entry for symlink buf"); @@ -259,17 +246,21 @@ int dentry_set_symlink(struct dentry *dentry, const char *target, lte->symlink_buf = symlink_buf; lte->resource_entry.original_size = symlink_buf_len; lte->resource_entry.size = symlink_buf_len; - memcpy(lte->hash, symlink_buf_hash, WIM_HASH_SIZE); + copy_hash(lte->hash, symlink_buf_hash); } - ret = dentry_set_symlink_buf(dentry, symlink_buf_hash); + ret = dentry_set_symlink_buf(dentry, lte); if (ret != 0) goto out_free_lte; + dentry->resolved = true; + DEBUG("Loaded symlink buf"); - if (!existing_lte) + if (existing_lte) + lte->refcnt++; + else lookup_table_insert(lookup_table, lte); if (lte_ret) *lte_ret = lte; diff --git a/src/util.c b/src/util.c index c229b5a6..8bcfa202 100644 --- a/src/util.c +++ b/src/util.c @@ -167,8 +167,12 @@ static const char *error_strings[] = { = "Failed to open a directory", [WIMLIB_ERR_READ] = "Could not read data from a file", + [WIMLIB_ERR_READLINK] + = "Could not read the target of a symbolic link", [WIMLIB_ERR_RENAME] = "Could not rename a file", + [WIMLIB_ERR_SPECIAL_FILE] + = "Encountered a special file that cannot be archived", [WIMLIB_ERR_SPLIT_INVALID] = "The WIM is part of an invalid split WIM", [WIMLIB_ERR_SPLIT_UNSUPPORTED] @@ -383,10 +387,8 @@ void randomize_char_array_with_alnum(char p[], size_t n) } /* Fills @n bytes pointer to by @p with random numbers. */ -void randomize_byte_array(void *__p, size_t n) +void randomize_byte_array(u8 *p, size_t n) { - u8 *p = __p; - if (!seeded) { srand(time(NULL)); seeded = true; diff --git a/src/util.h b/src/util.h index 73f86ed4..1fb1f099 100644 --- a/src/util.h +++ b/src/util.h @@ -124,7 +124,7 @@ extern char *utf16_to_utf8(const char *utf16_str, size_t utf16_len, extern char *utf8_to_utf16(const char *utf8_str, size_t utf8_len, size_t *utf16_len_ret); -extern void randomize_byte_array(void *p, size_t n); +extern void randomize_byte_array(u8 *p, size_t n); extern void randomize_char_array_with_alnum(char p[], size_t n); diff --git a/src/wim.c b/src/wim.c index b2ed8d98..d105e8ba 100644 --- a/src/wim.c +++ b/src/wim.c @@ -223,7 +223,7 @@ int wimlib_select_image(WIMStruct *w, int image) #ifdef ENABLE_DEBUG DEBUG("Reading metadata resource specified by the following " "lookup table entry:"); - print_lookup_table_entry(imd->metadata_lte, NULL); + print_lookup_table_entry(imd->metadata_lte); #endif return read_metadata_resource(w->fp, wimlib_get_compression_type(w), diff --git a/src/wimlib.h b/src/wimlib.h index 81218635..d2b230be 100644 --- a/src/wimlib.h +++ b/src/wimlib.h @@ -343,8 +343,10 @@ enum wimlib_error_code { WIMLIB_ERR_NTFS_3G, WIMLIB_ERR_OPEN, WIMLIB_ERR_OPENDIR, + WIMLIB_ERR_READLINK, WIMLIB_ERR_READ, WIMLIB_ERR_RENAME, + WIMLIB_ERR_SPECIAL_FILE, WIMLIB_ERR_SPLIT_INVALID, WIMLIB_ERR_SPLIT_UNSUPPORTED, WIMLIB_ERR_STAT, diff --git a/src/wimlib_internal.h b/src/wimlib_internal.h index bc7505d2..b33f728f 100644 --- a/src/wimlib_internal.h +++ b/src/wimlib_internal.h @@ -31,10 +31,6 @@ struct stat; -#ifndef WIM_HASH_SIZE -#define WIM_HASH_SIZE 20 -#endif - #define WIM_MAGIC_LEN 8 #define WIM_GID_LEN 16 #define WIM_UNUSED_LEN 60 @@ -312,12 +308,6 @@ static inline struct image_metadata *wim_get_current_image_metadata(WIMStruct *w return &w->image_metadata[w->current_image - 1]; } -/* Prints a hash code field. */ -static inline void print_hash(const u8 hash[]) -{ - print_byte_field(hash, WIM_HASH_SIZE); -} - /* hardlink.c */ struct link_group_table *new_link_group_table(u64 capacity);