}
/* 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))
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();
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;
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. */
}
}
}
+ 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);
}
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);
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*),
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,
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
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;
}
* 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;
}
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);
/* 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()
{
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;
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,
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 */
dentry = new_dentry(basename);
if (!dentry)
return -ENOMEM;
+ dentry->hard_link = next_link_group_id++;
link_dentry(dentry, parent);
}
return 0;
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. */
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)
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;
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;
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);