#define FUSE_USE_VERSION 26
+#include <sys/types.h> /* sometimes required before <attr/xattr.h> */
+
#include <attr/xattr.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/time.h>
-#include <sys/types.h>
#include <unistd.h>
#include <utime.h>
uid_t owner_uid;
gid_t owner_gid;
+ /* Absolute path to the mountpoint directory (may be needed for absolute
+ * symbolic link fixups) */
+ char *mountpoint_abspath;
+ size_t mountpoint_abspath_nchars;
+
/* Information about the staging directory for a read-write mount. */
int parent_dir_fd;
int staging_dir_fd;
* The path at which to create the first link to the new file. If a file
* already exists at this path, -EEXIST is returned.
* @mode
- * The UNIX mode for the new file. This is only honored if
+ * The UNIX mode for the new file. This is only fully honored if
* WIMLIB_MOUNT_FLAG_UNIX_DATA was passed to wimlib_mount_image().
* @rdev
* The device ID for the new file, encoding the major and minor device
* numbers. This is only honored if WIMLIB_MOUNT_FLAG_UNIX_DATA was passed
* to wimlib_mount_image().
- * @attributes
- * Windows file attributes to use for the new file.
* @dentry_ret
* On success, a pointer to the new dentry is returned here. Its d_inode
* member will point to the new inode that was created for it and added to
*/
static int
create_file(struct fuse_context *fuse_ctx, const char *path,
- mode_t mode, dev_t rdev, u32 attributes,
- struct wim_dentry **dentry_ret)
+ mode_t mode, dev_t rdev, struct wim_dentry **dentry_ret)
{
struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
struct wim_dentry *parent;
const char *basename;
- struct wim_dentry *new_dentry;
- struct wim_inode *new_inode;
+ struct wim_dentry *dentry;
+ struct wim_inode *inode;
parent = get_parent_dentry(wimfs_ctx->wim, path, WIMLIB_CASE_SENSITIVE);
if (!parent)
if (get_dentry_child_with_name(parent, basename, WIMLIB_CASE_SENSITIVE))
return -EEXIST;
- if (new_dentry_with_new_inode(basename, true, &new_dentry))
+ if (new_dentry_with_new_inode(basename, true, &dentry))
return -ENOMEM;
- new_inode = new_dentry->d_inode;
+ inode = dentry->d_inode;
+
+ inode->i_ino = wimfs_ctx->next_ino++;
- new_inode->i_ino = wimfs_ctx->next_ino++;
- new_inode->i_attributes = attributes;
+ /* Note: we still use FILE_ATTRIBUTE_NORMAL for device nodes, named
+ * pipes, and sockets. The real mode is in the UNIX metadata. */
+ if (S_ISDIR(mode))
+ inode->i_attributes = FILE_ATTRIBUTE_DIRECTORY;
+ else
+ inode->i_attributes = FILE_ATTRIBUTE_NORMAL;
if (wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) {
struct wimlib_unix_data unix_data;
unix_data.gid = fuse_ctx->gid;
unix_data.mode = fuse_mask_mode(mode, fuse_ctx);
unix_data.rdev = rdev;
- if (!inode_set_unix_data(new_inode, &unix_data, UNIX_DATA_ALL))
+ if (!inode_set_unix_data(inode, &unix_data, UNIX_DATA_ALL))
{
- free_dentry(new_dentry);
+ free_dentry(dentry);
return -ENOMEM;
}
}
- list_add_tail(&new_inode->i_list,
- &wim_get_current_image_metadata(wimfs_ctx->wim)->inode_list);
+ hlist_add_head(&inode->i_hlist_node,
+ &wim_get_current_image_metadata(wimfs_ctx->wim)->inode_list);
- dentry_add_child(parent, new_dentry);
+ dentry_add_child(parent, dentry);
- *dentry_ret = new_dentry;
+ *dentry_ret = dentry;
return 0;
}
filedes_init(&fd, staging_fd);
errno = 0;
extract_size = min(old_blob->size, size);
- result = extract_blob_to_fd(old_blob, &fd, extract_size);
+ result = extract_blob_prefix_to_fd(old_blob, extract_size, &fd);
} else {
extract_size = 0;
result = 0;
close(ctx->parent_dir_fd);
}
-/* Number the inodes in the mounted image sequentially. */
static void
-reassign_inode_numbers(struct wimfs_context *ctx)
+prepare_inodes(struct wimfs_context *ctx)
{
struct wim_image_metadata *imd;
struct wim_inode *inode;
ctx->next_ino = 1;
imd = wim_get_current_image_metadata(ctx->wim);
- image_for_each_inode(inode, imd)
+ image_for_each_inode(inode, imd) {
inode->i_ino = ctx->next_ino++;
+ inode->i_num_opened_fds = 0;
+ inode->i_num_allocated_fds = 0;
+ inode->i_fds = NULL;
+ }
}
static void
static void
close_all_fds(struct wimfs_context *ctx)
{
- struct wim_inode *inode, *tmp;
+ struct wim_inode *inode;
+ struct hlist_node *tmp;
struct wim_image_metadata *imd;
imd = wim_get_current_image_metadata(ctx->wim);
- list_for_each_entry_safe(inode, tmp, &imd->inode_list, i_list)
+ image_for_each_inode_safe(inode, tmp, imd)
inode_close_fds(inode);
}
size_t size)
{
const struct wimfs_context *ctx = wimfs_get_context();
- struct wim_inode *inode;
- struct wim_inode_stream *strm;
- struct blob_descriptor *blob;
+ const struct wim_inode *inode;
+ const struct wim_inode_stream *strm;
+ const struct blob_descriptor *blob;
if (!strncmp(name, "wimfs.", 6)) {
/* Handle some magical extended attributes. These really should
if (size < blob->size)
return -ERANGE;
- if (read_full_blob_into_buf(blob, value))
+ if (read_blob_into_buf(blob, value))
return errno ? -errno : -EIO;
}
return blob->size;
int ret;
/* Note: according to fuse.h, mode may not include S_IFDIR */
- ret = create_file(fuse_get_context(), path, mode | S_IFDIR, 0,
- FILE_ATTRIBUTE_DIRECTORY, &dentry);
+ ret = create_file(fuse_get_context(), path, mode | S_IFDIR, 0, &dentry);
if (ret)
return ret;
touch_parent(dentry);
!(wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
return -EPERM;
- /* Note: we still use FILE_ATTRIBUTE_NORMAL for device nodes,
- * named pipes, and sockets. The real mode is in the UNIX
- * metadata. */
- ret = create_file(fuse_ctx, path, mode, rdev,
- FILE_ATTRIBUTE_NORMAL, &dentry);
+ ret = create_file(fuse_ctx, path, mode, rdev, &dentry);
if (ret)
return ret;
touch_parent(dentry);
switch (blob->blob_location) {
case BLOB_IN_WIM:
- if (read_partial_wim_blob_into_buf(blob, size, offset, buf))
+ if (read_partial_wim_blob_into_buf(blob, offset, size, buf))
ret = errno ? -errno : -EIO;
else
ret = size;
break;
case BLOB_IN_STAGING_FILE:
- ret = raw_pread(&fd->f_staging_fd, buf, size, offset);
+ ret = pread(fd->f_staging_fd.fd, buf, size, offset);
if (ret < 0)
ret = -errno;
break;
return ret;
for_inode_child(child, inode) {
- char *file_name_mbs;
- size_t file_name_mbs_nbytes;
+ char *name;
+ size_t name_nbytes;
- ret = utf16le_to_tstr(child->file_name,
- child->file_name_nbytes,
- &file_name_mbs,
- &file_name_mbs_nbytes);
- if (ret)
+ if (utf16le_to_tstr(child->d_name, child->d_name_nbytes,
+ &name, &name_nbytes))
return -errno;
- ret = filler(buf, file_name_mbs, NULL, 0);
- FREE(file_name_mbs);
+ ret = filler(buf, name, NULL, 0);
+ FREE(name);
if (ret)
return ret;
}
}
static int
-wimfs_readlink(const char *path, char *buf, size_t buf_len)
+wimfs_readlink(const char *path, char *buf, size_t bufsize)
{
- WIMStruct *wim = wimfs_get_WIMStruct();
+ struct wimfs_context *ctx = wimfs_get_context();
const struct wim_inode *inode;
- ssize_t ret;
+ int ret;
- inode = wim_pathname_to_inode(wim, path);
+ inode = wim_pathname_to_inode(ctx->wim, path);
if (!inode)
return -errno;
- if (!inode_is_symlink(inode))
+ if (bufsize <= 0)
return -EINVAL;
- if (buf_len == 0)
- return -EINVAL;
- ret = wim_inode_readlink(inode, buf, buf_len - 1, NULL);
- if (ret >= 0) {
- buf[ret] = '\0';
- ret = 0;
- } else if (ret == -ENAMETOOLONG) {
- buf[buf_len - 1] = '\0';
- }
- return ret;
+ ret = wim_inode_readlink(inode, buf, bufsize - 1, NULL,
+ ctx->mountpoint_abspath,
+ ctx->mountpoint_abspath_nchars);
+ if (ret < 0)
+ return ret;
+ buf[ret] = '\0';
+ return 0;
}
/* We use this for both release() and releasedir(), since in both cases we
struct wim_dentry *dentry;
int ret;
- ret = create_file(fuse_ctx, from, S_IFLNK | 0777, 0,
- FILE_ATTRIBUTE_REPARSE_POINT, &dentry);
+ ret = create_file(fuse_ctx, from, S_IFLNK | 0777, 0, &dentry);
if (ret)
return ret;
- dentry->d_inode->i_reparse_tag = WIM_IO_REPARSE_TAG_SYMLINK;
ret = wim_inode_set_symlink(dentry->d_inode, to,
wimfs_ctx->wim->blob_table);
if (ret) {
struct wimfs_fd *fd = WIMFS_FD(fi);
ssize_t ret;
- ret = raw_pwrite(&fd->f_staging_fd, buf, size, offset);
+ ret = pwrite(fd->f_staging_fd.fd, buf, size, offset);
if (ret < 0)
return -errno;
}
}
- /* Assign new inode numbers. */
- reassign_inode_numbers(&ctx);
+ /* Number the inodes in the mounted image sequentially and initialize
+ * the file descriptor arrays */
+ prepare_inodes(&ctx);
/* If a read-write mount, mark the image as modified. */
if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)
imd->modified = 1;
+ /* Save the absolute path to the mountpoint directory. */
+ ctx.mountpoint_abspath = realpath(dir, NULL);
+ if (ctx.mountpoint_abspath)
+ ctx.mountpoint_abspath_nchars = strlen(ctx.mountpoint_abspath);
+
/* Build the FUSE command line. */
fuse_argc = 0;
/* Cleanup and return. */
if (ret)
ret = WIMLIB_ERR_FUSE;
+ FREE(ctx.mountpoint_abspath);
release_extra_refcnts(&ctx);
if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)
delete_staging_dir(&ctx);