#include <ftw.h>
#include <mqueue.h>
#include <utime.h>
+#include <signal.h>
#ifdef ENABLE_XATTR
#include <attr/xattr.h>
}
/* Overwrites the WIM file, with changes saved. */
-static int rebuild_wim(struct wimfs_context *ctx, int write_flags)
+static int rebuild_wim(struct wimfs_context *ctx, int write_flags,
+ wimlib_progress_func_t progress_func)
{
int ret;
struct lookup_table_entry *lte, *tmp;
}
xml_update_image_info(w, w->current_image);
- ret = wimlib_overwrite(w, write_flags, 0, NULL);
+ ret = wimlib_overwrite(w, write_flags, 0, progress_func);
if (ret != 0)
ERROR("Failed to commit changes to mounted WIM image");
return ret;
struct msg_unmount_request {
struct unmount_msg_hdr hdr;
u32 unmount_flags;
+ u8 want_progress_messages;
} PACKED;
struct msg_daemon_info {
int32_t status;
} PACKED;
+struct msg_write_streams_progress {
+ struct unmount_msg_hdr hdr;
+ union wimlib_progress_info info;
+} PACKED;
+
enum {
MSG_TYPE_UNMOUNT_REQUEST,
MSG_TYPE_DAEMON_INFO,
+ MSG_TYPE_WRITE_STREAMS_PROGRESS,
MSG_TYPE_UNMOUNT_FINISHED,
MSG_TYPE_MAX,
};
-struct msg_handler_context {
- bool is_daemon;
+struct msg_handler_context_hdr {
int timeout_seconds;
- union {
- struct {
- /*bool unmount_complete;*/
- pid_t daemon_pid;
- int mount_flags;
- int status;
- } unmount;
- struct {
- /*int unmount_flags;*/
- struct wimfs_context *wimfs_ctx;
- } daemon;
- };
};
-static int send_unmount_request_msg(mqd_t mq, int unmount_flags)
+struct unmount_msg_handler_context {
+ struct msg_handler_context_hdr hdr;
+ pid_t daemon_pid;
+ int mount_flags;
+ int status;
+ wimlib_progress_func_t progress_func;
+};
+
+struct daemon_msg_handler_context {
+ struct msg_handler_context_hdr hdr;
+ struct wimfs_context *wimfs_ctx;
+};
+
+static int send_unmount_request_msg(mqd_t mq, int unmount_flags,
+ u8 want_progress_messages)
{
DEBUG("Sending unmount request msg");
struct msg_unmount_request msg = {
.hdr = {
- .min_version = WIMLIB_MAKEVERSION(1, 2, 0),
+ .min_version = WIMLIB_MAKEVERSION(1, 2, 1),
.cur_version = WIMLIB_VERSION_CODE,
.msg_type = MSG_TYPE_UNMOUNT_REQUEST,
.msg_size = sizeof(msg),
},
.unmount_flags = unmount_flags,
+ .want_progress_messages = want_progress_messages,
};
if (mq_send(mq, (void*)&msg, sizeof(msg), 1)) {
struct msg_daemon_info msg = {
.hdr = {
- .min_version = WIMLIB_MAKEVERSION(1, 2, 0),
+ .min_version = WIMLIB_MAKEVERSION(1, 2, 1),
.cur_version = WIMLIB_VERSION_CODE,
.msg_type = MSG_TYPE_DAEMON_INFO,
.msg_size = sizeof(msg),
DEBUG("Sending unmount finished msg");
struct msg_unmount_finished msg = {
.hdr = {
- .min_version = WIMLIB_MAKEVERSION(1, 2, 0),
+ .min_version = WIMLIB_MAKEVERSION(1, 2, 1),
.cur_version = WIMLIB_VERSION_CODE,
.msg_type = MSG_TYPE_UNMOUNT_FINISHED,
.msg_size = sizeof(msg),
ERROR_WITH_ERRNO("Failed to send status to unmount process");
}
-static int msg_unmount_request_handler(const void *_msg,
- struct msg_handler_context *handler_ctx)
+static int unmount_progress_func(enum wimlib_progress_msg msg,
+ const union wimlib_progress_info *info)
+{
+ if (msg == WIMLIB_PROGRESS_MSG_WRITE_STREAMS) {
+ struct msg_write_streams_progress msg = {
+ .hdr = {
+ .min_version = WIMLIB_MAKEVERSION(1, 2, 1),
+ .cur_version = WIMLIB_VERSION_CODE,
+ .msg_type = MSG_TYPE_WRITE_STREAMS_PROGRESS,
+ .msg_size = sizeof(msg),
+ },
+ .info = *info,
+ };
+ if (mq_send(wimfs_get_context()->daemon_to_unmount_mq,
+ (void*)&msg, sizeof(msg), 1))
+ {
+ ERROR_WITH_ERRNO("Failed to send progress information "
+ "to unmount process");
+ }
+ }
+ return 0;
+}
+
+static int msg_unmount_request_handler(const void *_msg, void *_handler_ctx)
{
- const struct msg_unmount_request *msg;
+ const struct msg_unmount_request *msg = _msg;
+ struct daemon_msg_handler_context *handler_ctx = _handler_ctx;
struct wimfs_context *wimfs_ctx;
int status = 0;
int ret;
int unmount_flags;
+ wimlib_progress_func_t progress_func;
DEBUG("Handling unmount request msg");
- msg = _msg;
- wimfs_ctx = handler_ctx->daemon.wimfs_ctx;
-
+ wimfs_ctx = handler_ctx->wimfs_ctx;
if (msg->hdr.msg_size < sizeof(*msg)) {
status = WIMLIB_ERR_INVALID_UNMOUNT_MESSAGE;
goto out;
}
unmount_flags = msg->unmount_flags;
+ if (msg->want_progress_messages)
+ progress_func = unmount_progress_func;
+ else
+ progress_func = NULL;
ret = send_daemon_info_msg(wimfs_ctx->daemon_to_unmount_mq, getpid(),
wimfs_ctx->mount_flags);
write_flags |= WIMLIB_WRITE_FLAG_REBUILD;
if (unmount_flags & WIMLIB_UNMOUNT_FLAG_RECOMPRESS)
write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
- status = rebuild_wim(wimfs_ctx, write_flags);
+ status = rebuild_wim(wimfs_ctx, write_flags,
+ progress_func);
}
} else {
DEBUG("Read-only mount");
return MSG_BREAK_LOOP;
}
-static int msg_daemon_info_handler(const void *_msg,
- struct msg_handler_context *handler_ctx)
+static int msg_daemon_info_handler(const void *_msg, void *_handler_ctx)
{
const struct msg_daemon_info *msg = _msg;
+ struct unmount_msg_handler_context *handler_ctx = _handler_ctx;
+
DEBUG("Handling daemon info msg");
if (msg->hdr.msg_size < sizeof(*msg))
return WIMLIB_ERR_INVALID_UNMOUNT_MESSAGE;
- handler_ctx->unmount.daemon_pid = msg->daemon_pid;
- handler_ctx->unmount.mount_flags = msg->mount_flags;
- handler_ctx->timeout_seconds = 1;
+ handler_ctx->daemon_pid = msg->daemon_pid;
+ handler_ctx->mount_flags = msg->mount_flags;
+ handler_ctx->hdr.timeout_seconds = 1;
DEBUG("pid of daemon is %d; mount flags were %#x",
- handler_ctx->unmount.daemon_pid,
- handler_ctx->unmount.mount_flags);
+ handler_ctx->daemon_pid,
+ handler_ctx->mount_flags);
return 0;
}
-static int msg_unmount_finished_handler(const void *_msg,
- struct msg_handler_context *handler_ctx)
+static int msg_write_streams_progress_handler(const void *_msg,
+ void *_handler_ctx)
+{
+ const struct msg_write_streams_progress *msg = _msg;
+ struct unmount_msg_handler_context *handler_ctx = _handler_ctx;
+
+ if (msg->hdr.msg_size < sizeof(*msg))
+ return WIMLIB_ERR_INVALID_UNMOUNT_MESSAGE;
+ if (handler_ctx->progress_func) {
+ handler_ctx->progress_func(WIMLIB_PROGRESS_MSG_WRITE_STREAMS,
+ &msg->info);
+ }
+ return 0;
+}
+
+static int msg_unmount_finished_handler(const void *_msg, void *_handler_ctx)
{
const struct msg_unmount_finished *msg = _msg;
+ struct unmount_msg_handler_context *handler_ctx = _handler_ctx;
+
DEBUG("Handling unmount finished message");
if (msg->hdr.msg_size < sizeof(*msg))
return WIMLIB_ERR_INVALID_UNMOUNT_MESSAGE;
- handler_ctx->unmount.status = msg->status;
- DEBUG("status is %d", handler_ctx->unmount.status);
+ handler_ctx->status = msg->status;
+ DEBUG("status is %d", handler_ctx->status);
return MSG_BREAK_LOOP;
}
-static int unmount_timed_out_cb(struct msg_handler_context *handler_ctx)
+static int unmount_timed_out_cb(void *_handler_ctx)
{
- if (handler_ctx->unmount.daemon_pid == 0) {
+ struct unmount_msg_handler_context *handler_ctx = _handler_ctx;
+
+ if (handler_ctx->daemon_pid == 0) {
goto out_crashed;
} else {
- errno = 0;
- kill(handler_ctx->unmount.daemon_pid, 0);
+ kill(handler_ctx->daemon_pid, 0);
if (errno == ESRCH) {
goto out_crashed;
- } else if (errno != 0) {
- ERROR_WITH_ERRNO("Error determining state of "
- "filesystem daemon");
- return WIMLIB_ERR_MQUEUE;
} else {
DEBUG("Filesystem daemon is still alive... "
- "Waiting another %d seconds",
- handler_ctx->timeout_seconds);
+ "Waiting another %d seconds\n",
+ handler_ctx->hdr.timeout_seconds);
return 0;
}
}
return WIMLIB_ERR_FILESYSTEM_DAEMON_CRASHED;
}
-static int daemon_timed_out_cb(struct msg_handler_context *handler_ctx)
+static int daemon_timed_out_cb(void *_handler_ctx)
{
- DEBUG("Timed out");
+ ERROR("Timed out waiting for unmount request! "
+ "Changes to the mounted WIM will not be committed.");
return WIMLIB_ERR_TIMEOUT;
}
-typedef int (*msg_handler_t)(const void *_msg,
- struct msg_handler_context *handler_ctx);
+typedef int (*msg_handler_t)(const void *_msg, void *_handler_ctx);
struct msg_handler_callbacks {
- int (*timed_out)(struct msg_handler_context *);
+ int (*timed_out)(void * _handler_ctx);
msg_handler_t msg_handlers[MSG_TYPE_MAX];
};
.timed_out = unmount_timed_out_cb,
.msg_handlers = {
[MSG_TYPE_DAEMON_INFO] = msg_daemon_info_handler,
+ [MSG_TYPE_WRITE_STREAMS_PROGRESS] = msg_write_streams_progress_handler,
[MSG_TYPE_UNMOUNT_FINISHED] = msg_unmount_finished_handler,
},
};
},
};
-static int receive_message(mqd_t mq, struct msg_handler_context *handler_ctx,
+static int receive_message(mqd_t mq,
+ struct msg_handler_context_hdr *handler_ctx,
const msg_handler_t msg_handlers[],
long mailbox_size, void *mailbox)
{
mailbox_size, NULL, &timeout);
hdr = mailbox;
if (bytes_received == -1) {
- ERROR_WITH_ERRNO("mq_timedreceive()");
- if (errno == ETIMEDOUT)
+ if (errno == ETIMEDOUT) {
ret = WIMLIB_ERR_TIMEOUT;
- else
+ } else {
+ ERROR_WITH_ERRNO("mq_timedreceive()");
ret = WIMLIB_ERR_MQUEUE;
+ }
} else if (bytes_received < sizeof(*hdr) ||
bytes_received != hdr->msg_size) {
ret = WIMLIB_ERR_INVALID_UNMOUNT_MESSAGE;
static int message_loop(mqd_t mq,
const struct msg_handler_callbacks *callbacks,
- struct msg_handler_context *handler_ctx)
+ struct msg_handler_context_hdr *handler_ctx)
{
static const size_t MAX_MSG_SIZE = 512;
long msgsize;
/* Called when the filesystem is unmounted. */
static void wimfs_destroy(void *p)
{
- struct wimfs_context *wimfs_ctx;
-
- wimfs_ctx = wimfs_get_context();
-
- if (open_message_queues(wimfs_ctx, true))
- return;
-
- struct msg_handler_context handler_ctx = {
- .is_daemon = true,
- .timeout_seconds = 5,
- .daemon = {
+ struct wimfs_context *wimfs_ctx = wimfs_get_context();
+ if (open_message_queues(wimfs_ctx, true) == 0) {
+ struct daemon_msg_handler_context handler_ctx = {
+ .hdr = {
+ .timeout_seconds = 5,
+ },
.wimfs_ctx = wimfs_ctx,
- },
- };
-
- message_loop(wimfs_ctx->unmount_to_daemon_mq,
- &daemon_msg_handler_callbacks,
- &handler_ctx);
-
- close_message_queues(wimfs_ctx);
+ };
+ message_loop(wimfs_ctx->unmount_to_daemon_mq,
+ &daemon_msg_handler_callbacks,
+ &handler_ctx.hdr);
+ close_message_queues(wimfs_ctx);
+ }
}
#if 0
goto out_free_message_queue_names;
ret = send_unmount_request_msg(wimfs_ctx.unmount_to_daemon_mq,
- unmount_flags);
+ unmount_flags,
+ progress_func != NULL);
if (ret != 0)
goto out_close_message_queues;
if (ret != 0)
goto out_close_message_queues;
- struct msg_handler_context handler_ctx = {
- .is_daemon = false,
- .timeout_seconds = 5,
- .unmount = {
- .daemon_pid = 0,
+ struct unmount_msg_handler_context handler_ctx = {
+ .hdr = {
+ .timeout_seconds = 5,
},
+ .daemon_pid = 0,
+ .progress_func = progress_func,
};
ret = message_loop(wimfs_ctx.daemon_to_unmount_mq,
&unmount_msg_handler_callbacks,
- &handler_ctx);
+ &handler_ctx.hdr);
if (ret == 0)
- ret = handler_ctx.unmount.status;
+ ret = handler_ctx.status;
out_close_message_queues:
close_message_queues(&wimfs_ctx);
out_free_message_queue_names: