*/
/*
- * Copyright (C) 2012 Eric Biggers
+ * Copyright (C) 2012, 2013 Biggers
*
* This file is part of wimlib, a library for working with WIM files.
*
return 0;
}
-/*#define RECURSIVE_FOR_DENTRY_IN_TREE*/
-
-#ifdef RECURSIVE_FOR_DENTRY_IN_TREE
static int for_dentry_tree_in_rbtree(struct rb_node *node,
int (*visitor)(struct wim_dentry*, void*),
void *arg)
}
return 0;
}
-#endif
/*
* Calls a function on all directory entries in a WIM dentry tree. Logically,
int for_dentry_in_tree(struct wim_dentry *root,
int (*visitor)(struct wim_dentry*, void*), void *arg)
{
-#ifdef RECURSIVE_FOR_DENTRY_IN_TREE
int ret = visitor(root, arg);
if (ret != 0)
return ret;
return for_dentry_tree_in_rbtree(root->d_inode->i_children.rb_node, visitor, arg);
-#else
- int ret;
- struct list_head main_stack;
- struct list_head sibling_stack;
- struct list_head *sibling_stack_bottom;
- struct wim_dentry *main_dentry;
- struct rb_node *node;
- struct list_head *next_sibling;
- struct wim_dentry *dentry;
-
- ret = visitor(root, arg);
- if (ret != 0)
- return ret;
-
- main_dentry = root;
- sibling_stack_bottom = &sibling_stack;
- INIT_LIST_HEAD(&main_stack);
- INIT_LIST_HEAD(&sibling_stack);
-
- list_add(&root->tmp_list, &main_stack);
- node = root->d_inode->i_children.rb_node;
-
- while (1) {
- // Prepare for non-recursive in-order traversal of the red-black
- // tree of this dentry's children
-
- while (node) {
- // Push this node to the sibling stack and examine the
- // left neighbor, if any
- list_add(&rbnode_dentry(node)->tmp_list, &sibling_stack);
- node = node->rb_left;
- }
-
- next_sibling = sibling_stack.next;
- if (next_sibling == sibling_stack_bottom) {
- // Done with all siblings. Pop the main dentry to move
- // back up one level.
- main_dentry = container_of(main_stack.next,
- struct wim_dentry,
- tmp_list);
- list_del(&main_dentry->tmp_list);
-
- if (main_dentry == root)
- goto out;
-
- // Restore sibling stack bottom from the previous level
- sibling_stack_bottom = (void*)main_dentry->parent;
-
- // Restore the just-popped main dentry's parent
- main_dentry->parent = container_of(main_stack.next,
- struct wim_dentry,
- tmp_list);
-
- // The next sibling to traverse in the previous level,
- // in the in-order traversal of the red-black tree, is
- // the one to the right.
- node = main_dentry->rb_node.rb_right;
- } else {
- // The sibling stack is not empty, so there are more to
- // go!
-
- // Pop a sibling from the stack.
- list_del(next_sibling);
- dentry = container_of(next_sibling, struct wim_dentry, tmp_list);
-
- // Visit the sibling.
- ret = visitor(dentry, arg);
- if (ret != 0) {
- // Failed. Restore parent pointers for the
- // dentries in the main stack
- list_for_each_entry(dentry, &main_stack, tmp_list) {
- dentry->parent = container_of(dentry->tmp_list.next,
- struct wim_dentry,
- tmp_list);
- }
- goto out;
- }
-
- // We'd like to recursively visit the dentry tree rooted
- // at this sibling. To do this, add it to the main
- // stack, save the bottom of this level's sibling stack
- // in the dentry->parent field, re-set the bottom of the
- // sibling stack to be its current height, and set
- // main_dentry to the sibling so it becomes the parent
- // dentry in the next iteration through the outer loop.
- if (inode_has_children(dentry->d_inode)) {
- list_add(&dentry->tmp_list, &main_stack);
- dentry->parent = (void*)sibling_stack_bottom;
- sibling_stack_bottom = sibling_stack.next;
-
- main_dentry = dentry;
- node = main_dentry->d_inode->i_children.rb_node;
- } else {
- node = dentry->rb_node.rb_right;
- }
- }
- }
-out:
- root->parent = root;
- return ret;
-#endif
}
/*
int for_dentry_in_tree_depth(struct wim_dentry *root,
int (*visitor)(struct wim_dentry*, void*), void *arg)
{
-#if 1
int ret;
ret = for_dentry_tree_in_rbtree_depth(root->d_inode->i_children.rb_node,
visitor, arg);
if (ret != 0)
return ret;
return visitor(root, arg);
-
-#else
- int ret;
- struct list_head main_stack;
- struct list_head sibling_stack;
- struct list_head *sibling_stack_bottom;
- struct wim_dentry *main_dentry;
- struct rb_node *node;
- struct list_head *next_sibling;
- struct wim_dentry *dentry;
-
- main_dentry = root;
- sibling_stack_bottom = &sibling_stack;
- INIT_LIST_HEAD(&main_stack);
- INIT_LIST_HEAD(&sibling_stack);
-
- list_add(&main_dentry->tmp_list, &main_stack);
-
- while (1) {
- node = main_dentry->d_inode->i_children.rb_node;
-
- while (1) {
- if (node->rb_left) {
- list_add(&rbnode_dentry(node)->tmp_list, &sibling_stack);
- node = node->rb_left;
- continue;
- }
- if (node->rb_right) {
- list_add(&rbnode_dentry(node)->tmp_list, &sibling_stack);
- node = node->rb_right;
- continue;
- }
- list_add(&rbnode_dentry(node)->tmp_list, &sibling_stack);
- }
-
- pop_sibling:
- next_sibling = sibling_stack.next;
- if (next_sibling == sibling_stack_bottom) {
- main_dentry = container_of(main_stack.next,
- struct wim_dentry,
- tmp_list);
- list_del(&main_dentry->tmp_list);
-
-
- sibling_stack_bottom = (void*)main_dentry->parent;
-
- if (main_dentry == root) {
- main_dentry->parent = main_dentry;
- ret = visitor(dentry, arg);
- return ret;
- } else {
- main_dentry->parent = container_of(main_stack.next,
- struct wim_dentry,
- tmp_list);
- }
-
- ret = visitor(main_dentry, arg);
-
- if (ret != 0) {
- list_del(&root->tmp_list);
- list_for_each_entry(dentry, &main_stack, tmp_list) {
- dentry->parent = container_of(dentry->tmp_list.next,
- struct wim_dentry,
- tmp_list);
- }
- root->parent = root;
- return ret;
- }
- goto pop_sibling;
- } else {
-
- list_del(next_sibling);
- dentry = container_of(next_sibling, struct wim_dentry, tmp_list);
-
-
- list_add(&dentry->tmp_list, &main_stack);
- dentry->parent = (void*)sibling_stack_bottom;
- sibling_stack_bottom = sibling_stack.next;
-
- main_dentry = dentry;
- }
- }
-#endif
}
/*
static int compare_names(const char *name_1, u16 len_1,
const char *name_2, u16 len_2)
{
- int result = strncasecmp(name_1, name_2, min(len_1, len_2));
+ int result = strncmp(name_1, name_2, min(len_1, len_2));
if (result) {
return result;
} else {
printf("Full Path (UTF-8) = \"%s\"\n", dentry->full_path_utf8);
lte = inode_stream_lte(dentry->d_inode, 0, lookup_table);
if (lte) {
- print_lookup_table_entry(lte);
+ print_lookup_table_entry(lte, stdout);
} else {
hash = inode_stream_hash(inode, 0);
if (hash) {
print_hash(hash);
putchar('\n');
}
- print_lookup_table_entry(inode_stream_lte(inode, i + 1,
- lookup_table));
+ print_lookup_table_entry(inode_stream_lte(inode, i + 1, lookup_table),
+ stdout);
}
return 0;
}
return true;
}
-#ifdef WITH_FUSE
/* Unlink a WIM dentry from the directory entry tree. */
void unlink_dentry(struct wim_dentry *dentry)
{
return;
rb_erase(&dentry->rb_node, &parent->d_inode->i_children);
}
-#endif
-#ifdef WITH_FUSE
-/*
+/*
* Returns the alternate data stream entry belonging to @inode that has the
* stream name @stream_name.
*/
}
return NULL;
}
-#endif
-#if defined(WITH_FUSE) || defined(WITH_NTFS_3G)
/*
* Add an alternate stream entry to a WIM inode and return a pointer to it, or
* NULL if memory could not be allocated.
inode->i_num_ads = num_ads;
return new_entry;
}
-#endif
-#ifdef WITH_FUSE
+int inode_add_ads_with_data(struct wim_inode *inode, const char *name,
+ const u8 *value, size_t size,
+ struct wim_lookup_table *lookup_table)
+{
+ int ret = WIMLIB_ERR_NOMEM;
+ struct wim_ads_entry *new_ads_entry;
+ struct wim_lookup_table_entry *existing_lte;
+ struct wim_lookup_table_entry *lte;
+ u8 value_hash[SHA1_HASH_SIZE];
+
+ wimlib_assert(inode->i_resolved);
+ new_ads_entry = inode_add_ads(inode, name);
+ if (!new_ads_entry)
+ goto out;
+ sha1_buffer((const u8*)value, size, value_hash);
+ existing_lte = __lookup_resource(lookup_table, value_hash);
+ if (existing_lte) {
+ lte = existing_lte;
+ lte->refcnt++;
+ } else {
+ u8 *value_copy;
+ lte = new_lookup_table_entry();
+ if (!lte)
+ goto out_free_ads_entry;
+ value_copy = MALLOC(size);
+ if (!value_copy) {
+ FREE(lte);
+ goto out_free_ads_entry;
+ }
+ memcpy(value_copy, value, size);
+ lte->resource_location = RESOURCE_IN_ATTACHED_BUFFER;
+ lte->attached_buffer = value_copy;
+ lte->resource_entry.original_size = size;
+ lte->resource_entry.size = size;
+ lte->resource_entry.flags = 0;
+ copy_hash(lte->hash, value_hash);
+ lookup_table_insert(lookup_table, lte);
+ }
+ new_ads_entry->lte = lte;
+ ret = 0;
+ goto out;
+out_free_ads_entry:
+ inode_remove_ads(inode, new_ads_entry - inode->i_ads_entries,
+ lookup_table);
+out:
+ return ret;
+}
+
/* Remove an alternate data stream from a WIM inode */
void inode_remove_ads(struct wim_inode *inode, u16 idx,
struct wim_lookup_table *lookup_table)
destroy_ads_entry(ads_entry);
- memcpy(&inode->i_ads_entries[idx],
- &inode->i_ads_entries[idx + 1],
- (inode->i_num_ads - idx - 1) * sizeof(inode->i_ads_entries[0]));
+ memmove(&inode->i_ads_entries[idx],
+ &inode->i_ads_entries[idx + 1],
+ (inode->i_num_ads - idx - 1) * sizeof(inode->i_ads_entries[0]));
inode->i_num_ads--;
}
-#endif
+int inode_get_unix_data(const struct wim_inode *inode,
+ struct wimlib_unix_data *unix_data,
+ u16 *stream_idx_ret)
+{
+ const struct wim_ads_entry *ads_entry;
+ const struct wim_lookup_table_entry *lte;
+ size_t size;
+ int ret;
+
+ wimlib_assert(inode->i_resolved);
+
+ ads_entry = inode_get_ads_entry((struct wim_inode*)inode,
+ WIMLIB_UNIX_DATA_TAG, NULL);
+ if (!ads_entry)
+ return NO_UNIX_DATA;
+
+ if (stream_idx_ret)
+ *stream_idx_ret = ads_entry - inode->i_ads_entries;
+ lte = ads_entry->lte;
+ if (!lte)
+ return NO_UNIX_DATA;
+
+ size = wim_resource_size(lte);
+ if (size != sizeof(struct wimlib_unix_data))
+ return BAD_UNIX_DATA;
+
+ ret = read_full_wim_resource(lte, (u8*)unix_data, 0);
+ if (ret)
+ return ret;
+
+ if (unix_data->version != 0)
+ return BAD_UNIX_DATA;
+ return 0;
+}
+
+int inode_set_unix_data(struct wim_inode *inode,
+ uid_t uid, gid_t gid, mode_t mode,
+ struct wim_lookup_table *lookup_table,
+ int which)
+{
+ struct wimlib_unix_data unix_data;
+ int ret;
+ bool have_good_unix_data = false;
+ bool have_unix_data = false;
+ u16 stream_idx;
+
+ if (!(which & UNIX_DATA_CREATE)) {
+ ret = inode_get_unix_data(inode, &unix_data, &stream_idx);
+ if (ret == 0 || ret == BAD_UNIX_DATA || ret > 0)
+ have_unix_data = true;
+ if (ret == 0)
+ have_good_unix_data = true;
+ }
+ unix_data.version = 0;
+ if (which & UNIX_DATA_UID || !have_good_unix_data)
+ unix_data.uid = uid;
+ if (which & UNIX_DATA_GID || !have_good_unix_data)
+ unix_data.gid = gid;
+ if (which & UNIX_DATA_MODE || !have_good_unix_data)
+ unix_data.mode = mode;
+ ret = inode_add_ads_with_data(inode, WIMLIB_UNIX_DATA_TAG,
+ (const u8*)&unix_data,
+ sizeof(struct wimlib_unix_data),
+ lookup_table);
+ if (ret == 0 && have_unix_data)
+ inode_remove_ads(inode, stream_idx, lookup_table);
+ return ret;
+}
/*
* Reads the alternate data stream entries of a WIM dentry.
* recursively writing the directory trees rooted at each of the child
* dentries, since the on-disk dentries for a dentry's children are
* always located at consecutive positions in the metadata resource! */
- for_dentry_in_rbtree(parent->d_inode->i_children.rb_node, write_dentry_cb, &p);
+ for_dentry_child(parent, write_dentry_cb, &p);
/* write end of directory entry */
p = put_u64(p, 0);
/* Recurse on children. */
- for_dentry_in_rbtree(parent->d_inode->i_children.rb_node,
- write_dentry_tree_recursive_cb, &p);
+ for_dentry_child(parent, write_dentry_tree_recursive_cb, &p);
return p;
}