inode updates (IN PROGRESS)
authorEric Biggers <ebiggers3@gmail.com>
Mon, 3 Sep 2012 22:23:49 +0000 (17:23 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Mon, 3 Sep 2012 22:23:49 +0000 (17:23 -0500)
14 files changed:
src/dentry.c
src/dentry.h
src/extract.c
src/hardlink.c
src/lookup_table.c
src/lookup_table.h
src/modify.c
src/mount.c
src/ntfs-apply.c
src/ntfs-capture.c
src/resource.c
src/wimlib_internal.h
src/write.c
tests/test-imagex

index a9d13f6..32c8357 100644 (file)
@@ -196,6 +196,9 @@ struct ads_entry *inode_add_ads(struct inode *inode, const char *stream_name)
                return NULL;
        inode->num_ads = num_ads;
        ads_entries[num_ads - 1] = new_entry;
+#ifdef WITH_FUSE
+       new_entry->stream_id = inode->next_stream_id++;
+#endif
        return new_entry;
 }
 
@@ -912,7 +915,7 @@ void calculate_dir_tree_statistics(struct dentry *root, struct lookup_table *tab
        stats.file_count      = file_count_ret;
        stats.total_bytes     = total_bytes_ret;
        stats.hard_link_bytes = hard_link_bytes_ret;
-       for_lookup_table_entry(table, zero_out_refcnts, NULL);
+       for_lookup_table_entry(table, lte_zero_out_refcnt, NULL);
        for_dentry_in_tree(root, calculate_dentry_statistics, &stats);
 }
 
@@ -988,6 +991,10 @@ static int read_ads_entries(const u8 *p, struct inode *inode,
 
                ads_entries[i] = cur_entry;
 
+       #ifdef WITH_FUSE
+               ads_entries[i]->stream_id = i + 1;
+       #endif
+
                /* Read the base stream entry, excluding the stream name. */
                if (remaining_size < WIM_ADS_ENTRY_DISK_SIZE) {
                        ERROR("Stream entries go past end of metadata resource");
@@ -1072,6 +1079,9 @@ static int read_ads_entries(const u8 *p, struct inode *inode,
                        remaining_size -= total_length;
        }
        inode->ads_entries = ads_entries;
+#ifdef WITH_FUSE
+       inode->next_stream_id = inode->num_ads + 1;
+#endif
        return 0;
 out_free_ads_entries:
        for (u16 i = 0; i < num_ads; i++)
@@ -1334,25 +1344,23 @@ out_free_inode:
        return ret;
 }
 
-/* Run some miscellaneous verifications on a WIM dentry */
-int verify_dentry(struct dentry *dentry, void *wim)
+int verify_inode(struct inode *inode, const WIMStruct *w)
 {
-       const WIMStruct *w = wim;
        const struct lookup_table *table = w->lookup_table;
        const struct wim_security_data *sd = wim_const_security_data(w);
-       const struct inode *inode = dentry->inode;
+       const struct dentry *first_dentry = inode_first_dentry(inode);
        int ret = WIMLIB_ERR_INVALID_DENTRY;
 
        /* Check the security ID */
        if (inode->security_id < -1) {
                ERROR("Dentry `%s' has an invalid security ID (%d)",
-                       dentry->full_path_utf8, inode->security_id);
+                       first_dentry->full_path_utf8, inode->security_id);
                goto out;
        }
        if (inode->security_id >= sd->num_entries) {
                ERROR("Dentry `%s' has an invalid security ID (%d) "
                      "(there are only %u entries in the security table)",
-                       dentry->full_path_utf8, inode->security_id,
+                       first_dentry->full_path_utf8, inode->security_id,
                        sd->num_entries);
                goto out;
        }
@@ -1368,9 +1376,40 @@ int verify_dentry(struct dentry *dentry, void *wim)
                        lte = __lookup_resource(table, hash);
                        if (!lte && !is_zero_hash(hash)) {
                                ERROR("Could not find lookup table entry for stream "
-                                     "%u of dentry `%s'", i, dentry->full_path_utf8);
+                                     "%u of dentry `%s'", i, first_dentry->full_path_utf8);
                                goto out;
                        }
+                       if (lte && (lte->real_refcnt += inode->link_count) > lte->refcnt)
+                       {
+                       #ifdef ENABLE_ERROR_MESSAGES
+                               WARNING("The following lookup table entry "
+                                       "has a reference count of %u, but",
+                                       lte->refcnt);
+                               WARNING("We found %zu references to it",
+                                       lte->real_refcnt);
+                               WARNING("(One dentry referencing it is at `%s')",
+                                        first_dentry->full_path_utf8);
+
+                               print_lookup_table_entry(lte);
+                       #endif
+                               /* Guess what!  install.wim for Windows 8
+                                * contains a stream with 2 dentries referencing
+                                * it, but the lookup table entry has reference
+                                * count of 1.  So we will need to handle this
+                                * case and not just make it be an error...  I'm
+                                * just setting the reference count to the
+                                * number of references we found.
+                                * (Unfortunately, even after doing this, the
+                                * reference count could be too low if it's also
+                                * referenced in other WIM images) */
+
+                       #if 1
+                               lte->refcnt = lte->real_refcnt;
+                               WARNING("Fixing reference count");
+                       #else
+                               goto out;
+                       #endif
+                       }
                }
        }
 
@@ -1384,9 +1423,28 @@ int verify_dentry(struct dentry *dentry, void *wim)
        }
        if (num_unnamed_streams > 1) {
                ERROR("Dentry `%s' has multiple (%u) un-named streams", 
-                     dentry->full_path_utf8, num_unnamed_streams);
+                     first_dentry->full_path_utf8, num_unnamed_streams);
                goto out;
        }
+       inode->verified = true;
+       ret = 0;
+out:
+       return ret;
+}
+
+
+/* Run some miscellaneous verifications on a WIM dentry */
+int verify_dentry(struct dentry *dentry, void *wim)
+{
+       const WIMStruct *w = wim;
+       const struct inode *inode = dentry->inode;
+       int ret = WIMLIB_ERR_INVALID_DENTRY;
+
+       if (!dentry->inode->verified) {
+               ret = verify_inode(dentry->inode, w);
+               if (ret != 0)
+                       goto out;
+       }
 
        /* Cannot have a short name but no long name */
        if (dentry->short_name_len && !dentry->file_name_len) {
index 28d5ab3..e2b6294 100644 (file)
@@ -68,7 +68,8 @@ struct ads_entry {
                struct lookup_table_entry *lte;
        };
 
-       /* Length of stream name (UTF-16) */
+       /* Length of stream name (UTF-16).  This is in bytes, not characters,
+        * and does not include the terminating null character   */
        u16 stream_name_len;
 
        /* Length of stream name (UTF-8) */
@@ -136,7 +137,9 @@ struct inode {
         * the @lte field is valid, but the @hash field is not valid) 
         *
         * (This is not an on-disk field.) */
-       bool resolved;
+       u8 resolved : 1;
+
+       u8 verified : 1;
 
        u16 num_ads;
 
@@ -289,9 +292,17 @@ struct dentry {
 
        /* List of dentries in the hard link set */
        struct list_head inode_dentry_list;
-       struct list_head tmp_list;
+       union {
+               struct list_head tmp_list;
+               bool is_extracted;
+       };
 };
 
+static inline bool dentry_is_extracted(const struct dentry *dentry)
+{
+       return dentry->is_extracted;
+}
+
 
 extern struct ads_entry *inode_get_ads_entry(struct inode *inode,
                                             const char *stream_name,
@@ -330,7 +341,8 @@ extern int print_dentry(struct dentry *dentry, void *lookup_table);
 extern int print_dentry_full_path(struct dentry *entry, void *ignore);
 
 extern struct dentry *get_dentry(struct WIMStruct *w, const char *path);
-extern struct inode *wim_pathname_to_inode(WIMStruct *w, const char *path);
+extern struct inode *wim_pathname_to_inode(struct WIMStruct *w,
+                                          const char *path);
 extern struct dentry *get_parent_dentry(struct WIMStruct *w, const char *path);
 extern struct dentry *get_dentry_child_with_name(const struct dentry *dentry, 
                                                        const char *name);
@@ -373,11 +385,11 @@ extern u8 *write_dentry_tree(const struct dentry *tree, u8 *p);
 
 static inline struct dentry *inode_first_dentry(struct inode *inode)
 {
+       wimlib_assert(inode->dentry_list.next != &inode->dentry_list);
        return container_of(inode->dentry_list.next, struct dentry,
                            inode_dentry_list);
 }
 
-
 static inline bool dentry_is_root(const struct dentry *dentry)
 {
        return dentry->parent == dentry;
index 6e01191..1dd2f61 100644 (file)
@@ -204,14 +204,15 @@ static int extract_regular_file(WIMStruct *w,
 
        if ((extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK |
                              WIMLIB_EXTRACT_FLAG_HARDLINK)) && lte) {
-               if (++lte->out_refcnt != 1)
+               if (lte->extracted_file) {
                        return extract_regular_file_linked(dentry, output_dir,
                                                           output_path,
                                                           extract_flags, lte);
-               FREE(lte->extracted_file);
-               lte->extracted_file = STRDUP(output_path);
-               if (!lte->extracted_file)
-                       return WIMLIB_ERR_NOMEM;
+               } else {
+                       lte->extracted_file = STRDUP(output_path);
+                       if (!lte->extracted_file)
+                               return WIMLIB_ERR_NOMEM;
+               }
        }
 
        return extract_regular_file_unlinked(w, dentry, output_path,
@@ -429,8 +430,7 @@ WIMLIBAPI int wimlib_extract_image(WIMStruct *w, int image,
                w->lookup_table = joined_tab;
        }
 
-
-       for_lookup_table_entry(w->lookup_table, zero_out_refcnts, NULL);
+       for_lookup_table_entry(w->lookup_table, lte_free_extracted_file, NULL);
 
        if (image == WIM_ALL_IMAGES) {
                flags |= WIMLIB_EXTRACT_FLAG_MULTI_IMAGE;
index 7aedf8e..5c2f20c 100644 (file)
@@ -142,6 +142,7 @@ int inode_table_insert(struct dentry *dentry, void *__table)
  * next available inode ID. */
 u64 assign_inode_numbers(struct hlist_head *inode_list)
 {
+       DEBUG("Assigning inode numbers");
        struct inode *inode;
        struct hlist_node *cur;
        u64 cur_ino = 1;
@@ -153,8 +154,7 @@ u64 assign_inode_numbers(struct hlist_head *inode_list)
 }
 
 
-static void
-print_inode_dentries(const struct inode *inode)
+static void print_inode_dentries(const struct inode *inode)
 {
        struct dentry *dentry;
        list_for_each_entry(dentry, &inode->dentry_list, inode_dentry_list)
@@ -433,13 +433,14 @@ next_dentry_2:
 }
 
 /*
- * Goes through each inode and shares the inodes among members of a hard
- * inode.
+ * Goes through each hard link group (dentries sharing the same hard link group
+ * ID field) that's been inserted into the inode table and shars the `struct
+ * inode's among members of each hard link group.
  *
- * In the process, the dentries in each inode are checked for consistency.
- * If they contain data features that indicate they cannot really be in the same
- * inode, this should be an error, but in reality this case needs to
- * be handled, so we split the dentries into different inodes.
+ * In the process, the dentries belonging to each inode are checked for
+ * consistency.  If they contain data features that indicate they cannot really
+ * correspond to the same inode, this should be an error, but in reality this
+ * case needs to be handled, so we split the dentries into different inodes.
  */
 int fix_inodes(struct inode_table *table, struct hlist_head *inode_list)
 {
index 776ad94..61cc5a8 100644 (file)
@@ -358,10 +358,22 @@ int write_lookup_table_entry(struct lookup_table_entry *lte, void *__out)
 }
 
 
+int lte_zero_real_refcnt(struct lookup_table_entry *lte, void *ignore)
+{
+       lte->real_refcnt = 0;
+       return 0;
+}
+
+int lte_zero_out_refcnt(struct lookup_table_entry *lte, void *ignore)
+{
+       lte->out_refcnt = 0;
+       return 0;
+}
 
-int zero_out_refcnts(struct lookup_table_entry *entry, void *ignore)
+int lte_free_extracted_file(struct lookup_table_entry *lte, void *ignone)
 {
-       entry->out_refcnt = 0;
+       FREE(lte->extracted_file);
+       lte->extracted_file = NULL;
        return 0;
 }
 
@@ -513,7 +525,7 @@ out:
        return 0;
 }
 
-static int inode_resolve_ltes(struct inode *inode, struct lookup_table *table)
+static void inode_resolve_ltes(struct inode *inode, struct lookup_table *table)
 {
        struct lookup_table_entry *lte;
 
@@ -529,7 +541,6 @@ static int inode_resolve_ltes(struct inode *inode, struct lookup_table *table)
                lte = __lookup_resource(table, cur_entry->hash);
                cur_entry->lte = lte;
        }
-       return 0;
 }
 
 /* Resolve a dentry's lookup table entries 
@@ -543,25 +554,21 @@ static int inode_resolve_ltes(struct inode *inode, struct lookup_table *table)
  */
 int dentry_resolve_ltes(struct dentry *dentry, void *table)
 {
-       if (dentry->inode->resolved)
-               return 0;
-       else
-               return inode_resolve_ltes(dentry->inode, table);
+       if (!dentry->inode->resolved)
+               inode_resolve_ltes(dentry->inode, table);
+       return 0;
 }
 
-
-
-
-/* Return the lookup table entry for the unnamed data stream of a 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
- * inode.  So we need to check the alternate data streams too.
+ * 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.
  *
- * Also, note that a inode may appear to have than one unnamed stream, but if
+ * Also, note that a dentry may appear to have than one unnamed stream, but if
  * the SHA1 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
index d99f4b7..193cef0 100644 (file)
@@ -164,6 +164,8 @@ struct lookup_table_entry {
         * dentries. */
        u32 out_refcnt;
 
+       u32 real_refcnt;
+
        /* When a WIM file is written, @output_resource_entry is filled
         * in with the resource entry for the output WIM.  This will not
         * necessarily be the same as the @resource_entry since:
@@ -253,7 +255,9 @@ extern int lookup_resource(WIMStruct *w, const char *path,
                           struct lookup_table_entry **lte_ret,
                           u16 *stream_idx_ret);
 
-extern int zero_out_refcnts(struct lookup_table_entry *entry, void *ignore);
+extern int lte_zero_out_refcnt(struct lookup_table_entry *entry, void *ignore);
+extern int lte_zero_real_refcnt(struct lookup_table_entry *entry, void *ignore);
+extern int lte_free_extracted_file(struct lookup_table_entry *lte, void *ignone);
 
 extern void print_lookup_table_entry(const struct lookup_table_entry *entry);
 
index ae6f98b..2c92d82 100644 (file)
@@ -249,19 +249,21 @@ struct wim_pair {
 static int add_lte_to_dest_wim(struct dentry *dentry, void *arg)
 {
        WIMStruct *src_wim, *dest_wim;
+       struct inode *inode;
 
        src_wim = ((struct wim_pair*)arg)->src_wim;
        dest_wim = ((struct wim_pair*)arg)->dest_wim;
+       inode = dentry->inode;
 
-       wimlib_assert(!dentry->inode->resolved);
+       wimlib_assert(!inode->resolved);
 
-       for (unsigned i = 0; i < (unsigned)dentry->inode->num_ads + 1; i++) {
+       for (unsigned i = 0; i <= inode->num_ads; i++) {
                struct lookup_table_entry *src_lte, *dest_lte;
-               src_lte = inode_stream_lte_unresolved(dentry->inode, i,
+               src_lte = inode_stream_lte_unresolved(inode, i,
                                                      src_wim->lookup_table);
                if (!src_lte)
                        continue;
-               dest_lte = inode_stream_lte_unresolved(dentry->inode, i,
+               dest_lte = inode_stream_lte_unresolved(inode, i,
                                                       dest_wim->lookup_table);
                if (dest_lte) {
                        dest_lte->refcnt++;
index b67f40c..3c8f206 100644 (file)
@@ -108,6 +108,8 @@ static int alloc_wimlib_fd(struct inode *inode,
        static const u16 fds_per_alloc = 8;
        static const u16 max_fds = 0xffff;
 
+       DEBUG("Allocate wimlib fd");
+
        if (inode->num_opened_fds == inode->num_allocated_fds) {
                struct wimlib_fd **fds;
                u16 num_new_fds;
@@ -138,7 +140,9 @@ static int alloc_wimlib_fd(struct inode *inode,
                        *fd_ret        = fd;
                        inode->fds[i]  = fd;
                        inode->num_opened_fds++;
-                       lte->num_opened_fds++;
+                       if (lte)
+                               lte->num_opened_fds++;
+                       DEBUG("Allocated fd");
                        return 0;
                }
        }
@@ -207,7 +211,7 @@ static void remove_dentry(struct dentry *dentry,
        struct lookup_table_entry *lte;
        unsigned i;
 
-       for (i = 0; <= inode->num_ads; i++) {
+       for (i = 0; <= inode->num_ads; i++) {
                lte = inode_stream_lte_resolved(inode, i);
                if (lte)
                        lte_decrement_refcnt(lte, lookup_table);
@@ -433,6 +437,13 @@ static int extract_resource_to_staging_dir(struct inode *inode,
        new_lte->staging_file_name = staging_file_name;
        new_lte->resource_location = RESOURCE_IN_STAGING_FILE;
 
+       if (stream_id == 0)
+               inode->lte = new_lte;
+       else
+               for (u16 i = 0; i < inode->num_ads; i++)
+                       if (inode->ads_entries[i]->stream_id == stream_id)
+                               inode->ads_entries[i]->lte = new_lte;
+
        lookup_table_insert(w->lookup_table, new_lte);
        list_add(&new_lte->staging_list, &staging_list);
        *lte = new_lte;
@@ -1144,13 +1155,19 @@ static int wimfs_open(const char *path, struct fuse_file_info *fi)
        if (ret != 0)
                return ret;
 
+       DEBUG("dentry = %p", dentry);
+
        inode = dentry->inode;
 
+       DEBUG("stream_idx = %u", stream_idx);
+
        if (stream_idx == 0)
                stream_id = 0;
        else
                stream_id = inode->ads_entries[stream_idx - 1]->stream_id;
 
+       DEBUG("stream_id = %u", stream_id);
+
        /* The file resource may be in the staging directory (read-write mounts
         * only) or in the WIM.  If it's in the staging directory, we need to
         * open a native file descriptor for the corresponding file.  Otherwise,
@@ -1184,17 +1201,13 @@ static int wimfs_open(const char *path, struct fuse_file_info *fi)
 /* Opens a directory. */
 static int wimfs_opendir(const char *path, struct fuse_file_info *fi)
 {
-       struct dentry *dentry;
        struct inode *inode;
        int ret;
        struct wimlib_fd *fd = NULL;
        
-       dentry = get_dentry(w, path);
-       if (!dentry)
+       inode = wim_pathname_to_inode(w, path);
+       if (!inode)
                return -ENOENT;
-
-       inode = dentry->inode;
-
        if (!inode_is_directory(inode))
                return -ENOTDIR;
        ret = alloc_wimlib_fd(inode, 0, NULL, &fd);
@@ -1425,7 +1438,6 @@ static int wimfs_rmdir(const char *path)
 static int wimfs_setxattr(const char *path, const char *name,
                          const char *value, size_t size, int flags)
 {
-       struct dentry *dentry;
        struct ads_entry *existing_ads_entry;
        struct ads_entry *new_ads_entry;
        struct lookup_table_entry *existing_lte;
@@ -1441,21 +1453,20 @@ static int wimfs_setxattr(const char *path, const char *name,
                return -ENOATTR;
        name += 5;
 
-       dentry = get_dentry(w, path);
-       if (!dentry)
+       inode = wim_pathname_to_inode(w, path);
+       if (!inode)
                return -ENOENT;
-       inode = dentry->inode;
 
        existing_ads_entry = inode_get_ads_entry(inode, name, &ads_idx);
        if (existing_ads_entry) {
                if (flags & XATTR_CREATE)
                        return -EEXIST;
-               inode_remove_ads(dentry->inode, ads_idx, w->lookup_table);
+               inode_remove_ads(inode, ads_idx, w->lookup_table);
        } else {
                if (flags & XATTR_REPLACE)
                        return -ENOATTR;
        }
-       new_ads_entry = inode_add_ads(dentry, name);
+       new_ads_entry = inode_add_ads(inode, name);
        if (!new_ads_entry)
                return -ENOMEM;
 
@@ -1494,7 +1505,7 @@ static int wimfs_symlink(const char *to, const char *from)
 {
        struct dentry *dentry_parent, *dentry;
        const char *link_name;
-       struct lookup_table_entry *lte;
+       struct inode *inode;
        
        dentry_parent = get_parent_dentry(w, from);
        if (!dentry_parent)
@@ -1506,24 +1517,18 @@ static int wimfs_symlink(const char *to, const char *from)
 
        if (get_dentry_child_with_name(dentry_parent, link_name))
                return -EEXIST;
-       dentry = new_dentry(link_name);
+       dentry = new_dentry_with_inode(link_name);
        if (!dentry)
                return -ENOMEM;
+       inode = dentry->inode;
 
-       dentry->attributes = FILE_ATTRIBUTE_REPARSE_POINT;
-       dentry->reparse_tag = WIM_IO_REPARSE_TAG_SYMLINK;
-       dentry->link_group_id = next_link_group_id++;
+       inode->attributes  = FILE_ATTRIBUTE_REPARSE_POINT;
+       inode->reparse_tag = WIM_IO_REPARSE_TAG_SYMLINK;
+       inode->ino         = next_ino++;
 
-       if (dentry_set_symlink(dentry, to, w->lookup_table, &lte) != 0)
+       if (inode_set_symlink(inode, to, w->lookup_table, NULL) != 0)
                goto out_free_dentry;
 
-       wimlib_assert(lte);
-
-       dentry->ads_entries[1].lte_group_list.type = STREAM_TYPE_ADS;
-       list_add(&dentry->ads_entries[1].lte_group_list.list,
-                &lte->lte_group_list);
-       wimlib_assert(dentry->resolved);
-
        link_dentry(dentry, dentry_parent);
        return 0;
 out_free_dentry:
@@ -1538,7 +1543,9 @@ static int wimfs_truncate(const char *path, off_t size)
        struct dentry *dentry;
        struct lookup_table_entry *lte;
        int ret;
-       unsigned stream_idx;
+       u16 stream_idx;
+       u32 stream_id;
+       struct inode *inode;
        
        ret = lookup_resource(w, path, get_lookup_flags(), &dentry,
                              &lte, &stream_idx);
@@ -1549,6 +1556,13 @@ static int wimfs_truncate(const char *path, off_t size)
        if (!lte) /* Already a zero-length file */
                return 0;
 
+       inode = dentry->inode;
+
+       if (stream_idx == 0)
+               stream_id = 0;
+       else
+               stream_id = inode->ads_entries[stream_idx - 1]->stream_id;
+
        if (lte->resource_location == RESOURCE_IN_STAGING_FILE) {
                wimlib_assert(lte->staging_file_name);
                ret = truncate(lte->staging_file_name, size);
@@ -1559,7 +1573,7 @@ static int wimfs_truncate(const char *path, off_t size)
                wimlib_assert(lte->resource_location == RESOURCE_IN_WIM);
                /* File in WIM.  Extract it to the staging directory, but only
                 * the first @size bytes of it. */
-               ret = extract_resource_to_staging_dir(dentry, stream_idx,
+               ret = extract_resource_to_staging_dir(inode, stream_id,
                                                      &lte, size);
        }
        return ret;
@@ -1572,7 +1586,7 @@ static int wimfs_unlink(const char *path)
        struct lookup_table_entry *lte;
        struct inode *inode;
        int ret;
-       unsigned stream_idx;
+       u16 stream_idx;
        unsigned i;
        
        ret = lookup_resource(w, path, get_lookup_flags(), &dentry,
@@ -1711,46 +1725,6 @@ static struct fuse_operations wimfs_operations = {
 };
 
 
-static int check_lte_refcnt(struct lookup_table_entry *lte, void *ignore)
-{
-       size_t lte_group_size = 0;
-       struct list_head *cur;
-       list_for_each(cur, &lte->lte_group_list)
-               lte_group_size++;
-       if (lte_group_size > lte->refcnt) {
-#ifdef ENABLE_ERROR_MESSAGES
-               struct dentry *example_dentry;
-               struct list_head *next;
-               struct stream_list_head *head;
-               WARNING("The following lookup table entry has a reference count "
-                     "of %u, but", lte->refcnt);
-               WARNING("We found %zu references to it", lte_group_size);
-               next = lte->lte_group_list.next;
-               head = container_of(next, struct stream_list_head, list);
-               if (head->type == STREAM_TYPE_NORMAL) {
-                       example_dentry = container_of(head, struct dentry,
-                                                     lte_group_list);
-                       WARNING("(One dentry referencing it is at `%s')",
-                               example_dentry->full_path_utf8);
-               }
-               print_lookup_table_entry(lte);
-#endif
-               /* Guess what!  install.wim for Windows 8 contains a stream with
-                * 2 dentries referencing it, but the lookup table entry has
-                * reference count of 1.  So we will need to handle this case
-                * and not just make it be an error...  I'm just setting the
-                * reference count to the number of references we found. */
-
-               #if 1
-               lte->refcnt = lte_group_size;
-               WARNING("Fixing reference count");
-               #else
-               return WIMLIB_ERR_INVALID_DENTRY;
-               #endif
-       }
-       return 0;
-}
-
 /* Mounts a WIM file. */
 WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir, 
                           int flags, WIMStruct **additional_swms,
@@ -1761,6 +1735,7 @@ WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir,
        int ret;
        char *p;
        struct lookup_table *joined_tab, *wim_tab_save;
+       struct image_metadata *imd;
 
        DEBUG("Mount: wim = %p, image = %d, dir = %s, flags = %d, ",
                        wim, image, dir, flags);
@@ -1787,23 +1762,21 @@ WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir,
        if (ret != 0)
                goto out;
 
+       imd = &wim->image_metadata[image - 1];
+
        DEBUG("Selected image %d", image);
 
-       next_link_group_id = assign_link_group_ids(wim->image_metadata[image - 1].lgt);
+       next_ino = assign_inode_numbers(&imd->inode_list);
+
+       DEBUG("(next_ino = %"PRIu64")", next_ino);
 
-       DEBUG("Resolving lookup table entries");
        /* Resolve all the lookup table entries of the dentry tree */
-       for_dentry_in_tree(wim_root_dentry(wim), dentry_resolve_ltes,
+       DEBUG("Resolving lookup table entries");
+       for_dentry_in_tree(imd->root_dentry, dentry_resolve_ltes,
                           wim->lookup_table);
 
-       DEBUG("Checking lookup table entry reference counts");
-
-       ret = for_lookup_table_entry(wim->lookup_table, check_lte_refcnt, NULL);
-       if (ret != 0)
-               goto out;
-
        if (flags & WIMLIB_MOUNT_FLAG_READWRITE)
-               wim_get_current_image_metadata(wim)->modified = true;
+               imd->modified = true;
 
        if (!(flags & (WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
                       WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR |
index 8d14267..5e36469 100644 (file)
@@ -104,7 +104,7 @@ extract_wim_resource_to_ntfs_attr(const struct lookup_table_entry *lte,
 /* Writes the data streams to a NTFS file
  *
  * @ni:             The NTFS inode for the file.
- * @dentry:  The directory entry in the WIM file.
+ * @inode:   The WIM dentry that has an inode containing the streams.
  * @w:      The WIMStruct for the WIM containing the image we are applying.
  *
  * Returns 0 on success, nonzero on failure.
@@ -116,17 +116,18 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct dentry *dentry,
        unsigned stream_idx = 0;
        ntfschar *stream_name = AT_UNNAMED;
        u32 stream_name_len = 0;
+       const struct inode *inode = dentry->inode;
 
        DEBUG("Writing %u NTFS data stream%s for `%s'",
-             dentry->num_ads + 1,
-             (dentry->num_ads == 0 ? "" : "s"),
+             inode->num_ads + 1,
+             (inode->num_ads == 0 ? "" : "s"),
              dentry->full_path_utf8);
 
        while (1) {
                struct lookup_table_entry *lte;
                ntfs_attr *na;
 
-               lte = dentry_stream_lte(dentry, stream_idx, w->lookup_table);
+               lte = inode_stream_lte(inode, stream_idx, w->lookup_table);
 
                if (stream_name_len) {
                        /* Create an empty named stream. */
@@ -159,10 +160,10 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct dentry *dentry,
                                break;
                        ntfs_attr_close(na);
                }
-               if (stream_idx == dentry->num_ads)
+               if (stream_idx == inode->num_ads)
                        break;
-               stream_name = (ntfschar*)dentry->ads_entries[stream_idx].stream_name;
-               stream_name_len = dentry->ads_entries[stream_idx].stream_name_len / 2;
+               stream_name = (ntfschar*)inode->ads_entries[stream_idx]->stream_name;
+               stream_name_len = inode->ads_entries[stream_idx]->stream_name_len / 2;
                stream_idx++;
        }
        return ret;
@@ -173,12 +174,12 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct dentry *dentry,
  *
  * It is named @from_dentry->file_name and is located under the directory
  * specified by @dir_ni, and it is made to point to the previously extracted
- * file located at @to_dentry->extracted_file.
+ * file located at @inode->extracted_file.
  *
  * Return 0 on success, nonzero on failure.
  */
 static int wim_apply_hardlink_ntfs(const struct dentry *from_dentry,
-                                  const struct dentry *to_dentry,
+                                  const struct inode *inode,
                                   ntfs_inode *dir_ni,
                                   ntfs_inode **to_ni_ret)
 {
@@ -191,7 +192,7 @@ static int wim_apply_hardlink_ntfs(const struct dentry *from_dentry,
        ntfs_volume *vol;
 
        wimlib_assert(dentry_is_regular_file(from_dentry)
-                       && dentry_is_regular_file(to_dentry));
+                       && inode_is_regular_file(inode));
 
        if (ntfs_inode_close(dir_ni) != 0) {
                ERROR_WITH_ERRNO("Error closing directory");
@@ -201,13 +202,12 @@ static int wim_apply_hardlink_ntfs(const struct dentry *from_dentry,
        vol = dir_ni->vol;
 
        DEBUG("Extracting NTFS hard link `%s' => `%s'",
-             from_dentry->full_path_utf8, to_dentry->extracted_file);
+             from_dentry->full_path_utf8, inode->extracted_file);
 
-       to_ni = ntfs_pathname_to_inode(vol, NULL,
-                                      to_dentry->extracted_file);
+       to_ni = ntfs_pathname_to_inode(vol, NULL, inode->extracted_file);
        if (!to_ni) {
                ERROR_WITH_ERRNO("Could not find NTFS inode for `%s'",
-                                to_dentry->extracted_file);
+                                inode->extracted_file);
                return WIMLIB_ERR_NTFS_3G;
        }
        p = from_dentry->full_path_utf8 + from_dentry->full_path_utf8_len;
@@ -234,7 +234,7 @@ static int wim_apply_hardlink_ntfs(const struct dentry *from_dentry,
        if (ret != 0) {
                ERROR_WITH_ERRNO("Could not create hard link `%s' => `%s'",
                                 from_dentry->full_path_utf8,
-                                to_dentry->extracted_file);
+                                inode->extracted_file);
                ret = WIMLIB_ERR_NTFS_3G;
        }
        *to_ni_ret = to_ni;
@@ -250,14 +250,14 @@ apply_file_attributes_and_security_data(ntfs_inode *ni,
                                        const WIMStruct *w)
 {
        DEBUG("Setting NTFS file attributes on `%s' to %#"PRIx32,
-             dentry->full_path_utf8, dentry->attributes);
+             dentry->full_path_utf8, dentry->inode->attributes);
        int ret;
 #ifdef HAVE_NTFS_INODE_FUNCTIONS
-       ret = ntfs_set_inode_attributes(ni, dentry->attributes);
+       ret = ntfs_set_inode_attributes(ni, dentry->inode->attributes);
 #else
        struct SECURITY_CONTEXT ctx;
        u32 attributes_le32;
-       attributes_le32 = cpu_to_le32(dentry->attributes);
+       attributes_le32 = cpu_to_le32(dentry->inode->attributes);
        memset(&ctx, 0, sizeof(ctx));
        ctx.vol = ni->vol;
        ret = ntfs_xattr_system_setxattr(&ctx, XATTR_NTFS_ATTRIB,
@@ -270,15 +270,15 @@ apply_file_attributes_and_security_data(ntfs_inode *ni,
                       dentry->full_path_utf8);
                return WIMLIB_ERR_NTFS_3G;
        }
-       if (dentry->security_id != -1) {
+       if (dentry->inode->security_id != -1) {
                const struct wim_security_data *sd;
                const char *descriptor;
                
                sd = wim_const_security_data(w);
-               wimlib_assert(dentry->security_id < sd->num_entries);
-               descriptor = sd->descriptors[dentry->security_id];
+               wimlib_assert(dentry->inode->security_id < sd->num_entries);
+               descriptor = sd->descriptors[dentry->inode->security_id];
                DEBUG("Applying security descriptor %d to `%s'",
-                     dentry->security_id, dentry->full_path_utf8);
+                     dentry->inode->security_id, dentry->full_path_utf8);
 
        #ifdef HAVE_NTFS_INODE_FUNCTIONS
                u32 selection = OWNER_SECURITY_INFORMATION |
@@ -289,7 +289,7 @@ apply_file_attributes_and_security_data(ntfs_inode *ni,
        #else
                ret = ntfs_xattr_system_setxattr(&ctx, XATTR_NTFS_ACL,
                                                 ni, dir_ni, descriptor,
-                                                sd->sizes[dentry->security_id], 0);
+                                                sd->sizes[dentry->inode->security_id], 0);
        #endif
                                
                if (ret != 0) {
@@ -307,9 +307,9 @@ static int apply_reparse_data(ntfs_inode *ni, const struct dentry *dentry,
        struct lookup_table_entry *lte;
        int ret = 0;
 
-       wimlib_assert(dentry->attributes & FILE_ATTRIBUTE_REPARSE_POINT);
+       wimlib_assert(dentry->inode->attributes & FILE_ATTRIBUTE_REPARSE_POINT);
 
-       lte = dentry_unnamed_lte(dentry, w->lookup_table);
+       lte = inode_unnamed_lte(dentry->inode, w->lookup_table);
 
        DEBUG("Applying reparse data to `%s'", dentry->full_path_utf8);
 
@@ -327,7 +327,7 @@ static int apply_reparse_data(ntfs_inode *ni, const struct dentry *dentry,
 
        u8 reparse_data_buf[8 + wim_resource_size(lte)];
        u8 *p = reparse_data_buf;
-       p = put_u32(p, dentry->reparse_tag); /* ReparseTag */
+       p = put_u32(p, dentry->inode->reparse_tag); /* ReparseTag */
        p = put_u16(p, wim_resource_size(lte)); /* ReparseDataLength */
        p = put_u16(p, 0); /* Reserved */
 
@@ -364,10 +364,10 @@ static int preapply_dentry_with_dos_name(struct dentry *dentry,
        struct dentry *dentry_with_dos_name;
 
        dentry_with_dos_name = NULL;
-       list_for_each_entry(other, &dentry->link_group_list,
-                           link_group_list)
-       {
-               if (dentry->parent == other->parent && other->short_name_len) {
+       inode_for_each_dentry(other, dentry->inode) {
+               if (other != dentry && (dentry->parent == other->parent)
+                   && other->short_name_len)
+               {
                        if (dentry_with_dos_name) {
                                ERROR("Found multiple DOS names for file `%s' "
                                      "in the same directory",
@@ -379,7 +379,7 @@ static int preapply_dentry_with_dos_name(struct dentry *dentry,
        }
        /* If there's a dentry with a DOS name, extract it first */
        if (dentry_with_dos_name
-           && !dentry_with_dos_name->extracted_file)
+           && !dentry_with_dos_name->inode->extracted_file)
        {
                char *p;
                const char *dir_name;
@@ -430,8 +430,9 @@ static int do_wim_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni,
        ntfs_inode *ni = NULL;
        bool is_hardlink = false;
        ntfs_volume *vol = dir_ni->vol;
+       struct inode *inode = dentry->inode;
 
-       if (dentry->attributes & FILE_ATTRIBUTE_DIRECTORY) {
+       if (inode->attributes & FILE_ATTRIBUTE_DIRECTORY) {
                type = S_IFDIR;
        } else {
                struct dentry *other;
@@ -446,26 +447,26 @@ static int do_wim_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni,
                }
 
                type = S_IFREG;
-               /* See if we can make a hard link */
-               list_for_each_entry(other, &dentry->link_group_list,
-                                   link_group_list) {
-                       if (other->extracted_file) {
-                               /* Already extracted another dentry in the hard
-                                * link group.  We can make a hard link instead
-                                * of extracting the file data. */
-                               ret = wim_apply_hardlink_ntfs(dentry, other,
+
+               if (inode->link_count > 1) {
+                       /* Already extracted another dentry in the hard link
+                        * group.  We can make a hard link instead of extracting
+                        * the file data. */
+                       if (inode->extracted_file) {
+                               ret = wim_apply_hardlink_ntfs(dentry, inode,
                                                              dir_ni, &ni);
                                is_hardlink = true;
-                               if (ret) {
+                               if (ret)
                                        goto out_close_dir_ni;
-                               } else {
-                                       dentry->extracted_file = dentry->full_path_utf8;
+                               else
                                        goto out_set_dos_name;
-                               }
                        }
+                       /* Can't make a hard link; extract the file itself */
+                       FREE(inode->extracted_file);
+                       inode->extracted_file = STRDUP(dentry->full_path_utf8);
+                       if (!inode->extracted_file)
+                               return WIMLIB_ERR_NOMEM;
                }
-               /* Can't make a hard link; extract the file itself */
-               dentry->extracted_file = dentry->full_path_utf8;
        }
 
        /* 
@@ -486,8 +487,8 @@ static int do_wim_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni,
 
        /* Write the data streams, unless this is a directory or reparse point
         * */
-       if (!dentry_is_directory(dentry) &&
-            !(dentry->attributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
+       if (!(inode->attributes & (FILE_ATTRIBUTE_REPARSE_POINT |
+                                  FILE_ATTRIBUTE_DIRECTORY))) {
                ret = write_ntfs_data_streams(ni, dentry, w);
                if (ret != 0)
                        goto out_close_dir_ni;
@@ -498,7 +499,7 @@ static int do_wim_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni,
        if (ret != 0)
                goto out_close_dir_ni;
 
-       if (dentry->attributes & FILE_ATTR_REPARSE_POINT) {
+       if (inode->attributes & FILE_ATTR_REPARSE_POINT) {
                ret = apply_reparse_data(ni, dentry, w);
                if (ret != 0)
                        goto out_close_dir_ni;
@@ -625,7 +626,7 @@ static int wim_apply_dentry_ntfs(struct dentry *dentry, void *arg)
        char orig;
        const char *dir_name;
 
-       if (dentry->extracted_file)
+       if (dentry_is_extracted(dentry))
                return 0;
 
        wimlib_assert(dentry->full_path_utf8);
@@ -677,9 +678,9 @@ static int wim_apply_dentry_timestamps(struct dentry *dentry, void *arg)
        }
 
        p = buf;
-       p = put_u64(p, dentry->creation_time);
-       p = put_u64(p, dentry->last_write_time);
-       p = put_u64(p, dentry->last_access_time);
+       p = put_u64(p, dentry->inode->creation_time);
+       p = put_u64(p, dentry->inode->last_write_time);
+       p = put_u64(p, dentry->inode->last_access_time);
        ret = ntfs_inode_set_times(ni, (const char*)buf, 3 * sizeof(u64), 0);
        if (ret != 0) {
                ERROR_WITH_ERRNO("Failed to set NTFS timestamps on `%s'",
@@ -696,11 +697,9 @@ static int wim_apply_dentry_timestamps(struct dentry *dentry, void *arg)
        return ret;
 }
 
-static int dentry_clear_extracted_file(struct dentry *dentry, void *ignore)
+static int dentry_set_unextracted(struct dentry *dentry, void *ignore)
 {
-       if (dentry->extracted_file != dentry->full_path_utf8)
-               FREE(dentry->extracted_file);
-       dentry->extracted_file = NULL;
+       dentry->is_extracted = false;
        return 0;
 }
 
@@ -722,8 +721,7 @@ static int do_wim_apply_image_ntfs(WIMStruct *w, const char *device, int extract
        args.w = w;
        root = wim_root_dentry(w);
 
-       for_dentry_in_tree(root, dentry_clear_extracted_file, NULL);
-
+       for_dentry_in_tree(root, dentry_set_unextracted, NULL);
        ret = for_dentry_in_tree(root, wim_apply_dentry_ntfs, &args);
        if (ret != 0)
                goto out;
index 9a8991e..6751754 100644 (file)
@@ -336,7 +336,7 @@ static int capture_ntfs_streams(struct dentry *dentry, ntfs_inode *ni,
                                lte->ntfs_loc = ntfs_loc;
                                lte->resource_location = RESOURCE_IN_NTFS_VOLUME;
                                if (type == AT_REPARSE_POINT) {
-                                       dentry->reparse_tag = reparse_tag;
+                                       dentry->inode->reparse_tag = reparse_tag;
                                        ntfs_loc->is_reparse_point = true;
                                        lte->resource_entry.original_size = data_size - 8;
                                        lte->resource_entry.size = data_size - 8;
@@ -355,14 +355,14 @@ static int capture_ntfs_streams(struct dentry *dentry, ntfs_inode *ni,
                }
                if (name_length == 0) {
                        /* Unnamed data stream.  Put the reference to it in the
-                        * dentry. */
-                       if (dentry->lte) {
+                        * dentry's inode. */
+                       if (dentry->inode->lte) {
                                ERROR("Found two un-named data streams for "
                                      "`%s'", path);
                                ret = WIMLIB_ERR_NTFS_3G;
                                goto out_free_lte;
                        }
-                       dentry->lte = lte;
+                       dentry->inode->lte = lte;
                } else {
                        /* Named data stream.  Put the reference to it in the
                         * alternate data stream entries */
@@ -373,7 +373,7 @@ static int capture_ntfs_streams(struct dentry *dentry, ntfs_inode *ni,
                                                         &stream_name_utf8_len);
                        if (!stream_name_utf8)
                                goto out_free_lte;
-                       new_ads_entry = dentry_add_ads(dentry, stream_name_utf8);
+                       new_ads_entry = inode_add_ads(dentry->inode, stream_name_utf8);
                        FREE(stream_name_utf8);
                        if (!new_ads_entry)
                                goto out_free_lte;
@@ -557,7 +557,7 @@ static int build_dentry_tree_ntfs_recursive(struct dentry **root_p,
        if (flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE)
                printf("Scanning `%s'\n", path);
 
-       root = new_dentry(path_basename(path));
+       root = new_dentry_with_inode(path_basename(path));
        if (!root)
                return WIMLIB_ERR_NOMEM;
        *root_p = root;
@@ -584,12 +584,12 @@ static int build_dentry_tree_ntfs_recursive(struct dentry **root_p,
                }
        }
 
-       root->creation_time    = le64_to_cpu(ni->creation_time);
-       root->last_write_time  = le64_to_cpu(ni->last_data_change_time);
-       root->last_access_time = le64_to_cpu(ni->last_access_time);
-       root->attributes       = le32_to_cpu(attributes);
-       root->link_group_id    = ni->mft_no;
-       root->resolved         = true;
+       root->inode->creation_time    = le64_to_cpu(ni->creation_time);
+       root->inode->last_write_time  = le64_to_cpu(ni->last_data_change_time);
+       root->inode->last_access_time = le64_to_cpu(ni->last_access_time);
+       root->inode->attributes       = le32_to_cpu(attributes);
+       root->inode->ino              = ni->mft_no;
+       root->inode->resolved         = true;
 
        if (attributes & FILE_ATTR_REPARSE_POINT) {
                /* Junction point, symbolic link, or other reparse point */
@@ -672,20 +672,20 @@ static int build_dentry_tree_ntfs_recursive(struct dentry **root_p,
                                                 ni, dir_ni, sd, ret);
        }
        if (ret > 0) {
-               root->security_id = sd_set_add_sd(sd_set, sd, ret);
-               if (root->security_id == -1) {
+               root->inode->security_id = sd_set_add_sd(sd_set, sd, ret);
+               if (root->inode->security_id == -1) {
                        ERROR("Out of memory");
                        return WIMLIB_ERR_NOMEM;
                }
                DEBUG("Added security ID = %u for `%s'",
-                     root->security_id, path);
+                     root->inode->security_id, path);
                ret = 0;
        } else if (ret < 0) {
                ERROR_WITH_ERRNO("Failed to get security information from "
                                 "`%s'", path);
                ret = WIMLIB_ERR_NTFS_3G;
        } else {
-               root->security_id = -1;
+               root->inode->security_id = -1;
                DEBUG("No security ID for `%s'", path);
        }
 #endif
index 7baaa15..5f97ed0 100644 (file)
@@ -1204,7 +1204,7 @@ int read_metadata_resource(WIMStruct *w, struct image_metadata *imd)
        dentry->prev   = dentry;
        if (ret != 0)
                goto out_free_dentry_tree;
-       list_add(&dentry->inode_dentry_list, &dentry->inode->dentry_list);
+       inode_add_dentry(dentry, dentry->inode);
 
        /* Now read the entire directory entry tree into memory. */
        DEBUG("Reading dentry tree");
@@ -1226,13 +1226,14 @@ int read_metadata_resource(WIMStruct *w, struct image_metadata *imd)
 
        for_dentry_in_tree(dentry, inode_table_insert, &inode_tab);
 
-       DEBUG("Fixing inconsistencies in the link groups");
+       DEBUG("Fixing inconsistencies in the hard link groups");
        ret = fix_inodes(&inode_tab, &inode_list);
        destroy_inode_table(&inode_tab);
        if (ret != 0)
                goto out_free_dentry_tree;
 
        DEBUG("Running miscellaneous verifications on the dentry tree");
+       for_lookup_table_entry(w->lookup_table, lte_zero_real_refcnt, NULL);
        ret = for_dentry_in_tree(dentry, verify_dentry, w);
        if (ret != 0)
                goto out_free_dentry_tree;
@@ -1240,6 +1241,7 @@ int read_metadata_resource(WIMStruct *w, struct image_metadata *imd)
        DEBUG("Done reading image metadata");
 
        imd->root_dentry   = dentry;
+       imd->inode_list = inode_list;
        goto out_free_buf;
 out_free_dentry_tree:
        free_dentry_tree(dentry, NULL);
index c7a3f8f..4e2f1d2 100644 (file)
@@ -239,6 +239,8 @@ struct image_metadata {
         * resource. */
        struct lookup_table_entry *metadata_lte;
 
+       struct hlist_head inode_list;
+
        /* True if the filesystem of the image has been modified.  If this is
         * the case, the memory for the filesystem is not freed when switching
         * to a different WIM image. */
index 4971589..e06ad05 100644 (file)
@@ -426,7 +426,7 @@ WIMLIBAPI int wimlib_write(WIMStruct *w, const char *path, int image, int flags)
        if (ret != 0)
                goto done;
 
-       for_lookup_table_entry(w->lookup_table, zero_out_refcnts, NULL);
+       for_lookup_table_entry(w->lookup_table, lte_zero_out_refcnt, NULL);
 
        w->write_flags = flags;
 
index dc67da2..85c17b4 100755 (executable)
@@ -19,11 +19,10 @@ imagex_info() {
 }
 
 cleanup() {
+       fusermount -u tmp &> /dev/null || true
        rm -rf dir* tmp* *.wim *.swm
 }
-trap cleanup exit
-fusermount -u tmp || true
-rm -rf tmp || true
+cleanup
 
 # Make test directory
 mkdir dir
@@ -528,3 +527,4 @@ done
 echo "**********************************************************"
 echo "                 Basic imagex tests passed                "
 echo "**********************************************************"
+cleanup