X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fmount_image.c;h=b3ae030da0a4c0c875beeb6304a71925ed46d98f;hp=7bede83da5026abd01e202c0e0f62e970d441511;hb=d51804ff6b85dbcbb98a96f6c6bd5e9cec612bae;hpb=9f9d3eb4bb33782c66d52b825bb84578f74de817 diff --git a/src/mount_image.c b/src/mount_image.c index 7bede83d..b3ae030d 100644 --- a/src/mount_image.c +++ b/src/mount_image.c @@ -47,6 +47,7 @@ #include #include #include +#include #ifdef ENABLE_XATTR #include @@ -765,7 +766,8 @@ static int inode_close_fds(struct inode *inode) } /* 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; @@ -786,7 +788,7 @@ static int rebuild_wim(struct wimfs_context *ctx, int write_flags) } 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; @@ -987,6 +989,7 @@ struct unmount_msg_hdr { struct msg_unmount_request { struct unmount_msg_hdr hdr; u32 unmount_flags; + u8 want_progress_messages; } PACKED; struct msg_daemon_info { @@ -1000,41 +1003,49 @@ struct msg_unmount_finished { 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)) { @@ -1051,7 +1062,7 @@ static int send_daemon_info_msg(mqd_t mq, pid_t pid, int mount_flags) 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), @@ -1071,7 +1082,7 @@ static void send_unmount_finished_msg(mqd_t mq, int status) 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), @@ -1082,26 +1093,52 @@ static void send_unmount_finished_msg(mqd_t mq, int status) 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); @@ -1119,7 +1156,8 @@ static int msg_unmount_request_handler(const void *_msg, 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"); @@ -1139,51 +1177,65 @@ out: 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; } } @@ -1193,17 +1245,17 @@ out_crashed: 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]; }; @@ -1211,6 +1263,7 @@ static const struct msg_handler_callbacks unmount_msg_handler_callbacks = { .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, }, }; @@ -1222,7 +1275,8 @@ static const struct msg_handler_callbacks daemon_msg_handler_callbacks = { }, }; -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) { @@ -1240,11 +1294,12 @@ static int receive_message(mqd_t mq, struct msg_handler_context *handler_ctx, 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; @@ -1267,7 +1322,7 @@ static int receive_message(mqd_t mq, struct msg_handler_context *handler_ctx, 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; @@ -1408,26 +1463,19 @@ static int wimfs_chmod(const char *path, mode_t mask) /* 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 @@ -2465,7 +2513,8 @@ WIMLIBAPI int wimlib_unmount_image(const char *dir, int unmount_flags, 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; @@ -2473,19 +2522,19 @@ WIMLIBAPI int wimlib_unmount_image(const char *dir, int unmount_flags, 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: