dentry_first_lte() -> dentry_unnamed_lte()
authorEric Biggers <ebiggers3@gmail.com>
Tue, 28 Aug 2012 05:24:28 +0000 (00:24 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Tue, 28 Aug 2012 05:32:53 +0000 (00:32 -0500)
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.

src/extract.c
src/lookup_table.c
src/lookup_table.h
src/mount.c
src/ntfs-apply.c
src/resource.c
src/sha1.h
src/symlink.c

index ec6842d..b27c443 100644 (file)
@@ -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) {
index d15a308..92fb8a9 100644 (file)
@@ -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);
 }
 
index 43494ef..3a653bf 100644 (file)
@@ -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
index 1510fbf..f6c178b 100644 (file)
@@ -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);
index 4118a30..3ec0ae7 100644 (file)
@@ -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);
 
index 3c573f1..0c7a4cf 100644 (file)
@@ -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) {
index a5d695d..e153f53 100644 (file)
@@ -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;
 }
 
index ca2e422..3773fb0 100644 (file)
@@ -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;