{
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) {
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 "
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);
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);
}
{
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;
}
}
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
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);
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);
}
}
- 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) {
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;
}
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;