* filesystem anyway. */
u64 next_ino;
- /* List of lookup table entries for files in the staging directory */
- struct list_head staging_list;
-
/* List of inodes in the mounted image */
- struct hlist_head *image_inode_list;
+ struct list_head *image_inode_list;
/* Name and message queue descriptors for message queues between the
* filesystem daemon process and the unmount process. These are used
memset(ctx, 0, sizeof(*ctx));
ctx->unmount_to_daemon_mq = (mqd_t)-1;
ctx->daemon_to_unmount_mq = (mqd_t)-1;
- INIT_LIST_HEAD(&ctx->staging_list);
}
#define WIMFS_CTX(fuse_ctx) ((struct wimfs_context*)(fuse_ctx)->private_data)
fd->f_inode->i_ino, fd->f_inode->i_num_opened_fds,
fd->f_inode->i_num_allocated_fds);
ret = lte_put_fd(fd->f_lte, fd);
- if (ret != 0)
+ if (ret)
return ret;
inode_put_fd(fd->f_inode, fd);
return 0;
}
+static mode_t
+fuse_mask_mode(mode_t mode, struct fuse_context *fuse_ctx)
+{
+#if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 8)
+ mode &= ~fuse_ctx->umask;
+#endif
+ return mode;
+}
+
/*
* Add a new dentry with a new inode to a WIM image.
*
if (inode_set_unix_data(new->d_inode,
fuse_ctx->uid,
fuse_ctx->gid,
- mode & ~fuse_ctx->umask,
+ fuse_mask_mode(mode, fuse_ctx),
wimfs_ctx->wim->lookup_table,
UNIX_DATA_ALL | UNIX_DATA_CREATE))
{
}
}
dentry_add_child(parent, new);
- hlist_add_head(&new->d_inode->i_hlist, wimfs_ctx->image_inode_list);
+ list_add_tail(&new->d_inode->i_list, wimfs_ctx->image_inode_list);
if (dentry_ret)
*dentry_ret = new;
return 0;
lte_decrement_refcnt(lte, lookup_table);
}
unlink_dentry(dentry);
- put_dentry(dentry);
+ free_dentry(dentry);
}
static mode_t
}
}
- new_lte->refcnt = inode->i_nlink;
- new_lte->resource_location = RESOURCE_IN_STAGING_FILE;
- new_lte->staging_file_name = staging_file_name;
- new_lte->lte_inode = inode;
+ new_lte->refcnt = inode->i_nlink;
+ new_lte->resource_location = RESOURCE_IN_STAGING_FILE;
+ new_lte->staging_file_name = staging_file_name;
+ new_lte->resource_entry.original_size = size;
- if (stream_id == 0)
- inode->i_lte = new_lte;
- else
- for (u16 i = 0; i < inode->i_num_ads; i++)
- if (inode->i_ads_entries[i].stream_id == stream_id)
- inode->i_ads_entries[i].lte = new_lte;
-
- lookup_table_insert_unhashed(ctx->wim->lookup_table, new_lte);
- list_add_tail(&new_lte->staging_list, &ctx->staging_list);
+ lookup_table_insert_unhashed(ctx->wim->lookup_table, new_lte,
+ inode, stream_id);
+ *retrieve_lte_pointer(new_lte) = new_lte;
*lte = new_lte;
return 0;
out_revert_fd_changes:
return ret;
}
-static void
-inode_update_lte_ptr(struct wim_inode *inode,
- struct wim_lookup_table_entry *old_lte,
- struct wim_lookup_table_entry *new_lte)
-{
- if (inode->i_lte == old_lte) {
- inode->i_lte = new_lte;
- } else {
- for (unsigned i = 0; i < inode->i_num_ads; i++) {
- if (inode->i_ads_entries[i].lte == old_lte) {
- inode->i_ads_entries[i].lte = new_lte;
- break;
- }
- }
- }
-}
-
-static void
-free_lte_if_unneeded(struct wim_lookup_table_entry *lte)
-{
-
- if (wim_resource_size(lte) == 0) {
- /* Zero-length stream. No lookup table entry needed. */
- inode_update_lte_ptr(lte->lte_inode, lte, NULL);
- free_lookup_table_entry(lte);
- }
-}
-
static int
inode_close_fds(struct wim_inode *inode)
{
int ret;
struct wim_lookup_table_entry *lte, *tmp;
WIMStruct *w = ctx->wim;
+ struct wim_image_metadata *imd = wim_get_current_image_metadata(ctx->wim);
DEBUG("Closing all staging file descriptors.");
- list_for_each_entry_safe(lte, tmp, &ctx->staging_list, staging_list) {
- ret = inode_close_fds(lte->lte_inode);
- if (ret != 0)
+ image_for_each_unhashed_stream_safe(lte, tmp, imd) {
+ ret = inode_close_fds(lte->back_inode);
+ if (ret)
return ret;
}
DEBUG("Freeing entries for zero-length streams");
- list_for_each_entry_safe(lte, tmp, &ctx->staging_list, staging_list)
- free_lte_if_unneeded(lte);
+ image_for_each_unhashed_stream_safe(lte, tmp, imd) {
+ wimlib_assert(lte->unhashed);
+ if (wim_resource_size(lte) == 0) {
+ struct wim_lookup_table_entry **back_ptr;
+ back_ptr = retrieve_lte_pointer(lte);
+ *back_ptr = NULL;
+ list_del(<e->unhashed_list);
+ free_lookup_table_entry(lte);
+ }
+ }
xml_update_image_info(w, w->current_image);
- list_splice(&ctx->staging_list,
- &w->image_metadata[w->current_image - 1].unhashed_streams);
ret = wimlib_overwrite(w, write_flags, 0, progress_func);
- if (ret != 0)
+ if (ret)
ERROR("Failed to commit changes to mounted WIM image");
return ret;
}
return 0;
}
-#if 0
-static int wimfs_access(const char *path, int mask)
-{
- return -ENOSYS;
-}
-#endif
-
static int
wimfs_chmod(const char *path, mode_t mask)
{
}
}
-#if 0
-static int wimfs_fallocate(const char *path, int mode,
- off_t offset, off_t len, struct fuse_file_info *fi)
-{
- struct wimfs_fd *fd = (struct wimfs_fd*)(uintptr_t)fi->fh;
- wimlib_assert(fd->staging_fd != -1);
- return fallocate(fd->staging_fd, mode, offset, len);
-}
-
-#endif
-
static int
wimfs_fgetattr(const char *path, struct stat *stbuf,
struct fuse_file_info *fi)
if (res_size > size)
return -ERANGE;
- ret = read_full_resource_into_buf(lte, value, true);
- if (ret != 0)
+ ret = read_full_resource_into_buf(lte, value);
+ if (ret)
return -EIO;
return res_size;
struct wim_dentry *from_dentry, *from_dentry_parent;
const char *link_name;
struct wim_inode *inode;
- struct wim_lookup_table_entry *lte;
WIMStruct *w = wimfs_get_WIMStruct();
- u16 i;
int ret;
inode = wim_pathname_to_inode(w, to);
if (ret)
return -ENOMEM;
- inode_add_dentry(from_dentry, inode);
- from_dentry->d_inode = inode;
inode->i_nlink++;
-
- for (i = 0; i <= inode->i_num_ads; i++) {
- lte = inode_stream_lte_resolved(inode, i);
- if (lte)
- lte->refcnt++;
- }
+ inode_ref_streams(inode);
+ from_dentry->d_inode = inode;
+ inode_add_dentry(from_dentry, inode);
dentry_add_child(from_dentry_parent, from_dentry);
return 0;
}
u16 stream_idx;
u32 stream_id;
struct wimfs_context *ctx = wimfs_get_context();
+ struct wim_lookup_table_entry **back_ptr;
ret = lookup_resource(ctx->wim, path, get_lookup_flags(ctx),
&dentry, <e, &stream_idx);
- if (ret != 0)
+ if (ret)
return ret;
inode = dentry->d_inode;
- if (stream_idx == 0)
+ if (stream_idx == 0) {
stream_id = 0;
- else
+ back_ptr = &inode->i_lte;
+ } else {
stream_id = inode->i_ads_entries[stream_idx - 1].stream_id;
+ back_ptr = &inode->i_ads_entries[stream_idx - 1].lte;
+ }
/* The file resource may be in the staging directory (read-write mounts
* only) or in the WIM. If it's in the staging directory, we need to
u64 size = (lte) ? wim_resource_size(lte) : 0;
ret = extract_resource_to_staging_dir(inode, stream_id,
<e, size, ctx);
- if (ret != 0)
+ if (ret)
return ret;
+ *back_ptr = lte;
}
ret = alloc_wimfs_fd(inode, stream_id, lte, &fd,
wimfs_ctx_readonly(ctx));
- if (ret != 0)
+ if (ret)
return ret;
if (lte && lte->resource_location == RESOURCE_IN_STAGING_FILE) {
if (!fd)
return -EBADF;
- if (!fd->f_lte) /* Empty stream with no lookup table entry */
+ if (size == 0)
return 0;
- res_size = wim_resource_size(fd->f_lte);
+ if (fd->f_lte)
+ res_size = wim_resource_size(fd->f_lte);
+ else
+ res_size = 0;
+
if (offset > res_size)
return -EOVERFLOW;
- size = min(size, INT_MAX);
+
size = min(size, res_size - offset);
+ if (size == 0)
+ return 0;
switch (fd->f_lte->resource_location) {
case RESOURCE_IN_STAGING_FILE:
- ret = pread(fd->staging_fd, buf, size, offset);
- if (ret < 0)
+ ret = full_pread(fd->staging_fd, buf, size, offset);
+ if (ret != size)
ret = -errno;
break;
case RESOURCE_IN_WIM:
if (read_partial_wim_resource_into_buf(fd->f_lte, size,
- offset, buf, true))
+ offset, buf))
ret = -errno;
- ret = size;
+ else
+ ret = size;
break;
case RESOURCE_IN_ATTACHED_BUFFER:
memcpy(buf, fd->f_lte->attached_buffer + offset, size);
return -errno;
if (!inode_is_symlink(inode))
return -EINVAL;
-
- ret = inode_readlink(inode, buf, buf_len, ctx->wim, true);
- if (ret > 0)
+ if (buf_len == 0)
+ return -ENAMETOOLONG;
+ ret = wim_inode_readlink(inode, buf, buf_len - 1);
+ if (ret >= 0) {
+ wimlib_assert(ret <= buf_len - 1);
+ buf[ret] = '\0';
ret = 0;
+ } else if (ret == -ENAMETOOLONG) {
+ buf[buf_len - 1] = '\0';
+ }
return ret;
}
static int
wimfs_rename(const char *from, const char *to)
{
- struct wim_dentry *src;
- struct wim_dentry *dst;
- struct wim_dentry *parent_of_dst;
- WIMStruct *w = wimfs_get_WIMStruct();
- int ret;
-
- /* This rename() implementation currently only supports actual files
- * (not alternate data streams) */
-
- src = get_dentry(w, from);
- if (!src)
- return -errno;
-
- dst = get_dentry(w, to);
-
- if (dst) {
- /* Destination file exists */
-
- if (src == dst) /* Same file */
- return 0;
-
- if (!dentry_is_directory(src)) {
- /* Cannot rename non-directory to directory. */
- if (dentry_is_directory(dst))
- return -EISDIR;
- } else {
- /* Cannot rename directory to a non-directory or a non-empty
- * directory */
- if (!dentry_is_directory(dst))
- return -ENOTDIR;
- if (inode_has_children(dst->d_inode))
- return -ENOTEMPTY;
- }
- parent_of_dst = dst->parent;
- } else {
- /* Destination does not exist */
- parent_of_dst = get_parent_dentry(w, to);
- if (!parent_of_dst)
- return -errno;
-
- if (!dentry_is_directory(parent_of_dst))
- return -ENOTDIR;
- }
-
- ret = set_dentry_name(src, path_basename(to));
- if (ret != 0)
- return -ENOMEM;
- if (dst)
- remove_dentry(dst, w->lookup_table);
- unlink_dentry(src);
- dentry_add_child(parent_of_dst, src);
- return 0;
+ return rename_wim_path(wimfs_get_WIMStruct(), from, to);
}
/* Remove a directory */
FILE_ATTRIBUTE_REPARSE_POINT, &dentry);
if (ret == 0) {
dentry->d_inode->i_reparse_tag = WIM_IO_REPARSE_TAG_SYMLINK;
- if (inode_set_symlink(dentry->d_inode, to,
- wimfs_ctx->wim->lookup_table, NULL))
- {
+ ret = wim_inode_set_symlink(dentry->d_inode, to,
+ wimfs_ctx->wim->lookup_table);
+ if (ret) {
remove_dentry(dentry, wimfs_ctx->wim->lookup_table);
- ret = -ENOMEM;
+ if (ret == WIMLIB_ERR_NOMEM)
+ ret = -ENOMEM;
+ else
+ ret = -EIO;
}
}
return ret;
if (lte == NULL && size == 0)
return 0;
- inode = dentry->d_inode;
- if (stream_idx == 0)
- stream_id = 0;
- else
- stream_id = inode->i_ads_entries[stream_idx - 1].stream_id;
-
if (lte->resource_location == RESOURCE_IN_STAGING_FILE) {
ret = truncate(lte->staging_file_name, size);
- if (ret != 0)
+ if (ret)
ret = -errno;
+ else
+ lte->resource_entry.original_size = size;
} else {
/* File in WIM. Extract it to the staging directory, but only
* the first @size bytes of it. */
+ struct wim_lookup_table_entry **back_ptr;
+
+ inode = dentry->d_inode;
+ if (stream_idx == 0) {
+ stream_id = 0;
+ back_ptr = &inode->i_lte;
+ } else {
+ stream_id = inode->i_ads_entries[stream_idx - 1].stream_id;
+ back_ptr = &inode->i_ads_entries[stream_idx - 1].lte;
+ }
ret = extract_resource_to_staging_dir(inode, stream_id,
<e, size, ctx);
+ *back_ptr = lte;
}
- if (ret == 0)
- lte->resource_entry.original_size = size;
return ret;
}
wimlib_assert(fd->f_inode != NULL);
/* Write the data. */
- ret = pwrite(fd->staging_fd, buf, size, offset);
- if (ret == -1)
+ ret = full_pwrite(fd->staging_fd, buf, size, offset);
+ if (ret != size)
return -errno;
/* Update file size */
- if (offset + size > fd->f_lte->resource_entry.original_size)
+ if (offset + size > fd->f_lte->resource_entry.original_size) {
+ DEBUG("Update file size %"PRIu64 " => %"PRIu64"",
+ fd->f_lte->resource_entry.original_size,
+ offset + size);
fd->f_lte->resource_entry.original_size = offset + size;
+ }
/* Update timestamps */
touch_inode(fd->f_inode);
}
static struct fuse_operations wimfs_operations = {
-#if 0
- .access = wimfs_access,
-#endif
.chmod = wimfs_chmod,
.chown = wimfs_chown,
.destroy = wimfs_destroy,
-#if 0
- .fallocate = wimfs_fallocate,
-#endif
.fgetattr = wimfs_fgetattr,
.ftruncate = wimfs_ftruncate,
.getattr = wimfs_getattr,
struct wim_lookup_table *joined_tab, *wim_tab_save;
struct wim_image_metadata *imd;
struct wimfs_context ctx;
- struct hlist_node *cur_node;
struct wim_inode *inode;
DEBUG("Mount: wim = %p, image = %d, dir = %s, flags = %d, ",
wim, image, dir, mount_flags);
- if (!wim || !dir)
- return WIMLIB_ERR_INVALID_PARAM;
+ if (!wim || !dir) {
+ ret = WIMLIB_ERR_INVALID_PARAM;
+ goto out;
+ }
ret = verify_swm_set(wim, additional_swms, num_additional_swms);
- if (ret != 0)
- return ret;
+ if (ret)
+ goto out;
if ((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) && (wim->hdr.total_parts != 1)) {
ERROR("Cannot mount a split WIM read-write");
- return WIMLIB_ERR_SPLIT_UNSUPPORTED;
+ ret = WIMLIB_ERR_SPLIT_UNSUPPORTED;
+ goto out;
}
if (num_additional_swms) {
ret = new_joined_lookup_table(wim, additional_swms,
num_additional_swms,
&joined_tab);
- if (ret != 0)
- return ret;
+ if (ret)
+ goto out;
wim_tab_save = wim->lookup_table;
wim->lookup_table = joined_tab;
}
if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
ret = wim_run_full_verifications(wim);
- if (ret != 0)
- goto out;
+ if (ret)
+ goto out_restore_lookup_table;
}
+ ret = wim_checksum_unhashed_streams(wim);
+ if (ret)
+ goto out_restore_lookup_table;
+
ret = select_wim_image(wim, image);
- if (ret != 0)
- goto out;
+ if (ret)
+ goto out_restore_lookup_table;
DEBUG("Selected image %d", image);
imd = wim_get_current_image_metadata(wim);
- if (imd->root_dentry->refcnt != 1) {
+ if (imd->refcnt != 1) {
ERROR("Cannot mount image that was just exported with "
"wimlib_export_image()");
ret = WIMLIB_ERR_INVALID_PARAM;
- goto out;
+ goto out_restore_lookup_table;
}
- if (imd->inode_list.first) /* May be unneeded? */
- imd->inode_list.first->pprev = &imd->inode_list.first;
-
if (imd->modified) {
ERROR("Cannot mount image that was added "
"with wimlib_add_image()");
ret = WIMLIB_ERR_INVALID_PARAM;
- goto out;
+ goto out_restore_lookup_table;
}
if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
- ret = lock_wim(wim, wim->fp);
- if (ret != 0)
- goto out;
+ ret = lock_wim(wim, wim->in_fd);
+ if (ret)
+ goto out_restore_lookup_table;
}
/* Use default stream interface if one was not specified */
WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)))
mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR;
-
DEBUG("Initializing struct wimfs_context");
init_wimfs_context(&ctx);
ctx.wim = wim;
ctx.image_inode_list = &imd->inode_list;
ctx.default_uid = getuid();
ctx.default_gid = getgid();
+ wimlib_assert(list_empty(&imd->unhashed_streams));
+ ctx.wim->lookup_table->unhashed_streams = &imd->unhashed_streams;
if (mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
ctx.default_lookup_flags = LOOKUP_FLAG_ADS_OK;
DEBUG("Unlinking message queues in case they already exist");
ret = set_message_queue_names(&ctx, dir);
- if (ret != 0)
+ if (ret)
goto out_unlock;
unlink_message_queues(&ctx);
if ((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)) {
/* Read-write mount. Make the staging directory */
ret = make_staging_dir(&ctx, staging_dir);
- if (ret != 0)
+ if (ret)
goto out_free_dir_copy;
} else {
/* Read-only mount */
#endif
/* Mark dentry tree as modified if read-write mount. */
- if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
+ if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)
imd->modified = 1;
- imd->has_been_mounted_rw = 1;
- }
/* Resolve the lookup table entries for every inode in the image, and
* assign inode numbers */
DEBUG("Resolving lookup table entries and assigning inode numbers");
ctx.next_ino = 1;
- hlist_for_each_entry(inode, cur_node, &imd->inode_list, i_hlist) {
+ image_for_each_inode(inode, imd) {
inode_resolve_ltes(inode, wim->lookup_table);
inode->i_ino = ctx.next_ino++;
}
wim->wim_locked = 0;
out_free_message_queue_names:
free_message_queue_names(&ctx);
-out:
+out_restore_lookup_table:
if (num_additional_swms) {
free_lookup_table(wim->lookup_table);
wim->lookup_table = wim_tab_save;
}
+out:
return ret;
}