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;
}
{
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
*/
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);
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);
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);
/* 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 */
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;
}
}
}
#endif
- ret = 0;
-out:
- return ret;
+ return 0;
}
"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
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);
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;
}
* 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. */