]> wimlib.net Git - wimlib/blobdiff - src/dentry.c
Windows native build
[wimlib] / src / dentry.c
index 1165ed723a638a99a42e8fbf8a0eb93f2a37819c..15a44cee981c6e97ac64f0bc5ec057344f31fd0c 100644 (file)
@@ -9,7 +9,7 @@
  */
 
 /*
- * Copyright (C) 2012 Eric Biggers
+ * Copyright (C) 2012, 2013 Eric Biggers
  *
  * This file is part of wimlib, a library for working with WIM files.
  *
@@ -66,7 +66,7 @@ static u64 dentry_correct_length(const struct wim_dentry *dentry)
 
 /* Return %true iff the alternate data stream entry @entry has the UTF-8 stream
  * name @name that has length @name_len bytes. */
-static inline bool ads_entry_has_name(const struct ads_entry *entry,
+static inline bool ads_entry_has_name(const struct wim_ads_entry *entry,
                                      const char *name, size_t name_len)
 {
        if (entry->stream_name_utf8_len != name_len)
@@ -126,7 +126,7 @@ int set_dentry_name(struct wim_dentry *dentry, const char *new_name)
 
 /*
  * Changes the name of an alternate data stream */
-static int change_ads_name(struct ads_entry *entry, const char *new_name)
+static int change_ads_name(struct wim_ads_entry *entry, const char *new_name)
 {
        return get_names(&entry->stream_name, &entry->stream_name_utf8,
                         &entry->stream_name_len,
@@ -137,7 +137,7 @@ static int change_ads_name(struct ads_entry *entry, const char *new_name)
 /* Returns the total length of a WIM alternate data stream entry on-disk,
  * including the stream name, the null terminator, AND the padding after the
  * entry to align the next ADS entry or dentry on an 8-byte boundary. */
-static u64 ads_entry_total_length(const struct ads_entry *entry)
+static u64 ads_entry_total_length(const struct wim_ads_entry *entry)
 {
        u64 len = WIM_ADS_ENTRY_DISK_SIZE;
        if (entry->stream_name_len)
@@ -218,9 +218,6 @@ static int for_dentry_tree_in_rbtree_depth(struct rb_node *node,
        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)
@@ -239,7 +236,6 @@ static int for_dentry_tree_in_rbtree(struct rb_node *node,
        }
        return 0;
 }
-#endif
 
 /*
  * Calls a function on all directory entries in a WIM dentry tree.  Logically,
@@ -253,112 +249,10 @@ static int for_dentry_tree_in_rbtree(struct rb_node *node,
 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
 }
 
 /*
@@ -368,96 +262,12 @@ out:
 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
 }
 
 /*
@@ -561,7 +371,7 @@ void calculate_subdir_offsets(struct wim_dentry *dentry, u64 *subdir_offset_p)
 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 {
@@ -745,7 +555,7 @@ int print_dentry(struct wim_dentry *dentry, void *lookup_table)
        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) {
@@ -766,8 +576,8 @@ int print_dentry(struct wim_dentry *dentry, void *lookup_table)
                        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;
 }
@@ -870,7 +680,7 @@ struct wim_dentry *new_dentry_with_inode(const char *name)
 }
 
 
-static int init_ads_entry(struct ads_entry *ads_entry, const char *name)
+static int init_ads_entry(struct wim_ads_entry *ads_entry, const char *name)
 {
        int ret = 0;
        memset(ads_entry, 0, sizeof(*ads_entry));
@@ -879,7 +689,7 @@ static int init_ads_entry(struct ads_entry *ads_entry, const char *name)
        return ret;
 }
 
-static void destroy_ads_entry(struct ads_entry *ads_entry)
+static void destroy_ads_entry(struct wim_ads_entry *ads_entry)
 {
        FREE(ads_entry->stream_name);
        FREE(ads_entry->stream_name_utf8);
@@ -991,8 +801,8 @@ int increment_dentry_refcnt(struct wim_dentry *dentry, void *ignore)
 /*
  * Links a dentry into the directory tree.
  *
- * @dentry: The dentry to link.
  * @parent: The dentry that will be the parent of @dentry.
+ * @dentry: The dentry to link.
  */
 bool dentry_add_child(struct wim_dentry * restrict parent,
                      struct wim_dentry * restrict child)
@@ -1022,12 +832,7 @@ bool dentry_add_child(struct wim_dentry * restrict parent,
        return true;
 }
 
-#ifdef WITH_FUSE
-/*
- * Unlink a dentry from the directory tree.
- *
- * Note: This merely removes it from the in-memory tree structure.
- */
+/* Unlink a WIM dentry from the directory entry tree. */
 void unlink_dentry(struct wim_dentry *dentry)
 {
        struct wim_dentry *parent = dentry->parent;
@@ -1035,12 +840,12 @@ 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. */
-struct ads_entry *inode_get_ads_entry(struct wim_inode *inode,
+/*
+ * Returns the alternate data stream entry belonging to @inode that has the
+ * stream name @stream_name.
+ */
+struct wim_ads_entry *inode_get_ads_entry(struct wim_inode *inode,
                                      const char *stream_name,
                                      u16 *idx_ret)
 {
@@ -1059,18 +864,16 @@ struct ads_entry *inode_get_ads_entry(struct wim_inode *inode,
        }
        return NULL;
 }
-#endif
 
-#if defined(WITH_FUSE) || defined(WITH_NTFS_3G)
 /*
- * Add an alternate stream entry to an inode and return a pointer to it, or NULL
- * if memory could not be allocated.
+ * Add an alternate stream entry to a WIM inode and return a pointer to it, or
+ * NULL if memory could not be allocated.
  */
-struct ads_entry *inode_add_ads(struct wim_inode *inode, const char *stream_name)
+struct wim_ads_entry *inode_add_ads(struct wim_inode *inode, const char *stream_name)
 {
        u16 num_ads;
-       struct ads_entry *ads_entries;
-       struct ads_entry *new_entry;
+       struct wim_ads_entry *ads_entries;
+       struct wim_ads_entry *new_entry;
 
        DEBUG("Add alternate data stream \"%s\"", stream_name);
 
@@ -1096,14 +899,60 @@ struct ads_entry *inode_add_ads(struct wim_inode *inode, const char *stream_name
        inode->i_num_ads = num_ads;
        return new_entry;
 }
-#endif
 
-#ifdef WITH_FUSE
-/* Remove an alternate data stream from the inode  */
+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)
 {
-       struct ads_entry *ads_entry;
+       struct wim_ads_entry *ads_entry;
        struct wim_lookup_table_entry *lte;
 
        wimlib_assert(idx < inode->i_num_ads);
@@ -1119,17 +968,86 @@ void inode_remove_ads(struct wim_inode *inode, u16 idx,
 
        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
 
+#ifndef __WIN32__
+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;
+}
+#endif /* !__WIN32__ */
 
 /*
- * Reads the alternate data stream entries for a dentry.
+ * Reads the alternate data stream entries of a WIM dentry.
  *
  * @p: Pointer to buffer that starts with the first alternate stream entry.
  *
@@ -1142,7 +1060,7 @@ void inode_remove_ads(struct wim_inode *inode, u16 idx,
  *
  * The format of the on-disk alternate stream entries is as follows:
  *
- * struct ads_entry_on_disk {
+ * struct wim_ads_entry_on_disk {
  *     u64  length;          // Length of the entry, in bytes.  This includes
  *                                 all fields (including the stream name and
  *                                 null terminator if present, AND the padding!).
@@ -1165,14 +1083,14 @@ void inode_remove_ads(struct wim_inode *inode, u16 idx,
  * In addition, the entries are 8-byte aligned.
  *
  * Return 0 on success or nonzero on failure.  On success, inode->i_ads_entries
- * is set to an array of `struct ads_entry's of length inode->i_num_ads.  On
+ * is set to an array of `struct wim_ads_entry's of length inode->i_num_ads.  On
  * failure, @inode is not modified.
  */
 static int read_ads_entries(const u8 *p, struct wim_inode *inode,
                            u64 remaining_size)
 {
        u16 num_ads;
-       struct ads_entry *ads_entries;
+       struct wim_ads_entry *ads_entries;
        int ret;
 
        num_ads = inode->i_num_ads;
@@ -1184,7 +1102,7 @@ static int read_ads_entries(const u8 *p, struct wim_inode *inode,
        }
 
        for (u16 i = 0; i < num_ads; i++) {
-               struct ads_entry *cur_entry;
+               struct wim_ads_entry *cur_entry;
                u64 length;
                u64 length_no_padding;
                u64 total_length;
@@ -1292,7 +1210,7 @@ out_free_ads_entries:
 }
 
 /*
- * Reads a directory entry, including all alternate data stream entries that
+ * Reads a WIM directory entry, including all alternate data stream entries that
  * follow it, from the WIM image's metadata resource.
  *
  * @metadata_resource: Buffer containing the uncompressed metadata resource.
@@ -1475,7 +1393,7 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
                 *      u64 reserved1; (always 0)
                 *      u64 reserved2; (always 0)
                 * };*/
-               DEBUG("Dentry for file or directory `%s' has %zu extra "
+               DEBUG("Dentry for file or directory `%s' has %"PRIu64" extra "
                      "bytes of data",
                      file_name_utf8, dentry->length - calculated_size);
        }
@@ -1747,14 +1665,13 @@ static u8 *write_dentry_tree_recursive(const struct wim_dentry *parent, u8 *p)
         * 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;
 }