]> wimlib.net Git - wimlib/blobdiff - include/wimlib/inode.h
Rename i_dentry => i_alias_list and d_alias => d_alias_node
[wimlib] / include / wimlib / inode.h
index 3b0222990bf77a8476766b1fda097990e5a4740d..01254c82d1ccd9a7f9453ba7c345727e934ddc34 100644 (file)
 
 #include "wimlib/assert.h"
 #include "wimlib/list.h"
-#include "wimlib/lookup_table.h"
 #include "wimlib/sha1.h"
+#include "wimlib/types.h"
 
-#include <string.h>
-
-struct wim_ads_entry;
+struct avl_tree_node;
+struct blob_descriptor;
+struct blob_table;
 struct wim_dentry;
 struct wim_security_data;
-struct wim_lookup_table;
 struct wimfs_fd;
-struct avl_tree_node;
+
+/* Valid values for the 'stream_type' field of a 'struct wim_inode_stream'  */
+enum wim_inode_stream_type {
+
+       /* Data stream, may be unnamed (usual case) or named  */
+       STREAM_TYPE_DATA,
+
+       /* Reparse point stream.  This is the same as the data of the on-disk
+        * reparse point attribute, except that the first 8 bytes of the on-disk
+        * attribute are omitted.  The omitted bytes contain the reparse tag
+        * (which is instead stored in the on-disk WIM dentry), the reparse data
+        * size (which is redundant with the stream size), and a reserved field
+        * that is always zero.  */
+       STREAM_TYPE_REPARSE_POINT,
+
+       /* Encrypted data in the "EFSRPC raw data format" specified by [MS-EFSR]
+        * section 2.2.3.  This contains metadata for the Encrypting File System
+        * as well as the encrypted data of all the file's data streams.  */
+       STREAM_TYPE_EFSRPC_RAW_DATA,
+
+       /* Stream type could not be determined  */
+       STREAM_TYPE_UNKNOWN,
+};
+
+extern const utf16lechar NO_STREAM_NAME[1];
 
 /*
- * WIM inode.
+ * 'struct wim_inode_stream' describes a "stream", which associates a blob of
+ * data with an inode.  Each stream has a type and optionally a name.
+ *
+ * The most frequently seen kind of stream is the "unnamed data stream"
+ * (stream_type == STREAM_TYPE_DATA && stream_name == NO_STREAM_NAME), which is
+ * the "default file contents".  Many inodes just have an unnamed data stream
+ * and no other streams.  However, files on NTFS filesystems may have
+ * additional, "named" data streams, and this is supported by the WIM format.
  *
- * As mentioned in the comment above `struct wim_dentry', in WIM files there
- * is no on-disk analogue of a real inode, as most of these fields are
- * duplicated in the dentries.  Instead, a `struct wim_inode' is something we
- * create ourselves to simplify the handling of hard links.
+ * A "reparse point" is an inode with reparse data set.  The reparse data is
+ * stored in a stream of type STREAM_TYPE_REPARSE_POINT.  There should be only
+ * one such stream, and it should be unnamed.  However, it is possible for an
+ * inode to have both a reparse point stream and an unnamed data stream, and
+ * even named data streams as well.
  */
-struct wim_inode {
-       /* If i_resolved == 0:
-        *      SHA1 message digest of the contents of the unnamed-data stream
-        *      of this inode.
-        *
-        * If i_resolved == 1:
-        *      Pointer to the lookup table entry for the unnamed data stream
-        *      of this inode, or NULL.
+struct wim_inode_stream {
+
+       /* The name of the stream or NO_STREAM_NAME.  */
+       utf16lechar *stream_name;
+
+       /*
+        * If 'stream_resolved' = 0, then 'stream_hash' is the SHA-1 message
+        * digest of the uncompressed data of this stream, or all zeroes if this
+        * stream is empty.
         *
-        * i_hash corresponds to the 'unnamed_stream_hash' field of the `struct
-        * wim_dentry_on_disk' and the additional caveats documented about that
-        * field apply here (for example, the quirks regarding all-zero hashes).
+        * If 'stream_resolved' = 1, then 'stream_blob' is a pointer directly to
+        * a descriptor for this stream's blob, or NULL if this stream is empty.
         */
        union {
-               u8 i_hash[SHA1_HASH_SIZE];
-               struct wim_lookup_table_entry *i_lte;
-       };
+               u8 _stream_hash[SHA1_HASH_SIZE];
+               struct blob_descriptor *_stream_blob;
+       } _packed_attribute; /* union is SHA1_HASH_SIZE bytes */
+
+       /* 'stream_resolved' determines whether 'stream_hash' or 'stream_blob'
+        * is valid as described above.  */
+       u32 stream_resolved : 1;
+
+       /* A unique identifier for this stream within the context of its inode.
+        * This stays constant even if the streams array is reallocated.  */
+       u32 stream_id : 28;
+
+       /* The type of this stream as one of the STREAM_TYPE_* values  */
+       u32 stream_type : 3;
+};
+
+/*
+ * WIM inode - a "file" in an image which may be accessible via multiple paths
+ *
+ * Note: in WIM files there is no true on-disk analogue of an inode; there are
+ * only directory entries, and some fields are duplicated among all links to a
+ * file.  However, wimlib uses inode structures internally to simplify handling
+ * of hard links.
+ */
+struct wim_inode {
+
+       /*
+        * The collection of streams for this inode.  'i_streams' points to
+        * either 'i_embedded_streams' or an allocated array.
+        */
+       struct wim_inode_stream *i_streams;
+       struct wim_inode_stream i_embedded_streams[1];
+       unsigned i_num_streams;
 
-       /* Corresponds to the 'attributes' field of `struct wim_dentry_on_disk';
-        * bitwise OR of the FILE_ATTRIBUTE_* flags that give the attributes of
-        * this inode. */
+       /* Windows file attribute flags (FILE_ATTRIBUTE_*).  */
        u32 i_attributes;
 
        /* Root of a balanced binary search tree storing the child directory
@@ -60,51 +119,24 @@ struct wim_inode {
 
        /* List of dentries that are aliases for this inode.  There will be
         * i_nlink dentries in this list.  */
-       struct list_head i_dentry;
+       struct hlist_head i_alias_list;
 
-       /* Field to place this inode into a list. */
-       union {
-               /* Hash list node- used in inode_fixup.c when the inodes are
-                * placed into a hash table keyed by inode number and optionally
-                * device number, in order to detect dentries that are aliases
-                * 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. */
-               struct list_head i_list;
-       };
+       /* Field to place this inode into a list.  While reading a WIM image or
+        * adding files to a WIM image this is owned by the inode table;
+        * otherwise this links the inodes for the WIM image.  */
+       struct hlist_node i_hlist;
 
        /* Number of dentries that are aliases for this inode.  */
-       u32 i_nlink;
-
-       /* Number of alternate data streams (ADS) associated with this inode */
-       u16 i_num_ads;
-
-       /* Flag that indicates whether this inode's streams have been
-        * "resolved".  By default, the inode starts as "unresolved", meaning
-        * that the i_hash field, along with the hash field of any associated
-        * wim_ads_entry's, are valid and should be used as keys in the WIM
-        * lookup table to find the associated `struct wim_lookup_table_entry'.
-        * But if the inode has been resolved, then each of these fields is
-        * replaced with a pointer directly to the appropriate `struct
-        * wim_lookup_table_entry', or NULL if the stream is empty.  */
-       u8 i_resolved : 1;
+       u32 i_nlink : 30;
 
        /* Flag used to mark this inode as visited; this is used when visiting
         * all the inodes in a dentry tree exactly once.  It will be 0 by
         * default and must be cleared following the tree traversal, even in
         * error paths.  */
-       u8 i_visited : 1;
+       u32 i_visited : 1;
 
-       /* 1 iff all ADS entries of this inode are named or if this inode
-        * has no ADS entries  */
-       u8 i_canonical_streams : 1;
-
-       /* Pointer to a malloc()ed array of i_num_ads alternate data stream
-        * entries for this inode.  */
-       struct wim_ads_entry *i_ads_entries;
+       /* Cached value  */
+       u32 i_can_externally_back : 1;
 
        /* If not NULL, a pointer to the extra data that was read from the
         * dentry.  This should be a series of tagged items, each of which
@@ -115,36 +147,30 @@ struct wim_inode {
        /* 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;
 
        /* Corresponds to 'security_id' in `struct wim_dentry_on_disk':  The
         * index of this inode's security descriptor in the WIM image's table of
-        * security descriptors, or -1.  Note: in verify_inode(), called
-        * whenever a WIM image is loaded, out-of-bounds indices are set to -1,
-        * so the extraction code does not need to do bounds checks.  */
-       int32_t i_security_id;
-
-       /* Identity of a reparse point.  See
-        * http://msdn.microsoft.com/en-us/library/windows/desktop/aa365503(v=vs.85).aspx
-        * for what a reparse point is. */
-       u32 i_reparse_tag;
+        * security descriptors, or -1 if this inode does not have a security
+        * descriptor.  */
+       s32 i_security_id;
 
-       /* Unused/unknown fields that we just read into memory so we can
-        * re-write them unchanged.  */
-       u32 i_rp_unknown_1;
-       u16 i_rp_unknown_2;
+       /* Unknown field that we only read into memory so we can re-write it
+        * unchanged.  Probably it's actually just padding...  */
+       u32 i_unknown_0x54;
 
-       /* Corresponds to not_rpfixed in `struct wim_dentry_on_disk':  Set to 0
-        * if reparse point fixups have been done.  Otherwise set to 1.  Note:
-        * this actually may reflect the SYMBOLIC_LINK_RELATIVE flag.
-        */
-       u16 i_not_rpfixed;
+       /* The following fields correspond to 'reparse_tag', 'rp_reserved', and
+        * 'rp_flags' in `struct wim_dentry_on_disk'.  They are only meaningful
+        * for reparse point files.  */
+       u32 i_reparse_tag;
+       u16 i_rp_reserved;
+       u16 i_rp_flags;
 
        /* Inode number; corresponds to hard_link_group_id in the `struct
         * wim_dentry_on_disk'.  */
@@ -154,19 +180,19 @@ struct wim_inode {
                /* Device number, used only during image capture, so we can
                 * identify hard linked files by the combination of inode number
                 * and device number (rather than just inode number, which could
-                * be ambigious if the captured tree spans a mountpoint).  Set
+                * be ambiguous if the captured tree spans a mountpoint).  Set
                 * to 0 otherwise.  */
                u64 i_devno;
 
                /* Fields used only during extraction  */
                struct {
-                       /* List of aliases of this dentry that are being
-                        * extracted in the current extraction operation.  This
-                        * will be a (possibly nonproper) subset of the dentries
-                        * in the i_dentry list.  This list will be constructed
+                       /* A singly linked list of aliases of this inode that
+                        * are being extracted in the current extraction
+                        * operation.  This list may be shorter than the inode's
+                        * full alias list.  This list will be constructed
                         * regardless of whether the extraction backend supports
                         * hard links or not.  */
-                       struct list_head i_extraction_aliases;
+                       struct wim_dentry *i_first_extraction_alias;
 
                #ifdef WITH_NTFS_3G
                        /* In NTFS-3g extraction mode, this is set to the Master
@@ -178,9 +204,9 @@ struct wim_inode {
 
                /* Used during WIM writing with
                 * WIMLIB_WRITE_FLAG_SEND_DONE_WITH_FILE_MESSAGES:  the number
-                * of data streams this inode has that have not yet been fully
-                * read.  */
-               u32 num_unread_streams;
+                * of streams this inode has that have not yet been fully read.
+                * */
+               u32 i_num_remaining_streams;
 
 #ifdef WITH_FUSE
                struct {
@@ -202,86 +228,25 @@ struct wim_inode {
        u16 i_num_allocated_fds;
 #endif
 
-       /* Next alternate data stream ID to be assigned */
+       /* Next stream ID to be assigned  */
        u32 i_next_stream_id;
 };
 
-/* Alternate data stream entry.
- *
- * We read this from disk in the read_ads_entries() function; see that function
- * for more explanation. */
-struct wim_ads_entry {
-       union {
-               /* SHA-1 message digest of stream contents */
-               u8 hash[SHA1_HASH_SIZE];
-
-               /* The corresponding lookup table entry (only for resolved
-                * streams) */
-               struct wim_lookup_table_entry *lte;
-       };
-
-       /* Length of UTF16-encoded stream name, in bytes, not including the
-        * terminating null character; or 0 if the stream is unnamed. */
-       u16 stream_name_nbytes;
-
-       /* Number to identify an alternate data stream even after it's possibly
-        * been moved or renamed. */
-       u32 stream_id;
-
-       /* Stream name (UTF-16LE), null-terminated, or NULL if the stream is
-        * unnamed.  */
-       utf16lechar *stream_name;
-
-       /* Reserved field.  We read it into memory so we can write it out
-        * unchanged. */
-       u64 reserved;
-};
-
-/* 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;
-
-       le64  reserved;
-
-       /* SHA1 message digest of the uncompressed stream; or, alternatively,
-        * 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,
-        * 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;
-
-#define WIM_ADS_ENTRY_DISK_SIZE 38
-
 /*
- * Reparse tags documented at
- * http://msdn.microsoft.com/en-us/library/dd541667(v=prot.10).aspx
+ * The available reparse tags are documented at
+ * http://msdn.microsoft.com/en-us/library/dd541667(v=prot.10).aspx.
+ * Here we only define the ones of interest to us.
  */
-#define WIM_IO_REPARSE_TAG_RESERVED_ZERO       0x00000000
-#define WIM_IO_REPARSE_TAG_RESERVED_ONE                0x00000001
 #define WIM_IO_REPARSE_TAG_MOUNT_POINT         0xA0000003
-#define WIM_IO_REPARSE_TAG_HSM                 0xC0000004
-#define WIM_IO_REPARSE_TAG_HSM2                        0x80000006
-#define WIM_IO_REPARSE_TAG_DRIVER_EXTENDER     0x80000005
-#define WIM_IO_REPARSE_TAG_SIS                 0x80000007
-#define WIM_IO_REPARSE_TAG_DFS                 0x8000000A
-#define WIM_IO_REPARSE_TAG_DFSR                        0x80000012
-#define WIM_IO_REPARSE_TAG_FILTER_MANAGER      0x8000000B
 #define WIM_IO_REPARSE_TAG_SYMLINK             0xA000000C
+#define WIM_IO_REPARSE_TAG_WOF                 0x80000017
+
+/* Flags for the rp_flags field.  Currently the only known flag is NOT_FIXED,
+ * which indicates that the target of the absolute symbolic link or junction was
+ * not changed when it was stored.  */
+#define WIM_RP_FLAG_NOT_FIXED             0x0001
 
+/* Windows file attribute flags  */
 #define FILE_ATTRIBUTE_READONLY            0x00000001
 #define FILE_ATTRIBUTE_HIDDEN              0x00000002
 #define FILE_ATTRIBUTE_SYSTEM              0x00000004
@@ -299,67 +264,31 @@ struct wim_ads_entry_on_disk {
 #define FILE_ATTRIBUTE_VIRTUAL             0x00010000
 
 extern struct wim_inode *
-new_inode(void) _malloc_attribute;
+new_inode(struct wim_dentry *dentry, bool set_timestamps);
 
-extern struct wim_inode *
-new_timeless_inode(void) _malloc_attribute;
-
-extern void
-put_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) \
-               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.  */
-#define inode_add_dentry(dentry, inode) \
-               list_add_tail(&(dentry)->d_alias, &(inode)->i_dentry)
+       hlist_for_each_entry((dentry), &(inode)->i_alias_list, d_alias_node)
 
-/* Return an alias of an inode.  */
+/* Return an alias of the specified inode.  */
 #define inode_first_dentry(inode) \
-               container_of(inode->i_dentry.next, struct wim_dentry, d_alias)
+       hlist_entry(inode->i_alias_list.first, struct wim_dentry, d_alias_node)
 
-/* 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) \
-               dentry_full_path(inode_first_dentry(inode))
-
-extern struct wim_ads_entry *
-inode_get_ads_entry(struct wim_inode *inode, const tchar *stream_name);
+       dentry_full_path(inode_first_dentry(inode))
 
-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
+d_associate(struct wim_dentry *dentry, struct wim_inode *inode);
 
 extern void
-inode_remove_ads(struct wim_inode *inode, struct wim_ads_entry *entry,
-                struct wim_lookup_table *lookup_table);
+d_disassociate(struct wim_dentry *dentry);
 
-static inline bool
-ads_entry_is_named_stream(const struct wim_ads_entry *entry)
-{
-       return entry->stream_name_nbytes != 0;
-}
+#ifdef WITH_FUSE
+extern void
+inode_dec_num_opened_fds(struct wim_inode *inode);
+#endif
 
 /* Is the inode a directory?
  * This doesn't count directories with reparse data.
@@ -373,17 +302,6 @@ inode_is_directory(const struct wim_inode *inode)
                        == FILE_ATTRIBUTE_DIRECTORY;
 }
 
-/* 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).  */
-static inline bool
-inode_is_encrypted_directory(const struct wim_inode *inode)
-{
-       return ((inode->i_attributes & (FILE_ATTRIBUTE_DIRECTORY |
-                                       FILE_ATTRIBUTE_ENCRYPTED))
-               == (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ENCRYPTED));
-}
-
 /* Is the inode a symbolic link?
  * This returns true iff the inode is a reparse point that is either a "real"
  * symbolic link or a junction point.  */
@@ -395,145 +313,120 @@ inode_is_symlink(const struct wim_inode *inode)
                    inode->i_reparse_tag == WIM_IO_REPARSE_TAG_MOUNT_POINT);
 }
 
-/* Does the inode have children?
- * Currently (based on read_dentry_tree()), this can only return true for inodes
- * for which inode_is_directory() returns true.  (This also returns false on
- * empty directories.)  */
+/* Does the inode have children?  Currently (based on read_dentry_tree() as well
+ * as the various build-dentry-tree implementations), this can only return true
+ * for inodes for which inode_is_directory() returns true.  */
 static inline bool
 inode_has_children(const struct wim_inode *inode)
 {
        return inode->i_children != NULL;
 }
 
-extern int
-inode_resolve_streams(struct wim_inode *inode, struct wim_lookup_table *table,
-                     bool force);
+/* Does the inode have a security descriptor?  */
+static inline bool
+inode_has_security_descriptor(const struct wim_inode *inode)
+{
+       return inode->i_security_id >= 0;
+}
 
-extern int
-stream_not_found_error(const struct wim_inode *inode, const u8 *hash);
+extern struct wim_inode_stream *
+inode_get_stream(const struct wim_inode *inode, int stream_type,
+                const utf16lechar *stream_name);
 
-extern void
-inode_unresolve_streams(struct wim_inode *inode);
+extern struct wim_inode_stream *
+inode_get_unnamed_stream(const struct wim_inode *inode, int stream_type);
 
-static inline struct wim_lookup_table_entry *
-inode_stream_lte_resolved(const struct wim_inode *inode, unsigned stream_idx)
+static inline struct wim_inode_stream *
+inode_get_unnamed_data_stream(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_lte;
-       else
-               return inode->i_ads_entries[stream_idx - 1].lte;
+       return inode_get_unnamed_stream(inode, STREAM_TYPE_DATA);
 }
 
-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);
-}
+extern struct wim_inode_stream *
+inode_add_stream(struct wim_inode *inode, int stream_type,
+                const utf16lechar *stream_name, struct blob_descriptor *blob);
 
-extern struct wim_lookup_table_entry *
-inode_stream_lte(const struct wim_inode *inode, unsigned stream_idx,
-                const struct wim_lookup_table *table);
+extern void
+inode_replace_stream_blob(struct wim_inode *inode,
+                         struct wim_inode_stream *strm,
+                         struct blob_descriptor *new_blob,
+                         struct blob_table *blob_table);
 
-static inline const u8 *
-inode_stream_hash_unresolved(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_hash;
-       else
-               return inode->i_ads_entries[stream_idx - 1].hash;
-}
+extern bool
+inode_replace_stream_data(struct wim_inode *inode,
+                         struct wim_inode_stream *strm,
+                         const void *data, size_t size,
+                         struct blob_table *blob_table);
 
+extern bool
+inode_add_stream_with_data(struct wim_inode *inode, int stream_type,
+                          const utf16lechar *stream_name,
+                          const void *data, size_t size,
+                          struct blob_table *blob_table);
 
-static inline const u8 *
-inode_stream_hash_resolved(const struct wim_inode *inode, unsigned stream_idx)
+extern void
+inode_remove_stream(struct wim_inode *inode, struct wim_inode_stream *strm,
+                   struct blob_table *blob_table);
+
+static inline struct blob_descriptor *
+stream_blob_resolved(const struct wim_inode_stream *strm)
 {
-       struct wim_lookup_table_entry *lte;
-       lte = inode_stream_lte_resolved(inode, stream_idx);
-       if (lte)
-               return lte->hash;
-       else
-               return zero_hash;
+       wimlib_assert(strm->stream_resolved);
+       return strm->_stream_blob;
 }
 
-/*
- * 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)
+static inline bool
+stream_is_named(const struct wim_inode_stream *strm)
 {
-       if (inode->i_resolved)
-               return inode_stream_hash_resolved(inode, stream_idx);
-       else
-               return inode_stream_hash_unresolved(inode, stream_idx);
+       return strm->stream_name != NO_STREAM_NAME;
 }
 
-static inline u16
-inode_stream_name_nbytes(const struct wim_inode *inode, unsigned stream_idx)
+static inline bool
+stream_is_unnamed_data_stream(const struct wim_inode_stream *strm)
 {
-       wimlib_assert(stream_idx <= inode->i_num_ads);
-       if (stream_idx == 0)
-               return 0;
-       else
-               return inode->i_ads_entries[stream_idx - 1].stream_name_nbytes;
+       return strm->stream_type == STREAM_TYPE_DATA && !stream_is_named(strm);
 }
 
-static inline u32
-inode_stream_idx_to_id(const struct wim_inode *inode, unsigned stream_idx)
+static inline bool
+stream_is_named_data_stream(const struct wim_inode_stream *strm)
 {
-       if (stream_idx == 0)
-               return 0;
-       else
-               return inode->i_ads_entries[stream_idx - 1].stream_id;
+       return strm->stream_type == STREAM_TYPE_DATA && stream_is_named(strm);
 }
 
-extern struct wim_lookup_table_entry *
-inode_unnamed_stream_resolved(const struct wim_inode *inode, u16 *stream_idx_ret);
+extern bool
+inode_has_named_data_stream(const struct wim_inode *inode);
 
-extern struct wim_lookup_table_entry *
-inode_unnamed_lte_resolved(const struct wim_inode *inode);
+extern int
+inode_resolve_streams(struct wim_inode *inode,
+                     struct blob_table *table, bool force);
 
-extern struct wim_lookup_table_entry *
-inode_unnamed_lte_unresolved(const struct wim_inode *inode,
-                            const struct wim_lookup_table *table);
+extern int
+blob_not_found_error(const struct wim_inode *inode, const u8 *hash);
 
-extern struct wim_lookup_table_entry *
-inode_unnamed_lte(const struct wim_inode *inode, const struct wim_lookup_table *table);
+extern struct blob_descriptor *
+stream_blob(const struct wim_inode_stream *strm, const struct blob_table *table);
 
-extern const u8 *
-inode_unnamed_stream_hash(const struct wim_inode *inode);
+extern struct blob_descriptor *
+inode_get_blob_for_unnamed_data_stream(const struct wim_inode *inode,
+                                      const struct blob_table *blob_table);
 
-extern int
-read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode,
-                size_t *nbytes_remaining_p);
+extern struct blob_descriptor *
+inode_get_blob_for_unnamed_data_stream_resolved(const struct wim_inode *inode);
 
-extern int
-verify_inode(struct wim_inode *inode, const struct wim_security_data *sd);
+extern const u8 *
+stream_hash(const struct wim_inode_stream *strm);
+
+extern const u8 *
+inode_get_hash_of_unnamed_data_stream(const struct wim_inode *inode);
 
 extern void
-inode_ref_streams(struct wim_inode *inode);
+inode_ref_blobs(struct wim_inode *inode);
 
 extern void
-inode_unref_streams(struct wim_inode *inode,
-                   struct wim_lookup_table *lookup_table);
+inode_unref_blobs(struct wim_inode *inode, struct blob_table *blob_table);
 
 /* inode_fixup.c  */
 extern int
-dentry_tree_fix_inodes(struct wim_dentry *root, struct list_head *inode_list);
+dentry_tree_fix_inodes(struct wim_dentry *root, struct hlist_head *inode_list);
 
 #endif /* _WIMLIB_INODE_H  */