Various fixes
authorEric Biggers <ebiggers3@gmail.com>
Sun, 19 Aug 2012 17:11:44 +0000 (12:11 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Sun, 19 Aug 2012 17:11:44 +0000 (12:11 -0500)
src/dentry.c
src/dentry.h
src/hardlink.c
src/lookup_table.c
src/lookup_table.h
src/mount.c
src/resource.c
src/wimlib_internal.h

index 92828bb4b6d267c14d3ac82b6ca4e4dfc2e2d5b8..76ec2decbe82fffa81c14f38bff25697baa047c1 100644 (file)
@@ -93,10 +93,17 @@ void dentry_to_stbuf(const struct dentry *dentry, struct stat *stbuf,
                stbuf->st_mode = S_IFREG | 0644;
 
        /* Use the size of the unnamed (default) file stream. */
-       if (table && (lte = __lookup_resource(table, dentry_hash(dentry))))
-               stbuf->st_size = lte->resource_entry.original_size;
-       else
+       if (table && (lte = __lookup_resource(table, dentry_hash(dentry)))) {
+               if (lte->staging_file_name) {
+                       struct stat native_stat;
+                       stat(lte->staging_file_name, &native_stat);
+                       stbuf->st_size = native_stat.st_size;
+               } else {
+                       stbuf->st_size = lte->resource_entry.original_size;
+               }
+       } else {
                stbuf->st_size = 0;
+       }
 
        stbuf->st_nlink   = dentry_link_group_size(dentry);
        stbuf->st_ino     = dentry->hard_link;
@@ -161,7 +168,7 @@ void dentry_remove_ads(struct dentry *dentry, struct ads_entry *sentry)
 {
        destroy_ads_entry(sentry);
        memcpy(sentry, sentry + 1,
-              (dentry->num_ads - (sentry - dentry->ads_entries))
+              (dentry->num_ads - (sentry - dentry->ads_entries + 1))
                 * sizeof(struct ads_entry));
        dentry->num_ads--;
 }
@@ -474,6 +481,7 @@ static inline void dentry_common_init(struct dentry *dentry)
        memset(dentry, 0, sizeof(struct dentry));
        dentry->refcnt = 1;
        dentry->security_id = -1;
+       dentry->link_group_master_status = GROUP_SLAVE;
 }
 
 /* 
@@ -515,17 +523,90 @@ void dentry_free_ads_entries(struct dentry *dentry)
        dentry->num_ads = 0;
 }
 
-
-void free_dentry(struct dentry *dentry)
+static void __destroy_dentry(struct dentry *dentry)
 {
        FREE(dentry->file_name);
        FREE(dentry->file_name_utf8);
        FREE(dentry->short_name);
        FREE(dentry->full_path_utf8);
-       dentry_free_ads_entries(dentry);
+}
+
+void free_dentry(struct dentry *dentry)
+{
+       __destroy_dentry(dentry);
+       if (dentry->link_group_master_status != GROUP_SLAVE)
+               dentry_free_ads_entries(dentry);
        FREE(dentry);
 }
 
+void put_dentry(struct dentry *dentry)
+{
+       if (dentry->link_group_master_status == GROUP_MASTER) {
+               struct dentry *new_master;
+               list_for_each_entry(new_master, &dentry->link_group_list,
+                                   link_group_list)
+               {
+                       if (new_master->link_group_master_status == GROUP_SLAVE) {
+                               new_master->link_group_master_status = GROUP_MASTER;
+                               dentry->link_group_master_status = GROUP_SLAVE;
+                               break;
+                       }
+               }
+       }
+       list_del(&dentry->link_group_list);
+       free_dentry(dentry);
+}
+
+static bool dentries_have_same_ads(const struct dentry *d1,
+                                  const struct dentry *d2)
+{
+       /* Verify stream names and hashes are the same */
+       for (u16 i = 0; i < d1->num_ads; i++) {
+               if (strcmp(d1->ads_entries[i].stream_name_utf8,
+                          d2->ads_entries[i].stream_name_utf8) != 0)
+                       return false;
+               if (memcmp(d1->ads_entries[i].hash,
+                          d2->ads_entries[i].hash,
+                          WIM_HASH_SIZE) != 0)
+                       return false;
+       }
+       return true;
+}
+
+/* Share the alternate stream entries between hard-linked dentries. */
+int share_dentry_ads(struct dentry *master, struct dentry *slave)
+{
+       const char *mismatch_type;
+       wimlib_assert(master->num_ads == 0 ||
+                     master->ads_entries != slave->ads_entries);
+       if (master->attributes != slave->attributes) {
+               mismatch_type = "attributes";
+               goto mismatch;
+       }
+       if (master->security_id != slave->security_id) {
+               mismatch_type = "security ID";
+               goto mismatch;
+       }
+       if (memcmp(master->hash, slave->hash, WIM_HASH_SIZE) != 0) {
+               mismatch_type = "main file resource";
+               goto mismatch;
+       }
+       if (!dentries_have_same_ads(master, slave)) {
+               mismatch_type = "Alternate Stream Entries";
+               goto mismatch;
+       }
+       dentry_free_ads_entries(slave);
+       slave->ads_entries = master->ads_entries;
+       slave->link_group_master_status = GROUP_SLAVE;
+       return 0;
+mismatch:
+       ERROR("Dentries `%s' and `%s' in the same hard-link group but "
+             "do not share the same %s",
+             master->full_path_utf8, slave->full_path_utf8,
+             mismatch_type);
+       return WIMLIB_ERR_INVALID_DENTRY;
+}
+
 /* clones a dentry.
  *
  * Beware:
@@ -622,7 +703,13 @@ void link_dentry(struct dentry *dentry, struct dentry *parent)
        }
 }
 
-/* Unlink a dentry from the directory tree. */
+
+/* Unlink a dentry from the directory tree. 
+ *
+ * Note: This merely removes it from the in-memory tree structure.  See
+ * remove_dentry() in mount.c for a function implemented on top of this one that
+ * frees the dentry and implements reference counting for the lookup table
+ * entries. */
 void unlink_dentry(struct dentry *dentry)
 {
        if (dentry_is_root(dentry))
@@ -648,36 +735,33 @@ static inline void recalculate_dentry_size(struct dentry *dentry)
        dentry->length = (dentry->length + 7) & ~7;
 }
 
-static int do_name_change(char **file_name_ret,
-                         char **file_name_utf8_ret,
-                         u16 *file_name_len_ret,
-                         u16 *file_name_utf8_len_ret,
-                         const char *new_name)
+int get_names(char **name_utf16_ret, char **name_utf8_ret,
+             u16 *name_utf16_len_ret, u16 *name_utf8_len_ret,
+             const char *name)
 {
        size_t utf8_len;
        size_t utf16_len;
-       char *file_name, *file_name_utf8;
+       char *name_utf16, *name_utf8;
 
-       utf8_len = strlen(new_name);
+       utf8_len = strlen(name);
 
-       file_name = utf8_to_utf16(new_name, utf8_len, &utf16_len);
+       name_utf8 = utf8_to_utf16(name, utf8_len, &utf16_len);
 
-       if (!file_name)
+       if (!name_utf8)
                return WIMLIB_ERR_NOMEM;
 
-       file_name_utf8 = MALLOC(utf8_len + 1);
-       if (!file_name_utf8) {
-               FREE(file_name);
+       name_utf8 = MALLOC(utf8_len + 1);
+       if (!name_utf8) {
+               FREE(name_utf8);
                return WIMLIB_ERR_NOMEM;
        }
-       memcpy(file_name_utf8, new_name, utf8_len + 1);
-
-       FREE(*file_name_ret);
-       FREE(*file_name_utf8_ret);
-       *file_name_ret          = file_name;
-       *file_name_utf8_ret     = file_name_utf8;
-       *file_name_len_ret      = utf16_len;
-       *file_name_utf8_len_ret = utf8_len;
+       memcpy(name_utf8, name, utf8_len + 1);
+       FREE(*name_utf8_ret);
+       FREE(*name_utf16_ret);
+       *name_utf8_ret      = name_utf8;
+       *name_utf16_ret     = name_utf16;
+       *name_utf8_len_ret  = utf8_len;
+       *name_utf16_len_ret = utf16_len;
        return 0;
 }
 
@@ -688,9 +772,9 @@ int change_dentry_name(struct dentry *dentry, const char *new_name)
 {
        int ret;
 
-       ret = do_name_change(&dentry->file_name, &dentry->file_name_utf8,
-                            &dentry->file_name_len, &dentry->file_name_utf8_len,
-                            new_name);
+       ret = get_names(&dentry->file_name, &dentry->file_name_utf8,
+                       &dentry->file_name_len, &dentry->file_name_utf8_len,
+                        new_name);
        if (ret == 0)
                recalculate_dentry_size(dentry);
        return ret;
@@ -698,10 +782,10 @@ int change_dentry_name(struct dentry *dentry, const char *new_name)
 
 int change_ads_name(struct ads_entry *entry, const char *new_name)
 {
-       return do_name_change(&entry->stream_name, &entry->stream_name_utf8,
-                             &entry->stream_name_len,
-                             &entry->stream_name_utf8_len,
-                             new_name);
+       return get_names(&entry->stream_name, &entry->stream_name_utf8,
+                        &entry->stream_name_len,
+                        &entry->stream_name_utf8_len,
+                         new_name);
 }
 
 /* Parameters for calculate_dentry_statistics(). */
index 251e86f6034c235a8323d5c0ce194114a95266dc..b14a2eef4090bb2acdebc920bc46db786e6ba345 100644 (file)
@@ -192,11 +192,22 @@ struct dentry {
        /* Alternate stream entries for this dentry. */
        struct ads_entry *ads_entries;
 
-       /* Number of references to the dentry tree itself, as in multiple
-        * WIMStructs */
-       int refcnt;
+       union {
+               /* Number of references to the dentry tree itself, as in multiple
+                * WIMStructs */
+               int refcnt;
+
+               /* Number of times this dentry has been opened (only for
+                * directories!) */
+               u32 num_times_opened;
+       };
 
        /* List of dentries in the hard link set */
+       enum {
+               GROUP_INDEPENDENT,
+               GROUP_MASTER,
+               GROUP_SLAVE
+       } link_group_master_status;
        struct list_head link_group_list;
 };
 
@@ -251,6 +262,9 @@ extern int for_dentry_in_tree_depth(struct dentry *root,
 
 extern int calculate_dentry_full_path(struct dentry *dentry, void *ignore);
 extern void calculate_subdir_offsets(struct dentry *dentry, u64 *subdir_offset_p);
+extern int get_names(char **name_utf16_ret, char **name_utf8_ret,
+                    u16 *name_utf16_len_ret, u16 *name_utf8_len_ret,
+                    const char *name);
 extern int change_dentry_name(struct dentry *dentry, const char *new_name);
 extern int change_ads_name(struct ads_entry *entry, const char *new_name);
 
@@ -270,6 +284,9 @@ extern struct dentry *new_dentry(const char *name);
 
 extern void dentry_free_ads_entries(struct dentry *dentry);
 extern void free_dentry(struct dentry *dentry);
+extern void put_dentry(struct dentry *dentry);
+extern int share_dentry_streams(struct dentry *master,
+                               struct dentry *slave);
 extern struct dentry *clone_dentry(struct dentry *old);
 extern void free_dentry_tree(struct dentry *root,
                             struct lookup_table *lookup_table, 
index 81eb10d4d54b529630cc6602e00083e41a16b71e..9a128d4619ed4e3d1d1aab5375513c4069ed022a 100644 (file)
@@ -141,13 +141,35 @@ u64 assign_link_groups(struct link_group_table *table)
        return id;
 }
 
-#if 0
-/* Load a dentry tree into the link group table */
-int load_link_groups(struct link_group_table *table, struct dentry *root)
+static int link_group_free_duplicate_data(struct link_group *group)
 {
-       int ret = for_dentry_in_tree(dentry, link_group_table_insert, table);
-       if (ret == 0)
-               assign_link_groups(table);
-       return ret;
+       struct list_head *head;
+       struct dentry *master;
+
+       head = group->dentry_list;
+       master = container_of(head, struct dentry, link_group_list);
+       head = head->next;
+       master->link_group_master_status = GROUP_MASTER;
+       while (head != group->dentry_list) {
+               int ret = share_dentry_ads(master,
+                                          container_of(head, struct dentry,
+                                                       link_group_list));
+               if (ret != 0)
+                       return ret;
+       }
+       return 0;
+}
+
+int link_groups_free_duplicate_data(struct link_group_table *table)
+{
+       for (u64 i = 0; i < table->capacity; i++) {
+               struct link_group *group = table->array[i];
+               while (group) {
+                       int ret = link_group_free_duplicate_data(group);
+                       if (ret != 0)
+                               return ret;
+                       group = group->next;
+               }
+       }
+       return 0;
 }
-#endif
index 9693cc1b8c823624821d88f62aa29cabb7899c1d..4df37ea2eb343ea2e2239e48c3e5316326a251d3 100644 (file)
@@ -118,7 +118,8 @@ void lookup_table_unlink(struct lookup_table *table,
 /* Decrement the reference count for the dentry having hash value @hash in the
  * lookup table.  The lookup table entry is unlinked and freed if there are no
  * references to in remaining.  */
-bool lookup_table_decrement_refcnt(struct lookup_table* table, const u8 hash[])
+struct lookup_table_entry *
+lookup_table_decrement_refcnt(struct lookup_table* table, const u8 hash[])
 {
        size_t pos = *(size_t*)hash % table->capacity;
        struct lookup_table_entry *prev = NULL;
@@ -129,19 +130,21 @@ bool lookup_table_decrement_refcnt(struct lookup_table* table, const u8 hash[])
                if (memcmp(hash, entry->hash, WIM_HASH_SIZE) == 0) {
                        wimlib_assert(entry->refcnt != 0);
                        if (--entry->refcnt == 0) {
-                               if (entry->num_opened_fds == 0)
+                               if (entry->num_opened_fds == 0) {
                                        free_lookup_table_entry(entry);
+                                       entry = NULL;
+                               }
                                if (prev)
                                        prev->next = next;
                                else
                                        table->array[pos] = next;
-                               return true;
+                               break;
                        }
                }
                prev = entry;
                entry = next;
        }
-       return false;
+       return entry;
 }
 
 
index 423af6dc702566b11cac42ce8745b25d7c6016f4..434b9d89a48bb5d39e388480c379a820bd6df1c2 100644 (file)
@@ -115,8 +115,8 @@ extern void lookup_table_insert(struct lookup_table *table,
 extern void lookup_table_unlink(struct lookup_table *table, 
                                struct lookup_table_entry *lte);
 
-extern bool lookup_table_decrement_refcnt(struct lookup_table* table, 
-                                         const u8 hash[]);
+extern struct lookup_table_entry *
+lookup_table_decrement_refcnt(struct lookup_table* table, const u8 hash[]);
 
 
 extern struct lookup_table_entry *new_lookup_table_entry();
index 0588746e91929eb65ab6327e7f5b01eec1846e0a..b8fe52784c0d85b4603e0f9eb85432337f4f0078 100644 (file)
@@ -146,6 +146,45 @@ static int close_wimlib_fd(struct wimlib_fd *fd)
        return 0;
 }
 
+static void remove_dentry(struct dentry *dentry,
+                         struct lookup_table *lookup_table)
+{
+       const u8 *hash = dentry->hash;
+       u16 i = 0;
+       struct lookup_table_entry *lte;
+       while (1) {
+               lte = lookup_table_decrement_refcnt(lookup_table, hash);
+               if (lte && lte->num_opened_fds)
+                       for (u16 i = 0; i < lte->num_allocated_fds; i++)
+                               if (lte->fds[i] && lte->fds[i]->dentry == dentry)
+                                       lte->fds[i]->dentry = NULL;
+               if (i == dentry->num_ads)
+                       break;
+               hash = dentry->ads_entries[i].hash;
+               i++;
+       }
+
+       unlink_dentry(dentry);
+       put_dentry(dentry);
+}
+
+static void dentry_increment_lookup_table_refcnts(struct dentry *dentry,
+                                                 struct lookup_table *lookup_table)
+{
+       u16 i = 0;
+       const u8 *hash = dentry->hash;
+       struct lookup_table_entry *lte;
+       while (1) {
+               lte = __lookup_resource(lookup_table, hash);
+               if (lte)
+                       lte->refcnt++;
+               if (i == dentry->num_ads)
+                       break;
+               hash = dentry->ads_entries[i].hash;
+               i++;
+       }
+}
+
 /* Creates a new staging file and returns its file descriptor opened for
  * writing.
  *
@@ -221,7 +260,7 @@ static int extract_resource_to_staging_dir(struct dentry *dentry,
        int fd;
        struct lookup_table_entry *old_lte, *new_lte;
        size_t link_group_size;
-       
+
        old_lte = *lte;
        fd = create_staging_file(&staging_file_name, O_WRONLY);
        if (fd == -1)
@@ -238,9 +277,7 @@ static int extract_resource_to_staging_dir(struct dentry *dentry,
                else
                        ret = -EIO;
                close(fd);
-               unlink(staging_file_name);
-               FREE(staging_file_name);
-               return ret;
+               goto out_delete_staging_file;
        }
 
        link_group_size = dentry_link_group_size(dentry);
@@ -266,8 +303,10 @@ static int extract_resource_to_staging_dir(struct dentry *dentry,
                        wimlib_assert(old_lte->refcnt > link_group_size);
 
                        new_lte = new_lookup_table_entry();
-                       if (!new_lte)
-                               return -ENOMEM;
+                       if (!new_lte) {
+                               ret = -ENOMEM;
+                               goto out_delete_staging_file;
+                       }
 
                        u16 num_transferred_fds = 0;
                        for (u16 i = 0; i < old_lte->num_allocated_fds; i++) {
@@ -282,7 +321,8 @@ static int extract_resource_to_staging_dir(struct dentry *dentry,
                                              sizeof(new_lte->fds[0]));
                        if (!new_lte->fds) {
                                free_lookup_table_entry(new_lte);
-                               return -ENOMEM;
+                               ret = -ENOMEM;
+                               goto out_delete_staging_file;
                        }
                        u16 j = 0;
                        for (u16 i = 0; i < old_lte->num_allocated_fds; i++) {
@@ -302,6 +342,12 @@ static int extract_resource_to_staging_dir(struct dentry *dentry,
                        new_lte->num_opened_fds = j;
 
                } 
+       } else {
+               new_lte = new_lookup_table_entry();
+               if (!new_lte) {
+                       ret = -ENOMEM;
+                       goto out_delete_staging_file;
+               }
        }
        new_lte->resource_entry.original_size = size;
        new_lte->refcnt = link_group_size;
@@ -311,6 +357,10 @@ static int extract_resource_to_staging_dir(struct dentry *dentry,
        lookup_table_insert(w->lookup_table, new_lte);
        *lte = new_lte;
        return 0;
+out_delete_staging_file:
+       unlink(staging_file_name);
+       FREE(staging_file_name);
+       return ret;
 }
 
 /* 
@@ -777,6 +827,7 @@ static int wimfs_link(const char *to, const char *from)
        }
        list_add(&from_dentry->link_group_list, &to_dentry->link_group_list);
        link_dentry(from_dentry, from_dentry_parent);
+       dentry_increment_lookup_table_refcnts(from_dentry, w->lookup_table);
        return 0;
 }
 
@@ -836,11 +887,14 @@ static int wimfs_mknod(const char *path, mode_t mode, dev_t rdev)
                        return -ENOENT;
                if (!dentry_is_directory(parent))
                        return -ENOTDIR;
+
                basename = path_basename(path);
                if (get_dentry_child_with_name(parent, path))
                        return -EEXIST;
 
                dentry = new_dentry(basename);
+               if (!dentry)
+                       return -ENOMEM;
                link_dentry(dentry, parent);
        }
        return 0;
@@ -872,10 +926,10 @@ static int wimfs_open(const char *path, struct fuse_file_info *fi)
                        return 0;
                }
 
-               ret = extract_resource_to_staging_dir(dentry, &lte,
-                                                     lte->resource_entry.original_size);
+               ret = extract_resource_to_staging_dir(dentry, &lte, 0);
                if (ret != 0)
                        return ret;
+               memcpy(dentry_hash, lte->hash, WIM_HASH_SIZE);
        }
 
        ret = alloc_wimlib_fd(lte, &fd);
@@ -896,6 +950,7 @@ static int wimfs_open(const char *path, struct fuse_file_info *fi)
                                                      lte->resource_entry.original_size);
                if (ret != 0)
                        return ret;
+               memcpy(dentry_hash, lte->hash, WIM_HASH_SIZE);
        }
        if (lte->staging_file_name) {
                fd->staging_fd = open(lte->staging_file_name, fi->flags);
@@ -914,8 +969,11 @@ static int wimfs_opendir(const char *path, struct fuse_file_info *fi)
        struct dentry *dentry;
        
        dentry = get_dentry(w, path);
-       if (!dentry || !dentry_is_directory(dentry))
+       if (!dentry)
+               return -ENOENT;
+       if (!dentry_is_directory(dentry))
                return -ENOTDIR;
+       dentry->num_times_opened++;
        fi->fh = (uint64_t)dentry;
        return 0;
 }
@@ -942,6 +1000,7 @@ static int wimfs_read(const char *path, char *buf, size_t size,
                wimlib_assert(fd->staging_fd != -1);
 
                ssize_t ret;
+               DEBUG("Seek to offset %zu", offset);
 
                if (lseek(fd->staging_fd, offset, SEEK_SET) == -1)
                        return -errno;
@@ -1026,15 +1085,38 @@ static int wimfs_release(const char *path, struct fuse_file_info *fi)
                wimlib_assert(!(mount_flags & WIMLIB_MOUNT_FLAG_READWRITE));
                return 0;
        }
+
+       if (flags_writable(fi->flags) && fd->dentry) {
+               u64 now = get_timestamp();
+               fd->dentry->last_access_time = now;
+               fd->dentry->last_write_time = now;
+       }
+
        return close_wimlib_fd(fd);
 }
 
+static int wimfs_releasedir(const char *path, struct fuse_file_info *fi)
+{
+       struct dentry *dentry = (struct dentry *)fi->fh;
+
+       wimlib_assert(dentry->num_times_opened);
+       if (--dentry->num_times_opened == 0)
+               free_dentry(dentry);
+       return 0;
+}
+
 /* Renames a file or directory.  See rename (3) */
 static int wimfs_rename(const char *from, const char *to)
 {
        struct dentry *src;
        struct dentry *dst;
        struct dentry *parent_of_dst;
+       char *file_name_utf16 = NULL, *file_name_utf8 = NULL;
+       u16 file_name_utf16_len, file_name_utf8_len;
+       int ret;
+
+       /* This rename() implementation currently only supports actual files
+        * (not alternate data streams) */
        
        src = get_dentry(w, from);
        if (!src)
@@ -1042,7 +1124,17 @@ static int wimfs_rename(const char *from, const char *to)
 
        dst = get_dentry(w, to);
 
+
+       ret = get_names(&file_name_utf16, &file_name_utf8,
+                       &file_name_utf16_len, &file_name_utf8_len,
+                       path_basename(to));
+       if (ret != 0)
+               return -ENOMEM;
+
        if (dst) {
+               if (src == dst) /* Same file */
+                       return 0;
+
                if (!dentry_is_directory(src)) {
                        /* Cannot rename non-directory to directory. */
                        if (dentry_is_directory(dst))
@@ -1056,19 +1148,22 @@ static int wimfs_rename(const char *from, const char *to)
                                return -ENOTEMPTY;
                }
                parent_of_dst = dst->parent;
-               unlink_dentry(dst);
-               lookup_table_decrement_refcnt(w->lookup_table, dst->hash);
-               free_dentry(dst);
+               remove_dentry(dst, w->lookup_table);
        } else {
                parent_of_dst = get_parent_dentry(w, to);
                if (!parent_of_dst)
                        return -ENOENT;
        }
 
+       FREE(src->file_name);
+       FREE(src->file_name_utf8);
+       src->file_name          = file_name_utf16;
+       src->file_name_utf8     = file_name_utf8;
+       src->file_name_len      = file_name_utf16_len;
+       src->file_name_utf8_len = file_name_utf8_len;
+
        unlink_dentry(src);
-       change_dentry_name(src, path_basename(to));
        link_dentry(src, parent_of_dst);
-       /*calculate_dentry_full_path(src);*/
        return 0;
 }
 
@@ -1085,7 +1180,8 @@ static int wimfs_rmdir(const char *path)
                return -ENOTEMPTY;
 
        unlink_dentry(dentry);
-       free_dentry(dentry);
+       if (dentry->num_times_opened == 0)
+               free_dentry(dentry);
        return 0;
 }
 
@@ -1174,18 +1270,7 @@ static int wimfs_unlink(const char *path)
        if (dentry_hash == dentry->hash) {
                /* We are removing the full dentry including all alternate data
                 * streams. */
-               const u8 *hash = dentry->hash;
-               u16 i = 0;
-               while (1) {
-                       lookup_table_decrement_refcnt(w->lookup_table, hash);
-                       if (i == dentry->num_ads)
-                               break;
-                       hash = dentry->ads_entries[i].hash;
-                       i++;
-               }
-
-               unlink_dentry(dentry);
-               free_dentry(dentry);
+               remove_dentry(dentry, w->lookup_table);
        } else {
                /* We are removing an alternate data stream. */
                struct ads_entry *cur_entry = dentry->ads_entries;
@@ -1236,36 +1321,33 @@ static int wimfs_write(const char *path, const char *buf, size_t size,
        if (ret == -1)
                return -errno;
 
-       /* The file has been modified, so all its timestamps must be
-        * updated. */
-       dentry_update_all_timestamps(fd->dentry);
-
        return ret;
 }
 
 
 static struct fuse_operations wimfs_operations = {
-       .access    = wimfs_access,
-       .destroy   = wimfs_destroy,
-       .fgetattr  = wimfs_fgetattr,
-       .ftruncate = wimfs_ftruncate,
-       .getattr   = wimfs_getattr,
-       .link      = wimfs_link,
-       .mkdir     = wimfs_mkdir,
-       .mknod     = wimfs_mknod,
-       .open      = wimfs_open,
-       .opendir   = wimfs_opendir,
-       .read      = wimfs_read,
-       .readdir   = wimfs_readdir,
-       .readlink  = wimfs_readlink,
-       .release   = wimfs_release,
-       .rename    = wimfs_rename,
-       .rmdir     = wimfs_rmdir,
-       .symlink   = wimfs_symlink,
-       .truncate  = wimfs_truncate,
-       .unlink    = wimfs_unlink,
-       .utimens   = wimfs_utimens,
-       .write     = wimfs_write,
+       .access     = wimfs_access,
+       .destroy    = wimfs_destroy,
+       .fgetattr   = wimfs_fgetattr,
+       .ftruncate  = wimfs_ftruncate,
+       .getattr    = wimfs_getattr,
+       .link       = wimfs_link,
+       .mkdir      = wimfs_mkdir,
+       .mknod      = wimfs_mknod,
+       .open       = wimfs_open,
+       .opendir    = wimfs_opendir,
+       .read       = wimfs_read,
+       .readdir    = wimfs_readdir,
+       .readlink   = wimfs_readlink,
+       .release    = wimfs_release,
+       .releasedir = wimfs_releasedir,
+       .rename     = wimfs_rename,
+       .rmdir      = wimfs_rmdir,
+       .symlink    = wimfs_symlink,
+       .truncate   = wimfs_truncate,
+       .unlink     = wimfs_unlink,
+       .utimens    = wimfs_utimens,
+       .write      = wimfs_write,
 };
 
 
index 731bd1c0c3ebb258cbd8462b33ae1aaf5456ab79..4b71cb3f6d60990db4a3e819cf09bd72804aa095 100644 (file)
@@ -1008,6 +1008,10 @@ int read_metadata_resource(FILE *fp, int wim_ctype, struct image_metadata *imd)
        if (ret != 0)
                goto out_free_lgt;
 
+       ret = link_groups_free_duplicate_data(lgt);
+       if (ret != 0)
+               goto out_free_lgt;
+
        imd->lgt           = lgt;
        imd->security_data = sd;
        imd->root_dentry   = dentry;
index d9c7775647063c3e3732c71338bd66b302ca874d..68ec73f53d6d83e039df099a7dc26e09974c917d 100644 (file)
@@ -333,6 +333,7 @@ int link_group_table_insert(struct dentry *dentry,
                            struct link_group_table *table);
 void free_link_group_table(struct link_group_table *table);
 u64 assign_link_groups(struct link_group_table *table);
+int link_groups_free_duplicate_data(struct link_group_table *table);
 
 
 /* header.c */