X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fmount_image.c;h=8ad4fdc8663a4cc50b76df2b37d908ac513df6aa;hb=90f1e04a2a143876a4413577b25db60b5ba0fe97;hp=eeacf94d138864ab9c0bae8975d1ff0e475302a3;hpb=5538002965b9a7f08aef62c7b03194aa40bb0751;p=wimlib diff --git a/src/mount_image.c b/src/mount_image.c index eeacf94d..8ad4fdc8 100644 --- a/src/mount_image.c +++ b/src/mount_image.c @@ -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,9 +39,8 @@ #define FUSE_USE_VERSION 26 -#include /* sometimes required before */ - -#include +#include /* sometimes required before */ +#include #include #include #include @@ -71,6 +70,10 @@ # 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 @@ -164,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"). */ @@ -511,7 +514,7 @@ create_file(struct fuse_context *fuse_ctx, const char *path, } } - hlist_add_head(&inode->i_hlist, + hlist_add_head(&inode->i_hlist_node, &wim_get_current_image_metadata(wimfs_ctx->wim)->inode_list); dentry_add_child(parent, dentry); @@ -666,7 +669,7 @@ create_staging_file(const struct wimfs_context *ctx, char **name_ret) name[STAGING_FILE_NAME_LEN] = '\0'; retry: - randomize_char_array_with_alnum(name, STAGING_FILE_NAME_LEN); + get_random_alnum_chars(name, STAGING_FILE_NAME_LEN); fd = openat(ctx->staging_dir_fd, name, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0600); if (unlikely(fd < 0)) { @@ -850,7 +853,7 @@ make_staging_dir_at(int parent_dir_fd, const char *wim_basename, p = staging_dir_name; p = mempcpy(p, wim_basename, wim_basename_len); p = mempcpy(p, common_suffix, sizeof(common_suffix)); - randomize_char_array_with_alnum(p, random_suffix_len); + get_random_alnum_chars(p, random_suffix_len); p += random_suffix_len; *p = '\0'; @@ -964,17 +967,6 @@ prepare_inodes(struct wimfs_context *ctx) } } -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); -} - /* Delete the 'struct blob_descriptor' for any stream that was modified * or created in the read-write mounted image and had a final size of 0. */ static void @@ -1030,53 +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->unhashed = 1; - new_blob->is_metadata = 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; } @@ -1112,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; @@ -1678,7 +1669,7 @@ wimfs_read(const char *path, char *buf, size_t size, 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; @@ -1712,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; } @@ -2037,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; @@ -2048,7 +2036,7 @@ wimfs_write(const char *path, const char *buf, size_t size, return ret; } -static struct fuse_operations wimfs_operations = { +static const struct fuse_operations wimfs_operations = { .chmod = wimfs_chmod, .chown = wimfs_chown, .fgetattr = wimfs_fgetattr, @@ -2132,15 +2120,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; @@ -2164,57 +2153,27 @@ 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; - } - } - - 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; - } - } - } - } - /* 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) @@ -2305,11 +2264,11 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir, /* Cleanup and return. */ if (ret) ret = WIMLIB_ERR_FUSE; +out: FREE(ctx.mountpoint_abspath); - release_extra_refcnts(&ctx); - if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) + free_blob_descriptor(ctx.metadata_resource); + if (ctx.staging_dir_name) delete_staging_dir(&ctx); -out_unlock: unlock_wim_for_append(wim); return ret; } @@ -2346,7 +2305,7 @@ generate_message_queue_name(char name[WIMFS_MQUEUE_NAME_LEN + 1]) { name[0] = '/'; memcpy(name + 1, "wimfs-", 6); - randomize_char_array_with_alnum(name + 7, WIMFS_MQUEUE_NAME_LEN - 7); + get_random_alnum_chars(name + 7, WIMFS_MQUEUE_NAME_LEN - 7); name[WIMFS_MQUEUE_NAME_LEN] = '\0'; } @@ -2528,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;