X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fmount_image.c;h=0672c9c223834bf56c3f58ae4716586091be6671;hp=f8e733d872116cb3b0aa455d632f87e8320d4199;hb=b5fae0e5ddac332b25856e3df7556aa3ee7f69fb;hpb=0b1ef651852d008d61771c3386c2922aeab1f462 diff --git a/src/mount_image.c b/src/mount_image.c index f8e733d8..0672c9c2 100644 --- a/src/mount_image.c +++ b/src/mount_image.c @@ -1,29 +1,27 @@ /* * mount_image.c * - * This file implements mounting of WIM files using FUSE, which stands for - * Filesystem in Userspace. FUSE allows a filesystem to be implemented in a - * userspace process by implementing the filesystem primitives--- read(), - * write(), readdir(), etc. + * This file implements mounting of WIM images using FUSE + * (Filesystem in Userspace). See http://fuse.sourceforge.net/. + * + * Currently it is only expected to work on Linux. */ /* * Copyright (C) 2012, 2013, 2014 Eric Biggers * - * This file is part of wimlib, a library for working with WIM files. - * - * wimlib is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. + * This file is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) any + * later version. * - * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. See the GNU General Public License for more + * This file is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * - * You should have received a copy of the GNU General Public License - * along with wimlib; if not, see http://www.gnu.org/licenses/. + * You should have received a copy of the GNU Lesser General Public License + * along with this file; if not, see http://www.gnu.org/licenses/. */ #ifdef HAVE_CONFIG_H @@ -41,6 +39,7 @@ #include "wimlib/dentry.h" #include "wimlib/encoding.h" +#include "wimlib/lookup_table.h" #include "wimlib/metadata.h" #include "wimlib/paths.h" #include "wimlib/progress.h" @@ -325,15 +324,7 @@ close_wimfs_fd(struct wimfs_fd *fd) if (fd->f_idx < inode->i_next_fd) inode->i_next_fd = fd->f_idx; FREE(fd); - if (--inode->i_num_opened_fds == 0) { - /* The last file descriptor to this inode was closed. */ - FREE(inode->i_fds); - inode->i_fds = NULL; - inode->i_num_allocated_fds = 0; - if (inode->i_nlink == 0) - /* No links to this inode remain. Get rid of it. */ - free_inode(inode); - } + inode_dec_num_opened_fds(inode); return ret; } @@ -373,12 +364,12 @@ wim_pathname_to_stream(const struct wimfs_context *ctx, const char *path, int lookup_flags, struct wim_dentry **dentry_ret, struct wim_lookup_table_entry **lte_ret, - u16 *stream_idx_ret) + unsigned *stream_idx_ret) { WIMStruct *wim = ctx->wim; struct wim_dentry *dentry; struct wim_lookup_table_entry *lte; - u16 stream_idx; + unsigned stream_idx; const char *stream_name = NULL; struct wim_inode *inode; char *p = NULL; @@ -389,21 +380,20 @@ wim_pathname_to_stream(const struct wimfs_context *ctx, const char *path, stream_name = path_stream_name(path); if (stream_name) { p = (char *)stream_name - 1; - *p = T('\0'); + *p = '\0'; } } dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE); if (p) - *p = T(':'); + *p = ':'; if (!dentry) return -errno; inode = dentry->d_inode; - if (!inode->i_resolved) - if (inode_resolve_streams(inode, wim->lookup_table, false)) - return -EIO; + if (inode_resolve_streams(inode, wim->lookup_table, false)) + return -EIO; if (!(lookup_flags & LOOKUP_FLAG_DIRECTORY_OK) && inode_is_directory(inode)) @@ -505,8 +495,7 @@ create_dentry(struct fuse_context *fuse_ctx, const char *path, dentry_add_child(parent, new_dentry); - if (dentry_ret) - *dentry_ret = new_dentry; + *dentry_ret = new_dentry; return 0; } @@ -594,11 +583,11 @@ inode_to_stbuf(const struct wim_inode *inode, stbuf->st_mtim = wim_timestamp_to_timespec(inode->i_last_write_time); stbuf->st_ctim = stbuf->st_mtim; #else - stbuf->st_atime = wim_timestamp_to_unix(inode->i_last_access_time); - stbuf->st_mtime = wim_timestamp_to_unix(inode->i_last_write_time); + stbuf->st_atime = wim_timestamp_to_time_t(inode->i_last_access_time); + stbuf->st_mtime = wim_timestamp_to_time_t(inode->i_last_write_time); stbuf->st_ctime = stbuf->st_mtime; #endif - stbuf->st_blocks = (stbuf->st_size + 511) / 512; + stbuf->st_blocks = DIV_ROUND_UP(stbuf->st_size, 512); return 0; } @@ -606,7 +595,7 @@ inode_to_stbuf(const struct wim_inode *inode, static void touch_inode(struct wim_inode *inode) { - u64 now = get_wim_timestamp(); + u64 now = now_as_wim_timestamp(); inode->i_last_access_time = now; inode->i_last_write_time = now; } @@ -683,7 +672,7 @@ retry: */ static int extract_resource_to_staging_dir(struct wim_inode *inode, - u16 stream_idx, + unsigned stream_idx, struct wim_lookup_table_entry **lte_ptr, off_t size, const struct wimfs_context *ctx) @@ -944,7 +933,7 @@ out_restore_wim_filename: return ret; } -/* Deletes the staging directory, undoing the effects of a succesful call to +/* Deletes the staging directory, undoing the effects of a successful call to * make_staging_dir(). */ static void delete_staging_dir(struct wimfs_context *ctx) @@ -966,6 +955,7 @@ 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) { @@ -992,6 +982,8 @@ release_extra_refcnts(struct wimfs_context *ctx) } } +/* Delete the 'struct wim_lookup_table_entry' for any stream that was modified + * or created in the read-write mounted image and had a final size of 0. */ static void delete_empty_streams(struct wimfs_context *ctx) { @@ -1009,6 +1001,9 @@ delete_empty_streams(struct wimfs_context *ctx) } } +/* Close all file descriptors open to the specified inode. + * + * Note: closing the last file descriptor might free the inode. */ static void inode_close_fds(struct wim_inode *inode) { @@ -1021,6 +1016,7 @@ inode_close_fds(struct wim_inode *inode) } } +/* Close all file descriptors open to the mounted image. */ static void close_all_fds(struct wimfs_context *ctx) { @@ -1069,7 +1065,7 @@ renew_current_image(struct wimfs_context *ctx) if (ret) goto err_free_new_lte; - ret = xml_add_image(wim, T("")); + ret = xml_add_image(wim, ""); if (ret) goto err_undo_append; @@ -1128,16 +1124,20 @@ commit_image(struct wimfs_context *ctx, int unmount_flags, mqd_t mq) xml_update_image_info(ctx->wim, ctx->wim->current_image); write_flags = 0; + if (unmount_flags & WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY) write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY; + if (unmount_flags & WIMLIB_UNMOUNT_FLAG_REBUILD) write_flags |= WIMLIB_WRITE_FLAG_REBUILD; + if (unmount_flags & WIMLIB_UNMOUNT_FLAG_RECOMPRESS) write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS; + return wimlib_overwrite(ctx->wim, write_flags, 0); } -/* In the case of an allow_other mount, only the owner and root should be +/* In the case of an allow_other mount, only the mount owner and root are * allowed to unmount the filesystem. */ static bool may_unmount_wimfs(void) @@ -1149,6 +1149,7 @@ may_unmount_wimfs(void) fuse_ctx->uid == 0); } +/* Unmount the mounted image, called from the daemon process. */ static int unmount_wimfs(void) { @@ -1172,6 +1173,11 @@ unmount_wimfs(void) } if (wimfs_ctx->num_open_fds) { + + /* There are still open file descriptors to the image. */ + + /* With COMMIT, refuse to unmount unless FORCE is also + * specified. */ if ((unmount_flags & (WIMLIB_UNMOUNT_FLAG_COMMIT | WIMLIB_UNMOUNT_FLAG_FORCE)) == WIMLIB_UNMOUNT_FLAG_COMMIT) @@ -1179,16 +1185,20 @@ unmount_wimfs(void) ret = WIMLIB_ERR_MOUNTED_IMAGE_IS_BUSY; goto out; } + + /* Force-close all file descriptors. */ close_all_fds(wimfs_ctx); } if (unmount_flags & WIMLIB_UNMOUNT_FLAG_COMMIT) ret = commit_image(wimfs_ctx, unmount_flags, mq); else - ret = 0; + ret = 0; /* Read-only mount, or discarding changes to + a read-write mount */ + out: /* Leave the image mounted if commit failed, unless this is a - * forced unmount. The user can retry without commit if they + * forced unmount. The user can retry without COMMIT if they * want. */ if (!ret || (unmount_flags & WIMLIB_UNMOUNT_FLAG_FORCE)) { unlock_wim_for_append(wimfs_ctx->wim); @@ -1298,11 +1308,11 @@ wimfs_getattr(const char *path, struct stat *stbuf) static int copy_xattr(char *dest, size_t destsize, const void *src, size_t srcsize) { - if (!destsize) - return srcsize; - if (destsize < srcsize) - return -ERANGE; - memcpy(dest, src, srcsize); + if (destsize) { + if (destsize < srcsize) + return -ERANGE; + memcpy(dest, src, srcsize); + } return srcsize; } @@ -1380,11 +1390,11 @@ wimfs_getxattr(const char *path, const char *name, char *value, return -EFBIG; if (size) { - if (lte->size > size) + if (size < lte->size) return -ERANGE; if (read_full_stream_into_buf(lte, value)) - return -errno; + return errno ? -errno : -EIO; } return lte->size; } @@ -1421,12 +1431,10 @@ wimfs_link(const char *existing_path, const char *new_path) if (new_dentry(new_name, &new_alias)) return -ENOMEM; - new_alias->d_inode = inode; - inode_add_dentry(new_alias, inode); + inode_ref_streams(inode); + d_associate(new_alias, inode); dentry_add_child(dir, new_alias); touch_inode(dir->d_inode); - inode->i_nlink++; - inode_ref_streams(inode); return 0; } @@ -1567,7 +1575,7 @@ wimfs_open(const char *path, struct fuse_file_info *fi) struct wim_dentry *dentry; struct wim_inode *inode; struct wim_lookup_table_entry *lte; - u16 stream_idx; + unsigned stream_idx; struct wimfs_fd *fd; int ret; @@ -1659,7 +1667,7 @@ wimfs_read(const char *path, char *buf, size_t size, switch (lte->resource_location) { case RESOURCE_IN_WIM: if (read_partial_wim_stream_into_buf(lte, size, offset, buf)) - ret = -errno; + ret = errno ? -errno : -EIO; else ret = size; break; @@ -1815,7 +1823,8 @@ wimfs_setxattr(const char *path, const char *name, if (!strncmp(name, "wimfs.", 6)) { /* Handle some magical extended attributes. These really should * be ioctls, but directory ioctls aren't supported until - * libfuse 2.9, and even then they are broken. */ + * libfuse 2.9, and even then they are broken. [Fixed by + * libfuse commit e3b7d4c278a26520be63d99d6ea84b26906fe73d] */ name += 6; if (!strcmp(name, "unmount_info")) { if (!may_unmount_wimfs()) @@ -1894,7 +1903,7 @@ wimfs_truncate(const char *path, off_t size) const struct wimfs_context *ctx = wimfs_get_context(); struct wim_dentry *dentry; struct wim_lookup_table_entry *lte; - u16 stream_idx; + unsigned stream_idx; int ret; int fd; @@ -1928,7 +1937,7 @@ wimfs_unlink(const char *path) { const struct wimfs_context *ctx = wimfs_get_context(); struct wim_dentry *dentry; - u16 stream_idx; + unsigned stream_idx; int ret; ret = wim_pathname_to_stream(ctx, path, 0, &dentry, NULL, &stream_idx); @@ -1964,15 +1973,15 @@ wimfs_utimens(const char *path, const struct timespec tv[2]) if (tv[0].tv_nsec != UTIME_OMIT) { if (tv[0].tv_nsec == UTIME_NOW) - inode->i_last_access_time = get_wim_timestamp(); + inode->i_last_access_time = now_as_wim_timestamp(); else - inode->i_last_access_time = timespec_to_wim_timestamp(tv[0]); + inode->i_last_access_time = timespec_to_wim_timestamp(&tv[0]); } if (tv[1].tv_nsec != UTIME_OMIT) { if (tv[1].tv_nsec == UTIME_NOW) - inode->i_last_write_time = get_wim_timestamp(); + inode->i_last_write_time = now_as_wim_timestamp(); else - inode->i_last_write_time = timespec_to_wim_timestamp(tv[1]); + inode->i_last_write_time = timespec_to_wim_timestamp(&tv[1]); } return 0; } @@ -1987,8 +1996,8 @@ wimfs_utime(const char *path, struct utimbuf *times) if (!inode) return -errno; - inode->i_last_access_time = unix_timestamp_to_wim(times->actime); - inode->i_last_write_time = unix_timestamp_to_wim(times->modtime); + inode->i_last_access_time = time_t_to_wim_timestamp(times->actime); + inode->i_last_write_time = time_t_to_wim_timestamp(times->modtime); return 0; } #endif /* !HAVE_UTIMENSAT */ @@ -2080,7 +2089,9 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir, /* For read-write mount, check for write access to the WIM. */ if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) { - ret = can_delete_from_wim(wim); + if (!wim->filename) + return WIMLIB_ERR_NO_FILENAME; + ret = can_modify_wim(wim); if (ret) return ret; } @@ -2234,7 +2245,6 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir, char optstring[256] = "use_ino" ",subtype=wimfs" - ",attr_timeout=0" ",hard_remove" ",default_permissions" ",kernel_cache" @@ -2301,27 +2311,27 @@ generate_message_queue_name(char name[WIMFS_MQUEUE_NAME_LEN + 1]) } static mqd_t -create_message_queue(const char *name, bool have_progfunc) +create_message_queue(const char *name) { - bool am_root = (getuid() == 0); - mode_t umask_save = 0; - mode_t mode = 0600; + bool am_root; + mode_t umask_save; + mode_t mode; struct mq_attr attr; mqd_t mq; memset(&attr, 0, sizeof(attr)); attr.mq_maxmsg = 8; - if (have_progfunc) - attr.mq_msgsize = sizeof(struct commit_progress_report); - else - attr.mq_msgsize = sizeof(int); + attr.mq_msgsize = sizeof(struct commit_progress_report); + am_root = (geteuid() == 0); if (am_root) { /* Filesystem mounted as normal user with --allow-other should * be able to send messages to root user, if they're doing the * unmount. */ umask_save = umask(0); mode = 0666; + } else { + mode = 0600; } mq = mq_open(name, O_RDWR | O_CREAT | O_EXCL, mode, &attr); if (am_root) @@ -2392,7 +2402,7 @@ do_unmount_commit(const char *dir, int unmount_flags, if (progfunc) { generate_message_queue_name(unmount_info.mq_name); - mq = create_message_queue(unmount_info.mq_name, progfunc != NULL); + mq = create_message_queue(unmount_info.mq_name); if (mq == (mqd_t)-1) { ERROR_WITH_ERRNO("Can't create POSIX message queue"); return WIMLIB_ERR_MQUEUE; @@ -2416,7 +2426,7 @@ do_unmount_commit(const char *dir, int unmount_flags, ret = do_unmount(dir); if (progfunc) { /* Terminate the progress thread. */ - char empty[0]; + char empty[1]; mq_send(mq, empty, 0, 1); pthread_join(commit_progress_tid, NULL); } @@ -2478,7 +2488,9 @@ wimlib_unmount_image_with_progress(const char *dir, int unmount_flags, int mount_flags; int ret; - wimlib_global_init(WIMLIB_INIT_FLAG_ASSUME_UTF8); + ret = wimlib_global_init(WIMLIB_INIT_FLAG_ASSUME_UTF8); + if (ret) + return ret; if (unmount_flags & ~(WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY | WIMLIB_UNMOUNT_FLAG_COMMIT |