X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fmount_image.c;h=090a828026e95e197180cf96bd8f4513125a9208;hb=17dd0feabb235443ca310bfafbd95adfa54924cb;hp=e361ddb8abb47a650b3befa8baf4874737843125;hpb=d86acf5e9930ee5cdf5150f30b51701fc81c2204;p=wimlib diff --git a/src/mount_image.c b/src/mount_image.c index e361ddb8..090a8280 100644 --- a/src/mount_image.c +++ b/src/mount_image.c @@ -291,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++; @@ -1016,19 +1016,21 @@ enum { MSG_TYPE_MAX, }; -struct msg_handler_context { +struct msg_handler_context_hdr { int timeout_seconds; - union { - struct { - pid_t daemon_pid; - int mount_flags; - int status; - wimlib_progress_func_t progress_func; - } unmount; - struct { - struct wimfs_context *wimfs_ctx; - } daemon; - }; +}; + +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, @@ -1037,7 +1039,7 @@ static int send_unmount_request_msg(mqd_t mq, int unmount_flags, 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), @@ -1060,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), @@ -1080,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), @@ -1097,7 +1099,7 @@ static int unmount_progress_func(enum wimlib_progress_msg msg, if (msg == WIMLIB_PROGRESS_MSG_WRITE_STREAMS) { struct msg_write_streams_progress 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_WRITE_STREAMS_PROGRESS, .msg_size = sizeof(msg), @@ -1107,16 +1109,17 @@ static int unmount_progress_func(enum wimlib_progress_msg msg, if (mq_send(wimfs_get_context()->daemon_to_unmount_mq, (void*)&msg, sizeof(msg), 1)) { - ERROR_WITH_ERRNO("Failed to send status to unmount process"); + ERROR_WITH_ERRNO("Failed to send progress information " + "to unmount process"); } } return 0; } -static int msg_unmount_request_handler(const void *_msg, - struct msg_handler_context *handler_ctx) +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; @@ -1125,9 +1128,7 @@ static int msg_unmount_request_handler(const void *_msg, 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; @@ -1176,59 +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_write_streams_progress_handler(const void *_msg, - struct msg_handler_context *handler_ctx) + 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->unmount.progress_func) { - handler_ctx->unmount.progress_func(WIMLIB_PROGRESS_MSG_WRITE_STREAMS, - &msg->info); + 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, - struct msg_handler_context *handler_ctx) +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 { - kill(handler_ctx->unmount.daemon_pid, 0); + kill(handler_ctx->daemon_pid, 0); if (errno == ESRCH) { goto out_crashed; } else { DEBUG("Filesystem daemon is still alive... " "Waiting another %d seconds\n", - handler_ctx->timeout_seconds); + handler_ctx->hdr.timeout_seconds); return 0; } } @@ -1238,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]; }; @@ -1268,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) { @@ -1314,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; @@ -1381,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; } @@ -1455,25 +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 = { - .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 @@ -1600,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; @@ -2361,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()"); @@ -2520,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 = { - .timeout_seconds = 5, - .unmount = { - .daemon_pid = 0, - .progress_func = progress_func, + 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: