X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fmount_image.c;h=6f0c6e1cd1486ed46152c862ba3f3fed851bde39;hb=e4cdc80a6d033bb27ac0d1687ca32d0434673128;hp=e2f0ffbccac4e4f7498809adaf658fac3a71a631;hpb=8df639463ae0c754d2b1af3d6c1d22e59ee3ccf8;p=wimlib diff --git a/src/mount_image.c b/src/mount_image.c index e2f0ffbc..6f0c6e1c 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 @@ -164,9 +164,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"). */ @@ -964,17 +964,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 +1019,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 +1104,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 +1666,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; @@ -2034,7 +2022,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 +2117,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; @@ -2161,57 +2150,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) @@ -2302,11 +2261,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; } @@ -2525,7 +2484,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;