X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fmount_image.c;h=168ee8523bc9bc038a9c678bdbf9c2f50fce62e9;hb=1ea0ec53c60c4b34b594d1d4785f00fbef76c366;hp=ac993e17b2f7f54cc366780832c84b30ee5a865a;hpb=668b627e9c3400a579d7057038e03e6977369c4b;p=wimlib diff --git a/src/mount_image.c b/src/mount_image.c index ac993e17..168ee852 100644 --- a/src/mount_image.c +++ b/src/mount_image.c @@ -46,9 +46,11 @@ #include "wimlib/lookup_table.h" #include "wimlib/metadata.h" #include "wimlib/paths.h" +#include "wimlib/progress.h" #include "wimlib/reparse.h" #include "wimlib/resource.h" #include "wimlib/timestamp.h" +#include "wimlib/unix_data.h" #include "wimlib/version.h" #include "wimlib/write.h" #include "wimlib/xml.h" @@ -313,7 +315,8 @@ fuse_mask_mode(mode_t mode, struct fuse_context *fuse_ctx) */ static int create_dentry(struct fuse_context *fuse_ctx, const char *path, - mode_t mode, int attributes, struct wim_dentry **dentry_ret) + mode_t mode, dev_t rdev, int attributes, + struct wim_dentry **dentry_ret) { struct wim_dentry *parent; struct wim_dentry *new; @@ -341,12 +344,15 @@ create_dentry(struct fuse_context *fuse_ctx, const char *path, new->d_inode->i_attributes = attributes; if (wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) { - if (inode_set_unix_data(new->d_inode, - fuse_ctx->uid, - fuse_ctx->gid, - fuse_mask_mode(mode, fuse_ctx), - wimfs_ctx->wim->lookup_table, - UNIX_DATA_ALL | UNIX_DATA_CREATE)) + struct wimlib_unix_data unix_data; + + unix_data.uid = fuse_ctx->uid; + unix_data.gid = fuse_ctx->gid; + unix_data.mode = fuse_mask_mode(mode, fuse_ctx); + unix_data.rdev = rdev; + + if (!inode_set_unix_data(new->d_inode, &unix_data, + UNIX_DATA_ALL)) { free_dentry(new); return -ENOMEM; @@ -370,44 +376,39 @@ wim_pathname_to_inode(WIMStruct *wim, const tchar *path) return NULL; } -/* Remove a dentry from a mounted WIM image; i.e. remove an alias for the - * corresponding inode. - * - * If there are no remaining references to the inode either through dentries or - * open file descriptors, the inode is freed. Otherwise, the inode is not - * removed, but the dentry is unlinked and freed. - * - * Either way, all lookup table entries referenced by the inode have their - * reference count decremented. If a lookup table entry has no open file - * descriptors and no references remaining, it is freed, and the corresponding - * staging file is unlinked. +/* + * Remove a dentry from a mounted WIM image; i.e. remove an alias for an inode. */ static void remove_dentry(struct wim_dentry *dentry, struct wim_lookup_table *lookup_table) { - struct wim_inode *inode = dentry->d_inode; - struct wim_lookup_table_entry *lte; - unsigned i; + /* Put a reference to each stream the inode contains. */ + inode_unref_streams(dentry->d_inode, lookup_table); - for (i = 0; i <= inode->i_num_ads; i++) { - lte = inode_stream_lte(inode, i, lookup_table); - if (lte) - lte_decrement_refcnt(lte, lookup_table); - } + /* Unlink the dentry from the image's dentry tree. */ unlink_dentry(dentry); + + /* Delete the dentry. This will also decrement the link count of the + * corresponding inode. */ free_dentry(dentry); } static mode_t -inode_default_unix_mode(const struct wim_inode *inode) +inode_unix_file_type(const struct wim_inode *inode) { if (inode_is_symlink(inode)) - return S_IFLNK | 0777; + return S_IFLNK; else if (inode_is_directory(inode)) - return S_IFDIR | 0777; + return S_IFDIR; else - return S_IFREG | 0777; + return S_IFREG; +} + +static mode_t +inode_default_unix_mode(const struct wim_inode *inode) +{ + return inode_unix_file_type(inode) | 0777; } /* Transfers file attributes from a struct wim_inode to a `stat' buffer. @@ -421,18 +422,21 @@ inode_to_stbuf(const struct wim_inode *inode, struct stat *stbuf) { const struct wimfs_context *ctx = wimfs_get_context(); + struct wimlib_unix_data unix_data; memset(stbuf, 0, sizeof(struct stat)); - stbuf->st_mode = inode_default_unix_mode(inode); - stbuf->st_uid = ctx->default_uid; - stbuf->st_gid = ctx->default_gid; - if (ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) { - struct wimlib_unix_data unix_data; - if (inode_get_unix_data(inode, &unix_data, NULL) == 0) { - stbuf->st_uid = unix_data.uid; - stbuf->st_gid = unix_data.gid; - stbuf->st_mode = unix_data.mode; - } + if ((ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) && + inode_get_unix_data(inode, &unix_data)) + { + stbuf->st_uid = unix_data.uid; + stbuf->st_gid = unix_data.gid; + stbuf->st_mode = unix_data.mode; + stbuf->st_rdev = unix_data.rdev; + } else { + stbuf->st_uid = ctx->default_uid; + stbuf->st_gid = ctx->default_gid; + stbuf->st_mode = inode_default_unix_mode(inode); + stbuf->st_rdev = 0; } stbuf->st_ino = (ino_t)inode->i_ino; stbuf->st_nlink = inode->i_nlink; @@ -810,8 +814,7 @@ inode_close_fds(struct wim_inode *inode) /* Overwrites the WIM file, with changes saved. */ static int -rebuild_wim(struct wimfs_context *ctx, int write_flags, - wimlib_progress_func_t progress_func) +rebuild_wim(struct wimfs_context *ctx, int write_flags) { int ret; struct wim_lookup_table_entry *lte, *tmp; @@ -838,7 +841,7 @@ rebuild_wim(struct wimfs_context *ctx, int write_flags, } xml_update_image_info(wim, wim->current_image); - ret = wimlib_overwrite(wim, write_flags, 0, progress_func); + ret = wimlib_overwrite(wim, write_flags, 0); if (ret) ERROR("Failed to commit changes to mounted WIM image"); return ret; @@ -1090,7 +1093,8 @@ struct unmount_msg_handler_context { pid_t daemon_pid; int mount_flags; int status; - wimlib_progress_func_t progress_func; + wimlib_progress_func_t progfunc; + void *progctx; }; struct daemon_msg_handler_context { @@ -1162,9 +1166,9 @@ send_unmount_finished_msg(mqd_t mq, int status) ERROR_WITH_ERRNO("Failed to send status to unmount process"); } -static int +static enum wimlib_progress_status unmount_progress_func(enum wimlib_progress_msg msg, - const union wimlib_progress_info *info) + union wimlib_progress_info *info, void *_ignored_context) { if (msg == WIMLIB_PROGRESS_MSG_WRITE_STREAMS) { struct msg_write_streams_progress msg = { @@ -1183,7 +1187,7 @@ unmount_progress_func(enum wimlib_progress_msg msg, "to unmount process"); } } - return 0; + return WIMLIB_PROGRESS_STATUS_CONTINUE; } static void @@ -1269,7 +1273,6 @@ msg_unmount_request_handler(const void *_msg, void *_handler_ctx) int status = 0; int ret; int unmount_flags; - wimlib_progress_func_t progress_func; DEBUG("Handling unmount request msg"); @@ -1280,10 +1283,11 @@ msg_unmount_request_handler(const void *_msg, void *_handler_ctx) } unmount_flags = msg->unmount_flags; - if (msg->want_progress_messages) - progress_func = unmount_progress_func; - else - progress_func = NULL; + + wimlib_register_progress_function(wimfs_ctx->wim, + (msg->want_progress_messages ? + unmount_progress_func : NULL), + NULL); ret = send_daemon_info_msg(wimfs_ctx->daemon_to_unmount_mq, getpid(), wimfs_ctx->mount_flags); @@ -1313,8 +1317,7 @@ msg_unmount_request_handler(const void *_msg, void *_handler_ctx) 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, - progress_func); + status = rebuild_wim(wimfs_ctx, write_flags); } } else { DEBUG("Read-only mount"); @@ -1361,11 +1364,10 @@ msg_write_streams_progress_handler(const void *_msg, void *_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; + return call_progress(handler_ctx->progfunc, + WIMLIB_PROGRESS_MSG_WRITE_STREAMS, + (union wimlib_progress_info *)&msg->info, + handler_ctx->progctx); } static int @@ -1620,7 +1622,9 @@ static int wimfs_chmod(const char *path, mode_t mask) { struct wim_dentry *dentry; + struct wim_inode *inode; struct wimfs_context *ctx = wimfs_get_context(); + struct wimlib_unix_data unix_data; int ret; if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA)) @@ -1631,17 +1635,26 @@ wimfs_chmod(const char *path, mode_t mask) if (ret) return ret; - ret = inode_set_unix_data(dentry->d_inode, ctx->default_uid, - ctx->default_gid, mask, - ctx->wim->lookup_table, UNIX_DATA_MODE); - return ret ? -ENOMEM : 0; + inode = dentry->d_inode; + + unix_data.uid = ctx->default_uid; + unix_data.gid = ctx->default_gid; + unix_data.mode = mask; + unix_data.rdev = 0; + if (!inode_set_unix_data(inode, &unix_data, UNIX_DATA_MODE)) + return -ENOMEM; + + return 0; } static int wimfs_chown(const char *path, uid_t uid, gid_t gid) { struct wim_dentry *dentry; + struct wim_inode *inode; struct wimfs_context *ctx = wimfs_get_context(); + int which; + struct wimlib_unix_data unix_data; int ret; if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA)) @@ -1652,11 +1665,29 @@ wimfs_chown(const char *path, uid_t uid, gid_t gid) if (ret) return ret; - ret = inode_set_unix_data(dentry->d_inode, uid, gid, - inode_default_unix_mode(dentry->d_inode), - ctx->wim->lookup_table, - UNIX_DATA_UID | UNIX_DATA_GID); - return ret ? -ENOMEM : 0; + inode = dentry->d_inode; + + which = 0; + + if (uid != (uid_t)-1) + which |= UNIX_DATA_UID; + else + uid = ctx->default_uid; + + if (gid != (gid_t)-1) + which |= UNIX_DATA_GID; + else + gid = ctx->default_gid; + + + unix_data.uid = uid; + unix_data.gid = gid; + unix_data.mode = inode_default_unix_mode(inode); + unix_data.rdev = 0; + if (!inode_set_unix_data(inode, &unix_data, which)) + return -ENOMEM; + + return 0; } /* Called when the filesystem is unmounted. */ @@ -1864,11 +1895,12 @@ wimfs_listxattr(const char *path, char *list, size_t size) static int wimfs_mkdir(const char *path, mode_t mode) { - return create_dentry(fuse_get_context(), path, mode | S_IFDIR, + return create_dentry(fuse_get_context(), path, mode | S_IFDIR, 0, FILE_ATTRIBUTE_DIRECTORY, NULL); } -/* Create a regular file or alternate data stream in the WIM image. */ +/* Create a non-directory, non-symbolic-link file or alternate data stream in + * the WIM image. */ static int wimfs_mknod(const char *path, mode_t mode, dev_t rdev) { @@ -1876,11 +1908,12 @@ wimfs_mknod(const char *path, mode_t mode, dev_t rdev) struct fuse_context *fuse_ctx = fuse_get_context(); struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx); - if (!S_ISREG(mode)) - return -EPERM; - if ((wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS) && (stream_name = path_stream_name(path))) { + + if (!S_ISREG(mode)) + return -EPERM; + /* Make an alternate data stream */ struct wim_ads_entry *new_entry; struct wim_inode *inode; @@ -1901,8 +1934,12 @@ wimfs_mknod(const char *path, mode_t mode, dev_t rdev) return -ENOMEM; return 0; } else { - /* Make a normal file (not an alternate data stream) */ - return create_dentry(fuse_ctx, path, mode | S_IFREG, + if (!S_ISREG(mode) && + !(wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA)) + return -EPERM; + + /* Make a regular file, device node, named pipe, or socket. */ + return create_dentry(fuse_ctx, path, mode, rdev, FILE_ATTRIBUTE_NORMAL, NULL); } } @@ -2163,7 +2200,7 @@ static int wimfs_rename(const char *from, const char *to) { return rename_wim_path(wimfs_get_WIMStruct(), from, to, - WIMLIB_CASE_SENSITIVE); + WIMLIB_CASE_SENSITIVE, NULL); } /* Remove a directory */ @@ -2239,7 +2276,7 @@ wimfs_symlink(const char *to, const char *from) struct wim_dentry *dentry; int ret; - ret = create_dentry(fuse_ctx, from, S_IFLNK | 0777, + ret = create_dentry(fuse_ctx, from, S_IFLNK | 0777, 0, FILE_ATTRIBUTE_REPARSE_POINT, &dentry); if (ret == 0) { dentry->d_inode->i_reparse_tag = WIM_IO_REPARSE_TAG_SYMLINK; @@ -2679,8 +2716,8 @@ out_free_message_queue_names: /* API function documented in wimlib.h */ WIMLIBAPI int -wimlib_unmount_image(const char *dir, int unmount_flags, - wimlib_progress_func_t progress_func) +wimlib_unmount_image_with_progress(const tchar *dir, int unmount_flags, + wimlib_progress_func_t progfunc, void *progctx) { int ret; struct wimfs_context wimfs_ctx; @@ -2705,7 +2742,7 @@ wimlib_unmount_image(const char *dir, int unmount_flags, ret = send_unmount_request_msg(wimfs_ctx.unmount_to_daemon_mq, unmount_flags, - progress_func != NULL); + progfunc != NULL); if (ret != 0) goto out_close_message_queues; @@ -2718,7 +2755,8 @@ wimlib_unmount_image(const char *dir, int unmount_flags, .timeout_seconds = 5, }, .daemon_pid = 0, - .progress_func = progress_func, + .progfunc = progfunc, + .progctx = progctx, }; ret = message_loop(wimfs_ctx.daemon_to_unmount_mq, @@ -2750,8 +2788,8 @@ mount_unsupported_error(void) } WIMLIBAPI int -wimlib_unmount_image(const tchar *dir, int unmount_flags, - wimlib_progress_func_t progress_func) +wimlib_unmount_image_with_progress(const tchar *dir, int unmount_flags, + wimlib_progress_func_t progfunc, void *progctx) { return mount_unsupported_error(); } @@ -2764,3 +2802,10 @@ wimlib_mount_image(WIMStruct *wim, int image, const tchar *dir, } #endif /* !WITH_FUSE */ + + +WIMLIBAPI int +wimlib_unmount_image(const tchar *dir, int unmount_flags) +{ + return wimlib_unmount_image_with_progress(dir, unmount_flags, NULL, NULL); +}