X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fmount.c;h=6efe84c6a375468654f246b3313b055d5782f682;hb=35fe5c7c2f2e5054abd93a7b755c2c670ee476da;hp=7d1ba19970eac069684f6c9018b8d72add308da4;hpb=60b8f54df8fed44136bdc8ec615ee62703d87b69;p=wimlib diff --git a/src/mount.c b/src/mount.c index 7d1ba199..6efe84c6 100644 --- a/src/mount.c +++ b/src/mount.c @@ -29,6 +29,7 @@ #include "wimlib_internal.h" #ifdef WITH_FUSE + #include "sha1.h" #include "lookup_table.h" #include "xml.h" @@ -44,6 +45,7 @@ #include #include #include +#include #ifdef ENABLE_XATTR #include @@ -592,8 +594,8 @@ static inline int delete_staging_dir() * commands */ static char *unmount_to_daemon_mq_name; static char *daemon_to_unmount_mq_name; -static int unmount_to_daemon_mq; -static int daemon_to_unmount_mq; +static mqd_t unmount_to_daemon_mq; +static mqd_t daemon_to_unmount_mq; /* Simple function that returns the concatenation of 4 strings. */ static char *strcat_dup(const char *s1, const char *s2, const char *s3, @@ -681,7 +683,7 @@ static int open_message_queues(bool daemon) unmount_to_daemon_mq = mq_open(unmount_to_daemon_mq_name, flags, 0700, NULL); - if (unmount_to_daemon_mq == -1) { + if (unmount_to_daemon_mq == (mqd_t)-1) { ERROR_WITH_ERRNO("mq_open()"); ret = WIMLIB_ERR_MQUEUE; goto err2; @@ -695,7 +697,7 @@ static int open_message_queues(bool daemon) daemon_to_unmount_mq = mq_open(daemon_to_unmount_mq_name, flags, 0700, NULL); - if (daemon_to_unmount_mq == -1) { + if (daemon_to_unmount_mq == (mqd_t)-1) { ERROR_WITH_ERRNO("mq_open()"); ret = WIMLIB_ERR_MQUEUE; goto err3; @@ -1376,6 +1378,31 @@ static int wimfs_readlink(const char *path, char *buf, size_t buf_len) return ret; } +/* Creation time, write time, access time */ +static void +dentry_link_group_set_times(struct dentry *dentry, u64 times[3]) +{ + struct dentry *cur = dentry; + do { + if (times[0]) + cur->creation_time = times[0]; + if (times[1]) + cur->last_write_time = times[1]; + if (times[2]) + cur->last_access_time = times[2]; + } while ((cur = container_of(dentry->link_group_list.next, + struct dentry, + link_group_list)) != dentry); +} + +static void +dentry_link_group_update_times(struct dentry *dentry) +{ + u64 now = get_wim_timestamp(); + u64 times[3] = {now, now, now}; + dentry_link_group_set_times(dentry, times); +} + /* Close a file. */ static int wimfs_release(const char *path, struct fuse_file_info *fi) { @@ -1388,12 +1415,6 @@ static int wimfs_release(const char *path, struct fuse_file_info *fi) return 0; } - if (flags_writable(fi->flags) && fd->dentry) { - u64 now = get_wim_timestamp(); - fd->dentry->last_access_time = now; - fd->dentry->last_write_time = now; - } - return close_wimlib_fd(fd); } @@ -1655,7 +1676,7 @@ static int wimfs_truncate(const char *path, off_t size) ret = extract_resource_to_staging_dir(dentry, stream_idx, <e, size); } - dentry_update_all_timestamps(dentry); + dentry_link_group_update_times(dentry); return ret; } @@ -1688,6 +1709,7 @@ static int wimfs_unlink(const char *path) return 0; } +#ifdef HAVE_UTIMENSAT /* * Change the timestamp on a file dentry. * @@ -1698,20 +1720,36 @@ static int wimfs_utimens(const char *path, const struct timespec tv[2]) struct dentry *dentry = get_dentry(w, path); if (!dentry) return -ENOENT; + u64 times[3] = {0, 0, 0}; if (tv[0].tv_nsec != UTIME_OMIT) { if (tv[0].tv_nsec == UTIME_NOW) - dentry->last_access_time = get_wim_timestamp(); + times[2] = get_wim_timestamp(); else - dentry->last_access_time = timespec_to_wim_timestamp(&tv[0]); + times[2] = timespec_to_wim_timestamp(&tv[0]); } if (tv[1].tv_nsec != UTIME_OMIT) { if (tv[1].tv_nsec == UTIME_NOW) - dentry->last_write_time = get_wim_timestamp(); + times[1] = get_wim_timestamp(); else - dentry->last_write_time = timespec_to_wim_timestamp(&tv[1]); + times[1] = timespec_to_wim_timestamp(&tv[1]); } + dentry_link_group_set_times(dentry, times); return 0; } +#else +static int wimfs_utime(const char *path, struct utimbuf *times) +{ + struct dentry *dentry = get_dentry(w, path); + if (!dentry) + return -ENOENT; + u64 wim_times[3]; + wim_times[0] = 0; + wim_times[1] = unix_timestamp_to_wim(times->modtime); + wim_times[2] = unix_timestamp_to_wim(times->actime); + dentry_link_group_set_times(dentry, wim_times); + return 0; +} +#endif /* Writes to a file in the WIM filesystem. * It may be an alternate data stream, but here we don't even notice because we @@ -1736,6 +1774,12 @@ static int wimfs_write(const char *path, const char *buf, size_t size, if (ret == -1) return -errno; + if (fd->dentry) { + u64 now = get_wim_timestamp(); + u64 times[3] = {0, now, now}; + dentry_link_group_set_times(fd->dentry, times); + } + return ret; } @@ -1775,7 +1819,11 @@ static struct fuse_operations wimfs_operations = { .symlink = wimfs_symlink, .truncate = wimfs_truncate, .unlink = wimfs_unlink, +#ifdef HAVE_UTIMENSAT .utimens = wimfs_utimens, +#else + .utime = wimfs_utime, +#endif .write = wimfs_write, }; @@ -1822,35 +1870,54 @@ static int check_lte_refcnt(struct lookup_table_entry *lte, void *ignore) /* Mounts a WIM file. */ WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir, - int flags) + int flags, WIMStruct **additional_swms, + unsigned num_additional_swms) { int argc = 0; char *argv[16]; int ret; char *p; + struct lookup_table *joined_tab, *wim_tab_save; DEBUG("Mount: wim = %p, image = %d, dir = %s, flags = %d, ", wim, image, dir, flags); - if (!dir) + if (!wim || !dir) return WIMLIB_ERR_INVALID_PARAM; + ret = verify_swm_set(wim, additional_swms, num_additional_swms); + if (ret != 0) + return ret; + + if (num_additional_swms) { + ret = new_joined_lookup_table(wim, additional_swms, + num_additional_swms, + &joined_tab); + if (ret != 0) + return ret; + wim_tab_save = wim->lookup_table; + wim->lookup_table = joined_tab; + } + ret = wimlib_select_image(wim, image); if (ret != 0) - return ret; + goto out; DEBUG("Selected image %d", image); next_link_group_id = assign_link_group_ids(wim->image_metadata[image - 1].lgt); + DEBUG("Resolving lookup table entries"); /* Resolve all the lookup table entries of the dentry tree */ for_dentry_in_tree(wim_root_dentry(wim), dentry_resolve_ltes, wim->lookup_table); + DEBUG("Checking lookup table entry reference counts"); + ret = for_lookup_table_entry(wim->lookup_table, check_lte_refcnt, NULL); if (ret != 0) - return ret; + goto out; if (flags & WIMLIB_MOUNT_FLAG_READWRITE) wim_get_current_image_metadata(wim)->modified = true; @@ -1860,16 +1927,33 @@ WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir, WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS))) flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR; + DEBUG("Getting current directory"); + mount_dir = dir; working_directory = getcwd(NULL, 0); if (!working_directory) { ERROR_WITH_ERRNO("Could not determine current directory"); - return WIMLIB_ERR_NOTDIR; + ret = WIMLIB_ERR_NOTDIR; + goto out; } + DEBUG("Closing POSIX message queues"); + /* XXX hack to get rid of the message queues if they already exist for + * some reason (maybe left over from a previous mount that wasn't + * unmounted correctly) */ + ret = open_message_queues(true); + if (ret != 0) + goto out; + close_message_queues(); + + DEBUG("Preparing arguments to fuse_main()"); + + p = STRDUP(dir); - if (!p) - return WIMLIB_ERR_NOMEM; + if (!p) { + ret = WIMLIB_ERR_NOMEM; + goto out; + } argv[argc++] = "imagex"; argv[argc++] = p; @@ -1893,12 +1977,14 @@ WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir, make_staging_dir(); if (!staging_dir_name) { FREE(p); - return WIMLIB_ERR_MKDIR; + ret = WIMLIB_ERR_MKDIR; + goto out; } } else { /* Read-only mount */ strcat(optstring, ",ro"); } + strcat(optstring, ",subtype=wimfs,attr_timeout=0"); argv[argc] = NULL; #ifdef ENABLE_DEBUG @@ -1919,8 +2005,14 @@ WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir, mount_flags = flags; ret = fuse_main(argc, argv, &wimfs_operations, NULL); - - return (ret == 0) ? 0 : WIMLIB_ERR_FUSE; + if (ret) + ret = WIMLIB_ERR_FUSE; +out: + if (num_additional_swms) { + free_lookup_table(wim->lookup_table); + wim->lookup_table = wim_tab_save; + } + return ret; } @@ -1939,6 +2031,30 @@ WIMLIBAPI int wimlib_unmount(const char *dir, int flags) int msgsize; int errno_save; + mount_dir = dir; + + /* Open message queues between the unmount process and the + * filesystem daemon. */ + ret = open_message_queues(false); + if (ret != 0) + return ret; + + /* Send a message to the filesystem saying whether to commit or + * not. */ + msg[0] = (flags & WIMLIB_UNMOUNT_FLAG_COMMIT) ? 1 : 0; + msg[1] = (flags & WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY) ? 1 : 0; + + DEBUG("Sending message: %s, %s", + (msg[0] == 0) ? "don't commit" : "commit", + (msg[1] == 0) ? "don't check" : "check"); + ret = mq_send(unmount_to_daemon_mq, msg, 2, 1); + if (ret == -1) { + ERROR("Failed to notify filesystem daemon whether we want to " + "commit changes or not"); + close_message_queues(); + return WIMLIB_ERR_MQUEUE; + } + /* Execute `fusermount -u', which is installed setuid root, to unmount * the WIM. * @@ -1951,7 +2067,7 @@ WIMLIBAPI int wimlib_unmount(const char *dir, int flags) * the WIM file. */ - mount_dir = dir; + pid = fork(); if (pid == -1) { ERROR_WITH_ERRNO("Failed to fork()"); @@ -1960,10 +2076,10 @@ WIMLIBAPI int wimlib_unmount(const char *dir, int flags) if (pid == 0) { execlp("fusermount", "fusermount", "-u", dir, NULL); ERROR_WITH_ERRNO("Failed to execute `fusermount'"); - return WIMLIB_ERR_FUSERMOUNT; + exit(WIMLIB_ERR_FUSERMOUNT); } - ret = waitpid(pid, &status, 0); + ret = wait(&status); if (ret == -1) { ERROR_WITH_ERRNO("Failed to wait for fusermount process to " "terminate"); @@ -1972,31 +2088,35 @@ WIMLIBAPI int wimlib_unmount(const char *dir, int flags) if (status != 0) { ERROR("fusermount exited with status %d", status); - return WIMLIB_ERR_FUSERMOUNT; - } - /* Open message queues between the unmount process and the - * filesystem daemon. */ - ret = open_message_queues(false); - if (ret != 0) - return ret; + /* 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. */ - /* Send a message to the filesystem saying whether to commit or - * not. */ - msg[0] = (flags & WIMLIB_UNMOUNT_FLAG_COMMIT) ? 1 : 0; - msg[1] = (flags & WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY) ? 1 : 0; + pid = fork(); + if (pid == -1) { + ERROR_WITH_ERRNO("Failed to fork()"); + return WIMLIB_ERR_FORK; + } + if (pid == 0) { + execlp("umount", "umount", dir, NULL); + ERROR_WITH_ERRNO("Failed to execute `umount'"); + exit(WIMLIB_ERR_FUSERMOUNT); + } - DEBUG("Sending message: %s, %s", - (msg[0] == 0) ? "don't commit" : "commit", - (msg[1] == 0) ? "don't check" : "check"); - ret = mq_send(unmount_to_daemon_mq, msg, 2, 1); - if (ret == -1) { - ERROR("Failed to notify filesystem daemon whether we want to " - "commit changes or not"); - close_message_queues(); - return WIMLIB_ERR_MQUEUE; + 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; + } } + /* Wait for a message from the filesytem daemon indicating whether the * filesystem was unmounted successfully (0) or an error occurred (1). * This may take a long time if a big WIM file needs to be rewritten. */ @@ -2060,7 +2180,8 @@ WIMLIBAPI int wimlib_unmount(const char *dir, int flags) } WIMLIBAPI int wimlib_mount(WIMStruct *wim_p, int image, const char *dir, - int flags) + int flags, WIMStruct **additional_swms, + unsigned num_additional_swms) { return mount_unsupported_error(); }