]> wimlib.net Git - wimlib/commitdiff
inode.h, inode.c cleanup
authorEric Biggers <ebiggers3@gmail.com>
Sun, 14 Dec 2014 21:03:40 +0000 (15:03 -0600)
committerEric Biggers <ebiggers3@gmail.com>
Mon, 15 Dec 2014 02:35:31 +0000 (20:35 -0600)
21 files changed:
Makefile.am
include/wimlib/inode.h
src/compress.c
src/decompress_common.c
src/extract.c
src/inode.c
src/inode_table.c [new file with mode: 0644]
src/iterate_dir.c
src/metadata_resource.c
src/mount_image.c
src/ntfs-3g_apply.c
src/ntfs-3g_capture.c
src/template.c
src/textfile.c
src/unix_apply.c
src/update_image.c
src/wim.c
src/win32_apply.c
src/win32_capture.c
src/write.c
src/xml.c

index c19b7fcc716cb24cdc2c891d627edde0a41beb15..ed7ac51126511a11cc610e3d52d93bae744c2adf 100644 (file)
@@ -38,6 +38,7 @@ libwim_la_SOURCES =           \
        src/header.c            \
        src/inode.c             \
        src/inode_fixup.c       \
        src/header.c            \
        src/inode.c             \
        src/inode_fixup.c       \
+       src/inode_table.c       \
        src/integrity.c         \
        src/iterate_dir.c       \
        src/join.c              \
        src/integrity.c         \
        src/iterate_dir.c       \
        src/join.c              \
index 733d3847f8082fc12e0a204c443ecc46f8d50247..4b9567757aa1ba2f8fd78ac0d1a25c4c9867678e 100644 (file)
@@ -1,19 +1,17 @@
 #ifndef _WIMLIB_INODE_H
 #define _WIMLIB_INODE_H
 
 #ifndef _WIMLIB_INODE_H
 #define _WIMLIB_INODE_H
 
-#include "wimlib/assert.h"
 #include "wimlib/list.h"
 #include "wimlib/list.h"
-#include "wimlib/lookup_table.h"
 #include "wimlib/sha1.h"
 #include "wimlib/sha1.h"
+#include "wimlib/types.h"
 
 
-#include <string.h>
-
+struct avl_tree_node;
 struct wim_ads_entry;
 struct wim_dentry;
 struct wim_ads_entry;
 struct wim_dentry;
-struct wim_security_data;
 struct wim_lookup_table;
 struct wim_lookup_table;
+struct wim_lookup_table_entry;
+struct wim_security_data;
 struct wimfs_fd;
 struct wimfs_fd;
-struct avl_tree_node;
 
 /*
  * WIM inode.
 
 /*
  * WIM inode.
@@ -70,9 +68,9 @@ struct wim_inode {
                 * for the same inode. */
                struct hlist_node i_hlist;
 
                 * for the same inode. */
                struct hlist_node i_hlist;
 
-               /* Normal list node- used to connect all the inodes of a WIM image
-                * into a single linked list referenced from the
-                * `struct wim_image_metadata' for that image. */
+               /* Normal list node- used to connect all the inodes of a WIM
+                * image into a single linked list referenced from the `struct
+                * wim_image_metadata' for that image. */
                struct list_head i_list;
        };
 
                struct list_head i_list;
        };
 
@@ -118,10 +116,10 @@ struct wim_inode {
        /* Size of @i_extra buffer in bytes.  If 0, there is no extra data.  */
        size_t i_extra_size;
 
        /* Size of @i_extra buffer in bytes.  If 0, there is no extra data.  */
        size_t i_extra_size;
 
-       /* Creation time, last access time, and last write time for this inode, in
-        * 100-nanosecond intervals since 12:00 a.m UTC January 1, 1601.  They
-        * should correspond to the times gotten by calling GetFileTime() on
-        * Windows. */
+       /* Creation time, last access time, and last write time for this inode,
+        * in 100-nanosecond intervals since 12:00 a.m UTC January 1, 1601.
+        * They should correspond to the times gotten by calling GetFileTime()
+        * on Windows. */
        u64 i_creation_time;
        u64 i_last_access_time;
        u64 i_last_write_time;
        u64 i_creation_time;
        u64 i_last_access_time;
        u64 i_last_write_time;
@@ -243,28 +241,26 @@ struct wim_ads_entry {
 
 /* WIM alternate data stream entry (on-disk format) */
 struct wim_ads_entry_on_disk {
 
 /* WIM alternate data stream entry (on-disk format) */
 struct wim_ads_entry_on_disk {
-       /*  Length of the entry, in bytes.  This apparently includes all
-        *  fixed-length fields, plus the stream name and null terminator if
-        *  present, and the padding up to an 8 byte boundary.  wimlib is a
-        *  little less strict when reading the entries, and only requires that
-        *  the number of bytes from this field is at least as large as the size
-        *  of the fixed length fields and stream name without null terminator.
-        *  */
-       le64  length;
+       /* Length of the entry, in bytes.  This includes all fixed-length
+        * fields, plus the stream name and null terminator if present, and the
+        * padding up to an 8 byte boundary.  wimlib is a little less strict
+        * when reading the entries, and only requires that the number of bytes
+        * from this field is at least as large as the size of the fixed length
+        * fields and stream name without null terminator.  */
+       le64 length;
 
 
-       le64  reserved;
+       le64 reserved;
 
        /* SHA1 message digest of the uncompressed stream; or, alternatively,
 
        /* SHA1 message digest of the uncompressed stream; or, alternatively,
-        * can be all zeroes if the stream has zero length. */
+        * can be all zeroes if the stream has zero length.  */
        u8 hash[SHA1_HASH_SIZE];
 
        /* Length of the stream name, in bytes.  0 if the stream is unnamed.  */
        le16 stream_name_nbytes;
 
        /* Stream name in UTF-16LE.  It is @stream_name_nbytes bytes long,
        u8 hash[SHA1_HASH_SIZE];
 
        /* Length of the stream name, in bytes.  0 if the stream is unnamed.  */
        le16 stream_name_nbytes;
 
        /* Stream name in UTF-16LE.  It is @stream_name_nbytes bytes long,
-        * excluding the null terminator.  There is a null terminator
-        * character if @stream_name_nbytes != 0; i.e., if this stream is named.
-        * */
+        * excluding the null terminator.  There is a null terminator character
+        * if @stream_name_nbytes != 0; i.e., if this stream is named.  */
        utf16lechar stream_name[];
 } _packed_attribute;
 
        utf16lechar stream_name[];
 } _packed_attribute;
 
@@ -314,62 +310,23 @@ put_inode(struct wim_inode *inode);
 extern void
 free_inode(struct wim_inode *inode);
 
 extern void
 free_inode(struct wim_inode *inode);
 
-/* Iterate through each alias of an inode.  */
+/* Iterate through each alias of the specified inode.  */
 #define inode_for_each_dentry(dentry, inode) \
 #define inode_for_each_dentry(dentry, inode) \
-               list_for_each_entry((dentry), &(inode)->i_dentry, d_alias)
+       list_for_each_entry((dentry), &(inode)->i_dentry, d_alias)
 
 
-/* Add a new alias for an inode.  Does not increment i_nlink; that must be done
- * separately.  */
+/* Add a new alias for the specified inode.  Does not increment i_nlink; that
+ * must be done separately if needed.  */
 #define inode_add_dentry(dentry, inode) \
 #define inode_add_dentry(dentry, inode) \
-               list_add_tail(&(dentry)->d_alias, &(inode)->i_dentry)
+       list_add_tail(&(dentry)->d_alias, &(inode)->i_dentry)
 
 
-/* Return an alias of an inode.  */
+/* Return an alias of the specified inode.  */
 #define inode_first_dentry(inode) \
 #define inode_first_dentry(inode) \
-               container_of(inode->i_dentry.next, struct wim_dentry, d_alias)
+       container_of(inode->i_dentry.next, struct wim_dentry, d_alias)
 
 
-/* Return the full path of an alias of an inode, or NULL if it could not be
- * determined.  */
+/* Return the full path of an alias of the specified inode, or NULL if a full
+ * path could not be determined.  */
 #define inode_first_full_path(inode) \
 #define inode_first_full_path(inode) \
-               dentry_full_path(inode_first_dentry(inode))
-
-extern struct wim_ads_entry *
-inode_get_ads_entry(struct wim_inode *inode, const tchar *stream_name);
-
-extern struct wim_ads_entry *
-inode_add_ads_utf16le(struct wim_inode *inode,
-                     const utf16lechar *stream_name,
-                     size_t stream_name_nbytes);
-
-extern struct wim_ads_entry *
-inode_add_ads(struct wim_inode *dentry, const tchar *stream_name);
-
-extern struct wim_ads_entry *
-inode_add_ads_with_data(struct wim_inode *inode, const tchar *name,
-                       const void *value, size_t size,
-                       struct wim_lookup_table *lookup_table);
-
-extern bool
-inode_has_named_stream(const struct wim_inode *inode);
-
-extern int
-inode_set_unnamed_stream(struct wim_inode *inode, const void *data, size_t len,
-                        struct wim_lookup_table *lookup_table);
-
-extern void
-inode_remove_ads(struct wim_inode *inode, struct wim_ads_entry *entry,
-                struct wim_lookup_table *lookup_table);
-
-/*
- * Does the specified alternate data stream entry correspond to a named stream?
- *
- * See inode_needs_dummy_stream() for explanation of why an alternate data
- * stream entry might, in fact, not be named...
- */
-static inline bool
-ads_entry_is_named_stream(const struct wim_ads_entry *entry)
-{
-       return entry->stream_name_nbytes != 0;
-}
+       dentry_full_path(inode_first_dentry(inode))
 
 /* Is the inode a directory?
  * This doesn't count directories with reparse data.
 
 /* Is the inode a directory?
  * This doesn't count directories with reparse data.
@@ -384,8 +341,8 @@ inode_is_directory(const struct wim_inode *inode)
 }
 
 /* Is the inode a directory with the encrypted attribute set?
 }
 
 /* Is the inode a directory with the encrypted attribute set?
- * This currently returns true for encrypted directories even if they have
- * reparse data (not sure if such files can even exist).  */
+ * This returns true for encrypted directories even if they have reparse data
+ * (I'm not sure if such files can even exist!).  */
 static inline bool
 inode_is_encrypted_directory(const struct wim_inode *inode)
 {
 static inline bool
 inode_is_encrypted_directory(const struct wim_inode *inode)
 {
@@ -415,92 +372,81 @@ inode_has_children(const struct wim_inode *inode)
        return inode->i_children != NULL;
 }
 
        return inode->i_children != NULL;
 }
 
+extern struct wim_ads_entry *
+inode_get_ads_entry(struct wim_inode *inode, const tchar *stream_name);
+
+extern struct wim_ads_entry *
+inode_add_ads_utf16le(struct wim_inode *inode, const utf16lechar *stream_name,
+                     size_t stream_name_nbytes);
+
+extern struct wim_ads_entry *
+inode_add_ads(struct wim_inode *dentry, const tchar *stream_name);
+
+extern struct wim_ads_entry *
+inode_add_ads_with_data(struct wim_inode *inode, const tchar *name,
+                       const void *value, size_t size,
+                       struct wim_lookup_table *lookup_table);
+
+extern void
+inode_remove_ads(struct wim_inode *inode, struct wim_ads_entry *entry,
+                struct wim_lookup_table *lookup_table);
+
+extern bool
+inode_has_named_stream(const struct wim_inode *inode);
+
 extern int
 extern int
-inode_resolve_streams(struct wim_inode *inode, struct wim_lookup_table *table,
-                     bool force);
+inode_set_unnamed_stream(struct wim_inode *inode, const void *data, size_t len,
+                        struct wim_lookup_table *lookup_table);
 
 extern int
 
 extern int
-stream_not_found_error(const struct wim_inode *inode, const u8 *hash);
+inode_resolve_streams(struct wim_inode *inode, struct wim_lookup_table *table,
+                     bool force);
 
 extern void
 inode_unresolve_streams(struct wim_inode *inode);
 
 
 extern void
 inode_unresolve_streams(struct wim_inode *inode);
 
+extern int
+stream_not_found_error(const struct wim_inode *inode, const u8 *hash);
+
 static inline struct wim_lookup_table_entry *
 inode_stream_lte_resolved(const struct wim_inode *inode, unsigned stream_idx)
 {
 static inline struct wim_lookup_table_entry *
 inode_stream_lte_resolved(const struct wim_inode *inode, unsigned stream_idx)
 {
-       wimlib_assert(inode->i_resolved);
-       wimlib_assert(stream_idx <= inode->i_num_ads);
        if (stream_idx == 0)
                return inode->i_lte;
        if (stream_idx == 0)
                return inode->i_lte;
-       else
-               return inode->i_ads_entries[stream_idx - 1].lte;
-}
-
-static inline struct wim_lookup_table_entry *
-inode_stream_lte_unresolved(const struct wim_inode *inode, unsigned stream_idx,
-                           const struct wim_lookup_table *table)
-{
-       wimlib_assert(!inode->i_resolved);
-       wimlib_assert(stream_idx <= inode->i_num_ads);
-       if (table == NULL)
-               return NULL;
-       if (stream_idx == 0)
-               return lookup_stream(table, inode->i_hash);
-       else
-               return lookup_stream(table, inode->i_ads_entries[ stream_idx - 1].hash);
+       return inode->i_ads_entries[stream_idx - 1].lte;
 }
 
 extern struct wim_lookup_table_entry *
 inode_stream_lte(const struct wim_inode *inode, unsigned stream_idx,
                 const struct wim_lookup_table *table);
 
 }
 
 extern struct wim_lookup_table_entry *
 inode_stream_lte(const struct wim_inode *inode, unsigned stream_idx,
                 const struct wim_lookup_table *table);
 
-static inline const u8 *
-inode_stream_hash_unresolved(const struct wim_inode *inode, unsigned stream_idx)
+extern struct wim_lookup_table_entry *
+inode_unnamed_stream_resolved(const struct wim_inode *inode,
+                             unsigned *stream_idx_ret);
+
+static inline struct wim_lookup_table_entry *
+inode_unnamed_lte_resolved(const struct wim_inode *inode)
 {
 {
-       wimlib_assert(!inode->i_resolved);
-       wimlib_assert(stream_idx <= inode->i_num_ads);
-       if (stream_idx == 0)
-               return inode->i_hash;
-       else
-               return inode->i_ads_entries[stream_idx - 1].hash;
+       unsigned stream_idx;
+       return inode_unnamed_stream_resolved(inode, &stream_idx);
 }
 
 }
 
+extern struct wim_lookup_table_entry *
+inode_unnamed_lte(const struct wim_inode *inode,
+                 const struct wim_lookup_table *table);
 
 
-static inline const u8 *
-inode_stream_hash_resolved(const struct wim_inode *inode, unsigned stream_idx)
-{
-       struct wim_lookup_table_entry *lte;
-       lte = inode_stream_lte_resolved(inode, stream_idx);
-       if (lte)
-               return lte->hash;
-       else
-               return zero_hash;
-}
+extern const u8 *
+inode_stream_hash(const struct wim_inode *inode, unsigned stream_idx);
 
 
-/*
- * Returns the hash for stream @stream_idx of the inode, where stream_idx = 0
- * means the default un-named file stream, and stream_idx >= 1 corresponds to an
- * alternate data stream.
- *
- * This works for both resolved and un-resolved dentries.
- */
-static inline const u8 *
-inode_stream_hash(const struct wim_inode *inode, unsigned stream_idx)
-{
-       if (inode->i_resolved)
-               return inode_stream_hash_resolved(inode, stream_idx);
-       else
-               return inode_stream_hash_unresolved(inode, stream_idx);
-}
+extern const u8 *
+inode_unnamed_stream_hash(const struct wim_inode *inode);
 
 
-static inline u16
+static inline unsigned
 inode_stream_name_nbytes(const struct wim_inode *inode, unsigned stream_idx)
 {
 inode_stream_name_nbytes(const struct wim_inode *inode, unsigned stream_idx)
 {
-       wimlib_assert(stream_idx <= inode->i_num_ads);
        if (stream_idx == 0)
                return 0;
        if (stream_idx == 0)
                return 0;
-       else
-               return inode->i_ads_entries[stream_idx - 1].stream_name_nbytes;
+       return inode->i_ads_entries[stream_idx - 1].stream_name_nbytes;
 }
 
 static inline u32
 }
 
 static inline u32
@@ -508,25 +454,15 @@ inode_stream_idx_to_id(const struct wim_inode *inode, unsigned stream_idx)
 {
        if (stream_idx == 0)
                return 0;
 {
        if (stream_idx == 0)
                return 0;
-       else
-               return inode->i_ads_entries[stream_idx - 1].stream_id;
+       return inode->i_ads_entries[stream_idx - 1].stream_id;
 }
 
 }
 
-extern struct wim_lookup_table_entry *
-inode_unnamed_stream_resolved(const struct wim_inode *inode, u16 *stream_idx_ret);
-
-extern struct wim_lookup_table_entry *
-inode_unnamed_lte_resolved(const struct wim_inode *inode);
-
-extern struct wim_lookup_table_entry *
-inode_unnamed_lte_unresolved(const struct wim_inode *inode,
-                            const struct wim_lookup_table *table);
-
-extern struct wim_lookup_table_entry *
-inode_unnamed_lte(const struct wim_inode *inode, const struct wim_lookup_table *table);
+extern void
+inode_ref_streams(struct wim_inode *inode);
 
 
-extern const u8 *
-inode_unnamed_stream_hash(const struct wim_inode *inode);
+extern void
+inode_unref_streams(struct wim_inode *inode,
+                   struct wim_lookup_table *lookup_table);
 
 extern int
 read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode,
 
 extern int
 read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode,
@@ -535,13 +471,6 @@ read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode,
 extern void
 check_inode(struct wim_inode *inode, const struct wim_security_data *sd);
 
 extern void
 check_inode(struct wim_inode *inode, const struct wim_security_data *sd);
 
-extern void
-inode_ref_streams(struct wim_inode *inode);
-
-extern void
-inode_unref_streams(struct wim_inode *inode,
-                   struct wim_lookup_table *lookup_table);
-
 /* inode_fixup.c  */
 extern int
 dentry_tree_fix_inodes(struct wim_dentry *root, struct list_head *inode_list);
 /* inode_fixup.c  */
 extern int
 dentry_tree_fix_inodes(struct wim_dentry *root, struct list_head *inode_list);
index 414fad0f1e7dece566a2938668d57d61041a4843..1976579289dd416d76344cf7e0fc99c9e939a4e3 100644 (file)
@@ -27,7 +27,6 @@
 #endif
 
 #include "wimlib.h"
 #endif
 
 #include "wimlib.h"
-#include "wimlib/assert.h"
 #include "wimlib/error.h"
 #include "wimlib/compressor_ops.h"
 #include "wimlib/util.h"
 #include "wimlib/error.h"
 #include "wimlib/compressor_ops.h"
 #include "wimlib/util.h"
index 4ab9ccbe1c34fdb0519fa7cb0fe72e8e22bfc7ec..b08a3b4b130ed4d829297695bacde916a1686bd5 100644 (file)
@@ -14,6 +14,7 @@
 #  include "config.h"
 #endif
 
 #  include "config.h"
 #endif
 
+#include "wimlib/assert.h"
 #include "wimlib/decompress_common.h"
 
 #include <string.h>
 #include "wimlib/decompress_common.h"
 
 #include <string.h>
index 39899c4094e2c5eb80b296bc93d6e09161123de0..ac50fa8fb87c27e5e8a19eb6c8920515b185d22d 100644 (file)
@@ -40,6 +40,7 @@
 #endif
 
 #include "wimlib/apply.h"
 #endif
 
 #include "wimlib/apply.h"
+#include "wimlib/assert.h"
 #include "wimlib/dentry.h"
 #include "wimlib/encoding.h"
 #include "wimlib/endianness.h"
 #include "wimlib/dentry.h"
 #include "wimlib/encoding.h"
 #include "wimlib/endianness.h"
@@ -1008,7 +1009,7 @@ dentry_list_resolve_streams(struct list_head *dentry_list,
 }
 
 static int
 }
 
 static int
-ref_stream(struct wim_lookup_table_entry *lte, u32 stream_idx,
+ref_stream(struct wim_lookup_table_entry *lte, unsigned stream_idx,
           struct wim_dentry *dentry, struct apply_ctx *ctx)
 {
        struct wim_inode *inode = dentry->d_inode;
           struct wim_dentry *dentry, struct apply_ctx *ctx)
 {
        struct wim_inode *inode = dentry->d_inode;
@@ -1083,7 +1084,7 @@ ref_unnamed_stream(struct wim_dentry *dentry, struct apply_ctx *ctx)
 {
        struct wim_inode *inode = dentry->d_inode;
        int ret;
 {
        struct wim_inode *inode = dentry->d_inode;
        int ret;
-       u16 stream_idx;
+       unsigned stream_idx;
        struct wim_lookup_table_entry *stream;
 
        if (unlikely(inode_is_encrypted_directory(inode)))
        struct wim_lookup_table_entry *stream;
 
        if (unlikely(inode_is_encrypted_directory(inode)))
@@ -1120,8 +1121,8 @@ dentry_ref_streams(struct wim_dentry *dentry, struct apply_ctx *ctx)
         * extraction mode and volume, and to avoid complications, if not doing
         * a linked extraction.  */
        if (ctx->supported_features.named_data_streams) {
         * extraction mode and volume, and to avoid complications, if not doing
         * a linked extraction.  */
        if (ctx->supported_features.named_data_streams) {
-               for (u16 i = 0; i < inode->i_num_ads; i++) {
-                       if (!ads_entry_is_named_stream(&inode->i_ads_entries[i]))
+               for (unsigned i = 0; i < inode->i_num_ads; i++) {
+                       if (!inode->i_ads_entries[i].stream_name_nbytes)
                                continue;
                        ret = ref_stream(inode->i_ads_entries[i].lte, i + 1,
                                         dentry, ctx);
                                continue;
                        ret = ref_stream(inode->i_ads_entries[i].lte, i + 1,
                                         dentry, ctx);
index 585ed21a4bdc3dc0f3491693d1dda11884e4b072..9e4177c9ce57e46bd94151b42d9be592afc2b6e3 100644 (file)
 #  include "config.h"
 #endif
 
 #  include "config.h"
 #endif
 
+#include <errno.h>
+
 #include "wimlib/assert.h"
 #include "wimlib/assert.h"
-#include "wimlib/dentry.h" /* Only for dentry_full_path().  Otherwise the code
-                             in this file doesn't care about file names/paths.
-                           */
+#include "wimlib/dentry.h"
 #include "wimlib/encoding.h"
 #include "wimlib/endianness.h"
 #include "wimlib/error.h"
 #include "wimlib/inode.h"
 #include "wimlib/encoding.h"
 #include "wimlib/endianness.h"
 #include "wimlib/error.h"
 #include "wimlib/inode.h"
-#include "wimlib/inode_table.h"
 #include "wimlib/lookup_table.h"
 #include "wimlib/security.h"
 #include "wimlib/timestamp.h"
 
 #include "wimlib/lookup_table.h"
 #include "wimlib/security.h"
 #include "wimlib/timestamp.h"
 
-#include <errno.h>
-
 /* Allocate a new inode.  Set the timestamps to the current time.  */
 struct wim_inode *
 new_inode(void)
 /* Allocate a new inode.  Set the timestamps to the current time.  */
 struct wim_inode *
 new_inode(void)
@@ -74,7 +71,7 @@ new_timeless_inode(void)
        return inode;
 }
 
        return inode;
 }
 
-/* Decrement link count on an inode.  */
+/* Decrement an inode's link count.  */
 void
 put_inode(struct wim_inode *inode)
 {
 void
 put_inode(struct wim_inode *inode)
 {
@@ -105,7 +102,7 @@ free_inode(struct wim_inode *inode)
                return;
 
        if (unlikely(inode->i_ads_entries)) {
                return;
 
        if (unlikely(inode->i_ads_entries)) {
-               for (u16 i = 0; i < inode->i_num_ads; i++)
+               for (unsigned i = 0; i < inode->i_num_ads; i++)
                        destroy_ads_entry(&inode->i_ads_entries[i]);
                FREE(inode->i_ads_entries);
        }
                        destroy_ads_entry(&inode->i_ads_entries[i]);
                FREE(inode->i_ads_entries);
        }
@@ -118,20 +115,6 @@ free_inode(struct wim_inode *inode)
        FREE(inode);
 }
 
        FREE(inode);
 }
 
-/* Return %true iff the alternate data stream entry @entry has the UTF-16LE
- * stream name @name that has length @name_nbytes bytes.  */
-static inline bool
-ads_entry_has_name(const struct wim_ads_entry *entry,
-                  const utf16lechar *name, size_t name_nbytes,
-                  bool ignore_case)
-{
-       return 0 == cmp_utf16le_strings(name,
-                                       name_nbytes / 2,
-                                       entry->stream_name,
-                                       entry->stream_name_nbytes / 2,
-                                       ignore_case);
-}
-
 /*
  * Returns the alternate data stream entry belonging to @inode that has the
  * stream name @stream_name, or NULL if the inode has no alternate data stream
 /*
  * Returns the alternate data stream entry belonging to @inode that has the
  * stream name @stream_name, or NULL if the inode has no alternate data stream
@@ -148,7 +131,7 @@ inode_get_ads_entry(struct wim_inode *inode, const tchar *stream_name)
        int ret;
        const utf16lechar *stream_name_utf16le;
        size_t stream_name_utf16le_nbytes;
        int ret;
        const utf16lechar *stream_name_utf16le;
        size_t stream_name_utf16le_nbytes;
-       u16 i;
+       unsigned i;
        struct wim_ads_entry *result;
 
        if (inode->i_num_ads == 0) {
        struct wim_ads_entry *result;
 
        if (inode->i_num_ads == 0) {
@@ -169,10 +152,13 @@ inode_get_ads_entry(struct wim_inode *inode, const tchar *stream_name)
        i = 0;
        result = NULL;
        do {
        i = 0;
        result = NULL;
        do {
-               if (ads_entry_has_name(&inode->i_ads_entries[i],
-                                      stream_name_utf16le,
-                                      stream_name_utf16le_nbytes,
-                                      default_ignore_case))
+               if (!cmp_utf16le_strings(inode->i_ads_entries[i].stream_name,
+                                        inode->i_ads_entries[i].stream_name_nbytes /
+                                               sizeof(utf16lechar),
+                                        stream_name_utf16le,
+                                        stream_name_utf16le_nbytes /
+                                               sizeof(utf16lechar),
+                                        default_ignore_case))
                {
                        result = &inode->i_ads_entries[i];
                        break;
                {
                        result = &inode->i_ads_entries[i];
                        break;
@@ -190,11 +176,11 @@ static struct wim_ads_entry *
 do_inode_add_ads(struct wim_inode *inode,
                 utf16lechar *stream_name, size_t stream_name_nbytes)
 {
 do_inode_add_ads(struct wim_inode *inode,
                 utf16lechar *stream_name, size_t stream_name_nbytes)
 {
-       u16 num_ads;
+       unsigned num_ads;
        struct wim_ads_entry *ads_entries;
        struct wim_ads_entry *new_entry;
 
        struct wim_ads_entry *ads_entries;
        struct wim_ads_entry *new_entry;
 
-       if (inode->i_num_ads >= 0xfffe) {
+       if (unlikely(inode->i_num_ads >= 0xfffe)) {
                ERROR("File \"%"TS"\" has too many alternate data streams!",
                      inode_first_full_path(inode));
                errno = EFBIG;
                ERROR("File \"%"TS"\" has too many alternate data streams!",
                      inode_first_full_path(inode));
                errno = EFBIG;
@@ -288,44 +274,17 @@ inode_add_ads_with_data(struct wim_inode *inode, const tchar *name,
        wimlib_assert(inode->i_resolved);
 
        new_entry = inode_add_ads(inode, name);
        wimlib_assert(inode->i_resolved);
 
        new_entry = inode_add_ads(inode, name);
-       if (!new_entry)
+       if (unlikely(!new_entry))
                return NULL;
 
        new_entry->lte = new_stream_from_data_buffer(value, size, lookup_table);
                return NULL;
 
        new_entry->lte = new_stream_from_data_buffer(value, size, lookup_table);
-       if (!new_entry->lte) {
+       if (unlikely(!new_entry->lte)) {
                inode_remove_ads(inode, new_entry, NULL);
                return NULL;
        }
        return new_entry;
 }
 
                inode_remove_ads(inode, new_entry, NULL);
                return NULL;
        }
        return new_entry;
 }
 
-/*
- * Does the inode have any named data streams?
- */
-bool
-inode_has_named_stream(const struct wim_inode *inode)
-{
-       for (u16 i = 0; i < inode->i_num_ads; i++)
-               if (ads_entry_is_named_stream(&inode->i_ads_entries[i]))
-                       return true;
-       return false;
-}
-
-/* Set the unnamed stream of a WIM inode, given a data buffer containing the
- * stream contents.  The inode must be resolved and cannot have an unnamed
- * stream specified already.  */
-int
-inode_set_unnamed_stream(struct wim_inode *inode, const void *data, size_t len,
-                        struct wim_lookup_table *lookup_table)
-{
-       wimlib_assert(inode->i_resolved);
-       wimlib_assert(!inode->i_lte);
-       inode->i_lte = new_stream_from_data_buffer(data, len, lookup_table);
-       if (!inode->i_lte)
-               return WIMLIB_ERR_NOMEM;
-       return 0;
-}
-
 /* Remove an alternate data stream from a WIM inode.  */
 void
 inode_remove_ads(struct wim_inode *inode, struct wim_ads_entry *entry,
 /* Remove an alternate data stream from a WIM inode.  */
 void
 inode_remove_ads(struct wim_inode *inode, struct wim_ads_entry *entry,
@@ -349,6 +308,32 @@ inode_remove_ads(struct wim_inode *inode, struct wim_ads_entry *entry,
        inode->i_num_ads--;
 }
 
        inode->i_num_ads--;
 }
 
+/* Return true iff the specified inode has at least one named data stream.  */
+bool
+inode_has_named_stream(const struct wim_inode *inode)
+{
+       for (unsigned i = 0; i < inode->i_num_ads; i++)
+               if (inode->i_ads_entries[i].stream_name_nbytes)
+                       return true;
+       return false;
+}
+
+/* Set the unnamed stream of a WIM inode, given a data buffer containing the
+ * stream contents.  The inode must be resolved and cannot already have an
+ * unnamed stream.  */
+int
+inode_set_unnamed_stream(struct wim_inode *inode, const void *data, size_t len,
+                        struct wim_lookup_table *lookup_table)
+{
+       wimlib_assert(inode->i_resolved);
+       wimlib_assert(!inode->i_lte);
+
+       inode->i_lte = new_stream_from_data_buffer(data, len, lookup_table);
+       if (!inode->i_lte)
+               return WIMLIB_ERR_NOMEM;
+       return 0;
+}
+
 /*
  * Resolve an inode's single-instance streams.
  *
 /*
  * Resolve an inode's single-instance streams.
  *
@@ -403,7 +388,7 @@ inode_resolve_streams(struct wim_inode *inode, struct wim_lookup_table *table,
        }
 
        /* Resolve the alternate data streams */
        }
 
        /* Resolve the alternate data streams */
-       for (u16 i = 0; i < inode->i_num_ads; i++) {
+       for (unsigned i = 0; i < inode->i_num_ads; i++) {
                struct wim_ads_entry *cur_entry;
 
                ads_lte = NULL;
                struct wim_ads_entry *cur_entry;
 
                ads_lte = NULL;
@@ -426,7 +411,7 @@ inode_resolve_streams(struct wim_inode *inode, struct wim_lookup_table *table,
                ads_ltes[i] = ads_lte;
        }
        inode->i_lte = lte;
                ads_ltes[i] = ads_lte;
        }
        inode->i_lte = lte;
-       for (u16 i = 0; i < inode->i_num_ads; i++)
+       for (unsigned i = 0; i < inode->i_num_ads; i++)
                inode->i_ads_entries[i].lte = ads_ltes[i];
        inode->i_resolved = 1;
        return 0;
                inode->i_ads_entries[i].lte = ads_ltes[i];
        inode->i_resolved = 1;
        return 0;
@@ -451,7 +436,7 @@ inode_unresolve_streams(struct wim_inode *inode)
        else
                zero_out_hash(inode->i_hash);
 
        else
                zero_out_hash(inode->i_hash);
 
-       for (u16 i = 0; i < inode->i_num_ads; i++) {
+       for (unsigned i = 0; i < inode->i_num_ads; i++) {
                if (inode->i_ads_entries[i].lte)
                        copy_hash(inode->i_ads_entries[i].hash,
                                  inode->i_ads_entries[i].lte->hash);
                if (inode->i_ads_entries[i].lte)
                        copy_hash(inode->i_ads_entries[i].hash,
                                  inode->i_ads_entries[i].lte->hash);
@@ -478,11 +463,11 @@ stream_not_found_error(const struct wim_inode *inode, const u8 *hash)
 }
 
 /*
 }
 
 /*
- * Return the lookup table entry for stream @stream_idx of the inode, where
- * stream_idx = 0 means the default un-named file stream, and stream_idx >= 1
- * corresponds to an alternate data stream.
+ * Return the lookup table entry for the specified stream of the inode, or NULL
+ * if the specified stream is empty or not available.
  *
  *
- * This works for both resolved and un-resolved inodes.
+ * stream_idx = 0: default data stream
+ * stream_idx > 0: alternate data stream
  */
 struct wim_lookup_table_entry *
 inode_stream_lte(const struct wim_inode *inode, unsigned stream_idx,
  */
 struct wim_lookup_table_entry *
 inode_stream_lte(const struct wim_inode *inode, unsigned stream_idx,
@@ -490,56 +475,32 @@ inode_stream_lte(const struct wim_inode *inode, unsigned stream_idx,
 {
        if (inode->i_resolved)
                return inode_stream_lte_resolved(inode, stream_idx);
 {
        if (inode->i_resolved)
                return inode_stream_lte_resolved(inode, stream_idx);
-       else
-               return inode_stream_lte_unresolved(inode, stream_idx, table);
+       if (stream_idx == 0)
+               return lookup_stream(table, inode->i_hash);
+       return lookup_stream(table, inode->i_ads_entries[stream_idx - 1].hash);
 }
 
 /*
  * Return the lookup table entry for the unnamed data stream of a *resolved*
 }
 
 /*
  * Return the lookup table entry for the unnamed data stream of a *resolved*
- * inode, or NULL if there is none.  Also return the 0-based index of the
- * corresponding stream in *stream_idx_ret.
+ * inode, or NULL if the inode's unnamed data stream is empty.  Also return the
+ * 0-based index of the unnamed data stream in *stream_idx_ret.
  */
 struct wim_lookup_table_entry *
  */
 struct wim_lookup_table_entry *
-inode_unnamed_stream_resolved(const struct wim_inode *inode, u16 *stream_idx_ret)
+inode_unnamed_stream_resolved(const struct wim_inode *inode,
+                             unsigned *stream_idx_ret)
 {
        wimlib_assert(inode->i_resolved);
 {
        wimlib_assert(inode->i_resolved);
-       for (unsigned i = 0; i <= inode->i_num_ads; i++) {
-               if (inode_stream_name_nbytes(inode, i) == 0 &&
-                   !is_zero_hash(inode_stream_hash_resolved(inode, i)))
-               {
-                       *stream_idx_ret = i;
-                       return inode_stream_lte_resolved(inode, i);
-               }
-       }
-       *stream_idx_ret = 0;
-       return NULL;
-}
 
 
-/*
- * Return the lookup table entry for the unnamed data stream of a *resolved*
- * inode, or NULL if there is none.
- */
-struct wim_lookup_table_entry *
-inode_unnamed_lte_resolved(const struct wim_inode *inode)
-{
-       u16 stream_idx;
-       return inode_unnamed_stream_resolved(inode, &stream_idx);
-}
+       *stream_idx_ret = 0;
+       if (likely(inode->i_lte))
+               return inode->i_lte;
 
 
-/*
- * Return the lookup table entry for the unnamed data stream of an *unresolved*
- * inode, or NULL if there is none.
- */
-struct wim_lookup_table_entry *
-inode_unnamed_lte_unresolved(const struct wim_inode *inode,
-                            const struct wim_lookup_table *table)
-{
-       wimlib_assert(!inode->i_resolved);
-       for (unsigned i = 0; i <= inode->i_num_ads; i++) {
-               if (inode_stream_name_nbytes(inode, i) == 0 &&
-                   !is_zero_hash(inode_stream_hash_unresolved(inode, i)))
+       for (unsigned i = 0; i < inode->i_num_ads; i++) {
+               if (inode->i_ads_entries[i].stream_name_nbytes == 0 &&
+                   inode->i_ads_entries[i].lte)
                {
                {
-                       return inode_stream_lte_unresolved(inode, i, table);
+                       *stream_idx_ret = i + 1;
+                       return inode->i_ads_entries[i].lte;
                }
        }
        return NULL;
                }
        }
        return NULL;
@@ -547,37 +508,54 @@ inode_unnamed_lte_unresolved(const struct wim_inode *inode,
 
 /*
  * Return the lookup table entry for the unnamed data stream of an inode, or
 
 /*
  * Return the lookup table entry for the unnamed data stream of an inode, 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 inode 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 WIM
- * dentry itself.  So we need to check the alternate data streams too.
+ * NULL if the inode's unnamed data stream is empty or not available.
  *
  *
- * Also, note that a dentry may appear to have more than one unnamed stream, but
- * if the SHA-1 message digest is all 0's then the corresponding stream does not
- * really "count" (this is the case for the inode'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.
+ * Note: this is complicated by the fact that WIMGAPI may put the unnamed data
+ * stream in an alternate data stream entry rather than in the dentry itself.
  */
 struct wim_lookup_table_entry *
 inode_unnamed_lte(const struct wim_inode *inode,
                  const struct wim_lookup_table *table)
 {
  */
 struct wim_lookup_table_entry *
 inode_unnamed_lte(const struct wim_inode *inode,
                  const struct wim_lookup_table *table)
 {
+       struct wim_lookup_table_entry *lte;
+
        if (inode->i_resolved)
                return inode_unnamed_lte_resolved(inode);
        if (inode->i_resolved)
                return inode_unnamed_lte_resolved(inode);
-       else
-               return inode_unnamed_lte_unresolved(inode, table);
+
+       lte = lookup_stream(table, inode->i_hash);
+       if (likely(lte))
+               return lte;
+
+       for (unsigned i = 0; i < inode->i_num_ads; i++) {
+               if (inode->i_ads_entries[i].stream_name_nbytes)
+                       continue;
+               lte = lookup_stream(table, inode->i_ads_entries[i].hash);
+               if (lte)
+                       return lte;
+       }
+       return NULL;
 }
 
 }
 
-/*
- * Return the SHA-1 message digest of the unnamed data stream of a WIM inode.
- *
- * If inode does not have an unnamed data stream, this returns a void SHA-1
- * message digest containing all zero bytes.
- */
+/* Return the SHA-1 message digest of the specified stream of the inode, or a
+ * void SHA-1 of all zeroes if the specified stream is empty.   */
+const u8 *
+inode_stream_hash(const struct wim_inode *inode, unsigned stream_idx)
+{
+       if (inode->i_resolved) {
+               struct wim_lookup_table_entry *lte;
+
+               lte = inode_stream_lte_resolved(inode, stream_idx);
+               if (lte)
+                       return lte->hash;
+               return zero_hash;
+       }
+       if (stream_idx == 0)
+               return inode->i_hash;
+       return inode->i_ads_entries[stream_idx - 1].hash;
+}
+
+/* Return the SHA-1 message digest of the unnamed data stream of the inode, or a
+ * void SHA-1 of all zeroes if the inode's unnamed data stream is empty.   */
 const u8 *
 inode_unnamed_stream_hash(const struct wim_inode *inode)
 {
 const u8 *
 inode_unnamed_stream_hash(const struct wim_inode *inode)
 {
@@ -593,29 +571,35 @@ inode_unnamed_stream_hash(const struct wim_inode *inode)
        return zero_hash;
 }
 
        return zero_hash;
 }
 
-/*
- * Translate a single-instance stream entry into the pointer contained in the
- * inode (or ads entry of an inode) that references it.
+/* Acquire another reference to each single-instance stream referenced by this
+ * inode.  This is necessary when creating a hard link to this inode.
  *
  *
- * This is only possible for "unhashed" streams, which are guaranteed to have
- * only one reference, and that reference is guaranteed to be in a resolved
- * inode.  (It can't be in an unresolved inode, since that would imply the hash
- * is known!)
- */
-struct wim_lookup_table_entry **
-retrieve_lte_pointer(struct wim_lookup_table_entry *lte)
+ * The inode must be resolved.  */
+void
+inode_ref_streams(struct wim_inode *inode)
 {
 {
-       wimlib_assert(lte->unhashed);
-       struct wim_inode *inode = lte->back_inode;
-       u32 stream_id = lte->back_stream_id;
-       if (stream_id == 0)
-               return &inode->i_lte;
-       else
-               for (u16 i = 0; i < inode->i_num_ads; i++)
-                       if (inode->i_ads_entries[i].stream_id == stream_id)
-                               return &inode->i_ads_entries[i].lte;
-       wimlib_assert(0);
-       return NULL;
+       wimlib_assert(inode->i_resolved);
+
+       if (inode->i_lte)
+               inode->i_lte->refcnt++;
+       for (unsigned i = 0; i < inode->i_num_ads; i++)
+               if (inode->i_ads_entries[i].lte)
+                       inode->i_ads_entries[i].lte->refcnt++;
+}
+
+/* Drop a reference to each single-instance stream referenced by this inode.
+ * This is necessary when deleting a hard link to this inode.  */
+void
+inode_unref_streams(struct wim_inode *inode,
+                   struct wim_lookup_table *lookup_table)
+{
+       for (unsigned i = 0; i <= inode->i_num_ads; i++) {
+               struct wim_lookup_table_entry *lte;
+
+               lte = inode_stream_lte(inode, i, lookup_table);
+               if (lte)
+                       lte_decrement_refcnt(lte, lookup_table);
+       }
 }
 
 /*
 }
 
 /*
@@ -646,7 +630,7 @@ read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode,
                 size_t *nbytes_remaining_p)
 {
        size_t nbytes_remaining = *nbytes_remaining_p;
                 size_t *nbytes_remaining_p)
 {
        size_t nbytes_remaining = *nbytes_remaining_p;
-       u16 num_ads;
+       unsigned num_ads;
        struct wim_ads_entry *ads_entries;
        int ret;
 
        struct wim_ads_entry *ads_entries;
        int ret;
 
@@ -660,7 +644,7 @@ read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode,
                goto out_of_memory;
 
        /* Read the entries into our newly allocated buffer. */
                goto out_of_memory;
 
        /* Read the entries into our newly allocated buffer. */
-       for (u16 i = 0; i < num_ads; i++) {
+       for (unsigned i = 0; i < num_ads; i++) {
                u64 length;
                struct wim_ads_entry *cur_entry;
                const struct wim_ads_entry_on_disk *disk_entry =
                u64 length;
                struct wim_ads_entry *cur_entry;
                const struct wim_ads_entry_on_disk *disk_entry =
@@ -722,7 +706,7 @@ read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode,
                /* It's expected that the size of every ADS entry is a multiple
                 * of 8.  However, to be safe, I'm allowing the possibility of
                 * an ADS entry at the very end of the metadata resource ending
                /* It's expected that the size of every ADS entry is a multiple
                 * of 8.  However, to be safe, I'm allowing the possibility of
                 * an ADS entry at the very end of the metadata resource ending
-                * un-aligned.  So although we still need to increment the input
+                * unaligned.  So although we still need to increment the input
                 * pointer by @length to reach the next ADS entry, it's possible
                 * that less than @length is actually remaining in the metadata
                 * resource. We should set the remaining bytes to 0 if this
                 * pointer by @length to reach the next ADS entry, it's possible
                 * that less than @length is actually remaining in the metadata
                 * resource. We should set the remaining bytes to 0 if this
@@ -747,7 +731,7 @@ out_invalid:
        ret = WIMLIB_ERR_INVALID_METADATA_RESOURCE;
 out_free_ads_entries:
        if (ads_entries) {
        ret = WIMLIB_ERR_INVALID_METADATA_RESOURCE;
 out_free_ads_entries:
        if (ads_entries) {
-               for (u16 i = 0; i < num_ads; i++)
+               for (unsigned i = 0; i < num_ads; i++)
                        destroy_ads_entry(&ads_entries[i]);
                FREE(ads_entries);
        }
                        destroy_ads_entry(&ads_entries[i]);
                FREE(ads_entries);
        }
@@ -780,203 +764,33 @@ check_inode(struct wim_inode *inode, const struct wim_security_data *sd)
                        num_unnamed_streams++;
        }
        if (num_unnamed_streams > 1) {
                        num_unnamed_streams++;
        }
        if (num_unnamed_streams > 1) {
-               WARNING("\"%"TS"\" has multiple (%u) un-named streams",
+               WARNING("\"%"TS"\" has multiple (%u) unnamed streams",
                        inode_first_full_path(inode), num_unnamed_streams);
                /* We currently don't treat this as an error and will just end
                 * up using the first unnamed data stream in the inode.  */
        }
 }
 
                        inode_first_full_path(inode), num_unnamed_streams);
                /* We currently don't treat this as an error and will just end
                 * up using the first unnamed data stream in the inode.  */
        }
 }
 
-/* Acquire another reference to each single-instance stream referenced by this
- * inode.  This is necessary when creating a hard link to this inode.
- *
- * The inode must be resolved.  */
-void
-inode_ref_streams(struct wim_inode *inode)
-{
-       for (unsigned i = 0; i <= inode->i_num_ads; i++) {
-               struct wim_lookup_table_entry *lte;
-
-               lte = inode_stream_lte_resolved(inode, i);
-               if (lte)
-                       lte->refcnt++;
-       }
-}
-
-/* Drop a reference to each single-instance stream referenced by this inode.
- * This is necessary when deleting a hard link to this inode.  */
-void
-inode_unref_streams(struct wim_inode *inode,
-                   struct wim_lookup_table *lookup_table)
-{
-       for (unsigned i = 0; i <= inode->i_num_ads; i++) {
-               struct wim_lookup_table_entry *lte;
-
-               lte = inode_stream_lte(inode, i, lookup_table);
-               if (lte)
-                       lte_decrement_refcnt(lte, lookup_table);
-       }
-}
-
-/* Initialize a hash table for hard link detection.  */
-int
-init_inode_table(struct wim_inode_table *table, size_t capacity)
-{
-       table->array = CALLOC(capacity, sizeof(table->array[0]));
-       if (!table->array)
-               return WIMLIB_ERR_NOMEM;
-       table->num_entries  = 0;
-       table->capacity  = capacity;
-       INIT_LIST_HEAD(&table->extra_inodes);
-       return 0;
-}
-
-/* Free the memory allocated by init_inode_table().  */
-void
-destroy_inode_table(struct wim_inode_table *table)
-{
-       FREE(table->array);
-}
-
-static struct wim_inode *
-inode_table_get_inode(struct wim_inode_table *table, u64 ino, u64 devno)
-{
-       u64 hash = hash_u64(hash_u64(ino) + hash_u64(devno));
-       size_t pos = hash % table->capacity;
-       struct wim_inode *inode;
-       struct hlist_node *cur;
-
-       /* Search for an existing inode having the same inode number and device
-        * number.  */
-       hlist_for_each_entry(inode, cur, &table->array[pos], i_hlist) {
-               if (inode->i_ino == ino && inode->i_devno == devno) {
-                       /* Found; use the existing inode.  */
-                       inode->i_nlink++;
-                       return inode;
-               }
-       }
-
-       /* Create a new inode and insert it into the table.  */
-       inode = new_timeless_inode();
-       if (inode) {
-               inode->i_ino = ino;
-               inode->i_devno = devno;
-               hlist_add_head(&inode->i_hlist, &table->array[pos]);
-               table->num_entries++;
-       }
-       return inode;
-}
-
 /*
 /*
- * Allocate a new dentry, with hard link detection.
- *
- * @table
- *     The inode table being used for the current directory scan operation.  It
- *     will contain the mapping from (ino, devno) pairs to inodes.
- *
- * @name
- *     The name to give the new dentry.
- *
- * @ino
- *     The inode number of the file, read from the filesystem.
- *
- * @devno
- *     The device number of the file, read from the filesystem.  Proper setting
- *     of this parameter prevents cross-device hardlinks from being created.
- *     If this is not a problem (perhaps because the current directory scan
- *     operation is guaranteed to never traverse a filesystem boundary), then
- *     this parameter can just be a fixed value such as 0.
- *
- * @noshare
- *     If %true, the new dentry will not be hard linked to any existing inode,
- *     regardless of the values of @ino and @devno.  If %false, normal hard
- *     link detection will be done.
- *
- * @dentry_ret
- *     On success, a pointer to the new dentry will be returned in this
- *     location.  If i_nlink of the dentry's inode is greater than 1, then this
- *     function created a hard link to an existing inode rather than creating a
- *     new inode.
+ * Translate a single-instance stream entry into the pointer contained in the
+ * inode (or ads entry of an inode) that references it.
  *
  *
- * On success, returns 0.  On failure, returns WIMLIB_ERR_NOMEM or an error code
- * resulting from a failed string conversion.
- */
-int
-inode_table_new_dentry(struct wim_inode_table *table, const tchar *name,
-                      u64 ino, u64 devno, bool noshare,
-                      struct wim_dentry **dentry_ret)
-{
-       struct wim_dentry *dentry;
-       struct wim_inode *inode;
-       int ret;
-
-       if (noshare) {
-               /* File that cannot be hardlinked--- Return a new inode with its
-                * inode and device numbers left at 0. */
-               ret = new_dentry_with_timeless_inode(name, &dentry);
-               if (ret)
-                       return ret;
-               list_add_tail(&dentry->d_inode->i_list, &table->extra_inodes);
-       } else {
-               /* File that can be hardlinked--- search the table for an
-                * existing inode matching the inode number and device;
-                * otherwise create a new inode. */
-               ret = new_dentry(name, &dentry);
-               if (ret)
-                       return ret;
-               inode = inode_table_get_inode(table, ino, devno);
-               if (!inode) {
-                       free_dentry(dentry);
-                       return WIMLIB_ERR_NOMEM;
-               }
-               /* If using an existing inode, we need to gain a reference to
-                * each of its streams. */
-               if (inode->i_nlink > 1)
-                       inode_ref_streams(inode);
-               dentry->d_inode = inode;
-               inode_add_dentry(dentry, inode);
-       }
-       *dentry_ret = dentry;
-       return 0;
-}
-
-
-
-/*
- * Following the allocation of dentries with hard link detection using
- * inode_table_new_dentry(), this function will assign consecutive inode numbers
- * to the new set of inodes.  It will also append the list of new inodes to the
- * list @head, which must contain any inodes already existing in the WIM image.
+ * This is only possible for "unhashed" streams, which are guaranteed to have
+ * only one reference, and that reference is guaranteed to be in a resolved
+ * inode.  (It can't be in an unresolved inode, since that would imply the hash
+ * is known!)
  */
  */
-void
-inode_table_prepare_inode_list(struct wim_inode_table *table,
-                              struct list_head *head)
+struct wim_lookup_table_entry **
+retrieve_lte_pointer(struct wim_lookup_table_entry *lte)
 {
 {
-       struct wim_inode *inode, *tmp_inode;
-       struct hlist_node *cur, *tmp;
-       u64 cur_ino = 1;
-
-       /* Re-assign inode numbers in the existing list to avoid duplicates. */
-       list_for_each_entry(inode, head, i_list)
-               inode->i_ino = cur_ino++;
-
-       /* Assign inode numbers to the new inodes and move them to the image's
-        * inode list. */
-       for (size_t i = 0; i < table->capacity; i++) {
-               hlist_for_each_entry_safe(inode, cur, tmp, &table->array[i], i_hlist)
-               {
-                       inode->i_ino = cur_ino++;
-                       inode->i_devno = 0;
-                       list_add_tail(&inode->i_list, head);
-               }
-               INIT_HLIST_HEAD(&table->array[i]);
-       }
-       list_for_each_entry_safe(inode, tmp_inode, &table->extra_inodes, i_list)
-       {
-               inode->i_ino = cur_ino++;
-               inode->i_devno = 0;
-               list_add_tail(&inode->i_list, head);
-       }
-       INIT_LIST_HEAD(&table->extra_inodes);
-       table->num_entries = 0;
+       wimlib_assert(lte->unhashed);
+       struct wim_inode *inode = lte->back_inode;
+       u32 stream_id = lte->back_stream_id;
+       if (stream_id == 0)
+               return &inode->i_lte;
+       for (unsigned i = 0; i < inode->i_num_ads; i++)
+               if (inode->i_ads_entries[i].stream_id == stream_id)
+                       return &inode->i_ads_entries[i].lte;
+       wimlib_assert(0);
+       return NULL;
 }
 }
diff --git a/src/inode_table.c b/src/inode_table.c
new file mode 100644 (file)
index 0000000..6e1c143
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * inode_table.c - hard link detection
+ */
+
+/*
+ * Copyright (C) 2012, 2013, 2014 Eric Biggers
+ *
+ * This file is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option) any
+ * later version.
+ *
+ * This file is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this file; if not, see http://www.gnu.org/licenses/.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include "config.h"
+#endif
+
+#include "wimlib/dentry.h"
+#include "wimlib/error.h"
+#include "wimlib/inode.h"
+#include "wimlib/inode_table.h"
+#include "wimlib/list.h"
+#include "wimlib/util.h"
+
+/* Initialize a hash table for hard link detection.  */
+int
+init_inode_table(struct wim_inode_table *table, size_t capacity)
+{
+       table->array = CALLOC(capacity, sizeof(table->array[0]));
+       if (!table->array)
+               return WIMLIB_ERR_NOMEM;
+       table->num_entries = 0;
+       table->capacity = capacity;
+       INIT_LIST_HEAD(&table->extra_inodes);
+       return 0;
+}
+
+/* Free the memory allocated by init_inode_table().  */
+void
+destroy_inode_table(struct wim_inode_table *table)
+{
+       FREE(table->array);
+}
+
+static struct wim_inode *
+inode_table_get_inode(struct wim_inode_table *table, u64 ino, u64 devno)
+{
+       size_t pos;
+       struct wim_inode *inode;
+       struct hlist_node *cur;
+
+       /* Search for an existing inode having the same inode number and device
+        * number.  */
+       pos = hash_u64(hash_u64(ino) + hash_u64(devno)) % table->capacity;
+       hlist_for_each_entry(inode, cur, &table->array[pos], i_hlist) {
+               if (inode->i_ino == ino && inode->i_devno == devno) {
+                       /* Found; use the existing inode.  */
+                       inode->i_nlink++;
+                       return inode;
+               }
+       }
+
+       /* Create a new inode and insert it into the table.  */
+       inode = new_timeless_inode();
+       if (inode) {
+               inode->i_ino = ino;
+               inode->i_devno = devno;
+               hlist_add_head(&inode->i_hlist, &table->array[pos]);
+               table->num_entries++;
+       }
+       return inode;
+}
+
+/*
+ * Allocate a new dentry, with hard link detection.
+ *
+ * @table
+ *     The inode table being used for the current directory scan operation.  It
+ *     will contain the mapping from (ino, devno) pairs to inodes.
+ *
+ * @name
+ *     The name to give the new dentry.
+ *
+ * @ino
+ *     The inode number of the file, read from the filesystem.
+ *
+ * @devno
+ *     The device number of the file, read from the filesystem.  Proper setting
+ *     of this parameter prevents cross-device hardlinks from being created.
+ *     If this is not a problem (perhaps because the current directory scan
+ *     operation is guaranteed to never traverse a filesystem boundary), then
+ *     this parameter can just be a fixed value such as 0.
+ *
+ * @noshare
+ *     If %true, the new dentry will not be hard linked to any existing inode,
+ *     regardless of the values of @ino and @devno.  If %false, normal hard
+ *     link detection will be done.
+ *
+ * @dentry_ret
+ *     On success, a pointer to the new dentry will be returned in this
+ *     location.  If i_nlink of the dentry's inode is greater than 1, then this
+ *     function created a hard link to an existing inode rather than creating a
+ *     new inode.
+ *
+ * On success, returns 0.  On failure, returns WIMLIB_ERR_NOMEM or an error code
+ * resulting from a failed string conversion.
+ */
+int
+inode_table_new_dentry(struct wim_inode_table *table, const tchar *name,
+                      u64 ino, u64 devno, bool noshare,
+                      struct wim_dentry **dentry_ret)
+{
+       struct wim_dentry *dentry;
+       struct wim_inode *inode;
+       int ret;
+
+       if (noshare) {
+               /* File that cannot be hardlinked--- Return a new inode with its
+                * inode and device numbers left at 0. */
+               ret = new_dentry_with_timeless_inode(name, &dentry);
+               if (ret)
+                       return ret;
+               list_add_tail(&dentry->d_inode->i_list, &table->extra_inodes);
+       } else {
+               /* File that can be hardlinked--- search the table for an
+                * existing inode matching the inode number and device;
+                * otherwise create a new inode. */
+               ret = new_dentry(name, &dentry);
+               if (ret)
+                       return ret;
+               inode = inode_table_get_inode(table, ino, devno);
+               if (!inode) {
+                       free_dentry(dentry);
+                       return WIMLIB_ERR_NOMEM;
+               }
+               /* If using an existing inode, we need to gain a reference to
+                * each of its streams. */
+               if (inode->i_nlink > 1)
+                       inode_ref_streams(inode);
+               dentry->d_inode = inode;
+               inode_add_dentry(dentry, inode);
+       }
+       *dentry_ret = dentry;
+       return 0;
+}
+
+/*
+ * Following the allocation of dentries with hard link detection using
+ * inode_table_new_dentry(), this function will assign consecutive inode numbers
+ * to the new set of inodes.  It will also append the list of new inodes to the
+ * list @head, which must contain any inodes already existing in the WIM image.
+ */
+void
+inode_table_prepare_inode_list(struct wim_inode_table *table,
+                              struct list_head *head)
+{
+       struct wim_inode *inode, *tmp_inode;
+       struct hlist_node *cur, *tmp;
+       u64 cur_ino = 1;
+
+       /* Re-assign inode numbers in the existing list to avoid duplicates. */
+       list_for_each_entry(inode, head, i_list)
+               inode->i_ino = cur_ino++;
+
+       /* Assign inode numbers to the new inodes and move them to the image's
+        * inode list. */
+       for (size_t i = 0; i < table->capacity; i++) {
+               hlist_for_each_entry_safe(inode, cur, tmp, &table->array[i], i_hlist)
+               {
+                       inode->i_ino = cur_ino++;
+                       inode->i_devno = 0;
+                       list_add_tail(&inode->i_list, head);
+               }
+               INIT_HLIST_HEAD(&table->array[i]);
+       }
+       list_for_each_entry_safe(inode, tmp_inode, &table->extra_inodes, i_list)
+       {
+               inode->i_ino = cur_ino++;
+               inode->i_devno = 0;
+               list_add_tail(&inode->i_list, head);
+       }
+       INIT_LIST_HEAD(&table->extra_inodes);
+       table->num_entries = 0;
+}
index fb2c1b36507205631d657e0edfcc57af97072898..8e7f6cc3878d6c59c8229b20ee65c2dda795cc13 100644 (file)
@@ -99,7 +99,7 @@ init_wimlib_dentry(struct wimlib_dir_entry *wdentry, struct wim_dentry *dentry,
        }
 
        for (unsigned i = 0; i < inode->i_num_ads; i++) {
        }
 
        for (unsigned i = 0; i < inode->i_num_ads; i++) {
-               if (!ads_entry_is_named_stream(&inode->i_ads_entries[i]))
+               if (!inode->i_ads_entries[i].stream_name_nbytes)
                        continue;
                lte = inode_stream_lte(inode, i + 1, wim->lookup_table);
                wdentry->num_named_streams++;
                        continue;
                lte = inode_stream_lte(inode, i + 1, wim->lookup_table);
                wdentry->num_named_streams++;
index 54730598119568bf8a680ace268be946d701197f..54ea91532e6bcc5336f1ccac404d63f5435ca2bc 100644 (file)
@@ -23,6 +23,7 @@
 #  include "config.h"
 #endif
 
 #  include "config.h"
 #endif
 
+#include "wimlib/assert.h"
 #include "wimlib/dentry.h"
 #include "wimlib/error.h"
 #include "wimlib/lookup_table.h"
 #include "wimlib/dentry.h"
 #include "wimlib/error.h"
 #include "wimlib/lookup_table.h"
index 94feb4eeb473fa36cdbb85eff811919c2d3a0742..0bd4a1f1d76d3463aa642ce2581f8b780f38e1c2 100644 (file)
@@ -39,6 +39,7 @@
 
 #include "wimlib/dentry.h"
 #include "wimlib/encoding.h"
 
 #include "wimlib/dentry.h"
 #include "wimlib/encoding.h"
+#include "wimlib/lookup_table.h"
 #include "wimlib/metadata.h"
 #include "wimlib/paths.h"
 #include "wimlib/progress.h"
 #include "wimlib/metadata.h"
 #include "wimlib/paths.h"
 #include "wimlib/progress.h"
@@ -371,12 +372,12 @@ wim_pathname_to_stream(const struct wimfs_context *ctx, const char *path,
                       int lookup_flags,
                       struct wim_dentry **dentry_ret,
                       struct wim_lookup_table_entry **lte_ret,
                       int lookup_flags,
                       struct wim_dentry **dentry_ret,
                       struct wim_lookup_table_entry **lte_ret,
-                      u16 *stream_idx_ret)
+                      unsigned *stream_idx_ret)
 {
        WIMStruct *wim = ctx->wim;
        struct wim_dentry *dentry;
        struct wim_lookup_table_entry *lte;
 {
        WIMStruct *wim = ctx->wim;
        struct wim_dentry *dentry;
        struct wim_lookup_table_entry *lte;
-       u16 stream_idx;
+       unsigned stream_idx;
        const char *stream_name = NULL;
        struct wim_inode *inode;
        char *p = NULL;
        const char *stream_name = NULL;
        struct wim_inode *inode;
        char *p = NULL;
@@ -679,7 +680,7 @@ retry:
  */
 static int
 extract_resource_to_staging_dir(struct wim_inode *inode,
  */
 static int
 extract_resource_to_staging_dir(struct wim_inode *inode,
-                               u16 stream_idx,
+                               unsigned stream_idx,
                                struct wim_lookup_table_entry **lte_ptr,
                                off_t size,
                                const struct wimfs_context *ctx)
                                struct wim_lookup_table_entry **lte_ptr,
                                off_t size,
                                const struct wimfs_context *ctx)
@@ -1584,7 +1585,7 @@ wimfs_open(const char *path, struct fuse_file_info *fi)
        struct wim_dentry *dentry;
        struct wim_inode *inode;
        struct wim_lookup_table_entry *lte;
        struct wim_dentry *dentry;
        struct wim_inode *inode;
        struct wim_lookup_table_entry *lte;
-       u16 stream_idx;
+       unsigned stream_idx;
        struct wimfs_fd *fd;
        int ret;
 
        struct wimfs_fd *fd;
        int ret;
 
@@ -1912,7 +1913,7 @@ wimfs_truncate(const char *path, off_t size)
        const struct wimfs_context *ctx = wimfs_get_context();
        struct wim_dentry *dentry;
        struct wim_lookup_table_entry *lte;
        const struct wimfs_context *ctx = wimfs_get_context();
        struct wim_dentry *dentry;
        struct wim_lookup_table_entry *lte;
-       u16 stream_idx;
+       unsigned stream_idx;
        int ret;
        int fd;
 
        int ret;
        int fd;
 
@@ -1946,7 +1947,7 @@ wimfs_unlink(const char *path)
 {
        const struct wimfs_context *ctx = wimfs_get_context();
        struct wim_dentry *dentry;
 {
        const struct wimfs_context *ctx = wimfs_get_context();
        struct wim_dentry *dentry;
-       u16 stream_idx;
+       unsigned stream_idx;
        int ret;
 
        ret = wim_pathname_to_stream(ctx, path, 0, &dentry, NULL, &stream_idx);
        int ret;
 
        ret = wim_pathname_to_stream(ctx, path, 0, &dentry, NULL, &stream_idx);
index f589fb526490e5e6b4953ef97827495972ec05c1..ef4346f6f96f05c2062ce7fd84c89c34e399b0f7 100644 (file)
@@ -42,6 +42,7 @@
 #include "wimlib/dentry.h"
 #include "wimlib/encoding.h"
 #include "wimlib/error.h"
 #include "wimlib/dentry.h"
 #include "wimlib/encoding.h"
 #include "wimlib/error.h"
+#include "wimlib/lookup_table.h"
 #include "wimlib/metadata.h"
 #include "wimlib/ntfs_3g.h"
 #include "wimlib/reparse.h"
 #include "wimlib/metadata.h"
 #include "wimlib/ntfs_3g.h"
 #include "wimlib/reparse.h"
index 78199efa96fadc36d3a5058afbd7bdb91ffef292..cd0758ac42302950a3159c563d3e6e4481f863ee 100644 (file)
@@ -40,6 +40,7 @@
 #include <ntfs-3g/security.h>
 #include <ntfs-3g/volume.h>
 
 #include <ntfs-3g/security.h>
 #include <ntfs-3g/volume.h>
 
+#include "wimlib/assert.h"
 #include "wimlib/capture.h"
 #include "wimlib/dentry.h"
 #include "wimlib/encoding.h"
 #include "wimlib/capture.h"
 #include "wimlib/dentry.h"
 #include "wimlib/encoding.h"
index 438ff25c3c83f9b8256704b13b521723f85b1718..1c0e205f521ee33e371f6b4633e342c2f5b8c855 100644 (file)
@@ -26,6 +26,7 @@
 #endif
 
 #include "wimlib.h"
 #endif
 
 #include "wimlib.h"
+#include "wimlib/assert.h"
 #include "wimlib/dentry.h"
 #include "wimlib/error.h"
 #include "wimlib/lookup_table.h"
 #include "wimlib/dentry.h"
 #include "wimlib/error.h"
 #include "wimlib/lookup_table.h"
index 8c6efbe3386e2afddb162b67e796b4f341ed4df1..01c3959289e6045fc68d47e6b42159b358cc2fd7 100644 (file)
@@ -23,7 +23,6 @@
 #  include "config.h"
 #endif
 
 #  include "config.h"
 #endif
 
-#include "wimlib/assert.h"
 #include "wimlib/encoding.h"
 #include "wimlib/error.h"
 #include "wimlib/file_io.h"
 #include "wimlib/encoding.h"
 #include "wimlib/error.h"
 #include "wimlib/file_io.h"
index d0870299f3d281d29d29a175b885df35f74cd9fc..27f26576a4c36abba3616fabb4581da9cff1200c 100644 (file)
@@ -28,6 +28,7 @@
 #include "wimlib/dentry.h"
 #include "wimlib/error.h"
 #include "wimlib/file_io.h"
 #include "wimlib/dentry.h"
 #include "wimlib/error.h"
 #include "wimlib/file_io.h"
+#include "wimlib/lookup_table.h"
 #include "wimlib/reparse.h"
 #include "wimlib/timestamp.h"
 #include "wimlib/unix_data.h"
 #include "wimlib/reparse.h"
 #include "wimlib/timestamp.h"
 #include "wimlib/unix_data.h"
index facdfff202ed4f702cad097a10155690ad2d404e..65389e156cc227464c82d6df0cc0b7ad3e08cab7 100644 (file)
@@ -49,6 +49,7 @@
 #  include "config.h"
 #endif
 
 #  include "config.h"
 #endif
 
+#include "wimlib/assert.h"
 #include "wimlib/capture.h"
 #include "wimlib/dentry.h"
 #include "wimlib/encoding.h"
 #include "wimlib/capture.h"
 #include "wimlib/dentry.h"
 #include "wimlib/encoding.h"
index 880fa7ec216767cd204818d69935b4dbec43cf66..1c0e6efdf96ae5576b53de16161973010535ffef 100644 (file)
--- a/src/wim.c
+++ b/src/wim.c
@@ -24,6 +24,7 @@
 #endif
 
 #include "wimlib.h"
 #endif
 
 #include "wimlib.h"
+#include "wimlib/assert.h"
 #include "wimlib/bitops.h"
 #include "wimlib/dentry.h"
 #include "wimlib/encoding.h"
 #include "wimlib/bitops.h"
 #include "wimlib/dentry.h"
 #include "wimlib/encoding.h"
index 7580a71875e156c5a1dd2dab7f4ef6b35292e647..54c247ce83d8ddd4c0460fde8f9c7fe7dcc0c998 100644 (file)
@@ -28,6 +28,7 @@
 #include "wimlib/win32_common.h"
 
 #include "wimlib/apply.h"
 #include "wimlib/win32_common.h"
 
 #include "wimlib/apply.h"
+#include "wimlib/assert.h"
 #include "wimlib/capture.h" /* for mangle_pat() and match_pattern_list()  */
 #include "wimlib/dentry.h"
 #include "wimlib/error.h"
 #include "wimlib/capture.h" /* for mangle_pat() and match_pattern_list()  */
 #include "wimlib/dentry.h"
 #include "wimlib/error.h"
index 4adf3364cb8f5ae778f9bca4f4e787fe1fc07162..ab572cb27351b0e7238dab0e642bccec29cfa622 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "wimlib/win32_common.h"
 
 
 #include "wimlib/win32_common.h"
 
+#include "wimlib/assert.h"
 #include "wimlib/capture.h"
 #include "wimlib/dentry.h"
 #include "wimlib/encoding.h"
 #include "wimlib/capture.h"
 #include "wimlib/dentry.h"
 #include "wimlib/encoding.h"
index 1de3e7a98c671a06c3acabeb9362f12a889b6c34..fcc5983fca50ee2c300342a2e5a360285c8ef43d 100644 (file)
@@ -32,6 +32,7 @@
 #  include <sys/file.h>
 #endif
 
 #  include <sys/file.h>
 #endif
 
+#include "wimlib/assert.h"
 #include "wimlib/chunk_compressor.h"
 #include "wimlib/endianness.h"
 #include "wimlib/error.h"
 #include "wimlib/chunk_compressor.h"
 #include "wimlib/endianness.h"
 #include "wimlib/error.h"
index 1dd4d8398a7efa573b3b43c0060126411d283568..be5a3f80a7a1dd851bfad3508f942768f665279f 100644 (file)
--- a/src/xml.c
+++ b/src/xml.c
@@ -25,6 +25,7 @@
 #  include "config.h"
 #endif
 
 #  include "config.h"
 #endif
 
+#include "wimlib/assert.h"
 #include "wimlib/dentry.h"
 #include "wimlib/encoding.h"
 #include "wimlib/error.h"
 #include "wimlib/dentry.h"
 #include "wimlib/encoding.h"
 #include "wimlib/error.h"