* numbers. */
static u64 next_link_group_id;
+/* List of lookup table entries in the staging directory */
+static LIST_HEAD(staging_list);
static inline int get_lookup_flags()
{
}
}
+/* Change the hash value of the main or alternate file stream in a hard link
+ * group. This needs to be done if the hash of the corresponding lookup table
+ * entry was changed. */
+static void link_group_set_stream_hash(struct dentry *dentry,
+ unsigned stream_idx,
+ const u8 new_hash[])
+{
+ struct list_head *head, *cur;
+
+ if (stream_idx == 0) {
+ head = &dentry->link_group_list;
+ cur = head;
+ do {
+ dentry = container_of(cur, struct dentry, link_group_list);
+ memcpy(dentry->hash, new_hash, WIM_HASH_SIZE);
+ cur = cur->next;
+ } while (cur != head);
+ } else {
+ /* Dentries in the link group share their alternate stream
+ * entries. */
+ wimlib_assert(stream_idx <= dentry->num_ads);
+ memcpy(dentry->ads_entries[stream_idx - 1].hash, new_hash,
+ WIM_HASH_SIZE);
+ }
+}
+
/* Creates a new staging file and returns its file descriptor opened for
* writing.
*
new_lte->num_allocated_fds = num_transferred_fds;
}
} else {
+ /* No old_lte was supplied, so the resource had no lookup table
+ * entry before (it must be an empty resource) */
new_lte = new_lookup_table_entry();
if (!new_lte) {
ret = -ENOMEM;
new_lte->staging_file_name = staging_file_name;
lookup_table_insert(w->lookup_table, new_lte);
+ list_add(&new_lte->staging_list, &staging_list);
*lte = new_lte;
return 0;
out_delete_staging_file:
/* Closes the staging file descriptor associated with the lookup table entry, if
* it is opened. */
-static int close_lte_fds(struct lookup_table_entry *lte, void *ignore)
+static int close_lte_fds(struct lookup_table_entry *lte)
{
- for (u16 i = 0; i < lte->num_opened_fds; i++) {
+ for (u16 i = 0, j = 0; j < lte->num_opened_fds; i++) {
if (lte->fds[i] && lte->fds[i]->staging_fd != -1) {
if (close(lte->fds[i]->staging_fd) != 0) {
ERROR_WITH_ERRNO("Failed close file `%s'",
lte->staging_file_name);
return WIMLIB_ERR_WRITE;
}
+ j++;
}
}
return 0;
* file. Updates the SHA1 sum in the dentry and the lookup table entry. If
* there is already a lookup table entry with the same checksum, increment its
* reference count and destroy the lookup entry with the updated checksum. */
-static int calculate_sha1sum_for_staging_file(struct dentry *dentry,
- void *_lookup_table)
+static int calculate_sha1sum_of_staging_file(struct dentry *dentry,
+ void *__lookup_table)
{
- struct lookup_table *lookup_table = _lookup_table;
+ struct lookup_table *lookup_table = __lookup_table;
u8 *hash = dentry->hash;
u16 i = 0;
while (1) {
static int rebuild_wim(WIMStruct *w, bool check_integrity)
{
int ret;
- struct dentry *root;
-
- root = wim_root_dentry(w);
+ struct lookup_table_entry *lte;
- DEBUG("Closing all staging file descriptors.");
/* Close all the staging file descriptors. */
- ret = for_lookup_table_entry(w->lookup_table, close_lte_fds, NULL);
- if (ret != 0) {
- ERROR("Failed to close all staging files");
- return ret;
+ DEBUG("Closing all staging file descriptors.");
+ list_for_each_entry(lte, &staging_list, staging_list) {
+ ret = close_lte_fds(lte);
+ if (ret != 0)
+ return ret;
}
- DEBUG("Calculating SHA1 checksums for all new staging files.");
/* Calculate SHA1 checksums for all staging files, and merge unnecessary
* lookup table entries. */
- ret = for_dentry_in_tree(root, calculate_sha1sum_for_staging_file,
- w->lookup_table);
- if (ret != 0) {
- ERROR("Failed to calculate new SHA1 checksums");
+ DEBUG("Calculating SHA1 checksums for all new staging files.");
+ ret = for_dentry_in_tree(wim_root_dentry(w),
+ calculate_sha1sum_of_staging_file, w->lookup_table);
+ if (ret != 0)
return ret;
- }
xml_update_image_info(w, w->current_image);
/* Called when the filesystem is unmounted. */
static void wimfs_destroy(void *p)
{
-
/* For read-write mounts, the `imagex unmount' command, which is
* running in a separate process and is executing the
* wimlib_unmount() function, will send this process a byte
close_message_queues();
}
+static int wimfs_fallocate(const char *path, int mode,
+ off_t offset, off_t len, struct fuse_file_info *fi)
+{
+ struct wimlib_fd *fd = (struct wimlib_fd*)fi->fh;
+ wimlib_assert(fd->staging_fd != -1);
+ return fallocate(fd->staging_fd, mode, offset, len);
+}
+
static int wimfs_fgetattr(const char *path, struct stat *stbuf,
struct fuse_file_info *fi)
{
return dentry_to_stbuf(dentry, stbuf, w->lookup_table);
}
+static int wimfs_getxattr(const char *path, const char *name, char *value,
+ size_t size)
+{
+ /* XXX */
+ return -ENOTSUP;
+}
+
/* Create a hard link */
static int wimfs_link(const char *to, const char *from)
{
return 0;
}
+static int wimfs_listxattr(const char *path, char *list, size_t size)
+{
+ /* XXX */
+ return -ENOTSUP;
+}
+
/*
* Create a directory in the WIM.
* @mode is currently ignored.
u8 *dentry_hash;
int ret;
struct wimlib_fd *fd;
+ unsigned stream_idx;
ret = lookup_resource(w, path, get_lookup_flags(), &dentry, <e,
- &dentry_hash);
+ &stream_idx);
if (ret != 0)
return ret;
ret = extract_resource_to_staging_dir(dentry, <e, 0);
if (ret != 0)
return ret;
- memcpy(dentry_hash, lte->hash, WIM_HASH_SIZE);
+ link_group_set_stream_hash(dentry, stream_idx, lte->hash);
}
ret = alloc_wimlib_fd(lte, &fd);
lte->resource_entry.original_size);
if (ret != 0)
return ret;
- memcpy(dentry_hash, lte->hash, WIM_HASH_SIZE);
+ link_group_set_stream_hash(dentry, stream_idx, lte->hash);
}
if (lte->staging_file_name) {
fd->staging_fd = open(lte->staging_file_name, fi->flags);
return 0;
}
+static int wimfs_removexattr(const char *path, const char *name)
+{
+ /* XXX */
+ return -ENOTSUP;
+}
+
/* Renames a file or directory. See rename (3) */
static int wimfs_rename(const char *from, const char *to)
{
return 0;
}
+static int wimfs_setxattr(const char *path, const char *name,
+ const char *value, size_t size, int flags)
+{
+ /* XXX */
+ return -ENOTSUP;
+}
+
static int wimfs_symlink(const char *to, const char *from)
{
struct dentry *dentry_parent, *dentry;
struct dentry *dentry;
struct lookup_table_entry *lte;
int ret;
- u8 *dentry_hash;
ret = lookup_resource(w, path, get_lookup_flags(), &dentry,
- <e, &dentry_hash);
+ <e, NULL);
if (ret != 0)
return ret;
struct lookup_table_entry *lte;
int ret;
u8 *dentry_hash;
+ unsigned stream_idx;
ret = lookup_resource(w, path, get_lookup_flags(), &dentry,
- <e, &dentry_hash);
+ <e, &stream_idx);
if (ret != 0)
return ret;
- if (dentry_hash == dentry->hash) {
+ if (stream_idx == 0) {
/* We are removing the full dentry including all alternate data
* streams. */
remove_dentry(dentry, w->lookup_table);
} else {
/* We are removing an alternate data stream. */
- struct ads_entry *cur_entry = dentry->ads_entries;
- while (cur_entry->hash != dentry_hash)
- cur_entry++;
- lookup_table_decrement_refcnt(w->lookup_table, cur_entry->hash);
+ struct ads_entry *ads_entry;
+
+ ads_entry = &dentry->ads_entries[stream_idx - 1];
+
+ lookup_table_decrement_refcnt(w->lookup_table, ads_entry->hash);
- dentry_remove_ads(dentry, cur_entry);
+ dentry_remove_ads(dentry, ads_entry);
}
/* Beware: The lookup table entry(s) may still be referenced by users
* that have opened the corresponding streams. They are freed later in
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,
- .releasedir = wimfs_releasedir,
- .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,
+ .fallocate = wimfs_fallocate,
+ .fgetattr = wimfs_fgetattr,
+ .ftruncate = wimfs_ftruncate,
+ .getattr = wimfs_getattr,
+ .getxattr = wimfs_getxattr,
+ .link = wimfs_link,
+ .listxattr = wimfs_listxattr,
+ .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,
+ .removexattr = wimfs_removexattr,
+ .rename = wimfs_rename,
+ .rmdir = wimfs_rmdir,
+ .setxattr = wimfs_setxattr,
+ .symlink = wimfs_symlink,
+ .truncate = wimfs_truncate,
+ .unlink = wimfs_unlink,
+ .utimens = wimfs_utimens,
+ .write = wimfs_write,
};