X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fdentry.c;h=927b3da9baa1a80628e72d3da5ee2ef6cb548fa2;hp=7d17fb9c9db0408d3486c0ef0d1f2e705607d42c;hb=29a09c1a5c20e1b04cc11ef24f5863bf8db7796c;hpb=16e3b6e5615abcefc9e5bb9607e2804b64d19cc2 diff --git a/src/dentry.c b/src/dentry.c index 7d17fb9c..927b3da9 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -424,21 +424,22 @@ struct dentry *get_dentry_child_with_name(const struct dentry *dentry, static struct dentry *get_dentry_relative_path(struct dentry *cur_dir, const char *path) { - struct dentry *child; + struct dentry *child, *children; size_t base_len; const char *new_path; if (*path == '\0') return cur_dir; - child = cur_dir->d_inode->children; - if (child) { + children = cur_dir->d_inode->children; + if (children) { new_path = path_next_part(path, &base_len); + child = children; do { if (dentry_has_name(child, path, base_len)) return get_dentry_relative_path(child, new_path); child = child->next; - } while (child != cur_dir->d_inode->children); + } while (child != children); } return NULL; } @@ -457,10 +458,10 @@ struct inode *wim_pathname_to_inode(WIMStruct *w, const char *path) { struct dentry *dentry; dentry = get_dentry(w, path); - if (!dentry) - return NULL; - else + if (dentry) return dentry->d_inode; + else + return NULL; } /* Returns the dentry that corresponds to the parent directory of @path, or NULL @@ -740,9 +741,7 @@ static void put_inode(struct inode *inode) */ void free_dentry(struct dentry *dentry) { - wimlib_assert(dentry); - struct inode *inode; - + wimlib_assert(dentry != NULL); FREE(dentry->file_name); FREE(dentry->file_name_utf8); FREE(dentry->short_name); @@ -754,8 +753,8 @@ void free_dentry(struct dentry *dentry) void put_dentry(struct dentry *dentry) { - wimlib_assert(dentry); - wimlib_assert(dentry->refcnt); + wimlib_assert(dentry != NULL); + wimlib_assert(dentry->refcnt != 0); if (--dentry->refcnt == 0) free_dentry(dentry); @@ -901,7 +900,7 @@ static int verify_inode(struct inode *inode, const WIMStruct *w) WARNING("The following lookup table entry " "has a reference count of %u, but", lte->refcnt); - WARNING("We found %zu references to it", + WARNING("We found %u references to it", lte->real_refcnt); WARNING("(One dentry referencing it is at `%s')", first_dentry->full_path_utf8); @@ -951,21 +950,19 @@ out: /* Run some miscellaneous verifications on a WIM dentry */ int verify_dentry(struct dentry *dentry, void *wim) { - const WIMStruct *w = wim; - const struct inode *inode = dentry->d_inode; - int ret = WIMLIB_ERR_INVALID_DENTRY; + int ret; if (!dentry->d_inode->verified) { - ret = verify_inode(dentry->d_inode, w); + ret = verify_inode(dentry->d_inode, wim); if (ret != 0) - goto out; + return ret; } /* Cannot have a short name but no long name */ if (dentry->short_name_len && !dentry->file_name_len) { ERROR("Dentry `%s' has a short name but no long name", dentry->full_path_utf8); - goto out; + return WIMLIB_ERR_INVALID_DENTRY; } /* Make sure root dentry is unnamed */ @@ -973,7 +970,7 @@ int verify_dentry(struct dentry *dentry, void *wim) if (dentry->file_name_len) { ERROR("The root dentry is named `%s', but it must " "be unnamed", dentry->file_name_utf8); - goto out; + return WIMLIB_ERR_INVALID_DENTRY; } } @@ -986,9 +983,7 @@ int verify_dentry(struct dentry *dentry, void *wim) } #endif - ret = 0; -out: - return ret; + return 0; } @@ -1380,7 +1375,8 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, "short_name_len = %hu, file_name_len = %hu)", calculated_size, dentry->length, short_name_len, file_name_len); - return WIMLIB_ERR_INVALID_DENTRY; + ret = WIMLIB_ERR_INVALID_DENTRY; + goto out_free_inode; } /* Read the filename if present. Note: if the filename is empty, there @@ -1390,7 +1386,8 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, if (!file_name) { ERROR("Failed to allocate %hu bytes for dentry file name", file_name_len); - return WIMLIB_ERR_NOMEM; + ret = WIMLIB_ERR_NOMEM; + goto out_free_inode; } p = get_bytes(p, file_name_len, file_name); @@ -1455,7 +1452,7 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, p = get_bytes(p, short_name_len, short_name); if (*(u16*)p) - WARNING("Expected two zero bytes following the file name " + WARNING("Expected two zero bytes following the short name of " "`%s', but found non-zero bytes", file_name_utf8); p += 2; } @@ -1470,18 +1467,35 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, * included in the dentry->length field for some reason. */ if (inode->num_ads != 0) { - if (calculated_size > metadata_resource_len - offset) { - ERROR("Not enough space in metadata resource for " - "alternate stream entries"); - ret = WIMLIB_ERR_INVALID_DENTRY; - goto out_free_short_name; + + /* Trying different lengths is just a hack to make sure we have + * a chance of reading the ADS entries correctly despite the + * poor documentation. */ + + if (calculated_size != dentry->length) { + WARNING("Trying calculated dentry length (%"PRIu64") " + "instead of dentry->length field (%"PRIu64") " + "to read ADS entries", + calculated_size, dentry->length); } - ret = read_ads_entries(&metadata_resource[offset + calculated_size], - inode, - metadata_resource_len - offset - calculated_size); - if (ret != 0) - goto out_free_short_name; + u64 lengths_to_try[3] = {calculated_size, + (dentry->length + 7) & ~7, + dentry->length}; + ret = WIMLIB_ERR_INVALID_DENTRY; + for (size_t i = 0; i < ARRAY_LEN(lengths_to_try); i++) { + if (lengths_to_try[i] > metadata_resource_len - offset) + continue; + ret = read_ads_entries(&metadata_resource[offset + lengths_to_try[i]], + inode, + metadata_resource_len - offset - lengths_to_try[i]); + if (ret == 0) + goto out; + } + ERROR("Failed to read alternate data stream " + "entries of `%s'", dentry->file_name_utf8); + goto out_free_short_name; } +out: /* We've read all the data for this dentry. Set the names and their * lengths, and we've done. */