X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fmount_image.c;h=090a828026e95e197180cf96bd8f4513125a9208;hb=051e6d3d1c88715d21b422fbcc806ab02d61ab67;hp=7bede83da5026abd01e202c0e0f62e970d441511;hpb=9f9d3eb4bb33782c66d52b825bb84578f74de817;p=wimlib diff --git a/src/mount_image.c b/src/mount_image.c index 7bede83d..090a8280 100644 --- a/src/mount_image.c +++ b/src/mount_image.c @@ -47,6 +47,7 @@ #include #include #include +#include #ifdef ENABLE_XATTR #include @@ -290,7 +291,7 @@ static int create_dentry(struct wimfs_context *ctx, const char *path, new = new_dentry_with_inode(basename); if (!new) - return -ENOMEM; + return -errno; new->d_inode->resolved = 1; new->d_inode->ino = ctx->next_ino++; @@ -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; @@ -1334,46 +1389,53 @@ static int execute_fusermount(const char *dir) } /* Parent */ - ret = wait(&status); + ret = waitpid(pid, &status, 0); if (ret == -1) { ERROR_WITH_ERRNO("Failed to wait for fusermount process to " "terminate"); return WIMLIB_ERR_FUSERMOUNT; } - if (status != 0) { - if (status == WIMLIB_ERR_FUSERMOUNT) - ERROR("Could not find the `fusermount' program"); - else - ERROR("fusermount exited with status %d", status); + if (!WIFEXITED(status)) { + ERROR("'fusermount' did not terminate normally!"); + return WIMLIB_ERR_FUSERMOUNT; + } - /* Try again, but with the `umount' program. This is required - * on other FUSE implementations such as FreeBSD's that do not - * have a `fusermount' program. */ + status = WEXITSTATUS(status); - pid = fork(); - if (pid == -1) { - ERROR_WITH_ERRNO("Failed to fork()"); - return WIMLIB_ERR_FORK; - } - if (pid == 0) { - /* Child */ - execlp("umount", "umount", dir, NULL); - ERROR_WITH_ERRNO("Failed to execute `umount'"); - exit(WIMLIB_ERR_FUSERMOUNT); - } + if (status == 0) + return 0; - /* Parent */ - ret = wait(&status); - if (ret == -1) { - ERROR_WITH_ERRNO("Failed to wait for `umount' process to " - "terminate"); - return WIMLIB_ERR_FUSERMOUNT; - } - if (status != 0) { - ERROR("`umount' exited with failure status"); - return WIMLIB_ERR_FUSERMOUNT; - } + if (status != WIMLIB_ERR_FUSERMOUNT) + return WIMLIB_ERR_FUSERMOUNT; + + /* Try again, but with the `umount' program. This is required on other + * FUSE implementations such as FreeBSD's that do not have a + * `fusermount' program. */ + ERROR("Falling back to 'umount'. Note: you may need to be " + "root for this to work"); + pid = fork(); + if (pid == -1) { + ERROR_WITH_ERRNO("Failed to fork()"); + return WIMLIB_ERR_FORK; + } + if (pid == 0) { + /* Child */ + execlp("umount", "umount", dir, NULL); + ERROR_WITH_ERRNO("Failed to execute `umount'"); + exit(WIMLIB_ERR_FUSERMOUNT); + } + + /* Parent */ + ret = waitpid(pid, &status, 0); + if (ret == -1) { + ERROR_WITH_ERRNO("Failed to wait for `umount' process to " + "terminate"); + return WIMLIB_ERR_FUSERMOUNT; + } + if (status != 0) { + ERROR("`umount' did not successfully complete"); + return WIMLIB_ERR_FUSERMOUNT; } return 0; } @@ -1408,26 +1470,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 @@ -1554,7 +1609,7 @@ static int wimfs_link(const char *to, const char *from) return -EEXIST; from_dentry = new_dentry(link_name); if (!from_dentry) - return -ENOMEM; + return -errno; inode_add_dentry(from_dentry, inode); from_dentry->d_inode = inode; @@ -2315,6 +2370,9 @@ WIMLIBAPI int wimlib_mount_image(WIMStruct *wim, int image, const char *dir, goto out; } + if (imd->inode_list.first) + imd->inode_list.first->pprev = &imd->inode_list.first; + if (imd->modified) { ERROR("Cannot mount image that was added " "with wimlib_add_image()"); @@ -2465,7 +2523,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 +2532,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: