wimfs_write(), dentry_to_stbuf()
authorEric Biggers <ebiggers3@gmail.com>
Sun, 19 Aug 2012 21:35:08 +0000 (16:35 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Sun, 19 Aug 2012 21:35:08 +0000 (16:35 -0500)
src/dentry.c
src/dentry.h
src/hardlink.c
src/lookup_table.c
src/mount.c
src/resource.c

index 0c607e0b2360aa515d74d80f5d8ee0f75f58b9ff..ea21e07b57e90540adfccd65fb0485adeab3e39e 100644 (file)
@@ -80,13 +80,11 @@ void stbuf_to_dentry(const struct stat *stbuf, struct dentry *dentry)
 }
 
 /* Transfers file attributes from a struct dentry to a `stat' buffer. */
-void dentry_to_stbuf(const struct dentry *dentry, struct stat *stbuf, 
-                    const struct lookup_table *table)
+int dentry_to_stbuf(const struct dentry *dentry, struct stat *stbuf, 
+                   const struct lookup_table *table)
 {
        struct lookup_table_entry *lte;
 
-
-
        if (dentry_is_symlink(dentry))
                stbuf->st_mode = S_IFLNK | 0777;
        else if (dentry_is_directory(dentry))
@@ -94,7 +92,8 @@ void dentry_to_stbuf(const struct dentry *dentry, struct stat *stbuf,
        else
                stbuf->st_mode = S_IFREG | 0644;
 
-       stbuf->st_ino   = dentry->hard_link;
+       stbuf->st_ino = (ino_t)dentry->hard_link;
+
        stbuf->st_nlink = dentry_link_group_size(dentry);
        stbuf->st_uid   = getuid();
        stbuf->st_gid   = getgid();
@@ -103,7 +102,8 @@ void dentry_to_stbuf(const struct dentry *dentry, struct stat *stbuf,
        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);
+                       if (stat(lte->staging_file_name, &native_stat) != 0)
+                               return -errno;
                        stbuf->st_size = native_stat.st_size;
                } else {
                        stbuf->st_size = lte->resource_entry.original_size;
@@ -116,6 +116,7 @@ void dentry_to_stbuf(const struct dentry *dentry, struct stat *stbuf,
        stbuf->st_mtime   = ms_timestamp_to_unix(dentry->last_write_time);
        stbuf->st_ctime   = ms_timestamp_to_unix(dentry->creation_time);
        stbuf->st_blocks  = (stbuf->st_size + 511) / 512;
+       return 0;
 }
 
 /* Makes all timestamp fields for the dentry be the current time. */
@@ -556,7 +557,11 @@ void put_dentry(struct dentry *dentry)
                        }
                }
        }
+       struct list_head *next;
+       next = dentry->link_group_list.next;
        list_del(&dentry->link_group_list);
+       /*if (next->next == next)*/
+               /*container_of(next, struct dentry, link_group_list)->hard_link = 0;*/
        free_dentry(dentry);
 }
 
@@ -1171,8 +1176,13 @@ static u8 *write_dentry(const struct dentry *dentry, u8 *p)
                p = put_u32(p, dentry->reparse_tag);
                p = put_zeroes(p, 4);
        } else {
+               u64 hard_link;
                p = put_u32(p, dentry->reparse_tag);
-               p = put_u64(p, dentry->hard_link);
+               if (dentry->link_group_list.next == &dentry->link_group_list)
+                       hard_link = 0;
+               else
+                       hard_link = dentry->hard_link;
+               p = put_u64(p, hard_link);
        }
        p = put_u16(p, dentry->num_ads);
        p = put_u16(p, dentry->short_name_len);
index b14a2eef4090bb2acdebc920bc46db786e6ba345..3a3432eadbeafe36a41839235404b53b33884d2f 100644 (file)
@@ -249,8 +249,8 @@ extern u64 dentry_total_length(const struct dentry *dentry);
 
 extern void stbuf_to_dentry(const struct stat *stbuf, struct dentry *dentry);
 
-extern void dentry_to_stbuf(const struct dentry *dentry, struct stat *stbuf, 
-                           const struct lookup_table *table);
+extern int dentry_to_stbuf(const struct dentry *dentry, struct stat *stbuf, 
+                          const struct lookup_table *table);
 
 extern int for_dentry_in_tree(struct dentry *root, 
                              int (*visitor)(struct dentry*, void*), 
@@ -285,8 +285,8 @@ 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 int share_dentry_ads(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 e3f30b45b1513ca8f92261278db52dc4ab3ed4d5..4640c9cf12524471f7efb92b977e5c8ecaf73358 100644 (file)
@@ -13,13 +13,33 @@ struct link_group_table {
        struct link_group **array;
        u64 num_entries;
        u64 capacity;
+       struct link_group *singles;
 };
 
 #include <sys/mman.h>
 
 struct link_group_table *new_link_group_table(u64 capacity)
 {
-       return (struct link_group_table*)new_lookup_table(capacity);
+       struct link_group_table *table;
+       struct link_group **array;
+
+       table = MALLOC(sizeof(struct link_group_table));
+       if (!table)
+               goto err;
+       array = CALLOC(capacity, sizeof(array[0]));
+       if (!array) {
+               FREE(table);
+               goto err;
+       }
+       table->num_entries = 0;
+       table->capacity = capacity;
+       table->array = array;
+       table->singles = NULL;
+       return table;
+err:
+       ERROR("Failed to allocate memory for link group table with capacity %zu",
+             capacity);
+       return NULL;
 }
 
 /* Insert a dentry into the hard link group table based on its hard link group
@@ -37,7 +57,18 @@ int link_group_table_insert(struct dentry *dentry, struct link_group_table *tabl
        struct link_group *group;
 
        if (dentry->hard_link == 0) {
+               /* Single group--- Add to the singles list (we can't put it in
+                * the table itself because all the singles have a link group ID
+                * of 0) */
+               group = MALLOC(sizeof(struct link_group));
+               if (!group)
+                       return WIMLIB_ERR_NOMEM;
+               DEBUG("Insert single group `%s'", dentry->full_path_utf8);
+               group->link_group_id = 0;
+               group->next          = table->singles;
+               table->singles       = group;
                INIT_LIST_HEAD(&dentry->link_group_list);
+               group->dentry_list = &dentry->link_group_list;
                return 0;
        }
 
@@ -92,51 +123,46 @@ void free_link_group_table(struct link_group_table *table)
  * next available link group ID. */
 u64 assign_link_groups(struct link_group_table *table)
 {
-       struct link_group *remaining_groups = NULL;
+       DEBUG("Assigning link groups");
        u64 id = 1;
        for (u64 i = 0; i < table->capacity; i++) {
                struct link_group *group = table->array[i];
                struct link_group *next_group;
                struct dentry *dentry;
+               struct list_head *cur;
                while (group) {
-                       next_group = group->next;
-                       u64 cur_id;
-                       struct list_head *dentry_list = group->dentry_list;
-                       if (dentry_list->next == dentry_list) {
-                               /* Hard link group of size 1.  Change the hard
-                                * link ID to 0 and discard the link_group */
-                               cur_id = 0;
-                               FREE(group);
-                       } else {
-                               /* Hard link group of size > 1.  Assign the
-                                * dentries in the group the next available hard
-                                * link IDs and queue the group to be
-                                * re-inserted into the table. */
-                               cur_id = id++;
-                               group->next = remaining_groups;
-                               remaining_groups = group;
-                       }
-                       struct list_head *cur = dentry_list;
+                       cur = group->dentry_list;
                        do {
                                dentry = container_of(cur,
                                                      struct dentry,
                                                      link_group_list);
-                               dentry->hard_link = cur_id;
+                               dentry->hard_link = id;
                                cur = cur->next;
-                       } while (cur != dentry_list);
-                       group = next_group;
+                       } while (cur != group->dentry_list);
+                       id++;
+                       group = group->next;
                }
        }
-       memset(table->array, 0, table->capacity * sizeof(table->array[0]));
-       table->num_entries = 0;
-       while (remaining_groups) {
-               struct link_group *group = remaining_groups;
-               size_t pos = group->link_group_id % table->capacity;
-
-               table->num_entries++;
-               group->next = table->array[pos];
-               table->array[pos] = group;
-               remaining_groups = remaining_groups->next;
+       /* Singles */
+       struct link_group *single = table->singles;
+       while (single) {
+               struct dentry *dentry;
+               struct link_group *next_single;
+               size_t pos;
+
+               next_single = single->next;
+
+               dentry = container_of(single->dentry_list, struct dentry,
+                                     link_group_list);
+               dentry->hard_link = id;
+               DEBUG("Assign single `%s'", dentry->full_path_utf8);
+
+               pos = id % table->capacity;
+               single->next = table->array[pos];
+               table->array[pos] = single;
+
+               single = next_single;
+               id++;
        }
        return id;
 }
index 4df37ea2eb343ea2e2239e48c3e5316326a251d3..6ad8872f37c579bdebb1782c04066d448939f53a 100644 (file)
@@ -261,7 +261,8 @@ int write_lookup_table_entry(struct lookup_table_entry *lte, void *__out)
                return 0;
 
        if (lte->output_resource_entry.flags & WIM_RESHDR_FLAG_METADATA)
-               DEBUG("Writing metadata entry at %lu", ftello(out));
+               DEBUG("Writing metadata entry at %lu (orig size = %zu)",
+                     ftello(out), lte->output_resource_entry.original_size);
 
        p = put_resource_entry(buf, &lte->output_resource_entry);
        p = put_u16(p, lte->part_number);
index 7817c58e0a980b9e88b22a538d1b4c07c5e2b3ef..289516f7c09921b55298dcc0e6d72b044d091b2f 100644 (file)
@@ -73,6 +73,10 @@ static int mount_flags;
 /* Name of the directory on which the WIM file is mounted. */
 static const char *mount_dir;
 
+/* Next hard link group ID to be assigned.  These are also used as the inode
+ * numbers. */
+static u64 next_link_group_id;
+
 
 static inline int get_lookup_flags()
 {
@@ -139,8 +143,11 @@ static int close_wimlib_fd(struct wimlib_fd *fd)
                if (close(fd->staging_fd) != 0)
                        return -errno;
        }
-       if (--lte->num_opened_fds == 0 && lte->refcnt == 0)
+       if (--lte->num_opened_fds == 0 && lte->refcnt == 0) {
+               if (lte->staging_file_name)
+                       unlink(lte->staging_file_name);
                free_lookup_table_entry(lte);
+       }
        lte->fds[fd->idx] = NULL;
        FREE(fd);
        return 0;
@@ -779,8 +786,7 @@ static int wimfs_fgetattr(const char *path, struct stat *stbuf,
                          struct fuse_file_info *fi)
 {
        struct wimlib_fd *fd = (struct wimlib_fd*)fi->fh;
-       dentry_to_stbuf(fd->dentry, stbuf, w->lookup_table);
-       return 0;
+       return dentry_to_stbuf(fd->dentry, stbuf, w->lookup_table);
 }
 
 static int wimfs_ftruncate(const char *path, off_t size,
@@ -802,8 +808,7 @@ static int wimfs_getattr(const char *path, struct stat *stbuf)
        struct dentry *dentry = get_dentry(w, path);
        if (!dentry)
                return -ENOENT;
-       dentry_to_stbuf(dentry, stbuf, w->lookup_table);
-       return 0;
+       return dentry_to_stbuf(dentry, stbuf, w->lookup_table);
 }
 
 /* Create a hard link */
@@ -905,6 +910,7 @@ static int wimfs_mknod(const char *path, mode_t mode, dev_t rdev)
                dentry = new_dentry(basename);
                if (!dentry)
                        return -ENOMEM;
+               dentry->hard_link = next_link_group_id++;
                link_dentry(dentry, parent);
        }
        return 0;
@@ -1273,10 +1279,6 @@ static int wimfs_unlink(const char *path)
        if (ret != 0)
                return ret;
 
-       if (lte && lte->staging_file_name)
-               if (unlink(lte->staging_file_name) != 0)
-                       return -errno;
-
        if (dentry_hash == dentry->hash) {
                /* We are removing the full dentry including all alternate data
                 * streams. */
@@ -1326,6 +1328,10 @@ static int wimfs_write(const char *path, const char *buf, size_t size,
        wimlib_assert(fd->lte->staging_file_name);
        wimlib_assert(fd->staging_fd != -1);
 
+       /* Seek to the requested position */
+       if (lseek(fd->staging_fd, offset, SEEK_SET) == -1)
+               return -errno;
+
        /* Write the data. */
        ret = write(fd->staging_fd, buf, size);
        if (ret == -1)
@@ -1381,6 +1387,10 @@ WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir,
        if (ret != 0)
                return ret;
 
+       DEBUG("Selected image %d", image);
+
+       next_link_group_id = assign_link_groups(wim->image_metadata[image - 1].lgt);
+
        if (flags & WIMLIB_MOUNT_FLAG_READWRITE)
                wim_get_current_image_metadata(wim)->modified = true;
 
index 6ca59c917f3bb272dde54a2c5effcf06ae570a03..48f54804576a3d68fdb25d308fe4d8d26dc61e01 100644 (file)
@@ -1015,6 +1015,7 @@ int read_metadata_resource(FILE *fp, int wim_ctype, struct image_metadata *imd)
        ret = link_groups_free_duplicate_data(lgt);
        if (ret != 0)
                goto out_free_lgt;
+       DEBUG("Done reading image metadata");
 
        imd->lgt           = lgt;
        imd->security_data = sd;
@@ -1090,6 +1091,9 @@ int write_metadata_resource(WIMStruct *w)
        if (ret != 0)
                return ret;
 
+       DEBUG("Updating metadata lookup table entry (size %zu)",
+             metadata_original_size);
+
        /* Update the lookup table entry, including the hash and output resource
         * entry fields, for this image's metadata resource.  */
        lte = wim_metadata_lookup_table_entry(w);