]> wimlib.net Git - wimlib/blobdiff - src/mount_image.c
libattr is no longer needed
[wimlib] / src / mount_image.c
index 7fe8bb537fb1621a5e5742fba40aa98ed8347dde..3641b204c3aec966d938b57d86517f181c5d9589 100644 (file)
@@ -8,7 +8,7 @@
  */
 
 /*
- * Copyright (C) 2012, 2013, 2014, 2015 Eric Biggers
+ * Copyright (C) 2012-2016 Eric Biggers
  *
  * 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
@@ -39,7 +39,8 @@
 
 #define FUSE_USE_VERSION 26
 
-#include <attr/xattr.h>
+#include <sys/types.h> /* sometimes required before <sys/xattr.h> */
+#include <sys/xattr.h>
 #include <dirent.h>
 #include <errno.h>
 #include <fuse.h>
@@ -50,7 +51,6 @@
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/time.h>
-#include <sys/types.h>
 #include <unistd.h>
 #include <utime.h>
 
 #  define O_NOFOLLOW 0  /* Security only...  */
 #endif
 
+#ifndef ENOATTR
+#  define ENOATTR ENODATA
+#endif
+
 #define WIMFS_MQUEUE_NAME_LEN 32
 
 #define WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS 0x80000000
@@ -144,6 +148,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;
@@ -158,9 +167,9 @@ struct wimfs_context {
        /* Number of file descriptors open to the mounted WIM image.  */
        unsigned long num_open_fds;
 
-       /* Original list of blobs in the mounted image, linked by
-        * 'struct blob_descriptor'.orig_blob_list.  */
-       struct list_head orig_blob_list;
+       /* For read-write mounts, the original metadata resource of the mounted
+        * image.  */
+       struct blob_descriptor *metadata_resource;
 
        /* Parameters for unmounting the image (can be set via extended
         * attribute "wimfs.unmount_info").  */
@@ -357,7 +366,7 @@ inode_get_data_stream_tstr(const struct wim_inode *inode,
        struct wim_inode_stream *strm;
 
        if (!stream_name || !*stream_name) {
-               strm = inode_get_unnamed_stream(inode, STREAM_TYPE_DATA);
+               strm = inode_get_unnamed_data_stream(inode);
        } else {
                const utf16lechar *uname;
 
@@ -442,14 +451,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 +466,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 +486,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 +507,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;
 }
 
@@ -549,6 +561,25 @@ inode_default_unix_mode(const struct wim_inode *inode)
        return inode_unix_file_type(inode) | 0777;
 }
 
+static u64
+blob_size(const struct blob_descriptor *blob)
+{
+       if (!blob)
+               return 0;
+       return blob->size;
+}
+
+static u64
+blob_stored_size(const struct blob_descriptor *blob)
+{
+       if (!blob)
+               return 0;
+       if (blob->blob_location == BLOB_IN_WIM &&
+           blob->size == blob->rdesc->uncompressed_size)
+               return blob->rdesc->size_in_wim;
+       return blob->size;
+}
+
 /*
  * Retrieve standard UNIX metadata ('struct stat') for a WIM inode.
  *
@@ -586,8 +617,7 @@ inode_to_stbuf(const struct wim_inode *inode,
        }
        stbuf->st_ino = inode->i_ino;
        stbuf->st_nlink = inode->i_nlink;
-       if (blob)
-               stbuf->st_size = blob->size;
+       stbuf->st_size = blob_size(blob);
 #ifdef HAVE_STAT_NANOSECOND_PRECISION
        stbuf->st_atim = wim_timestamp_to_timespec(inode->i_last_access_time);
        stbuf->st_mtim = wim_timestamp_to_timespec(inode->i_last_write_time);
@@ -597,7 +627,7 @@ inode_to_stbuf(const struct wim_inode *inode,
        stbuf->st_mtime = wim_timestamp_to_time_t(inode->i_last_write_time);
        stbuf->st_ctime = stbuf->st_mtime;
 #endif
-       stbuf->st_blocks = DIV_ROUND_UP(stbuf->st_size, 512);
+       stbuf->st_blocks = DIV_ROUND_UP(blob_stored_size(blob), 512);
        return 0;
 }
 
@@ -698,7 +728,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;
@@ -921,28 +951,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++;
-}
-
-static void
-release_extra_refcnts(struct wimfs_context *ctx)
-{
-       struct list_head *list = &ctx->orig_blob_list;
-       struct blob_table *blob_table = ctx->wim->blob_table;
-       struct blob_descriptor *blob, *tmp;
-
-       list_for_each_entry_safe(blob, tmp, list, orig_blob_list)
-               blob_subtract_refcnt(blob, blob_table, blob->out_refcnt);
+               inode->i_num_opened_fds = 0;
+               inode->i_num_allocated_fds = 0;
+               inode->i_fds = NULL;
+       }
 }
 
 /* Delete the 'struct blob_descriptor' for any stream that was modified
@@ -983,12 +1005,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);
 }
 
@@ -999,52 +1022,56 @@ static int
 renew_current_image(struct wimfs_context *ctx)
 {
        WIMStruct *wim = ctx->wim;
-       int idx = wim->current_image - 1;
-       struct wim_image_metadata *imd = wim->image_metadata[idx];
-       struct wim_image_metadata *replace_imd;
-       struct blob_descriptor *new_blob;
+       int image = wim->current_image;
+       struct wim_image_metadata *imd;
+       struct wim_inode *inode;
        int ret;
 
-       /* Create 'replace_imd' structure to use for the reset original,
-        * unmodified image.  */
        ret = WIMLIB_ERR_NOMEM;
-       replace_imd = new_image_metadata();
-       if (!replace_imd)
+       imd = new_unloaded_image_metadata(ctx->metadata_resource);
+       if (!imd)
                goto err;
 
-       /* Create new blob descriptor for the modified image's metadata
-        * resource, which doesn't exist yet.  */
-       ret = WIMLIB_ERR_NOMEM;
-       new_blob = new_blob_descriptor();
-       if (!new_blob)
-               goto err_put_replace_imd;
-       new_blob->refcnt = 1;
-       new_blob->flags = WIM_RESHDR_FLAG_METADATA;
-       new_blob->unhashed = 1;
-
-       /* Make the image being moved available at a new index.  Increments the
-        * WIM's image count, but does not increment the reference count of the
-        * 'struct image_metadata'.  */
-       ret = append_image_metadata(wim, imd);
+       ret = append_image_metadata(wim, wim->image_metadata[image - 1]);
        if (ret)
-               goto err_free_new_blob;
+               goto err_put_imd;
 
-       ret = xml_add_image(wim, "");
+       ret = xml_export_image(wim->xml_info, image,
+                              wim->xml_info, NULL, NULL, false);
        if (ret)
                goto err_undo_append;
 
-       replace_imd->metadata_blob = imd->metadata_blob;
-       imd->metadata_blob = new_blob;
-       wim->image_metadata[idx] = replace_imd;
+       wim->image_metadata[image - 1] = imd;
        wim->current_image = wim->hdr.image_count;
+
+       ret = select_wim_image(wim, image);
+       if (ret)
+               goto err_undo_export;
+
+       image_for_each_inode(inode, imd) {
+               for (unsigned i = 0; i < inode->i_num_streams; i++) {
+                       struct blob_descriptor *blob;
+
+                       blob = stream_blob(&inode->i_streams[i],
+                                          wim->blob_table);
+                       if (blob)
+                               blob->refcnt += inode->i_nlink;
+               }
+       }
+
+       select_wim_image(wim, wim->hdr.image_count);
+       ctx->metadata_resource = NULL;
        return 0;
 
+err_undo_export:
+       xml_delete_image(wim->xml_info, wim->hdr.image_count);
+       wim->image_metadata[image - 1] = wim->image_metadata[wim->hdr.image_count - 1];
+       wim->current_image = image;
 err_undo_append:
        wim->hdr.image_count--;
-err_free_new_blob:
-       free_blob_descriptor(new_blob);
-err_put_replace_imd:
-       put_image_metadata(replace_imd, NULL);
+err_put_imd:
+       imd->metadata_blob = NULL;
+       put_image_metadata(imd);
 err:
        return ret;
 }
@@ -1080,12 +1107,8 @@ commit_image(struct wimfs_context *ctx, int unmount_flags, mqd_t mq)
                int ret = renew_current_image(ctx);
                if (ret)
                        return ret;
-       } else {
-               release_extra_refcnts(ctx);
        }
-       INIT_LIST_HEAD(&ctx->orig_blob_list);
        delete_empty_blobs(ctx);
-       xml_update_image_info(ctx->wim, ctx->wim->current_image);
 
        write_flags = 0;
 
@@ -1287,9 +1310,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
@@ -1362,7 +1385,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;
@@ -1467,8 +1490,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);
@@ -1530,11 +1552,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);
@@ -1572,7 +1590,7 @@ wimfs_open(const char *path, struct fuse_file_info *fi)
             (!blob || blob->blob_location != BLOB_IN_STAGING_FILE)) {
                ret = extract_blob_to_staging_dir(inode,
                                                  strm,
-                                                 blob ? blob->size : 0,
+                                                 blob_size(blob),
                                                  ctx);
                if (ret)
                        return ret;
@@ -1612,7 +1630,7 @@ wimfs_opendir(const char *path, struct fuse_file_info *fi)
                return -errno;
        if (!inode_is_directory(inode))
                return -ENOTDIR;
-       strm = inode_get_unnamed_stream(inode, STREAM_TYPE_DATA);
+       strm = inode_get_unnamed_data_stream(inode);
        if (!strm)
                return -ENOTDIR;
        ret = alloc_wimfs_fd(inode, strm, &fd);
@@ -1645,13 +1663,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;
@@ -1685,18 +1703,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;
        }
@@ -1704,27 +1719,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))
-               return -EINVAL;
-       if (buf_len == 0)
+       if (bufsize <= 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
@@ -1883,11 +1895,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) {
@@ -2015,7 +2025,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;
 
@@ -2110,20 +2120,26 @@ 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;
        }
 
+       if (wim_has_solid_resources(wim)) {
+               WARNING("Mounting a WIM file containing solid-compressed data; "
+                       "file access may be slow.");
+       }
+
        /* If the user did not specify an interface for accessing named
         * data streams, use the default (extended attributes).  */
        if (!(mount_flags & (WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
@@ -2137,55 +2153,31 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
        ctx.mount_flags = mount_flags;
        if (mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
                ctx.default_lookup_flags = LOOKUP_FLAG_ADS_OK;
-       /* For read-write mount, create the staging directory.  */
+
+       /* For read-write mounts, create the staging directory, save a reference
+        * to the image's metadata resource, and mark the image dirty.  */
        if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
                ret = make_staging_dir(&ctx, staging_dir);
                if (ret)
-                       goto out_unlock;
+                       goto out;
+               ret = WIMLIB_ERR_NOMEM;
+               ctx.metadata_resource = clone_blob_descriptor(
+                                                       imd->metadata_blob);
+               if (!ctx.metadata_resource)
+                       goto out;
+               mark_image_dirty(imd);
        }
        ctx.owner_uid = getuid();
        ctx.owner_gid = getgid();
 
-       /* Add each blob referenced by files in the image to a list and
-        * preemptively double the number of references to each.  This is done
-        * to allow implementing the WIMLIB_UNMOUNT_FLAG_NEW_IMAGE semantics.
-        */
-       INIT_LIST_HEAD(&ctx.orig_blob_list);
-       if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
-               unsigned i;
-               struct wim_inode *inode;
-               struct blob_descriptor *blob;
-
-               image_for_each_inode(inode, imd) {
-                       for (i = 0; i < inode->i_num_streams; i++) {
-                               blob = stream_blob(&inode->i_streams[i],
-                                                  wim->blob_table);
-                               if (blob)
-                                       blob->out_refcnt = 0;
-                       }
-               }
+       /* Number the inodes in the mounted image sequentially and initialize
+        * the file descriptor arrays  */
+       prepare_inodes(&ctx);
 
-               image_for_each_inode(inode, imd) {
-                       for (i = 0; i < inode->i_num_streams; i++) {
-                               blob = stream_blob(&inode->i_streams[i],
-                                                  wim->blob_table);
-                               if (blob) {
-                                       if (blob->out_refcnt == 0)
-                                               list_add(&blob->orig_blob_list,
-                                                        &ctx.orig_blob_list);
-                                       blob->out_refcnt += inode->i_nlink;
-                                       blob->refcnt += inode->i_nlink;
-                               }
-                       }
-               }
-       }
-
-       /* Assign new inode numbers.  */
-       reassign_inode_numbers(&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.  */
 
@@ -2272,10 +2264,11 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
        /* Cleanup and return.  */
        if (ret)
                ret = WIMLIB_ERR_FUSE;
-       release_extra_refcnts(&ctx);
-       if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)
+out:
+       FREE(ctx.mountpoint_abspath);
+       free_blob_descriptor(ctx.metadata_resource);
+       if (ctx.staging_dir_name)
                delete_staging_dir(&ctx);
-out_unlock:
        unlock_wim_for_append(wim);
        return ret;
 }
@@ -2494,7 +2487,7 @@ wimlib_unmount_image_with_progress(const char *dir, int unmount_flags,
        int mount_flags;
        int ret;
 
-       ret = wimlib_global_init(WIMLIB_INIT_FLAG_ASSUME_UTF8);
+       ret = wimlib_global_init(0);
        if (ret)
                return ret;