+ mq = mq_open(name, O_RDWR | O_CREAT | O_EXCL, mode, &attr);
+ if (am_root)
+ umask(umask_save);
+ return mq;
+}
+
+/* Unmount a read-only or read-write mounted WIM image. */
+static int
+do_unmount(const char *dir)
+{
+ int status;
+ ssize_t len;
+
+ len = getxattr(dir, "wimfs.unmount", &status, sizeof(int));
+ if (len == sizeof(int))
+ return status;
+ else if (len < 0 && (errno == EACCES || errno == EPERM))
+ return WIMLIB_ERR_NOT_PERMITTED_TO_UNMOUNT;
+ else
+ return WIMLIB_ERR_NOT_A_MOUNTPOINT;
+}
+
+static int
+set_unmount_info(const char *dir, const struct wimfs_unmount_info *unmount_info)
+{
+ if (!setxattr(dir, "wimfs.unmount_info",
+ unmount_info, sizeof(struct wimfs_unmount_info), 0))
+ return 0;
+ else if (errno == EROFS)
+ return 0;
+ else if (errno == EACCES || errno == EPERM)
+ return WIMLIB_ERR_NOT_PERMITTED_TO_UNMOUNT;
+ else
+ return WIMLIB_ERR_NOT_A_MOUNTPOINT;
+}
+
+static int
+do_unmount_discard(const char *dir)
+{
+ int ret;
+ struct wimfs_unmount_info unmount_info;
+
+ memset(&unmount_info, 0, sizeof(unmount_info));
+
+ ret = set_unmount_info(dir, &unmount_info);
+ if (ret)
+ return ret;
+ return do_unmount(dir);
+}
+
+/* Unmount a read-write mounted WIM image, committing the changes. */
+static int
+do_unmount_commit(const char *dir, int unmount_flags,
+ wimlib_progress_func_t progfunc, void *progctx)
+{
+ struct wimfs_unmount_info unmount_info;
+ mqd_t mq;
+ struct commit_progress_thread_args args;
+ pthread_t commit_progress_tid;
+ int ret;
+
+ memset(&unmount_info, 0, sizeof(unmount_info));
+ unmount_info.unmount_flags = unmount_flags;
+
+ /* The current thread will be stuck in getxattr() until the image is
+ * committed. Create a thread to handle the progress messages. */
+ if (progfunc) {
+ generate_message_queue_name(unmount_info.mq_name);
+
+ mq = create_message_queue(unmount_info.mq_name, progfunc != NULL);
+ if (mq == (mqd_t)-1) {
+ ERROR_WITH_ERRNO("Can't create POSIX message queue");
+ return WIMLIB_ERR_MQUEUE;
+ }
+ args.mq = mq;
+ args.progfunc = progfunc;
+ args.progctx = progctx;
+ ret = pthread_create(&commit_progress_tid, NULL,
+ commit_progress_thread_proc, &args);
+ if (ret) {
+ errno = ret;
+ ERROR_WITH_ERRNO("Can't create thread");
+ ret = WIMLIB_ERR_NOMEM;
+ goto out_delete_mq;
+ }
+ unmount_info.unmount_flags |= WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS;