Acquire advisory lock when doing a read-write mount
authorEric Biggers <ebiggers3@gmail.com>
Thu, 22 Nov 2012 04:42:59 +0000 (22:42 -0600)
committerEric Biggers <ebiggers3@gmail.com>
Thu, 22 Nov 2012 04:42:59 +0000 (22:42 -0600)
src/mount.c
src/wimlib.h
src/wimlib_internal.h
src/write.c

index e130b08..1290bd5 100644 (file)
@@ -1915,6 +1915,12 @@ WIMLIBAPI int wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
                goto out;
        }
 
+       if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
+               ret = lock_wim(wim->fp, wim->filename);
+               if (ret != 0)
+                       goto out;
+       }
+
        if (!(mount_flags & (WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
                       WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR |
                       WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)))
index 0b0f04b..0ba59d4 100644 (file)
@@ -1399,6 +1399,11 @@ extern int wimlib_join(const char **swms, unsigned num_swms,
  *     directory in the future.  Set to @c NULL.
  *
  * @return 0 on success; nonzero on error.
+ * @retval ::WIMLIB_ERR_ALREADY_LOCKED
+ *     A read-write mount was requested, but an an exclusive advisory lock on
+ *     the on-disk WIM file could not be acquired because another thread or
+ *     process has mounted an image from the WIM read-write or is currently
+ *     modifying the WIM in-place.
  * @retval ::WIMLIB_ERR_DECOMPRESSION
  *     Could not decompress the metadata resource for @a image in @a wim.
  * @retval ::WIMLIB_ERR_FUSE
@@ -1577,10 +1582,10 @@ extern int wimlib_open_wim(const char *wim_file, int open_flags,
  * @return 0 on success; nonzero on error.  This function may return any value
  * returned by wimlib_write() as well as the following error codes:
  * @retval ::WIMLIB_ERR_ALREADY_LOCKED
- *     The append-only overwrite mode was going to be used, but an exclusive
- *     advisory lock on the on-disk WIM file could not be acquired, probably
- *     because another thread or process was calling wimlib_overwrite() on the
- *     same underlying on-disk file at the same time.
+ *     The WIM was going to be modifien in-place (with no temporary file), but
+ *     an exclusive advisory lock on the on-disk WIM file could not be acquired
+ *     because another thread or process has mounted an image from the WIM
+ *     read-write or is currently modifying the WIM in-place.
  * @retval ::WIMLIB_ERR_NO_FILENAME
  *     @a wim corresponds to a WIM created with wimlib_create_new_wim() rather
  *     than a WIM read with wimlib_open_wim().
index 1949783..9b8c6b7 100644 (file)
@@ -545,5 +545,14 @@ extern int begin_write(WIMStruct *w, const char *path, int write_flags);
 extern int finish_write(WIMStruct *w, int image, int write_flags,
                        wimlib_progress_func_t progress_func);
 
+#if defined(HAVE_SYS_FILE_H) && defined(HAVE_FLOCK)
+extern int lock_wim(FILE *fp, const char *path);
+#else
+static inline int lock_wim(FILE *fp, const char *path)
+{
+       return 0;
+}
+#endif
+
 #endif /* _WIMLIB_INTERNAL_H */
 
index 773de0b..e441b58 100644 (file)
@@ -1492,6 +1492,29 @@ out:
        return ret;
 }
 
+#if defined(HAVE_SYS_FILE_H) && defined(HAVE_FLOCK)
+int lock_wim(FILE *fp, const char *path)
+{
+       int ret = 0;
+       if (fp) {
+               ret = flock(fileno(fp), LOCK_EX | LOCK_NB);
+               if (ret != 0) {
+                       if (errno == EWOULDBLOCK) {
+                               ERROR("`%s' is already being modified or has been "
+                                     "mounted read-write\n"
+                                     "        by another process!", path);
+                               ret = WIMLIB_ERR_ALREADY_LOCKED;
+                       } else {
+                               WARNING("Failed to lock `%s': %s",
+                                       path, strerror(errno));
+                               ret = 0;
+                       }
+               }
+       }
+       return ret;
+}
+#endif
+
 static int open_wim_writable(WIMStruct *w, const char *path,
                             bool trunc, bool readable)
 {
@@ -1513,24 +1536,13 @@ static int open_wim_writable(WIMStruct *w, const char *path,
                ERROR_WITH_ERRNO("Failed to open `%s' for writing", path);
                return WIMLIB_ERR_OPEN;
        }
-#if defined(HAVE_SYS_FILE_H) && defined(HAVE_FLOCK)
-       if (!trunc) {
-               ret = flock(fileno(w->out_fp), LOCK_EX | LOCK_NB);
+       if (trunc) {
+               ret = lock_wim(w->out_fp, path);
                if (ret != 0) {
-                       if (errno == EWOULDBLOCK) {
-                               ERROR("`%s' is already being modified "
-                                     "by another process", path);
-                               ret = WIMLIB_ERR_ALREADY_LOCKED;
-                               fclose(w->out_fp);
-                               w->out_fp = NULL;
-                       } else {
-                               WARNING("Failed to lock `%s': %s",
-                                       path, strerror(errno));
-                               ret = 0;
-                       }
+                       fclose(w->out_fp);
+                       w->out_fp = NULL;
                }
        }
-#endif
        return ret;
 }