From: Eric Biggers Date: Tue, 28 Aug 2012 05:24:28 +0000 (-0500) Subject: dentry_first_lte() -> dentry_unnamed_lte() X-Git-Tag: v1.0.0~57 X-Git-Url: https://wimlib.net/git/?p=wimlib;a=commitdiff_plain;h=c6127ff151b2963c5b90e4018f08f53051a97dfd dentry_first_lte() -> dentry_unnamed_lte() This probably doesn't make a difference, but when we were looking for the "first" lookup table entry what we really wanted was to find the lookup table for the un-named data stream, even if it's in an alternate data stream rather than the expected location in the dentry. --- diff --git a/src/extract.c b/src/extract.c index ec6842dc..b27c4432 100644 --- a/src/extract.c +++ b/src/extract.c @@ -200,7 +200,7 @@ static int extract_regular_file(WIMStruct *w, { struct lookup_table_entry *lte; - lte = dentry_first_lte(dentry, w->lookup_table); + lte = dentry_unnamed_lte(dentry, w->lookup_table); if ((extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK | WIMLIB_EXTRACT_FLAG_HARDLINK)) && lte) { diff --git a/src/lookup_table.c b/src/lookup_table.c index d15a3088..92fb8a9f 100644 --- a/src/lookup_table.c +++ b/src/lookup_table.c @@ -221,6 +221,14 @@ int read_lookup_table(WIMStruct *w) p = get_u32(p, &cur_entry->refcnt); p = get_bytes(p, SHA1_HASH_SIZE, cur_entry->hash); + if (is_zero_hash(cur_entry->hash)) { + ERROR("The WIM lookup table contains an entry with a " + "SHA1 message digest of all 0's"); + ret = WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY; + FREE(cur_entry); + goto out; + } + duplicate_entry = __lookup_resource(table, cur_entry->hash); if (duplicate_entry) { ERROR("The WIM lookup table contains two entries with the " @@ -230,6 +238,7 @@ int read_lookup_table(WIMStruct *w) ERROR("The second entry is:"); print_lookup_table_entry(cur_entry); ret = WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY; + FREE(cur_entry); goto out; } lookup_table_insert(table, cur_entry); @@ -481,12 +490,29 @@ int dentry_resolve_ltes(struct dentry *dentry, void *__table) return 0; } +/* Return the lookup table entry for the unnamed data stream of a dentry, or + * NULL if there is none. + * + * You'd think this would be easier than it actually is, since the unnamed data + * stream should be the one referenced from the dentry itself. Alas, if there + * are named data streams, Microsoft's "imagex.exe" program will put the unnamed + * data stream in one of the alternate data streams instead of inside the + * dentry. So we need to check the alternate data streams too. + * + * Also, note that a dentry may appear to have than one unnamed stream, but if + * the SHA1 message digest is all 0's then the corresponding stream does not + * really "count" (this is the case for the dentry's own file stream when the + * file stream that should be there is actually in one of the alternate stream + * entries.). This is despite the fact that we may need to extract such a + * missing entry as an empty file or empty named data stream. + */ struct lookup_table_entry * -dentry_first_lte(const struct dentry *dentry, const struct lookup_table *table) +dentry_unnamed_lte(const struct dentry *dentry, + const struct lookup_table *table) { if (dentry->resolved) - return dentry_first_lte_resolved(dentry); + return dentry_unnamed_lte_resolved(dentry); else - return dentry_first_lte_unresolved(dentry, table); + return dentry_unnamed_lte_unresolved(dentry, table); } diff --git a/src/lookup_table.h b/src/lookup_table.h index 43494efe..3a653bfb 100644 --- a/src/lookup_table.h +++ b/src/lookup_table.h @@ -299,7 +299,7 @@ static inline u16 dentry_stream_name_len(const struct dentry *dentry, { wimlib_assert(stream_idx <= dentry->num_ads); if (stream_idx == 0) - return dentry->file_name_len; + return 0; else return dentry->ads_entries[stream_idx - 1].stream_name_len; } @@ -332,35 +332,34 @@ static inline const u8 *dentry_stream_hash(const struct dentry *dentry, } static inline struct lookup_table_entry * -dentry_first_lte_resolved(const struct dentry *dentry) +dentry_unnamed_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; - } + for (unsigned i = 0; i <= dentry->num_ads; i++) + if (dentry_stream_name_len(dentry, i) == 0 && + !is_zero_hash(dentry_stream_hash_resolved(dentry, i))) + return dentry_stream_lte_resolved(dentry, i); return NULL; } static inline struct lookup_table_entry * -dentry_first_lte_unresolved(const struct dentry *dentry, - const struct lookup_table *table) +dentry_unnamed_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; - } + for (unsigned i = 0; i <= dentry->num_ads; i++) + if (dentry_stream_name_len(dentry, i) == 0 && + !is_zero_hash(dentry_stream_hash_unresolved(dentry, i))) + return dentry_stream_lte_unresolved(dentry, i, table); return NULL; } extern struct lookup_table_entry * -dentry_first_lte(const struct dentry *dentry, const struct lookup_table *table); +dentry_unnamed_lte(const struct dentry *dentry, + const struct lookup_table *table); #endif diff --git a/src/mount.c b/src/mount.c index 1510fbfb..f6c178b4 100644 --- a/src/mount.c +++ b/src/mount.c @@ -221,7 +221,7 @@ int dentry_to_stbuf(const struct dentry *dentry, struct stat *stbuf) stbuf->st_gid = getgid(); /* Use the size of the unnamed (default) file stream. */ - lte = dentry_first_lte_resolved(dentry); + lte = dentry_unnamed_lte_resolved(dentry); if (lte) { if (lte->resource_location == RESOURCE_IN_STAGING_FILE) { wimlib_assert(lte->staging_file_name); diff --git a/src/ntfs-apply.c b/src/ntfs-apply.c index 4118a30a..3ec0ae75 100644 --- a/src/ntfs-apply.c +++ b/src/ntfs-apply.c @@ -268,7 +268,7 @@ static int apply_reparse_data(ntfs_inode *ni, const struct dentry *dentry, wimlib_assert(dentry->attributes & FILE_ATTRIBUTE_REPARSE_POINT); - lte = dentry_first_lte(dentry, w->lookup_table); + lte = dentry_unnamed_lte(dentry, w->lookup_table); DEBUG("Applying reparse data to `%s'", dentry->full_path_utf8); diff --git a/src/resource.c b/src/resource.c index 3c573f1c..0c7a4cf9 100644 --- a/src/resource.c +++ b/src/resource.c @@ -882,7 +882,9 @@ static int write_wim_resource(struct lookup_table_entry *lte, } } - if (new_compressed_size > original_size) { + if (new_compressed_size >= original_size && + out_ctype != WIM_COMPRESSION_TYPE_NONE && !raw) + { /* Oops! We compressed the resource to larger than the original * size. Write the resource uncompressed instead. */ if (fseeko(out_fp, file_offset, SEEK_SET) != 0) { diff --git a/src/sha1.h b/src/sha1.h index a5d695d6..e153f533 100644 --- a/src/sha1.h +++ b/src/sha1.h @@ -39,9 +39,10 @@ static inline void print_hash(const u8 hash[SHA1_HASH_SIZE]) static inline bool is_zero_hash(const u8 hash[SHA1_HASH_SIZE]) { - for (u8 i = 0; i < SHA1_HASH_SIZE / 4; i++) - if (((u32*)hash)[i]) - return false; + if (hash) + for (u8 i = 0; i < SHA1_HASH_SIZE / 4; i++) + if (((u32*)hash)[i]) + return false; return true; } diff --git a/src/symlink.c b/src/symlink.c index ca2e422f..3773fb05 100644 --- a/src/symlink.c +++ b/src/symlink.c @@ -168,7 +168,7 @@ ssize_t dentry_readlink(const struct dentry *dentry, char *buf, size_t buf_len, wimlib_assert(dentry_is_symlink(dentry)); - lte = dentry_first_lte(dentry, w->lookup_table); + lte = dentry_unnamed_lte(dentry, w->lookup_table); if (!lte) return -EIO;