wimlib_mount_image(): Correctly return NOMEM in one case
[wimlib] / src / mount_image.c
index b1a3f1c..41478d9 100644 (file)
@@ -41,6 +41,8 @@
 
 #include "wimlib/encoding.h"
 #include "wimlib/file_io.h"
+#include "wimlib/dentry.h"
+#include "wimlib/inode.h"
 #include "wimlib/lookup_table.h"
 #include "wimlib/metadata.h"
 #include "wimlib/paths.h"
@@ -152,12 +154,6 @@ wimfs_get_WIMStruct(void)
        return wimfs_get_context()->wim;
 }
 
-static inline bool
-wimfs_ctx_readonly(const struct wimfs_context *ctx)
-{
-       return (ctx->mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) == 0;
-}
-
 static inline int
 get_lookup_flags(const struct wimfs_context *ctx)
 {
@@ -168,7 +164,8 @@ get_lookup_flags(const struct wimfs_context *ctx)
 static inline int
 flags_writable(int open_flags)
 {
-       return open_flags & (O_RDWR | O_WRONLY);
+       int accmode = (open_flags & O_ACCMODE);
+       return (accmode == O_RDWR || accmode == O_WRONLY);
 }
 
 /*
@@ -178,7 +175,6 @@ flags_writable(int open_flags)
  * @stream_id: ID of the stream we're opening
  * @lte:       Lookup table entry for the stream (may be NULL)
  * @fd_ret:    Return the allocated file descriptor if successful.
- * @readonly:  True if this is a read-only mount.
  *
  * Return 0 iff successful or error code if unsuccessful.
  */
@@ -186,8 +182,7 @@ static int
 alloc_wimfs_fd(struct wim_inode *inode,
               u32 stream_id,
               struct wim_lookup_table_entry *lte,
-              struct wimfs_fd **fd_ret,
-              bool readonly)
+              struct wimfs_fd **fd_ret)
 {
        static const u16 fds_per_alloc = 8;
        static const u16 max_fds = 0xffff;
@@ -236,7 +231,7 @@ alloc_wimfs_fd(struct wim_inode *inode,
                        *fd_ret         = fd;
                        inode->i_fds[i] = fd;
                        inode->i_num_opened_fds++;
-                       if (lte && !readonly)
+                       if (lte)
                                lte->num_opened_fds++;
                        DEBUG("Allocated fd (idx = %u)", fd->idx);
                        ret = 0;
@@ -329,7 +324,7 @@ create_dentry(struct fuse_context *fuse_ctx, const char *path,
        struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
        int ret;
 
-       parent = get_parent_dentry(wimfs_ctx->wim, path);
+       parent = get_parent_dentry(wimfs_ctx->wim, path, WIMLIB_CASE_SENSITIVE);
        if (!parent)
                return -errno;
 
@@ -337,7 +332,7 @@ create_dentry(struct fuse_context *fuse_ctx, const char *path,
                return -ENOTDIR;
 
        basename = path_basename(path);
-       if (get_dentry_child_with_name(parent, basename))
+       if (get_dentry_child_with_name(parent, basename, WIMLIB_CASE_SENSITIVE))
                return -EEXIST;
 
        ret = new_dentry_with_inode(basename, &new);
@@ -367,6 +362,17 @@ create_dentry(struct fuse_context *fuse_ctx, const char *path,
        return 0;
 }
 
+static struct wim_inode *
+wim_pathname_to_inode(WIMStruct *wim, const tchar *path)
+{
+       struct wim_dentry *dentry;
+       dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
+       if (dentry)
+               return dentry->d_inode;
+       else
+               return NULL;
+}
+
 /* Remove a dentry from a mounted WIM image; i.e. remove an alias for the
  * corresponding inode.
  *
@@ -569,8 +575,7 @@ extract_resource_to_staging_dir(struct wim_inode *inode,
                struct filedes wimlib_fd;
                filedes_init(&wimlib_fd, fd);
                extract_size = min(old_lte->size, size);
-               ret = extract_wim_resource_to_fd(old_lte, &wimlib_fd,
-                                                extract_size);
+               ret = extract_stream_to_fd(old_lte, &wimlib_fd, extract_size);
        } else {
                ret = 0;
                extract_size = 0;
@@ -663,13 +668,14 @@ extract_resource_to_staging_dir(struct wim_inode *inode,
                }
        }
 
+       lte_put_resource(new_lte);
        new_lte->refcnt              = inode->i_nlink;
        new_lte->resource_location   = RESOURCE_IN_STAGING_FILE;
        new_lte->staging_file_name   = staging_file_name;
        new_lte->size                = size;
 
-       lookup_table_insert_unhashed(ctx->wim->lookup_table, new_lte,
-                                    inode, stream_id);
+       add_unhashed_stream(new_lte, inode, stream_id,
+                           &wim_get_current_image_metadata(ctx->wim)->unhashed_streams);
        *retrieve_lte_pointer(new_lte) = new_lte;
        *lte = new_lte;
        return 0;
@@ -1294,25 +1300,19 @@ msg_unmount_finished_handler(const void *_msg, void *_handler_ctx)
 static int
 unmount_timed_out_cb(void *_handler_ctx)
 {
-       struct unmount_msg_handler_context *handler_ctx = _handler_ctx;
+       const struct unmount_msg_handler_context *handler_ctx = _handler_ctx;
 
-       if (handler_ctx->daemon_pid == 0) {
-               goto out_crashed;
-       } else {
-               kill(handler_ctx->daemon_pid, 0);
-               if (errno == ESRCH) {
-                       goto out_crashed;
-               } else {
-                       DEBUG("Filesystem daemon is still alive... "
-                             "Waiting another %d seconds\n",
-                             handler_ctx->hdr.timeout_seconds);
-                       return 0;
-               }
+       if (handler_ctx->daemon_pid == 0 ||
+           (kill(handler_ctx->daemon_pid, 0) != 0 && errno == ESRCH))
+       {
+               ERROR("The filesystem daemon has crashed!  Changes to the "
+                     "WIM may not have been commited.");
+               return WIMLIB_ERR_FILESYSTEM_DAEMON_CRASHED;
        }
-out_crashed:
-       ERROR("The filesystem daemon has crashed!  Changes to the "
-             "WIM may not have been commited.");
-       return WIMLIB_ERR_FILESYSTEM_DAEMON_CRASHED;
+
+       DEBUG("Filesystem daemon is still alive... "
+             "Waiting another %d seconds", handler_ctx->hdr.timeout_seconds);
+       return 0;
 }
 
 static int
@@ -1522,10 +1522,12 @@ execute_fusermount(const char *dir, bool lazy)
                                 "terminate");
                return WIMLIB_ERR_FUSERMOUNT;
        }
-       if (status != 0) {
+
+       if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
                ERROR("`umount' did not successfully complete");
                return WIMLIB_ERR_FUSERMOUNT;
        }
+
        return 0;
 }
 
@@ -1667,7 +1669,7 @@ wimfs_getxattr(const char *path, const char *name, char *value,
        if (stream_size > size)
                return -ERANGE;
 
-       ret = read_full_resource_into_buf(lte, value);
+       ret = read_full_stream_into_buf(lte, value);
        if (ret) {
                if (errno)
                        return -errno;
@@ -1696,14 +1698,15 @@ wimfs_link(const char *to, const char *from)
                                   FILE_ATTRIBUTE_REPARSE_POINT))
                return -EPERM;
 
-       from_dentry_parent = get_parent_dentry(wim, from);
+       from_dentry_parent = get_parent_dentry(wim, from, WIMLIB_CASE_SENSITIVE);
        if (!from_dentry_parent)
                return -errno;
        if (!dentry_is_directory(from_dentry_parent))
                return -ENOTDIR;
 
        link_name = path_basename(from);
-       if (get_dentry_child_with_name(from_dentry_parent, link_name))
+       if (get_dentry_child_with_name(from_dentry_parent, link_name,
+                                      WIMLIB_CASE_SENSITIVE))
                return -EEXIST;
 
        ret = new_dentry(link_name, &from_dentry);
@@ -1865,8 +1868,7 @@ wimfs_open(const char *path, struct fuse_file_info *fi)
                *back_ptr = lte;
        }
 
-       ret = alloc_wimfs_fd(inode, stream_id, lte, &fd,
-                            wimfs_ctx_readonly(ctx));
+       ret = alloc_wimfs_fd(inode, stream_id, lte, &fd);
        if (ret)
                return ret;
 
@@ -1900,7 +1902,7 @@ wimfs_opendir(const char *path, struct fuse_file_info *fi)
                return -errno;
        if (!inode_is_directory(inode))
                return -ENOTDIR;
-       ret = alloc_wimfs_fd(inode, 0, NULL, &fd, wimfs_ctx_readonly(ctx));
+       ret = alloc_wimfs_fd(inode, 0, NULL, &fd);
        fi->fh = (uintptr_t)fd;
        return ret;
 }
@@ -1942,9 +1944,9 @@ wimfs_read(const char *path, char *buf, size_t size,
                        ret = -errno;
                break;
        case RESOURCE_IN_WIM:
-               if (read_partial_wim_resource_into_buf(fd->f_lte, size,
-                                                      offset, buf))
-                       ret = -errno;
+               if (read_partial_wim_stream_into_buf(fd->f_lte, size,
+                                                    offset, buf))
+                       ret = errno ? -errno : -EIO;
                else
                        ret = size;
                break;
@@ -2024,7 +2026,7 @@ wimfs_readlink(const char *path, char *buf, size_t buf_len)
        if (!inode_is_symlink(inode))
                return -EINVAL;
        if (buf_len == 0)
-               return -ENAMETOOLONG;
+               return -EINVAL;
        ret = wim_inode_readlink(inode, buf, buf_len - 1, NULL);
        if (ret >= 0) {
                wimlib_assert(ret <= buf_len - 1);
@@ -2085,7 +2087,8 @@ wimfs_removexattr(const char *path, const char *name)
 static int
 wimfs_rename(const char *from, const char *to)
 {
-       return rename_wim_path(wimfs_get_WIMStruct(), from, to);
+       return rename_wim_path(wimfs_get_WIMStruct(), from, to,
+                              WIMLIB_CASE_SENSITIVE);
 }
 
 /* Remove a directory */
@@ -2095,7 +2098,7 @@ wimfs_rmdir(const char *path)
        struct wim_dentry *dentry;
        WIMStruct *wim = wimfs_get_WIMStruct();
 
-       dentry = get_dentry(wim, path);
+       dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
        if (!dentry)
                return -errno;
 
@@ -2263,7 +2266,7 @@ wimfs_utimens(const char *path, const struct timespec tv[2])
        struct wim_inode *inode;
        WIMStruct *wim = wimfs_get_WIMStruct();
 
-       dentry = get_dentry(wim, path);
+       dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
        if (!dentry)
                return -errno;
        inode = dentry->d_inode;
@@ -2290,7 +2293,7 @@ wimfs_utime(const char *path, struct utimbuf *times)
        struct wim_inode *inode;
        WIMStruct *wim = wimfs_get_WIMStruct();
 
-       dentry = get_dentry(wim, path);
+       dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
        if (!dentry)
                return -errno;
        inode = dentry->d_inode;
@@ -2409,6 +2412,15 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
        if (!wim || !dir)
                return WIMLIB_ERR_INVALID_PARAM;
 
+       if (mount_flags & ~(WIMLIB_MOUNT_FLAG_READWRITE |
+                           WIMLIB_MOUNT_FLAG_DEBUG |
+                           WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
+                           WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR |
+                           WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS |
+                           WIMLIB_MOUNT_FLAG_UNIX_DATA |
+                           WIMLIB_MOUNT_FLAG_ALLOW_OTHER))
+               return WIMLIB_ERR_INVALID_PARAM;
+
        if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
                ret = can_delete_from_wim(wim);
                if (ret)
@@ -2423,15 +2435,12 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
 
        imd = wim_get_current_image_metadata(wim);
 
-       if (imd->refcnt != 1) {
-               ERROR("Cannot mount image that was just exported with "
-                     "wimlib_export_image()");
-               return WIMLIB_ERR_INVALID_PARAM;
-       }
-
        if (imd->modified) {
-               ERROR("Cannot mount image that was added "
-                     "with wimlib_add_image()");
+               /* wimfs_read() only supports a limited number of stream
+                * locations, not including RESOURCE_IN_FILE_ON_DISK,
+                * RESOURCE_IN_NTFS_VOLUME, etc. that might appear if files were
+                * added to the WIM image.  */
+               ERROR("Cannot mount an image with newly added files!");
                return WIMLIB_ERR_INVALID_PARAM;
        }
 
@@ -2455,7 +2464,6 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
        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;
 
@@ -2468,8 +2476,10 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
        DEBUG("Preparing arguments to fuse_main()");
 
        dir_copy = STRDUP(dir);
-       if (!dir_copy)
+       if (!dir_copy) {
+               ret = WIMLIB_ERR_NOMEM;
                goto out_free_message_queue_names;
+       }
 
        argc = 0;
        argv[argc++] = "wimlib";
@@ -2573,6 +2583,13 @@ wimlib_unmount_image(const char *dir, int unmount_flags,
        int ret;
        struct wimfs_context wimfs_ctx;
 
+       if (unmount_flags & ~(WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY |
+                             WIMLIB_UNMOUNT_FLAG_COMMIT |
+                             WIMLIB_UNMOUNT_FLAG_REBUILD |
+                             WIMLIB_UNMOUNT_FLAG_RECOMPRESS |
+                             WIMLIB_UNMOUNT_FLAG_LAZY))
+               return WIMLIB_ERR_INVALID_PARAM;
+
        init_wimfs_context(&wimfs_ctx);
 
        ret = set_message_queue_names(&wimfs_ctx, dir);