Forbid modifying multi-referenced images
authorEric Biggers <ebiggers3@gmail.com>
Mon, 19 Oct 2015 00:39:34 +0000 (19:39 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Mon, 19 Oct 2015 02:01:11 +0000 (21:01 -0500)
include/wimlib.h
src/error.c
src/mount_image.c
src/update_image.c

index 93e44d7..cdc2988 100644 (file)
@@ -2497,6 +2497,7 @@ enum wimlib_error_code {
        WIMLIB_ERR_UNABLE_TO_READ_CAPTURE_CONFIG      = 83,
        WIMLIB_ERR_WIM_IS_INCOMPLETE                  = 84,
        WIMLIB_ERR_COMPACTION_NOT_POSSIBLE            = 85,
+       WIMLIB_ERR_IMAGE_HAS_MULTIPLE_REFERENCES      = 86,
 };
 
 
@@ -2715,12 +2716,17 @@ wimlib_delete_path(WIMStruct *wim, int image,
  *
  * Export an image, or all images, from a ::WIMStruct into another ::WIMStruct.
  *
- * Note: after calling this function, the exported WIM image(s) cannot be
- * independently modified because the image metadata will be shared between the
- * two ::WIMStruct's.
+ * Specifically, if the destination ::WIMStruct contains <tt>n</tt> images, then
+ * the source image(s) will be appended, in order, starting at destination index
+ * <tt>n + 1</tt>.  By default, all image metadata will be exported verbatim,
+ * but certain changes can be made by passing appropriate parameters.
  *
- * Note: no changes are committed to disk until wimlib_write() or
- * wimlib_overwrite() is called.
+ * wimlib_export_image() is only an in-memory operation; no changes are
+ * committed to disk until wimlib_write() or wimlib_overwrite() is called.
+ *
+ * A limitation of the current implementation of wimlib_export_image() is that
+ * the directory tree of a source or destination image cannot be updated
+ * following an export until one of the two images has been freed from memory.
  *
  * @param src_wim
  *     The WIM from which to export the images, specified as a pointer to the
@@ -3468,6 +3474,10 @@ wimlib_join_with_progress(const wimlib_tchar * const *swms,
  *     Another process is currently modifying the WIM file.
  * @retval ::WIMLIB_ERR_FUSE
  *     A non-zero status code was returned by @c fuse_main().
+ * @retval ::WIMLIB_ERR_IMAGE_HAS_MULTIPLE_REFERENCES
+ *     There are currently multiple references to the WIM image as a result of
+ *     a call to wimlib_export_image().  Free one before attempting the
+ *     read-write mount.
  * @retval ::WIMLIB_ERR_INVALID_IMAGE
  *     @p image does not exist in @p wim.
  * @retval ::WIMLIB_ERR_INVALID_PARAM
@@ -4351,6 +4361,9 @@ wimlib_unmount_image_with_progress(const wimlib_tchar *dir,
  * @retval ::WIMLIB_ERR_FVE_LOCKED_VOLUME
  *     Windows-only: One of the "add" commands attempted to add files from an
  *     encrypted BitLocker volume that hasn't yet been unlocked.
+ * @retval ::WIMLIB_ERR_IMAGE_HAS_MULTIPLE_REFERENCES
+ *     There are currently multiple references to the WIM image as a result of
+ *     a call to wimlib_export_image().  Free one before attempting the update.
  * @retval ::WIMLIB_ERR_INVALID_CAPTURE_CONFIG
  *     The contents of a capture configuration file were invalid.
  * @retval ::WIMLIB_ERR_INVALID_IMAGE
index 40d00a5..af212db 100644 (file)
@@ -337,6 +337,9 @@ static const tchar * const error_strings[] = {
        [WIMLIB_ERR_COMPACTION_NOT_POSSIBLE]
                = T("The WIM file cannot be compacted because of its format, "
                    "its layout, or the write parameters specified by the user"),
+       [WIMLIB_ERR_IMAGE_HAS_MULTIPLE_REFERENCES]
+               = T("The WIM image cannot be modified because it is currently "
+                   "referenced from multiple places"),
 };
 
 WIMLIBAPI const tchar *
index 239184a..7750a4e 100644 (file)
@@ -2137,6 +2137,8 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
        }
 
        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;
index 49492a3..66e5ed8 100644 (file)
@@ -1396,6 +1396,7 @@ wimlib_update_image(WIMStruct *wim,
                    int update_flags)
 {
        int ret;
+       struct wim_image_metadata *imd;
        struct wimlib_update_command *cmds_copy;
 
        if (update_flags & ~WIMLIB_UPDATE_FLAG_SEND_PROGRESS)
@@ -1404,7 +1405,14 @@ wimlib_update_image(WIMStruct *wim,
        /* Load the metadata for the image to modify (if not loaded already) */
        ret = select_wim_image(wim, image);
        if (ret)
-               goto out;
+               return ret;
+
+       imd = wim->image_metadata[image - 1];
+
+       /* Don't allow updating an image currently being shared by multiple
+        * WIMStructs (as a result of an export)  */
+       if (imd->refcnt > 1)
+               return WIMLIB_ERR_IMAGE_HAS_MULTIPLE_REFERENCES;
 
        /* Make a copy of the update commands, in the process doing certain
         * canonicalizations on paths (e.g. translating backslashes to forward
@@ -1412,7 +1420,7 @@ wimlib_update_image(WIMStruct *wim,
         * commands. */
        ret = copy_update_commands(cmds, num_cmds, &cmds_copy);
        if (ret)
-               goto out;
+               return ret;
 
        /* Perform additional checks on the update commands before we execute
         * them. */
@@ -1425,7 +1433,7 @@ wimlib_update_image(WIMStruct *wim,
        if (ret)
                goto out_free_cmds_copy;
 
-       mark_image_dirty(wim->image_metadata[image - 1]);
+       mark_image_dirty(imd);
 
        /* Statistics about the WIM image, such as the numbers of files and
         * directories, may have changed.  Call xml_update_image_info() to
@@ -1438,7 +1446,6 @@ wimlib_update_image(WIMStruct *wim,
                        wim->hdr.flags |= WIM_HDR_FLAG_RP_FIX;
 out_free_cmds_copy:
        free_update_commands(cmds_copy, num_cmds);
-out:
        return ret;
 }