X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fmount_image.c;h=bca9e4390e473c7987ae04f0522ccf6ab91901c7;hp=3e9566b57404d23df9f8978a5754edfd042e4832;hb=52c44c6a506cdfae17fd5fd5c6611622d342c128;hpb=be5acf31aa8292dcd4a2829492faefb0b200d28f diff --git a/src/mount_image.c b/src/mount_image.c index 3e9566b5..bca9e439 100644 --- a/src/mount_image.c +++ b/src/mount_image.c @@ -39,6 +39,8 @@ #define FUSE_USE_VERSION 26 +#include /* sometimes required before */ + #include #include #include @@ -50,7 +52,6 @@ #include #include #include -#include #include #include @@ -144,6 +145,11 @@ struct wimfs_context { 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; @@ -442,14 +448,12 @@ wim_pathname_to_stream(const struct wimfs_context *ctx, * 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 @@ -459,14 +463,13 @@ wim_pathname_to_stream(const struct wimfs_context *ctx, */ 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) @@ -480,13 +483,19 @@ create_file(struct fuse_context *fuse_ctx, const char *path, 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; @@ -495,19 +504,19 @@ create_file(struct fuse_context *fuse_ctx, const char *path, 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; } @@ -716,7 +725,7 @@ extract_blob_to_staging_dir(struct wim_inode *inode, 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; @@ -939,17 +948,20 @@ delete_staging_dir(struct wimfs_context *ctx) 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 @@ -1001,12 +1013,13 @@ inode_close_fds(struct wim_inode *inode) 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); } @@ -1038,7 +1051,6 @@ renew_current_image(struct wimfs_context *ctx) goto err_put_replace_imd; new_blob->refcnt = 1; - new_blob->unhashed = 1; new_blob->is_metadata = 1; /* Make the image being moved available at a new index. Increments the @@ -1048,7 +1060,7 @@ renew_current_image(struct wimfs_context *ctx) if (ret) goto err_free_new_blob; - ret = xml_add_image(wim, ""); + ret = xml_add_image(wim->xml_info, NULL); if (ret) goto err_undo_append; @@ -1104,7 +1116,7 @@ commit_image(struct wimfs_context *ctx, int unmount_flags, mqd_t mq) } INIT_LIST_HEAD(&ctx->orig_blob_list); delete_empty_blobs(ctx); - xml_update_image_info(ctx->wim, ctx->wim->current_image); + mark_image_dirty(wim_get_current_image_metadata(ctx->wim)); write_flags = 0; @@ -1306,9 +1318,9 @@ wimfs_getxattr(const char *path, const char *name, char *value, 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 @@ -1381,7 +1393,7 @@ wimfs_getxattr(const char *path, const char *name, char *value, 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; @@ -1486,8 +1498,7 @@ wimfs_mkdir(const char *path, mode_t mode) 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); @@ -1549,11 +1560,7 @@ wimfs_mknod(const char *path, mode_t mode, dev_t rdev) !(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); @@ -1664,13 +1671,13 @@ wimfs_read(const char *path, char *buf, size_t size, 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; @@ -1704,18 +1711,15 @@ wimfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, 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; } @@ -1723,27 +1727,24 @@ wimfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, } 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 @@ -1902,11 +1903,9 @@ wimfs_symlink(const char *to, const char *from) 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) { @@ -2034,7 +2033,7 @@ wimfs_write(const char *path, const char *buf, size_t size, 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; @@ -2129,15 +2128,16 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir, /* Get the metadata for the image to mount. */ imd = wim_get_current_image_metadata(wim); - if (imd->modified) { - /* To avoid complicating things, we don't support mounting - * images to which in-memory modifications have already been - * made. */ + /* To avoid complicating things, we don't support mounting images to + * which in-memory modifications have already been made. */ + if (is_image_dirty(imd)) { ERROR("Cannot mount a modified WIM image!"); return WIMLIB_ERR_INVALID_PARAM; } if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) { + if (imd->refcnt > 1) + return WIMLIB_ERR_IMAGE_HAS_MULTIPLE_REFERENCES; ret = lock_wim_for_append(wim); if (ret) return ret; @@ -2204,12 +2204,14 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir, } } - /* 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. */ @@ -2296,6 +2298,7 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir, /* 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);