inode.c: cleanup
authorEric Biggers <ebiggers3@gmail.com>
Thu, 24 Jul 2014 06:20:38 +0000 (01:20 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Thu, 24 Jul 2014 06:20:38 +0000 (01:20 -0500)
include/wimlib/inode.h
src/dentry.c
src/inode.c
src/metadata_resource.c

index 3b0222990bf77a8476766b1fda097990e5a4740d..03c9acd8ca05aa22810b1776d234b5073499fd4a 100644 (file)
@@ -125,9 +125,10 @@ struct wim_inode {
 
        /* 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.  */
+        * security descriptors, or -1.  Note: when a WIM image is loaded,
+        * wimlib sets out-of-bounds indices and values less than -1 in this
+        * field to -1.  So the extraction code need not do an upper bound check
+        * after checking for -1 (or equivalently < 0).  */
        int32_t i_security_id;
 
        /* Identity of a reparse point.  See
@@ -355,6 +356,12 @@ 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)
 {
@@ -522,8 +529,8 @@ extern int
 read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode,
                 size_t *nbytes_remaining_p);
 
-extern int
-verify_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);
index 62283c18b2e7a15f49c9ebc40f5b641ed635ff59..fb268039590d3d75babba42206e78103b86425f5 100644 (file)
@@ -299,7 +299,7 @@ dentry_set_name_utf16le(struct wim_dentry *dentry, const utf16lechar *name,
  * indices.  For dentries that are currently linked into the tree, use
  * rename_wim_path().
  *
- * Returns 0 or an error code resulting from string conversion.
+ * Returns 0 or an error code resulting from a failed string conversion.
  */
 int
 dentry_set_name(struct wim_dentry *dentry, const tchar *name)
@@ -472,7 +472,7 @@ for_dentry_in_tree_depth(struct wim_dentry *root,
  * Whenever possible, use dentry_full_path() instead of calling this and
  * accessing _full_path directly.
  *
- * Returns 0 or an error code resulting from string conversion.
+ * Returns 0 or an error code resulting from a failed string conversion.
  */
 int
 calculate_dentry_full_path(struct wim_dentry *dentry)
@@ -896,7 +896,7 @@ get_parent_dentry(WIMStruct *wim, const tchar *path,
  *
  * On success, returns 0 and a pointer to the new, allocated dentry is stored in
  * *dentry_ret.  On failure, returns WIMLIB_ERR_NOMEM or an error code resulting
- * from string conversion.
+ * from a failed string conversion.
  */
 int
 new_dentry(const tchar *name, struct wim_dentry **dentry_ret)
index c9aa14b80d948b02ac96b3c6cde4d208668c0bdd..0111004ac23aaf749695ba02acc2829dba402c60 100644 (file)
@@ -1,9 +1,14 @@
 /*
  * inode.c
+ *
+ * Functions that operate on WIM inodes.
+ *
+ * See dentry.c for a description of the relationship between WIM dentries and
+ * WIM inodes.
  */
 
 /*
- * Copyright (C) 2012, 2013 Eric Biggers
+ * Copyright (C) 2012, 2013, 2014 Eric Biggers
  *
  * This file is part of wimlib, a library for working with WIM files.
  *
@@ -54,7 +59,6 @@ new_inode(void)
        return inode;
 }
 
-
 /* Allocate a new inode.  Leave the timestamps zeroed out.  */
 struct wim_inode *
 new_timeless_inode(void)
@@ -79,9 +83,7 @@ put_inode(struct wim_inode *inode)
        wimlib_assert(inode->i_nlink != 0);
        if (--inode->i_nlink == 0) {
                /* If FUSE mounts are enabled, we must keep a unlinked inode
-                * around until all file descriptors to it have been closed.
-                * inode_put_fd() in mount_image.c handles dropping a file
-                * descriptor.  */
+                * around until all file descriptors to it have been closed.  */
        #ifdef WITH_FUSE
                if (inode->i_num_opened_fds == 0)
        #endif
@@ -89,7 +91,7 @@ put_inode(struct wim_inode *inode)
        }
 }
 
-/* De-allocate memory for an alternate data stream entry.  */
+/* Free memory allocated within an alternate data stream entry.  */
 static void
 destroy_ads_entry(struct wim_ads_entry *ads_entry)
 {
@@ -101,15 +103,15 @@ destroy_ads_entry(struct wim_ads_entry *ads_entry)
 void
 free_inode(struct wim_inode *inode)
 {
-       if (inode == NULL)
+       if (unlikely(!inode))
                return;
 
-       if (inode->i_ads_entries) {
+       if (unlikely(inode->i_ads_entries)) {
                for (u16 i = 0; i < inode->i_num_ads; i++)
                        destroy_ads_entry(&inode->i_ads_entries[i]);
                FREE(inode->i_ads_entries);
        }
-       if (inode->i_extra)
+       if (unlikely(inode->i_extra))
                FREE(inode->i_extra);
        /* HACK: This may instead delete the inode from i_list, but hlist_del()
         * behaves the same as list_del(). */
@@ -195,17 +197,17 @@ do_inode_add_ads(struct wim_inode *inode,
        struct wim_ads_entry *new_entry;
 
        if (inode->i_num_ads >= 0xfffe) {
-               ERROR("Too many alternate data streams in one inode!");
+               ERROR("File \"%"TS"\" has too many alternate data streams!",
+                     inode_first_full_path(inode));
                errno = EFBIG;
                return NULL;
        }
        num_ads = inode->i_num_ads + 1;
        ads_entries = REALLOC(inode->i_ads_entries,
                              num_ads * sizeof(inode->i_ads_entries[0]));
-       if (ads_entries == NULL) {
-               ERROR("Failed to allocate memory for new alternate data stream");
+       if (!ads_entries)
                return NULL;
-       }
+
        inode->i_ads_entries = ads_entries;
 
        new_entry = &inode->i_ads_entries[num_ads - 1];
@@ -218,6 +220,12 @@ do_inode_add_ads(struct wim_inode *inode,
        return new_entry;
 }
 
+/*
+ * Add an alternate data stream entry to a WIM inode (UTF-16LE version).  On
+ * success, returns a pointer to the new entry.  Note that this pointer might
+ * become invalid if another ADS entry is added to the inode.  On failure,
+ * returns NULL and sets errno.
+ */
 struct wim_ads_entry *
 inode_add_ads_utf16le(struct wim_inode *inode,
                      const utf16lechar *stream_name, size_t stream_name_nbytes)
@@ -238,8 +246,10 @@ inode_add_ads_utf16le(struct wim_inode *inode,
 }
 
 /*
- * Add an alternate stream entry to a WIM inode.  On success, returns a pointer
- * to the new entry; on failure, returns NULL and sets errno.
+ * Add an alternate data stream entry to a WIM inode (tchar version).  On
+ * success, returns a pointer to the new entry.  Note that this pointer might
+ * become invalid if another ADS entry is added to the inode.  On failure,
+ * returns NULL and sets errno.
  */
 struct wim_ads_entry *
 inode_add_ads(struct wim_inode *inode, const tchar *stream_name)
@@ -262,6 +272,14 @@ inode_add_ads(struct wim_inode *inode, const tchar *stream_name)
        return result;
 }
 
+/*
+ * Add an data alternate stream entry to a WIM inode, where the contents of the
+ * new stream are specified in a data buffer.  The inode must be resolved.
+ *
+ * On success, returns a pointer to the new alternate data stream entry.  Note
+ * that this pointer might become invalid if another ADS entry is added to the
+ * inode.  On failure, returns NULL and sets errno.
+ */
 struct wim_ads_entry *
 inode_add_ads_with_data(struct wim_inode *inode, const tchar *name,
                        const void *value, size_t size,
@@ -277,12 +295,15 @@ inode_add_ads_with_data(struct wim_inode *inode, const tchar *name,
 
        new_entry->lte = new_stream_from_data_buffer(value, size, lookup_table);
        if (!new_entry->lte) {
-               inode_remove_ads(inode, new_entry, lookup_table);
+               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)
 {
@@ -293,19 +314,21 @@ inode_has_named_stream(const struct wim_inode *inode)
 }
 
 /* Set the unnamed stream of a WIM inode, given a data buffer containing the
- * stream contents. */
+ * 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 == NULL)
+       if (!inode->i_lte)
                return WIMLIB_ERR_NOMEM;
        return 0;
 }
 
-/* Remove an alternate data stream from a WIM inode  */
+/* Remove an alternate data stream from a WIM inode.  */
 void
 inode_remove_ads(struct wim_inode *inode, struct wim_ads_entry *entry,
                 struct wim_lookup_table *lookup_table)
@@ -329,103 +352,132 @@ inode_remove_ads(struct wim_inode *inode, struct wim_ads_entry *entry,
 }
 
 /*
- * Resolve an inode's lookup table entries.
+ * Resolve an inode's single-instance streams.
  *
- * This replaces the SHA1 hash fields (which are used to lookup an entry in the
- * lookup table) with pointers directly to the lookup table entries.
+ * This takes each SHA-1 message digest stored in the inode or one of its ADS
+ * entries and replaces it with a pointer directly to the appropriate 'struct
+ * wim_lookup_table_entry' currently inserted into @table to represent the
+ * single-instance stream having that SHA-1 message digest.
  *
  * If @force is %false:
- *     If any needed SHA1 message digests are not found in the lookup table,
- *     WIMLIB_ERR_RESOURCE_NOT_FOUND is returned and the inode is left
- *     unmodified.
+ *     If any of the needed single-instance streams do not exist in @table,
+ *     return WIMLIB_ERR_RESOURCE_NOT_FOUND and leave the inode unmodified.
  * If @force is %true:
- *     If any needed SHA1 message digests are not found in the lookup table,
- *     new entries are allocated and inserted into the lookup table.
+ *     If any of the needed single-instance streams do not exist in @table,
+ *     allocate new entries for them and insert them into @table.  This does
+ *     not, of course, cause these streams to magically exist, but this is
+ *     needed by the code for extraction from a pipe.
+ *
+ * If the inode is already resolved, this function does nothing.
+ *
+ * Returns 0 on success; WIMLIB_ERR_NOMEM if out of memory; or
+ * WIMLIB_ERR_RESOURCE_NOT_FOUND if @force is %false and at least one
+ * single-instance stream referenced by the inode was missing.
  */
 int
 inode_resolve_streams(struct wim_inode *inode, struct wim_lookup_table *table,
                      bool force)
 {
        const u8 *hash;
+       struct wim_lookup_table_entry *lte, *ads_lte;
 
-       if (!inode->i_resolved) {
-               struct wim_lookup_table_entry *lte, *ads_lte;
+       if (inode->i_resolved)
+               return 0;
+
+       struct wim_lookup_table_entry *ads_ltes[inode->i_num_ads];
+
+       /* Resolve the default data stream */
+       lte = NULL;
+       hash = inode->i_hash;
+       if (!is_zero_hash(hash)) {
+               lte = lookup_stream(table, hash);
+               if (!lte) {
+                       if (force) {
+                               lte = new_lookup_table_entry();
+                               if (!lte)
+                                       return WIMLIB_ERR_NOMEM;
+                               copy_hash(lte->hash, hash);
+                               lookup_table_insert(table, lte);
+                       } else {
+                               goto stream_not_found;
+                       }
+               }
+       }
+
+       /* Resolve the alternate data streams */
+       for (u16 i = 0; i < inode->i_num_ads; i++) {
+               struct wim_ads_entry *cur_entry;
 
-               /* Resolve the default file stream */
-               lte = NULL;
-               hash = inode->i_hash;
+               ads_lte = NULL;
+               cur_entry = &inode->i_ads_entries[i];
+               hash = cur_entry->hash;
                if (!is_zero_hash(hash)) {
-                       lte = lookup_stream(table, hash);
-                       if (!lte) {
+                       ads_lte = lookup_stream(table, hash);
+                       if (!ads_lte) {
                                if (force) {
-                                       lte = new_lookup_table_entry();
-                                       if (!lte)
+                                       ads_lte = new_lookup_table_entry();
+                                       if (!ads_lte)
                                                return WIMLIB_ERR_NOMEM;
-                                       copy_hash(lte->hash, hash);
-                                       lookup_table_insert(table, lte);
+                                       copy_hash(ads_lte->hash, hash);
+                                       lookup_table_insert(table, ads_lte);
                                } else {
                                        goto stream_not_found;
                                }
                        }
                }
-
-               /* Resolve the alternate data streams */
-               struct wim_lookup_table_entry *ads_ltes[inode->i_num_ads];
-               for (u16 i = 0; i < inode->i_num_ads; i++) {
-                       struct wim_ads_entry *cur_entry;
-
-                       ads_lte = NULL;
-                       cur_entry = &inode->i_ads_entries[i];
-                       hash = cur_entry->hash;
-                       if (!is_zero_hash(hash)) {
-                               ads_lte = lookup_stream(table, hash);
-                               if (!ads_lte) {
-                                       if (force) {
-                                               ads_lte = new_lookup_table_entry();
-                                               if (!ads_lte)
-                                                       return WIMLIB_ERR_NOMEM;
-                                               copy_hash(ads_lte->hash, hash);
-                                               lookup_table_insert(table, ads_lte);
-                                       } else {
-                                               goto stream_not_found;
-                                       }
-                               }
-                       }
-                       ads_ltes[i] = ads_lte;
-               }
-               inode->i_lte = lte;
-               for (u16 i = 0; i < inode->i_num_ads; i++)
-                       inode->i_ads_entries[i].lte = ads_ltes[i];
-               inode->i_resolved = 1;
+               ads_ltes[i] = ads_lte;
        }
+       inode->i_lte = lte;
+       for (u16 i = 0; i < inode->i_num_ads; i++)
+               inode->i_ads_entries[i].lte = ads_ltes[i];
+       inode->i_resolved = 1;
        return 0;
 
 stream_not_found:
        return stream_not_found_error(inode, hash);
 }
 
+/*
+ * Undo the effects of inode_resolve_streams().
+ *
+ * If the inode is not resolved, this function does nothing.
+ */
 void
 inode_unresolve_streams(struct wim_inode *inode)
 {
-       if (inode->i_resolved) {
-               if (inode->i_lte)
-                       copy_hash(inode->i_hash, inode->i_lte->hash);
+       if (!inode->i_resolved)
+               return;
+
+       if (inode->i_lte)
+               copy_hash(inode->i_hash, inode->i_lte->hash);
+       else
+               zero_out_hash(inode->i_hash);
+
+       for (u16 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);
                else
-                       zero_out_hash(inode->i_hash);
-
-               for (u16 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);
-                       else
-                               zero_out_hash(inode->i_ads_entries[i].hash);
-               }
-               inode->i_resolved = 0;
+                       zero_out_hash(inode->i_ads_entries[i].hash);
        }
+       inode->i_resolved = 0;
+}
+
+int
+stream_not_found_error(const struct wim_inode *inode, const u8 *hash)
+{
+       if (wimlib_print_errors) {
+               ERROR("\"%"TS"\": stream not found", inode_first_full_path(inode));
+               tfprintf(wimlib_error_file,
+                        T("        SHA-1 message digest of missing stream:\n        "));
+               print_hash(hash, wimlib_error_file);
+               tputc(T('\n'), wimlib_error_file);
+       }
+       return WIMLIB_ERR_RESOURCE_NOT_FOUND;
 }
 
 /*
- * Returns the lookup table entry for stream @stream_idx of the inode, where
+ * 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.
  *
@@ -441,6 +493,11 @@ inode_stream_lte(const struct wim_inode *inode, unsigned stream_idx,
                return inode_stream_lte_unresolved(inode, stream_idx, table);
 }
 
+/*
+ * 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.
+ */
 struct wim_lookup_table_entry *
 inode_unnamed_stream_resolved(const struct wim_inode *inode, u16 *stream_idx_ret)
 {
@@ -457,6 +514,10 @@ inode_unnamed_stream_resolved(const struct wim_inode *inode, u16 *stream_idx_ret
        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)
 {
@@ -464,6 +525,10 @@ inode_unnamed_lte_resolved(const struct wim_inode *inode)
        return inode_unnamed_stream_resolved(inode, &stream_idx);
 }
 
+/*
+ * 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)
@@ -479,7 +544,8 @@ inode_unnamed_lte_unresolved(const struct wim_inode *inode,
        return NULL;
 }
 
-/* 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
@@ -489,7 +555,7 @@ inode_unnamed_lte_unresolved(const struct wim_inode *inode,
  * dentry itself.  So we need to check the alternate data streams too.
  *
  * Also, note that a dentry may appear to have more than one unnamed stream, but
- * if the SHA1 message digest is all 0's then the corresponding stream does not
+ * 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
@@ -505,9 +571,12 @@ inode_unnamed_lte(const struct wim_inode *inode,
                return inode_unnamed_lte_unresolved(inode, table);
 }
 
-/* Returns the SHA1 message digest of the unnamed data stream of a WIM inode, or
- * 'zero_hash' if the unnamed data stream is missing has all zeroes in its SHA1
- * message digest field.  */
+/*
+ * 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.
+ */
 const u8 *
 inode_unnamed_stream_hash(const struct wim_inode *inode)
 {
@@ -523,8 +592,15 @@ inode_unnamed_stream_hash(const struct wim_inode *inode)
        return zero_hash;
 }
 
-/* Given an unhashed stream, get the pointer to it in an inode.
- * As this is only for unhashed streams, there can only be one such pointer.  */
+/*
+ * Translate a single-instance stream entry into the pointer contained in the
+ * inode (or ads entry of an inode) that references it.
+ *
+ * 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)
 {
@@ -541,21 +617,8 @@ retrieve_lte_pointer(struct wim_lookup_table_entry *lte)
        return NULL;
 }
 
-int
-stream_not_found_error(const struct wim_inode *inode, const u8 *hash)
-{
-       if (wimlib_print_errors) {
-               ERROR("\"%"TS"\": stream not found", inode_first_full_path(inode));
-               tfprintf(wimlib_error_file,
-                        T("        SHA-1 message digest of missing stream:\n        "));
-               print_hash(hash, wimlib_error_file);
-               tputc(T('\n'), wimlib_error_file);
-       }
-       return WIMLIB_ERR_RESOURCE_NOT_FOUND;
-}
-
 /*
- * Reads the alternate data stream entries of a WIM dentry.
+ * Read the alternate data stream entries of a WIM dentry.
  *
  * @p:
  *     Pointer to buffer that starts with the first alternate stream entry.
@@ -592,7 +655,7 @@ read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode,
         * data stream entries. */
        num_ads = inode->i_num_ads;
        ads_entries = CALLOC(num_ads, sizeof(inode->i_ads_entries[0]));
-       if (ads_entries == NULL)
+       if (!ads_entries)
                goto out_of_memory;
 
        /* Read the entries into our newly allocated buffer. */
@@ -648,7 +711,7 @@ read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode,
 
                        cur_entry->stream_name = utf16le_dupz(disk_entry->stream_name,
                                                              cur_entry->stream_name_nbytes);
-                       if (cur_entry->stream_name == NULL)
+                       if (!cur_entry->stream_name)
                                goto out_of_memory;
                } else {
                        /* Mark inode as having weird stream entries.  */
@@ -691,18 +754,9 @@ out:
        return ret;
 }
 
-/*
- * Verify a WIM inode:
- *
- * - Check to make sure the security ID is valid
- * - Check to make sure there is at most one unnamed stream
- * - Check to make sure there is at most one DOS name.
- *
- * Return values:
- *     WIMLIB_ERR_SUCCESS (0)
- */
-int
-verify_inode(struct wim_inode *inode, const struct wim_security_data *sd)
+/* Check a WIM inode for unusual field values.  */
+void
+check_inode(struct wim_inode *inode, const struct wim_security_data *sd)
 {
        /* Check the security ID.  -1 is valid and means "no security
         * descriptor".  Anything else has to be a valid index into the WIM
@@ -727,50 +781,56 @@ verify_inode(struct wim_inode *inode, const struct wim_security_data *sd)
        if (num_unnamed_streams > 1) {
                WARNING("\"%"TS"\" has multiple (%u) un-named 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.  */
        }
-
-       return 0;
 }
 
+/* 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)
 {
-       struct wim_lookup_table_entry *lte;
-       unsigned i;
+       for (unsigned i = 0; i <= inode->i_num_ads; i++) {
+               struct wim_lookup_table_entry *lte;
 
-       for (i = 0; i <= inode->i_num_ads; i++) {
                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 == NULL) {
-               ERROR("Cannot initalize inode table: out of memory");
+       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)
 {
@@ -785,14 +845,17 @@ inode_table_get_inode(struct wim_inode_table *table, u64 ino, u64 devno)
        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) {
-                       DEBUG("Using existing inode {devno=%"PRIu64", ino=%"PRIu64"}",
-                             devno, ino);
+                       /* 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;
@@ -803,13 +866,39 @@ inode_table_get_inode(struct wim_inode_table *table, u64 ino, u64 devno)
        return inode;
 }
 
-
-/* Given a directory entry with the name @name for the file with the inode
- * number @ino and device number @devno, create a new WIM dentry with an
- * associated inode, where the inode is shared if an inode with the same @ino
- * and @devno has already been created.  On success, the new WIM dentry is
- * written to *dentry_ret, and its inode has i_nlink > 1 if a previously
- * existing inode was used.
+/*
+ * 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,
@@ -852,9 +941,12 @@ inode_table_new_dentry(struct wim_inode_table *table, const tchar *name,
 
 
 
-/* Assign consecutive inode numbers to a new set of inodes from the inode table,
- * and append the inodes to a single list @head that contains the inodes already
- * existing in the WIM image.  */
+/*
+ * 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)
index 206c274ab0fa0a587344b60a530e376e9feeb68f..ee3f80ca8bc9dc9338e7e03431b4184cefd724f8 100644 (file)
@@ -112,11 +112,8 @@ read_metadata_resource(WIMStruct *wim, struct wim_image_metadata *imd)
        if (ret)
                goto out_free_dentry_tree;
 
-       image_for_each_inode(inode, imd) {
-               ret = verify_inode(inode, sd);
-               if (ret)
-                       goto out_free_dentry_tree;
-       }
+       image_for_each_inode(inode, imd)
+               check_inode(inode, sd);
 
        /* Success; fill in the image_metadata structure.  */
        imd->root_dentry = root;