From 2a7e6a7d014689899c90a926a095a53753488967 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 19 Aug 2012 16:35:08 -0500 Subject: [PATCH] wimfs_write(), dentry_to_stbuf() --- src/dentry.c | 24 ++++++++---- src/dentry.h | 8 ++-- src/hardlink.c | 92 +++++++++++++++++++++++++++++----------------- src/lookup_table.c | 3 +- src/mount.c | 28 +++++++++----- src/resource.c | 4 ++ 6 files changed, 105 insertions(+), 54 deletions(-) diff --git a/src/dentry.c b/src/dentry.c index 0c607e0b..ea21e07b 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -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); diff --git a/src/dentry.h b/src/dentry.h index b14a2eef..3a3432ea 100644 --- a/src/dentry.h +++ b/src/dentry.h @@ -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, diff --git a/src/hardlink.c b/src/hardlink.c index e3f30b45..4640c9cf 100644 --- a/src/hardlink.c +++ b/src/hardlink.c @@ -13,13 +13,33 @@ struct link_group_table { struct link_group **array; u64 num_entries; u64 capacity; + struct link_group *singles; }; #include 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; } diff --git a/src/lookup_table.c b/src/lookup_table.c index 4df37ea2..6ad8872f 100644 --- a/src/lookup_table.c +++ b/src/lookup_table.c @@ -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, <e->output_resource_entry); p = put_u16(p, lte->part_number); diff --git a/src/mount.c b/src/mount.c index 7817c58e..289516f7 100644 --- a/src/mount.c +++ b/src/mount.c @@ -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; diff --git a/src/resource.c b/src/resource.c index 6ca59c91..48f54804 100644 --- a/src/resource.c +++ b/src/resource.c @@ -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); -- 2.43.0