4 * This file implements mounting of WIM images using FUSE
5 * (Filesystem in Userspace). See http://fuse.sourceforge.net/.
7 * Currently it is only expected to work on Linux.
11 * Copyright (C) 2012-2016 Eric Biggers
13 * This file is free software; you can redistribute it and/or modify it under
14 * the terms of the GNU Lesser General Public License as published by the Free
15 * Software Foundation; either version 3 of the License, or (at your option) any
18 * This file is distributed in the hope that it will be useful, but WITHOUT
19 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
23 * You should have received a copy of the GNU Lesser General Public License
24 * along with this file; if not, see http://www.gnu.org/licenses/.
32 #include "wimlib/error.h"
37 # error "FUSE mount not supported on Windows! Please configure --without-fuse"
40 #define FUSE_USE_VERSION 26
42 #include <sys/types.h> /* sometimes required before <attr/xattr.h> */
44 #include <attr/xattr.h>
58 #include "wimlib/blob_table.h"
59 #include "wimlib/dentry.h"
60 #include "wimlib/encoding.h"
61 #include "wimlib/metadata.h"
62 #include "wimlib/paths.h"
63 #include "wimlib/progress.h"
64 #include "wimlib/reparse.h"
65 #include "wimlib/timestamp.h"
66 #include "wimlib/unix_data.h"
67 #include "wimlib/write.h"
68 #include "wimlib/xml.h"
71 # define O_NOFOLLOW 0 /* Security only... */
74 #define WIMFS_MQUEUE_NAME_LEN 32
76 #define WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS 0x80000000
78 struct wimfs_unmount_info {
79 unsigned unmount_flags;
80 char mq_name[WIMFS_MQUEUE_NAME_LEN + 1];
83 struct commit_progress_report {
84 enum wimlib_progress_msg msg;
85 union wimlib_progress_info info;
88 /* Description of an open file on a mounted WIM image. Actually, this
89 * represents the open state of a particular data stream of an inode, rather
90 * than the inode itself. (An inode might have multiple named data streams in
91 * addition to the default, unnamed data stream.) At a given time, an inode in
92 * the WIM image might have multiple file descriptors open to it, each to any
93 * one of its data streams. */
96 /* Pointer to the inode of this open file.
97 * 'i_num_opened_fds' of the inode tracks the number of file descriptors
98 * that reference it. */
99 struct wim_inode *f_inode;
101 /* Pointer to the blob descriptor for the data stream that has been
102 * opened. 'num_opened_fds' of the blob descriptor tracks the number of
103 * file descriptors that reference it. Or, this value may be NULL,
104 * which indicates that the opened stream is empty and consequently does
105 * not have a blob descriptor. */
106 struct blob_descriptor *f_blob;
108 /* If valid (filedes_valid(&f_staging_fd)), this contains the
109 * corresponding native file descriptor for the staging file that has
110 * been created for reading from and/or writing to this open stream. A
111 * single staging file might have multiple file descriptors open to it
112 * simultaneously, each used by a different 'struct wimfs_fd'.
114 * Or, if invalid (!filedes_valid(&f_staging_fd)), this 'struct
115 * wimfs_fd' is not associated with a staging file. This is permissible
116 * only if this 'struct wimfs_fd' was opened read-only and the stream
117 * has not yet been extracted to a staging file. */
118 struct filedes f_staging_fd;
120 /* 0-based index of this file descriptor in the file descriptor table of
124 /* Unique ID of the opened stream in the inode. This will stay the same
125 * even if the indices of the inode's streams are changed by a deletion.
130 #define WIMFS_FD(fi) ((struct wimfs_fd *)(uintptr_t)((fi)->fh))
132 /* Context structure for a mounted WIM image. */
133 struct wimfs_context {
134 /* The WIMStruct containing the mounted image. The mounted image is the
135 * currently selected image (wim->current_image). */
138 /* Flags passed to wimlib_mount_image() (WIMLIB_MOUNT_FLAG_*). */
141 /* Default flags for path lookup in the WIM image. */
142 int default_lookup_flags;
144 /* Information about the user who has mounted the WIM image */
148 /* Absolute path to the mountpoint directory (may be needed for absolute
149 * symbolic link fixups) */
150 char *mountpoint_abspath;
151 size_t mountpoint_abspath_nchars;
153 /* Information about the staging directory for a read-write mount. */
156 char *staging_dir_name;
158 /* For read-write mounts, the inode number to be assigned to the next
159 * created file. Note: since this isn't a persistent filesystem and we
160 * can re-assign the inode numbers just before mounting the image, it's
161 * good enough to just generate inode numbers sequentially. */
164 /* Number of file descriptors open to the mounted WIM image. */
165 unsigned long num_open_fds;
167 /* For read-write mounts, the original metadata resource of the mounted
169 struct blob_descriptor *metadata_resource;
171 /* Parameters for unmounting the image (can be set via extended
172 * attribute "wimfs.unmount_info"). */
173 struct wimfs_unmount_info unmount_info;
176 #define WIMFS_CTX(fuse_ctx) ((struct wimfs_context*)(fuse_ctx)->private_data)
178 /* Retrieve the context structure for the currently mounted WIM image.
180 * Note: this is a per-thread variable. It is possible for different threads to
181 * mount different images at the same time in the same process, although they
182 * must use different WIMStructs! */
183 static inline struct wimfs_context *
184 wimfs_get_context(void)
186 return WIMFS_CTX(fuse_get_context());
190 wimfs_inc_num_open_fds(void)
192 wimfs_get_context()->num_open_fds++;
196 wimfs_dec_num_open_fds(void)
198 wimfs_get_context()->num_open_fds--;
201 /* Retrieve the WIMStruct for the currently mounted WIM image. */
202 static inline WIMStruct *
203 wimfs_get_WIMStruct(void)
205 return wimfs_get_context()->wim;
208 /* Is write permission requested on the file? */
210 flags_writable(int open_flags)
212 int accmode = (open_flags & O_ACCMODE);
213 return (accmode == O_RDWR || accmode == O_WRONLY);
217 fuse_mask_mode(mode_t mode, const struct fuse_context *fuse_ctx)
219 #if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 8)
220 mode &= ~fuse_ctx->umask;
226 * Allocate a file descriptor to a data stream in the mounted WIM image.
229 * The inode containing the stream being opened
231 * The stream of the inode being opened
233 * On success, a pointer to the new file descriptor will be stored here.
235 * Returns 0 or a -errno code.
238 alloc_wimfs_fd(struct wim_inode *inode,
239 struct wim_inode_stream *strm,
240 struct wimfs_fd **fd_ret)
242 static const u16 min_fds_per_alloc = 8;
243 static const u16 max_fds = 0xffff;
247 if (inode->i_num_opened_fds == inode->i_num_allocated_fds) {
249 struct wimfs_fd **fds;
251 /* Expand this inode's file descriptor table. */
253 num_new_fds = max(min_fds_per_alloc,
254 inode->i_num_allocated_fds / 4);
256 num_new_fds = min(num_new_fds,
257 max_fds - inode->i_num_allocated_fds);
259 if (num_new_fds == 0)
262 fds = REALLOC(inode->i_fds,
263 (inode->i_num_allocated_fds + num_new_fds) *
268 memset(&fds[inode->i_num_allocated_fds], 0,
269 num_new_fds * sizeof(fds[0]));
271 inode->i_num_allocated_fds += num_new_fds;
272 inode->i_next_fd = inode->i_num_opened_fds;
275 /* Allocate the file descriptor in the first available space in the
276 * inode's file descriptor table.
278 * i_next_fd is the lower bound on the next open slot. */
279 for (i = inode->i_next_fd; inode->i_fds[i]; i++)
282 fd = MALLOC(sizeof(*fd));
287 fd->f_blob = stream_blob_resolved(strm);
288 filedes_invalidate(&fd->f_staging_fd);
290 fd->f_stream_id = strm->stream_id;
292 inode->i_fds[i] = fd;
293 inode->i_num_opened_fds++;
295 fd->f_blob->num_opened_fds++;
296 wimfs_inc_num_open_fds();
297 inode->i_next_fd = i + 1;
302 * Close a file descriptor to a data stream in the mounted WIM image.
304 * Returns 0 or a -errno code. The file descriptor is always closed.
307 close_wimfs_fd(struct wimfs_fd *fd)
310 struct wim_inode *inode;
312 /* Close the staging file if open. */
313 if (filedes_valid(&fd->f_staging_fd))
314 if (filedes_close(&fd->f_staging_fd))
317 /* Release this file descriptor from its blob descriptor. */
319 blob_decrement_num_opened_fds(fd->f_blob);
321 wimfs_dec_num_open_fds();
323 /* Release this file descriptor from its inode. */
325 inode->i_fds[fd->f_idx] = NULL;
326 if (fd->f_idx < inode->i_next_fd)
327 inode->i_next_fd = fd->f_idx;
329 inode_dec_num_opened_fds(inode);
334 * Translate a path into the corresponding inode in the mounted WIM image.
336 * See get_dentry() for more information.
338 * Returns a pointer to the resulting inode, or NULL with errno set.
340 static struct wim_inode *
341 wim_pathname_to_inode(WIMStruct *wim, const char *path)
343 struct wim_dentry *dentry;
345 dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
348 return dentry->d_inode;
351 /* Can look up named data stream with colon syntax */
352 #define LOOKUP_FLAG_ADS_OK 0x01
354 /* Can look up directory (otherwise get -ENOTDIR) */
355 #define LOOKUP_FLAG_DIRECTORY_OK 0x02
357 /* Get the data stream of the specified name from the specified inode. Returns
358 * NULL with errno set if not found. */
359 static struct wim_inode_stream *
360 inode_get_data_stream_tstr(const struct wim_inode *inode,
361 const char *stream_name)
363 struct wim_inode_stream *strm;
365 if (!stream_name || !*stream_name) {
366 strm = inode_get_unnamed_data_stream(inode);
368 const utf16lechar *uname;
370 if (tstr_get_utf16le(stream_name, &uname))
372 strm = inode_get_stream(inode, STREAM_TYPE_DATA, uname);
373 tstr_put_utf16le(uname);
381 * Translate a path into the corresponding dentry and stream in the mounted WIM
384 * Returns 0 or a -errno code. @dentry_ret and @strm_ret are both optional.
387 wim_pathname_to_stream(const struct wimfs_context *ctx,
390 struct wim_dentry **dentry_ret,
391 struct wim_inode_stream **strm_ret)
393 WIMStruct *wim = ctx->wim;
394 struct wim_dentry *dentry;
395 struct wim_inode *inode;
396 struct wim_inode_stream *strm;
397 const char *stream_name = NULL;
400 lookup_flags |= ctx->default_lookup_flags;
402 if (lookup_flags & LOOKUP_FLAG_ADS_OK) {
403 stream_name = path_stream_name(path);
405 p = (char *)stream_name - 1;
410 dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
416 inode = dentry->d_inode;
418 if (inode_resolve_streams(inode, wim->blob_table, false))
421 if (!(lookup_flags & LOOKUP_FLAG_DIRECTORY_OK)
422 && inode_is_directory(inode))
425 strm = inode_get_data_stream_tstr(inode, stream_name);
427 /* Force creation of an unnamed data stream */
429 strm = inode_add_stream(inode, STREAM_TYPE_DATA,
430 NO_STREAM_NAME, NULL);
436 *dentry_ret = dentry;
443 * Create a new file in the mounted WIM image.
446 * The FUSE context for the mounted image.
448 * The path at which to create the first link to the new file. If a file
449 * already exists at this path, -EEXIST is returned.
451 * The UNIX mode for the new file. This is only fully honored if
452 * WIMLIB_MOUNT_FLAG_UNIX_DATA was passed to wimlib_mount_image().
454 * The device ID for the new file, encoding the major and minor device
455 * numbers. This is only honored if WIMLIB_MOUNT_FLAG_UNIX_DATA was passed
456 * to wimlib_mount_image().
458 * On success, a pointer to the new dentry is returned here. Its d_inode
459 * member will point to the new inode that was created for it and added to
460 * the mounted WIM image.
462 * Returns 0 or a -errno code.
465 create_file(struct fuse_context *fuse_ctx, const char *path,
466 mode_t mode, dev_t rdev, struct wim_dentry **dentry_ret)
468 struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
469 struct wim_dentry *parent;
470 const char *basename;
471 struct wim_dentry *dentry;
472 struct wim_inode *inode;
474 parent = get_parent_dentry(wimfs_ctx->wim, path, WIMLIB_CASE_SENSITIVE);
478 if (!dentry_is_directory(parent))
481 basename = path_basename(path);
483 if (get_dentry_child_with_name(parent, basename, WIMLIB_CASE_SENSITIVE))
486 if (new_dentry_with_new_inode(basename, true, &dentry))
489 inode = dentry->d_inode;
491 inode->i_ino = wimfs_ctx->next_ino++;
493 /* Note: we still use FILE_ATTRIBUTE_NORMAL for device nodes, named
494 * pipes, and sockets. The real mode is in the UNIX metadata. */
496 inode->i_attributes = FILE_ATTRIBUTE_DIRECTORY;
498 inode->i_attributes = FILE_ATTRIBUTE_NORMAL;
500 if (wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) {
501 struct wimlib_unix_data unix_data;
503 unix_data.uid = fuse_ctx->uid;
504 unix_data.gid = fuse_ctx->gid;
505 unix_data.mode = fuse_mask_mode(mode, fuse_ctx);
506 unix_data.rdev = rdev;
507 if (!inode_set_unix_data(inode, &unix_data, UNIX_DATA_ALL))
514 hlist_add_head(&inode->i_hlist_node,
515 &wim_get_current_image_metadata(wimfs_ctx->wim)->inode_list);
517 dentry_add_child(parent, dentry);
519 *dentry_ret = dentry;
524 * Remove a dentry from the mounted WIM image; i.e. remove an alias for an
528 remove_dentry(struct wim_dentry *dentry, struct blob_table *blob_table)
530 /* Drop blob references. */
531 inode_unref_blobs(dentry->d_inode, blob_table);
533 /* Unlink the dentry from the image's dentry tree. */
534 unlink_dentry(dentry);
536 /* Delete the dentry. This will also decrement the link count of the
537 * corresponding inode, and possibly cause it to be deleted as well. */
541 /* Generate UNIX filetype mode bits for the specified WIM inode, based on its
542 * Windows file attributes. */
544 inode_unix_file_type(const struct wim_inode *inode)
546 if (inode_is_symlink(inode))
548 else if (inode_is_directory(inode))
554 /* Generate a default UNIX mode for the specified WIM inode. */
556 inode_default_unix_mode(const struct wim_inode *inode)
558 return inode_unix_file_type(inode) | 0777;
562 blob_size(const struct blob_descriptor *blob)
570 blob_stored_size(const struct blob_descriptor *blob)
574 if (blob->blob_location == BLOB_IN_WIM &&
575 blob->size == blob->rdesc->uncompressed_size)
576 return blob->rdesc->size_in_wim;
581 * Retrieve standard UNIX metadata ('struct stat') for a WIM inode.
583 * @blob is the blob descriptor for the stream of the inode that is being
584 * queried, or NULL. We mostly return the same information for all streams, but
585 * st_size and st_blocks may be different for different streams.
587 * This always returns 0.
590 inode_to_stbuf(const struct wim_inode *inode,
591 const struct blob_descriptor *blob, struct stat *stbuf)
593 const struct wimfs_context *ctx = wimfs_get_context();
594 struct wimlib_unix_data unix_data;
596 memset(stbuf, 0, sizeof(struct stat));
597 if ((ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) &&
598 inode_get_unix_data(inode, &unix_data))
600 /* Use the user ID, group ID, mode, and device ID from the
601 * inode's extra UNIX metadata information. */
602 stbuf->st_uid = unix_data.uid;
603 stbuf->st_gid = unix_data.gid;
604 stbuf->st_mode = unix_data.mode;
605 stbuf->st_rdev = unix_data.rdev;
607 /* Generate default values for the user ID, group ID, and mode.
609 * Note: in the case of an allow_other mount, fuse_context.uid
610 * may not be the same as wimfs_context.owner_uid! */
611 stbuf->st_uid = ctx->owner_uid;
612 stbuf->st_gid = ctx->owner_gid;
613 stbuf->st_mode = inode_default_unix_mode(inode);
615 stbuf->st_ino = inode->i_ino;
616 stbuf->st_nlink = inode->i_nlink;
617 stbuf->st_size = blob_size(blob);
618 #ifdef HAVE_STAT_NANOSECOND_PRECISION
619 stbuf->st_atim = wim_timestamp_to_timespec(inode->i_last_access_time);
620 stbuf->st_mtim = wim_timestamp_to_timespec(inode->i_last_write_time);
621 stbuf->st_ctim = stbuf->st_mtim;
623 stbuf->st_atime = wim_timestamp_to_time_t(inode->i_last_access_time);
624 stbuf->st_mtime = wim_timestamp_to_time_t(inode->i_last_write_time);
625 stbuf->st_ctime = stbuf->st_mtime;
627 stbuf->st_blocks = DIV_ROUND_UP(blob_stored_size(blob), 512);
631 /* Update the last access and last write timestamps of a WIM inode. */
633 touch_inode(struct wim_inode *inode)
635 u64 now = now_as_wim_timestamp();
636 inode->i_last_access_time = now;
637 inode->i_last_write_time = now;
641 touch_parent(struct wim_dentry *dentry)
643 touch_inode(dentry->d_parent->d_inode);
647 * Create a new file in the staging directory for a read-write mounted image.
649 * On success, returns the file descriptor for the new staging file, opened for
650 * writing. In addition, stores the allocated name of the staging file in
653 * On failure, returns -1 and sets errno.
656 create_staging_file(const struct wimfs_context *ctx, char **name_ret)
659 static const size_t STAGING_FILE_NAME_LEN = 20;
663 name = MALLOC(STAGING_FILE_NAME_LEN + 1);
666 name[STAGING_FILE_NAME_LEN] = '\0';
669 randomize_char_array_with_alnum(name, STAGING_FILE_NAME_LEN);
670 fd = openat(ctx->staging_dir_fd, name,
671 O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0600);
672 if (unlikely(fd < 0)) {
673 if (unlikely(errno == EEXIST))
674 /* Try again with another name. */
684 * Extract a blob to the staging directory. This is necessary when a stream
685 * using the blob is being opened for writing and the blob has not already been
686 * extracted to the staging directory.
689 * The inode containing the stream being opened for writing.
691 * The stream being opened for writing. The blob descriptor to which the
692 * stream refers will be changed by this function.
694 * Number of bytes of the blob to extract and include in the staging file.
695 * It may be less than the actual blob length, in which case only a prefix
696 * of the blob will be extracted. It may also be more than the actual blob
697 * length, in which case the extra space will be zero-filled.
699 * Returns 0 or a -errno code.
702 extract_blob_to_staging_dir(struct wim_inode *inode,
703 struct wim_inode_stream *strm,
704 off_t size, const struct wimfs_context *ctx)
706 struct blob_descriptor *old_blob;
707 struct blob_descriptor *new_blob;
708 char *staging_file_name;
714 old_blob = stream_blob_resolved(strm);
716 /* Create the staging file. */
717 staging_fd = create_staging_file(ctx, &staging_file_name);
718 if (unlikely(staging_fd < 0))
721 /* Extract the stream to the staging file (possibly truncated). */
725 filedes_init(&fd, staging_fd);
727 extract_size = min(old_blob->size, size);
728 result = extract_blob_prefix_to_fd(old_blob, extract_size, &fd);
734 /* In the case of truncate() to more than the file length, extend the
735 * staging file with zeroes by calling ftruncate(). */
736 if (!result && size > extract_size)
737 result = ftruncate(staging_fd, size);
739 /* Close the staging file. */
740 if (close(staging_fd))
743 /* If an error occurred, unlink the staging file. */
744 if (unlikely(result)) {
745 /* extract_blob_to_fd() should set errno, but if it didn't,
746 * set a default value. */
747 ret = errno ? -errno : -EIO;
748 goto out_delete_staging_file;
751 /* Create a blob descriptor for the staging file. */
752 new_blob = new_blob_descriptor();
753 if (unlikely(!new_blob)) {
755 goto out_delete_staging_file;
758 /* There may already be open file descriptors to this stream if it's
759 * previously been opened read-only, but just now we're opening it
760 * read-write. Identify those file descriptors, update them to use the
761 * new blob descriptor, and open staging file descriptors for them. */
762 for (u16 i = 0, j = 0; j < inode->i_num_opened_fds; i++) {
766 fd = inode->i_fds[i];
772 if (fd->f_stream_id != strm->stream_id)
775 /* This is a readonly fd for the same stream. */
776 fd->f_blob = new_blob;
777 new_blob->num_opened_fds++;
778 raw_fd = openat(ctx->staging_dir_fd, staging_file_name,
779 O_RDONLY | O_NOFOLLOW);
780 if (unlikely(raw_fd < 0)) {
782 goto out_revert_fd_changes;
784 filedes_init(&fd->f_staging_fd, raw_fd);
788 old_blob->num_opened_fds -= new_blob->num_opened_fds;
790 new_blob->blob_location = BLOB_IN_STAGING_FILE;
791 new_blob->staging_file_name = staging_file_name;
792 new_blob->staging_dir_fd = ctx->staging_dir_fd;
793 new_blob->size = size;
795 prepare_unhashed_blob(new_blob, inode, strm->stream_id,
796 &wim_get_current_image_metadata(ctx->wim)->unhashed_blobs);
797 inode_replace_stream_blob(inode, strm, new_blob, ctx->wim->blob_table);
800 out_revert_fd_changes:
801 for (u16 i = 0; new_blob->num_opened_fds; i++) {
802 struct wimfs_fd *fd = inode->i_fds[i];
803 if (fd && fd->f_stream_id == strm->stream_id) {
804 fd->f_blob = old_blob;
805 if (filedes_valid(&fd->f_staging_fd)) {
806 filedes_close(&fd->f_staging_fd);
807 filedes_invalidate(&fd->f_staging_fd);
809 new_blob->num_opened_fds--;
812 free_blob_descriptor(new_blob);
813 out_delete_staging_file:
814 unlinkat(ctx->staging_dir_fd, staging_file_name, 0);
815 FREE(staging_file_name);
820 * Create the staging directory for the WIM file.
822 * The staging directory will be created in the directory specified by the open
823 * file descriptor @parent_dir_fd. It will be given a randomly generated name
824 * based on @wim_basename, the name of the WIM file.
826 * On success, returns a file descriptor to the open staging directory with
827 * O_RDONLY access. In addition, stores the allocated name of the staging
828 * directory (relative to @parent_dir_fd) in @staging_dir_name_ret.
829 * On failure, returns -1 and sets errno.
832 make_staging_dir_at(int parent_dir_fd, const char *wim_basename,
833 char **staging_dir_name_ret)
835 static const char common_suffix[8] = ".staging";
836 static const size_t random_suffix_len = 10;
837 size_t wim_basename_len;
838 size_t staging_dir_name_len;
839 char *staging_dir_name;
843 wim_basename_len = strlen(wim_basename);
844 staging_dir_name_len = wim_basename_len + sizeof(common_suffix) +
846 staging_dir_name = MALLOC(staging_dir_name_len + 1);
847 if (!staging_dir_name)
850 p = staging_dir_name;
851 p = mempcpy(p, wim_basename, wim_basename_len);
852 p = mempcpy(p, common_suffix, sizeof(common_suffix));
853 randomize_char_array_with_alnum(p, random_suffix_len);
854 p += random_suffix_len;
857 if (mkdirat(parent_dir_fd, staging_dir_name, 0700))
860 fd = openat(parent_dir_fd, staging_dir_name,
861 O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
865 *staging_dir_name_ret = staging_dir_name;
869 unlinkat(parent_dir_fd, staging_dir_name, AT_REMOVEDIR);
871 FREE(staging_dir_name);
876 * Create the staging directory and set ctx->staging_dir_fd,
877 * ctx->staging_dir_name, and ctx->parent_dir_fd.
880 make_staging_dir(struct wimfs_context *ctx, const char *parent_dir_path)
882 const char *wim_basename;
886 wim_basename = path_basename(ctx->wim->filename);
888 if (!parent_dir_path) {
889 /* The user did not specify a directory. Default to creating
890 * the staging directory alongside the WIM file. */
891 if (wim_basename > ctx->wim->filename) {
892 parent_dir_path = ctx->wim->filename;
893 end = (char *)(wim_basename - 1);
894 /* *end must be a slash. Temporarily overwrite it so we
895 * can open the parent directory. */
898 parent_dir_path = ".";
902 /* Open the parent directory (in which we'll create our staging
904 ctx->parent_dir_fd = open(parent_dir_path, O_RDONLY | O_DIRECTORY);
905 if (ctx->parent_dir_fd < 0) {
906 ERROR_WITH_ERRNO("Can't open directory \"%s\"",
908 ret = WIMLIB_ERR_OPENDIR;
909 goto out_restore_wim_filename;
912 ctx->staging_dir_fd = make_staging_dir_at(ctx->parent_dir_fd,
914 &ctx->staging_dir_name);
915 if (ctx->staging_dir_fd < 0) {
916 ERROR_WITH_ERRNO("Can't create staging directory in \"%s\"",
918 close(ctx->parent_dir_fd);
919 ret = WIMLIB_ERR_MKDIR;
920 goto out_restore_wim_filename;
923 out_restore_wim_filename:
929 /* Deletes the staging directory, undoing the effects of a successful call to
930 * make_staging_dir(). */
932 delete_staging_dir(struct wimfs_context *ctx)
937 dir = fdopendir(ctx->staging_dir_fd);
939 while ((ent = readdir(dir)))
940 unlinkat(ctx->staging_dir_fd, ent->d_name, 0);
943 close(ctx->staging_dir_fd);
945 if (unlinkat(ctx->parent_dir_fd, ctx->staging_dir_name, AT_REMOVEDIR))
946 WARNING_WITH_ERRNO("Could not delete staging directory");
947 FREE(ctx->staging_dir_name);
948 close(ctx->parent_dir_fd);
952 prepare_inodes(struct wimfs_context *ctx)
954 struct wim_image_metadata *imd;
955 struct wim_inode *inode;
958 imd = wim_get_current_image_metadata(ctx->wim);
959 image_for_each_inode(inode, imd) {
960 inode->i_ino = ctx->next_ino++;
961 inode->i_num_opened_fds = 0;
962 inode->i_num_allocated_fds = 0;
967 /* Delete the 'struct blob_descriptor' for any stream that was modified
968 * or created in the read-write mounted image and had a final size of 0. */
970 delete_empty_blobs(struct wimfs_context *ctx)
972 struct blob_descriptor *blob, *tmp;
973 struct wim_image_metadata *imd;
975 imd = wim_get_current_image_metadata(ctx->wim);
977 image_for_each_unhashed_blob_safe(blob, tmp, imd) {
979 *retrieve_pointer_to_unhashed_blob(blob) = NULL;
980 list_del(&blob->unhashed_list);
981 free_blob_descriptor(blob);
986 /* Close all file descriptors open to the specified inode.
988 * Note: closing the last file descriptor might free the inode. */
990 inode_close_fds(struct wim_inode *inode)
992 u16 num_open_fds = inode->i_num_opened_fds;
993 for (u16 i = 0; num_open_fds; i++) {
994 if (inode->i_fds[i]) {
995 close_wimfs_fd(inode->i_fds[i]);
1001 /* Close all file descriptors open to the mounted image. */
1003 close_all_fds(struct wimfs_context *ctx)
1005 struct wim_inode *inode;
1006 struct hlist_node *tmp;
1007 struct wim_image_metadata *imd;
1009 imd = wim_get_current_image_metadata(ctx->wim);
1011 image_for_each_inode_safe(inode, tmp, imd)
1012 inode_close_fds(inode);
1015 /* Moves the currently selected image, which may have been modified, to a new
1016 * index, and sets the original index to refer to a reset (unmodified) copy of
1019 renew_current_image(struct wimfs_context *ctx)
1021 WIMStruct *wim = ctx->wim;
1022 int image = wim->current_image;
1023 struct wim_image_metadata *imd;
1024 struct wim_inode *inode;
1027 ret = WIMLIB_ERR_NOMEM;
1028 imd = new_unloaded_image_metadata(ctx->metadata_resource);
1032 ret = append_image_metadata(wim, wim->image_metadata[image - 1]);
1036 ret = xml_export_image(wim->xml_info, image,
1037 wim->xml_info, NULL, NULL, false);
1039 goto err_undo_append;
1041 wim->image_metadata[image - 1] = imd;
1042 wim->current_image = wim->hdr.image_count;
1044 ret = select_wim_image(wim, image);
1046 goto err_undo_export;
1048 image_for_each_inode(inode, imd) {
1049 for (unsigned i = 0; i < inode->i_num_streams; i++) {
1050 struct blob_descriptor *blob;
1052 blob = stream_blob(&inode->i_streams[i],
1055 blob->refcnt += inode->i_nlink;
1059 select_wim_image(wim, wim->hdr.image_count);
1060 ctx->metadata_resource = NULL;
1064 xml_delete_image(wim->xml_info, wim->hdr.image_count);
1065 wim->image_metadata[image - 1] = wim->image_metadata[wim->hdr.image_count - 1];
1066 wim->current_image = image;
1068 wim->hdr.image_count--;
1070 imd->metadata_blob = NULL;
1071 put_image_metadata(imd);
1076 static enum wimlib_progress_status
1077 commit_progress_func(enum wimlib_progress_msg msg,
1078 union wimlib_progress_info *info, void *progctx)
1080 mqd_t mq = *(mqd_t *)progctx;
1081 struct commit_progress_report report;
1083 memset(&report, 0, sizeof(report));
1086 report.info = *info;
1087 mq_send(mq, (const char *)&report, sizeof(report), 1);
1088 return WIMLIB_PROGRESS_STATUS_CONTINUE;
1091 /* Commit the mounted image to the underlying WIM file. */
1093 commit_image(struct wimfs_context *ctx, int unmount_flags, mqd_t mq)
1097 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS)
1098 wimlib_register_progress_function(ctx->wim,
1099 commit_progress_func, &mq);
1101 wimlib_register_progress_function(ctx->wim, NULL, NULL);
1103 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_NEW_IMAGE) {
1104 int ret = renew_current_image(ctx);
1108 delete_empty_blobs(ctx);
1112 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY)
1113 write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
1115 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_REBUILD)
1116 write_flags |= WIMLIB_WRITE_FLAG_REBUILD;
1118 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_RECOMPRESS)
1119 write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
1121 return wimlib_overwrite(ctx->wim, write_flags, 0);
1124 /* In the case of an allow_other mount, only the mount owner and root are
1125 * allowed to unmount the filesystem. */
1127 may_unmount_wimfs(void)
1129 const struct fuse_context *fuse_ctx = fuse_get_context();
1130 const struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1132 return (fuse_ctx->uid == wimfs_ctx->owner_uid ||
1133 fuse_ctx->uid == 0);
1136 /* Unmount the mounted image, called from the daemon process. */
1140 struct fuse_context *fuse_ctx = fuse_get_context();
1141 struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1142 const struct wimfs_unmount_info *info = &wimfs_ctx->unmount_info;
1143 int unmount_flags = info->unmount_flags;
1144 mqd_t mq = (mqd_t)-1;
1147 /* Ignore COMMIT if the image is mounted read-only. */
1148 if (!(wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_READWRITE))
1149 unmount_flags &= ~WIMLIB_UNMOUNT_FLAG_COMMIT;
1151 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS) {
1152 mq = mq_open(info->mq_name, O_WRONLY | O_NONBLOCK);
1153 if (mq == (mqd_t)-1) {
1154 ret = WIMLIB_ERR_MQUEUE;
1159 if (wimfs_ctx->num_open_fds) {
1161 /* There are still open file descriptors to the image. */
1163 /* With COMMIT, refuse to unmount unless FORCE is also
1165 if ((unmount_flags & (WIMLIB_UNMOUNT_FLAG_COMMIT |
1166 WIMLIB_UNMOUNT_FLAG_FORCE))
1167 == WIMLIB_UNMOUNT_FLAG_COMMIT)
1169 ret = WIMLIB_ERR_MOUNTED_IMAGE_IS_BUSY;
1173 /* Force-close all file descriptors. */
1174 close_all_fds(wimfs_ctx);
1177 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_COMMIT)
1178 ret = commit_image(wimfs_ctx, unmount_flags, mq);
1180 ret = 0; /* Read-only mount, or discarding changes to
1181 a read-write mount */
1184 /* Leave the image mounted if commit failed, unless this is a
1185 * forced unmount. The user can retry without COMMIT if they
1187 if (!ret || (unmount_flags & WIMLIB_UNMOUNT_FLAG_FORCE)) {
1188 unlock_wim_for_append(wimfs_ctx->wim);
1189 fuse_exit(fuse_ctx->fuse);
1191 if (mq != (mqd_t)-1)
1197 wimfs_chmod(const char *path, mode_t mask)
1199 const struct wimfs_context *ctx = wimfs_get_context();
1200 struct wim_inode *inode;
1201 struct wimlib_unix_data unix_data;
1203 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
1206 inode = wim_pathname_to_inode(ctx->wim, path);
1210 unix_data.uid = ctx->owner_uid;
1211 unix_data.gid = ctx->owner_gid;
1212 unix_data.mode = mask;
1215 if (!inode_set_unix_data(inode, &unix_data, UNIX_DATA_MODE))
1222 wimfs_chown(const char *path, uid_t uid, gid_t gid)
1224 const struct wimfs_context *ctx = wimfs_get_context();
1225 struct wim_inode *inode;
1226 struct wimlib_unix_data unix_data;
1229 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
1232 inode = wim_pathname_to_inode(ctx->wim, path);
1238 if (uid != (uid_t)-1)
1239 which |= UNIX_DATA_UID;
1241 uid = ctx->owner_uid;
1243 if (gid != (gid_t)-1)
1244 which |= UNIX_DATA_GID;
1246 gid = ctx->owner_gid;
1248 unix_data.uid = uid;
1249 unix_data.gid = gid;
1250 unix_data.mode = inode_default_unix_mode(inode);
1253 if (!inode_set_unix_data(inode, &unix_data, which))
1260 wimfs_fgetattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi)
1262 struct wimfs_fd *fd = WIMFS_FD(fi);
1263 return inode_to_stbuf(fd->f_inode, fd->f_blob, stbuf);
1267 wimfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi)
1269 struct wimfs_fd *fd = WIMFS_FD(fi);
1270 if (ftruncate(fd->f_staging_fd.fd, size))
1272 touch_inode(fd->f_inode);
1273 fd->f_blob->size = size;
1278 wimfs_getattr(const char *path, struct stat *stbuf)
1280 const struct wimfs_context *ctx = wimfs_get_context();
1281 struct wim_dentry *dentry;
1282 struct wim_inode_stream *strm;
1285 ret = wim_pathname_to_stream(ctx, path, LOOKUP_FLAG_DIRECTORY_OK,
1290 return inode_to_stbuf(dentry->d_inode,
1291 stream_blob_resolved(strm), stbuf);
1295 copy_xattr(char *dest, size_t destsize, const void *src, size_t srcsize)
1298 if (destsize < srcsize)
1300 memcpy(dest, src, srcsize);
1306 wimfs_getxattr(const char *path, const char *name, char *value,
1309 const struct wimfs_context *ctx = wimfs_get_context();
1310 const struct wim_inode *inode;
1311 const struct wim_inode_stream *strm;
1312 const struct blob_descriptor *blob;
1314 if (!strncmp(name, "wimfs.", 6)) {
1315 /* Handle some magical extended attributes. These really should
1316 * be ioctls, but directory ioctls aren't supported until
1317 * libfuse 2.9, and even then they are broken. */
1319 if (!strcmp(name, "wim_filename")) {
1320 return copy_xattr(value, size, ctx->wim->filename,
1321 strlen(ctx->wim->filename));
1323 if (!strcmp(name, "wim_info")) {
1324 struct wimlib_wim_info info;
1326 wimlib_get_wim_info(ctx->wim, &info);
1328 return copy_xattr(value, size, &info, sizeof(info));
1330 if (!strcmp(name, "mounted_image")) {
1331 return copy_xattr(value, size,
1332 &ctx->wim->current_image, sizeof(int));
1334 if (!strcmp(name, "mount_flags")) {
1335 return copy_xattr(value, size,
1336 &ctx->mount_flags, sizeof(int));
1338 if (!strcmp(name, "unmount")) {
1339 if (!may_unmount_wimfs())
1344 if (size < sizeof(int))
1346 status = unmount_wimfs();
1347 memcpy(value, &status, sizeof(int));
1354 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1357 if (strncmp(name, "user.", 5))
1364 /* Querying a named data stream */
1366 inode = wim_pathname_to_inode(ctx->wim, path);
1370 strm = inode_get_data_stream_tstr(inode, name);
1372 return (errno == ENOENT) ? -ENOATTR : -errno;
1374 blob = stream_blob_resolved(strm);
1378 if (unlikely(blob->size > INT_MAX))
1382 if (size < blob->size)
1385 if (read_blob_into_buf(blob, value))
1386 return errno ? -errno : -EIO;
1392 wimfs_link(const char *existing_path, const char *new_path)
1394 WIMStruct *wim = wimfs_get_WIMStruct();
1395 const char *new_name;
1396 struct wim_inode *inode;
1397 struct wim_dentry *dir;
1398 struct wim_dentry *new_alias;
1400 inode = wim_pathname_to_inode(wim, existing_path);
1404 if (inode->i_attributes & (FILE_ATTRIBUTE_DIRECTORY |
1405 FILE_ATTRIBUTE_REPARSE_POINT))
1408 new_name = path_basename(new_path);
1410 dir = get_parent_dentry(wim, new_path, WIMLIB_CASE_SENSITIVE);
1414 if (!dentry_is_directory(dir))
1417 if (get_dentry_child_with_name(dir, new_name, WIMLIB_CASE_SENSITIVE))
1420 if (new_dentry_with_existing_inode(new_name, inode, &new_alias))
1423 dentry_add_child(dir, new_alias);
1424 touch_inode(dir->d_inode);
1429 wimfs_listxattr(const char *path, char *list, size_t size)
1431 const struct wimfs_context *ctx = wimfs_get_context();
1432 const struct wim_inode *inode;
1434 char *end = list + size;
1437 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1440 /* List named data streams, or get the list size. We report each named
1441 * data stream "X" as an extended attribute "user.X". */
1443 inode = wim_pathname_to_inode(ctx->wim, path);
1447 for (unsigned i = 0; i < inode->i_num_streams; i++) {
1448 const struct wim_inode_stream *strm;
1449 char *stream_name_mbs;
1450 size_t stream_name_mbs_nbytes;
1452 strm = &inode->i_streams[i];
1454 if (!stream_is_named_data_stream(strm))
1457 if (utf16le_to_tstr(strm->stream_name,
1458 utf16le_len_bytes(strm->stream_name),
1460 &stream_name_mbs_nbytes))
1463 if (unlikely(INT_MAX - total_size < stream_name_mbs_nbytes + 6)) {
1464 FREE(stream_name_mbs);
1468 total_size += stream_name_mbs_nbytes + 6;
1470 if (end - p < stream_name_mbs_nbytes + 6) {
1471 FREE(stream_name_mbs);
1474 p = mempcpy(p, "user.", 5);
1475 p = mempcpy(p, stream_name_mbs, stream_name_mbs_nbytes);
1478 FREE(stream_name_mbs);
1484 wimfs_mkdir(const char *path, mode_t mode)
1486 struct wim_dentry *dentry;
1489 /* Note: according to fuse.h, mode may not include S_IFDIR */
1490 ret = create_file(fuse_get_context(), path, mode | S_IFDIR, 0, &dentry);
1493 touch_parent(dentry);
1498 wimfs_mknod(const char *path, mode_t mode, dev_t rdev)
1500 struct fuse_context *fuse_ctx = fuse_get_context();
1501 struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1502 const char *stream_name;
1504 if ((wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
1505 && (stream_name = path_stream_name(path)))
1507 struct wim_inode *inode;
1508 struct wim_inode_stream *existing_strm;
1509 struct wim_inode_stream *new_strm;
1511 const utf16lechar *uname;
1513 /* Create a named data stream. */
1518 p = (char *)stream_name - 1;
1521 inode = wim_pathname_to_inode(wimfs_ctx->wim, path);
1526 if (tstr_get_utf16le(stream_name, &uname))
1529 existing_strm = inode_get_stream(inode, STREAM_TYPE_DATA, uname);
1530 if (existing_strm) {
1531 tstr_put_utf16le(uname);
1535 new_strm = inode_add_stream(inode, STREAM_TYPE_DATA, uname, NULL);
1537 tstr_put_utf16le(uname);
1543 /* Create a regular file, device node, named pipe, or socket.
1545 struct wim_dentry *dentry;
1548 if (!S_ISREG(mode) &&
1549 !(wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
1552 ret = create_file(fuse_ctx, path, mode, rdev, &dentry);
1555 touch_parent(dentry);
1561 wimfs_open(const char *path, struct fuse_file_info *fi)
1563 struct wimfs_context *ctx = wimfs_get_context();
1564 struct wim_dentry *dentry;
1565 struct wim_inode *inode;
1566 struct wim_inode_stream *strm;
1567 struct blob_descriptor *blob;
1568 struct wimfs_fd *fd;
1571 ret = wim_pathname_to_stream(ctx, path, 0, &dentry, &strm);
1575 inode = dentry->d_inode;
1576 blob = stream_blob_resolved(strm);
1578 /* The data of the file being opened may be in the staging directory
1579 * (read-write mounts only) or in the WIM. If it's in the staging
1580 * directory, we need to open a native file descriptor for the
1581 * corresponding file. Otherwise, we can read the file data directly
1582 * from the WIM file if we are opening it read-only, but we need to
1583 * extract the data to the staging directory if we are opening it
1586 if (flags_writable(fi->flags) &&
1587 (!blob || blob->blob_location != BLOB_IN_STAGING_FILE)) {
1588 ret = extract_blob_to_staging_dir(inode,
1594 blob = stream_blob_resolved(strm);
1597 ret = alloc_wimfs_fd(inode, strm, &fd);
1601 if (blob && blob->blob_location == BLOB_IN_STAGING_FILE) {
1604 raw_fd = openat(blob->staging_dir_fd, blob->staging_file_name,
1605 (fi->flags & O_ACCMODE) | O_NOFOLLOW);
1610 filedes_init(&fd->f_staging_fd, raw_fd);
1612 fi->fh = (uintptr_t)fd;
1617 wimfs_opendir(const char *path, struct fuse_file_info *fi)
1619 WIMStruct *wim = wimfs_get_WIMStruct();
1620 struct wim_inode *inode;
1621 struct wim_inode_stream *strm;
1622 struct wimfs_fd *fd;
1625 inode = wim_pathname_to_inode(wim, path);
1628 if (!inode_is_directory(inode))
1630 strm = inode_get_unnamed_data_stream(inode);
1633 ret = alloc_wimfs_fd(inode, strm, &fd);
1636 fi->fh = (uintptr_t)fd;
1641 wimfs_read(const char *path, char *buf, size_t size,
1642 off_t offset, struct fuse_file_info *fi)
1644 struct wimfs_fd *fd = WIMFS_FD(fi);
1645 const struct blob_descriptor *blob;
1652 if (offset >= blob->size)
1655 if (size > blob->size - offset)
1656 size = blob->size - offset;
1661 switch (blob->blob_location) {
1663 if (read_partial_wim_blob_into_buf(blob, offset, size, buf))
1664 ret = errno ? -errno : -EIO;
1668 case BLOB_IN_STAGING_FILE:
1669 ret = pread(fd->f_staging_fd.fd, buf, size, offset);
1673 case BLOB_IN_ATTACHED_BUFFER:
1674 memcpy(buf, blob->attached_buffer + offset, size);
1685 wimfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
1686 off_t offset, struct fuse_file_info *fi)
1688 struct wimfs_fd *fd = WIMFS_FD(fi);
1689 const struct wim_inode *inode;
1690 const struct wim_dentry *child;
1693 inode = fd->f_inode;
1695 ret = filler(buf, ".", NULL, 0);
1698 ret = filler(buf, "..", NULL, 0);
1702 for_inode_child(child, inode) {
1706 if (utf16le_to_tstr(child->d_name, child->d_name_nbytes,
1707 &name, &name_nbytes))
1710 ret = filler(buf, name, NULL, 0);
1719 wimfs_readlink(const char *path, char *buf, size_t bufsize)
1721 struct wimfs_context *ctx = wimfs_get_context();
1722 const struct wim_inode *inode;
1725 inode = wim_pathname_to_inode(ctx->wim, path);
1730 ret = wim_inode_readlink(inode, buf, bufsize - 1, NULL,
1731 ctx->mountpoint_abspath,
1732 ctx->mountpoint_abspath_nchars);
1739 /* We use this for both release() and releasedir(), since in both cases we
1740 * simply need to close the file descriptor. */
1742 wimfs_release(const char *path, struct fuse_file_info *fi)
1744 return close_wimfs_fd(WIMFS_FD(fi));
1748 wimfs_removexattr(const char *path, const char *name)
1750 struct wimfs_context *ctx = wimfs_get_context();
1751 struct wim_inode *inode;
1752 struct wim_inode_stream *strm;
1754 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1757 if (strncmp(name, "user.", 5))
1764 /* Removing a named data stream. */
1766 inode = wim_pathname_to_inode(ctx->wim, path);
1770 strm = inode_get_data_stream_tstr(inode, name);
1772 return (errno == ENOENT) ? -ENOATTR : -errno;
1774 inode_remove_stream(inode, strm, ctx->wim->blob_table);
1779 wimfs_rename(const char *from, const char *to)
1781 return rename_wim_path(wimfs_get_WIMStruct(), from, to,
1782 WIMLIB_CASE_SENSITIVE, NULL);
1786 wimfs_rmdir(const char *path)
1788 WIMStruct *wim = wimfs_get_WIMStruct();
1789 struct wim_dentry *dentry;
1791 dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
1795 if (!dentry_is_directory(dentry))
1798 if (dentry_has_children(dentry))
1801 touch_parent(dentry);
1802 remove_dentry(dentry, wim->blob_table);
1807 wimfs_setxattr(const char *path, const char *name,
1808 const char *value, size_t size, int flags)
1810 struct wimfs_context *ctx = wimfs_get_context();
1811 struct wim_inode *inode;
1812 struct wim_inode_stream *strm;
1813 const utf16lechar *uname;
1816 if (!strncmp(name, "wimfs.", 6)) {
1817 /* Handle some magical extended attributes. These really should
1818 * be ioctls, but directory ioctls aren't supported until
1819 * libfuse 2.9, and even then they are broken. [Fixed by
1820 * libfuse commit e3b7d4c278a26520be63d99d6ea84b26906fe73d] */
1822 if (!strcmp(name, "unmount_info")) {
1823 if (!may_unmount_wimfs())
1825 if (size < sizeof(struct wimfs_unmount_info))
1827 memcpy(&ctx->unmount_info, value,
1828 sizeof(struct wimfs_unmount_info));
1834 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1837 if (strncmp(name, "user.", 5))
1844 /* Setting the contents of a named data stream. */
1846 inode = wim_pathname_to_inode(ctx->wim, path);
1850 ret = tstr_get_utf16le(name, &uname);
1854 strm = inode_get_stream(inode, STREAM_TYPE_DATA, uname);
1857 if (flags & XATTR_CREATE)
1861 if (flags & XATTR_REPLACE)
1866 if (!inode_replace_stream_data(inode, strm, value, size,
1867 ctx->wim->blob_table))
1873 if (!inode_add_stream_with_data(inode, STREAM_TYPE_DATA, uname,
1874 value, size, ctx->wim->blob_table))
1883 tstr_put_utf16le(uname);
1888 wimfs_symlink(const char *to, const char *from)
1890 struct fuse_context *fuse_ctx = fuse_get_context();
1891 struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1892 struct wim_dentry *dentry;
1895 ret = create_file(fuse_ctx, from, S_IFLNK | 0777, 0, &dentry);
1898 ret = wim_inode_set_symlink(dentry->d_inode, to,
1899 wimfs_ctx->wim->blob_table);
1901 remove_dentry(dentry, wimfs_ctx->wim->blob_table);
1902 if (ret == WIMLIB_ERR_NOMEM)
1907 touch_parent(dentry);
1913 wimfs_truncate(const char *path, off_t size)
1915 const struct wimfs_context *ctx = wimfs_get_context();
1916 struct wim_dentry *dentry;
1917 struct wim_inode_stream *strm;
1918 struct blob_descriptor *blob;
1922 ret = wim_pathname_to_stream(ctx, path, 0, &dentry, &strm);
1926 blob = stream_blob_resolved(strm);
1931 if (!blob || blob->blob_location != BLOB_IN_STAGING_FILE) {
1932 return extract_blob_to_staging_dir(dentry->d_inode,
1936 /* Truncate the staging file. */
1937 fd = openat(blob->staging_dir_fd, blob->staging_file_name,
1938 O_WRONLY | O_NOFOLLOW);
1941 ret = ftruncate(fd, size);
1942 if (close(fd) || ret)
1945 touch_inode(dentry->d_inode);
1950 wimfs_unlink(const char *path)
1952 const struct wimfs_context *ctx = wimfs_get_context();
1953 struct wim_dentry *dentry;
1954 struct wim_inode_stream *strm;
1957 ret = wim_pathname_to_stream(ctx, path, 0, &dentry, &strm);
1961 if (stream_is_named(strm)) {
1962 inode_remove_stream(dentry->d_inode, strm,
1963 ctx->wim->blob_table);
1965 touch_parent(dentry);
1966 remove_dentry(dentry, ctx->wim->blob_table);
1971 #ifdef HAVE_UTIMENSAT
1973 * Change the timestamp on a file dentry.
1975 * Note that alternate data streams do not have their own timestamps.
1978 wimfs_utimens(const char *path, const struct timespec tv[2])
1980 WIMStruct *wim = wimfs_get_WIMStruct();
1981 struct wim_inode *inode;
1983 inode = wim_pathname_to_inode(wim, path);
1987 if (tv[0].tv_nsec != UTIME_OMIT) {
1988 if (tv[0].tv_nsec == UTIME_NOW)
1989 inode->i_last_access_time = now_as_wim_timestamp();
1991 inode->i_last_access_time = timespec_to_wim_timestamp(&tv[0]);
1993 if (tv[1].tv_nsec != UTIME_OMIT) {
1994 if (tv[1].tv_nsec == UTIME_NOW)
1995 inode->i_last_write_time = now_as_wim_timestamp();
1997 inode->i_last_write_time = timespec_to_wim_timestamp(&tv[1]);
2001 #else /* HAVE_UTIMENSAT */
2003 wimfs_utime(const char *path, struct utimbuf *times)
2005 WIMStruct *wim = wimfs_get_WIMStruct();
2006 struct wim_inode *inode;
2008 inode = wim_pathname_to_inode(wim, path);
2012 inode->i_last_access_time = time_t_to_wim_timestamp(times->actime);
2013 inode->i_last_write_time = time_t_to_wim_timestamp(times->modtime);
2016 #endif /* !HAVE_UTIMENSAT */
2019 wimfs_write(const char *path, const char *buf, size_t size,
2020 off_t offset, struct fuse_file_info *fi)
2022 struct wimfs_fd *fd = WIMFS_FD(fi);
2025 ret = pwrite(fd->f_staging_fd.fd, buf, size, offset);
2029 if (offset + size > fd->f_blob->size)
2030 fd->f_blob->size = offset + size;
2032 touch_inode(fd->f_inode);
2036 static struct fuse_operations wimfs_operations = {
2037 .chmod = wimfs_chmod,
2038 .chown = wimfs_chown,
2039 .fgetattr = wimfs_fgetattr,
2040 .ftruncate = wimfs_ftruncate,
2041 .getattr = wimfs_getattr,
2042 .getxattr = wimfs_getxattr,
2044 .listxattr = wimfs_listxattr,
2045 .mkdir = wimfs_mkdir,
2046 .mknod = wimfs_mknod,
2048 .opendir = wimfs_opendir,
2050 .readdir = wimfs_readdir,
2051 .readlink = wimfs_readlink,
2052 .release = wimfs_release,
2053 .releasedir = wimfs_release,
2054 .removexattr = wimfs_removexattr,
2055 .rename = wimfs_rename,
2056 .rmdir = wimfs_rmdir,
2057 .setxattr = wimfs_setxattr,
2058 .symlink = wimfs_symlink,
2059 .truncate = wimfs_truncate,
2060 .unlink = wimfs_unlink,
2061 #ifdef HAVE_UTIMENSAT
2062 .utimens = wimfs_utimens,
2064 .utime = wimfs_utime,
2066 .write = wimfs_write,
2068 /* We keep track of file descriptor structures (struct wimfs_fd), so
2069 * there is no need to have the file path provided on operations such as
2071 #if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 8)
2072 .flag_nullpath_ok = 1,
2074 #if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 9)
2076 .flag_utime_omit_ok = 1,
2080 /* API function documented in wimlib.h */
2082 wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
2083 int mount_flags, const char *staging_dir)
2086 struct wim_image_metadata *imd;
2087 struct wimfs_context ctx;
2088 char *fuse_argv[16];
2091 if (!wim || !dir || !*dir)
2092 return WIMLIB_ERR_INVALID_PARAM;
2094 if (mount_flags & ~(WIMLIB_MOUNT_FLAG_READWRITE |
2095 WIMLIB_MOUNT_FLAG_DEBUG |
2096 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
2097 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR |
2098 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS |
2099 WIMLIB_MOUNT_FLAG_UNIX_DATA |
2100 WIMLIB_MOUNT_FLAG_ALLOW_OTHER))
2101 return WIMLIB_ERR_INVALID_PARAM;
2103 /* For read-write mount, check for write access to the WIM. */
2104 if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
2106 return WIMLIB_ERR_NO_FILENAME;
2107 ret = can_modify_wim(wim);
2112 /* Select the image to mount. */
2113 ret = select_wim_image(wim, image);
2117 /* Get the metadata for the image to mount. */
2118 imd = wim_get_current_image_metadata(wim);
2120 /* To avoid complicating things, we don't support mounting images to
2121 * which in-memory modifications have already been made. */
2122 if (is_image_dirty(imd)) {
2123 ERROR("Cannot mount a modified WIM image!");
2124 return WIMLIB_ERR_INVALID_PARAM;
2127 if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
2128 if (imd->refcnt > 1)
2129 return WIMLIB_ERR_IMAGE_HAS_MULTIPLE_REFERENCES;
2130 ret = lock_wim_for_append(wim);
2135 if (wim_has_solid_resources(wim)) {
2136 WARNING("Mounting a WIM file containing solid-compressed data; "
2137 "file access may be slow.");
2140 /* If the user did not specify an interface for accessing named
2141 * data streams, use the default (extended attributes). */
2142 if (!(mount_flags & (WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
2143 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR |
2144 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)))
2145 mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR;
2147 /* Start initializing the wimfs_context. */
2148 memset(&ctx, 0, sizeof(struct wimfs_context));
2150 ctx.mount_flags = mount_flags;
2151 if (mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
2152 ctx.default_lookup_flags = LOOKUP_FLAG_ADS_OK;
2154 /* For read-write mounts, create the staging directory, save a reference
2155 * to the image's metadata resource, and mark the image dirty. */
2156 if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
2157 ret = make_staging_dir(&ctx, staging_dir);
2160 ret = WIMLIB_ERR_NOMEM;
2161 ctx.metadata_resource = clone_blob_descriptor(
2162 imd->metadata_blob);
2163 if (!ctx.metadata_resource)
2165 mark_image_dirty(imd);
2167 ctx.owner_uid = getuid();
2168 ctx.owner_gid = getgid();
2170 /* Number the inodes in the mounted image sequentially and initialize
2171 * the file descriptor arrays */
2172 prepare_inodes(&ctx);
2174 /* Save the absolute path to the mountpoint directory. */
2175 ctx.mountpoint_abspath = realpath(dir, NULL);
2176 if (ctx.mountpoint_abspath)
2177 ctx.mountpoint_abspath_nchars = strlen(ctx.mountpoint_abspath);
2179 /* Build the FUSE command line. */
2182 fuse_argv[fuse_argc++] = "wimlib";
2183 fuse_argv[fuse_argc++] = (char *)dir;
2185 /* Disable multi-threaded operation. */
2186 fuse_argv[fuse_argc++] = "-s";
2188 /* Enable FUSE debug mode (don't fork) if requested by the user. */
2189 if (mount_flags & WIMLIB_MOUNT_FLAG_DEBUG)
2190 fuse_argv[fuse_argc++] = "-d";
2193 * Build the FUSE mount options:
2196 * FUSE will use the inode numbers we provide. We want this,
2197 * because we have inodes and will number them ourselves.
2200 * Name for our filesystem (main type is "fuse").
2203 * If an open file is unlinked, unlink it for real rather than
2204 * renaming it to a hidden file. Our code supports this; an
2205 * unlinked inode is retained until all its file descriptors have
2208 * default_permissions
2209 * FUSE will perform permission checking. Useful when
2210 * WIMLIB_MOUNT_FLAG_UNIX_DATA is provided and the WIM image
2211 * contains the UNIX permissions for each file.
2214 * Cache the contents of files. This will speed up repeated access
2215 * to files on a mounted WIM image, since they won't need to be
2216 * decompressed repeatedly. This option is valid because data in
2217 * the WIM image should never be changed externally. (Although, if
2218 * someone really wanted to they could modify the WIM file or mess
2219 * with the staging directory; but then they're asking for
2222 * entry_timeout=1000000000
2223 * Cache positive name lookups indefinitely, since names can only
2224 * be added, removed, or modified through the mounted filesystem
2227 * negative_timeout=1000000000
2228 * Cache negative name lookups indefinitely, since names can only
2229 * be added, removed, or modified through the mounted filesystem
2233 * Don't cache file/directory attributes. This is needed as a
2234 * workaround for the fact that when caching attributes, the high
2235 * level interface to libfuse considers a file which has several
2236 * hard-linked names as several different files. (Otherwise, we
2237 * could cache our file/directory attributes indefinitely, since
2238 * they can only be changed through the mounted filesystem itself.)
2240 char optstring[256] =
2244 ",default_permissions"
2246 ",entry_timeout=1000000000"
2247 ",negative_timeout=1000000000"
2250 fuse_argv[fuse_argc++] = "-o";
2251 fuse_argv[fuse_argc++] = optstring;
2252 if (!(mount_flags & WIMLIB_MOUNT_FLAG_READWRITE))
2253 strcat(optstring, ",ro");
2254 if (mount_flags & WIMLIB_MOUNT_FLAG_ALLOW_OTHER)
2255 strcat(optstring, ",allow_other");
2256 fuse_argv[fuse_argc] = NULL;
2258 /* Mount our filesystem. */
2259 ret = fuse_main(fuse_argc, fuse_argv, &wimfs_operations, &ctx);
2261 /* Cleanup and return. */
2263 ret = WIMLIB_ERR_FUSE;
2265 FREE(ctx.mountpoint_abspath);
2266 free_blob_descriptor(ctx.metadata_resource);
2267 if (ctx.staging_dir_name)
2268 delete_staging_dir(&ctx);
2269 unlock_wim_for_append(wim);
2273 struct commit_progress_thread_args {
2275 wimlib_progress_func_t progfunc;
2280 commit_progress_thread_proc(void *_args)
2282 struct commit_progress_thread_args *args = _args;
2283 struct commit_progress_report report;
2287 ret = mq_receive(args->mq,
2288 (char *)&report, sizeof(report), NULL);
2289 if (ret == sizeof(report)) {
2290 call_progress(args->progfunc, report.msg,
2291 &report.info, args->progctx);
2293 if (ret == 0 || (ret < 0 && errno != EINTR))
2301 generate_message_queue_name(char name[WIMFS_MQUEUE_NAME_LEN + 1])
2304 memcpy(name + 1, "wimfs-", 6);
2305 randomize_char_array_with_alnum(name + 7, WIMFS_MQUEUE_NAME_LEN - 7);
2306 name[WIMFS_MQUEUE_NAME_LEN] = '\0';
2310 create_message_queue(const char *name)
2315 struct mq_attr attr;
2318 memset(&attr, 0, sizeof(attr));
2320 attr.mq_msgsize = sizeof(struct commit_progress_report);
2322 am_root = (geteuid() == 0);
2324 /* Filesystem mounted as normal user with --allow-other should
2325 * be able to send messages to root user, if they're doing the
2327 umask_save = umask(0);
2332 mq = mq_open(name, O_RDWR | O_CREAT | O_EXCL, mode, &attr);
2338 /* Unmount a read-only or read-write mounted WIM image. */
2340 do_unmount(const char *dir)
2345 len = getxattr(dir, "wimfs.unmount", &status, sizeof(int));
2346 if (len == sizeof(int))
2348 else if (len < 0 && (errno == EACCES || errno == EPERM))
2349 return WIMLIB_ERR_NOT_PERMITTED_TO_UNMOUNT;
2351 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2355 set_unmount_info(const char *dir, const struct wimfs_unmount_info *unmount_info)
2357 if (!setxattr(dir, "wimfs.unmount_info",
2358 unmount_info, sizeof(struct wimfs_unmount_info), 0))
2360 else if (errno == EROFS)
2362 else if (errno == EACCES || errno == EPERM)
2363 return WIMLIB_ERR_NOT_PERMITTED_TO_UNMOUNT;
2365 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2369 do_unmount_discard(const char *dir)
2372 struct wimfs_unmount_info unmount_info;
2374 memset(&unmount_info, 0, sizeof(unmount_info));
2376 ret = set_unmount_info(dir, &unmount_info);
2379 return do_unmount(dir);
2382 /* Unmount a read-write mounted WIM image, committing the changes. */
2384 do_unmount_commit(const char *dir, int unmount_flags,
2385 wimlib_progress_func_t progfunc, void *progctx)
2387 struct wimfs_unmount_info unmount_info;
2389 struct commit_progress_thread_args args;
2390 pthread_t commit_progress_tid;
2393 memset(&unmount_info, 0, sizeof(unmount_info));
2394 unmount_info.unmount_flags = unmount_flags;
2396 /* The current thread will be stuck in getxattr() until the image is
2397 * committed. Create a thread to handle the progress messages. */
2399 generate_message_queue_name(unmount_info.mq_name);
2401 mq = create_message_queue(unmount_info.mq_name);
2402 if (mq == (mqd_t)-1) {
2403 ERROR_WITH_ERRNO("Can't create POSIX message queue");
2404 return WIMLIB_ERR_MQUEUE;
2407 args.progfunc = progfunc;
2408 args.progctx = progctx;
2409 ret = pthread_create(&commit_progress_tid, NULL,
2410 commit_progress_thread_proc, &args);
2413 ERROR_WITH_ERRNO("Can't create thread");
2414 ret = WIMLIB_ERR_NOMEM;
2417 unmount_info.unmount_flags |= WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS;
2420 ret = set_unmount_info(dir, &unmount_info);
2422 ret = do_unmount(dir);
2424 /* Terminate the progress thread. */
2426 mq_send(mq, empty, 0, 1);
2427 pthread_join(commit_progress_tid, NULL);
2432 mq_unlink(unmount_info.mq_name);
2438 begin_unmount(const char *dir, int unmount_flags, int *mount_flags_ret,
2439 wimlib_progress_func_t progfunc, void *progctx)
2443 int wim_filename_len;
2444 union wimlib_progress_info progress;
2446 if (getxattr(dir, "wimfs.mount_flags",
2447 &mount_flags, sizeof(int)) != sizeof(int))
2448 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2450 *mount_flags_ret = mount_flags;
2455 if (getxattr(dir, "wimfs.mounted_image",
2456 &mounted_image, sizeof(int)) != sizeof(int))
2457 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2459 wim_filename_len = getxattr(dir, "wimfs.wim_filename", NULL, 0);
2460 if (wim_filename_len < 0)
2461 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2463 char wim_filename[wim_filename_len + 1];
2464 if (getxattr(dir, "wimfs.wim_filename",
2465 wim_filename, wim_filename_len) != wim_filename_len)
2466 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2467 wim_filename[wim_filename_len] = '\0';
2469 progress.unmount.mountpoint = dir;
2470 progress.unmount.mounted_wim = wim_filename;
2471 progress.unmount.mounted_image = mounted_image;
2472 progress.unmount.mount_flags = mount_flags;
2473 progress.unmount.unmount_flags = unmount_flags;
2475 return call_progress(progfunc, WIMLIB_PROGRESS_MSG_UNMOUNT_BEGIN,
2476 &progress, progctx);
2479 /* API function documented in wimlib.h */
2481 wimlib_unmount_image_with_progress(const char *dir, int unmount_flags,
2482 wimlib_progress_func_t progfunc, void *progctx)
2487 ret = wimlib_global_init(WIMLIB_INIT_FLAG_ASSUME_UTF8);
2491 if (unmount_flags & ~(WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY |
2492 WIMLIB_UNMOUNT_FLAG_COMMIT |
2493 WIMLIB_UNMOUNT_FLAG_REBUILD |
2494 WIMLIB_UNMOUNT_FLAG_RECOMPRESS |
2495 WIMLIB_UNMOUNT_FLAG_FORCE |
2496 WIMLIB_UNMOUNT_FLAG_NEW_IMAGE))
2497 return WIMLIB_ERR_INVALID_PARAM;
2499 ret = begin_unmount(dir, unmount_flags, &mount_flags,
2504 if ((unmount_flags & WIMLIB_UNMOUNT_FLAG_COMMIT) &&
2505 (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE))
2506 return do_unmount_commit(dir, unmount_flags,
2509 return do_unmount_discard(dir);
2512 #else /* WITH_FUSE */
2516 mount_unsupported_error(void)
2518 #if defined(__WIN32__)
2519 ERROR("Sorry-- Mounting WIM images is not supported on Windows!");
2521 ERROR("wimlib was compiled with --without-fuse, which disables support "
2522 "for mounting WIMs.");
2524 return WIMLIB_ERR_UNSUPPORTED;
2528 wimlib_unmount_image_with_progress(const tchar *dir, int unmount_flags,
2529 wimlib_progress_func_t progfunc, void *progctx)
2531 return mount_unsupported_error();
2535 wimlib_mount_image(WIMStruct *wim, int image, const tchar *dir,
2536 int mount_flags, const tchar *staging_dir)
2538 return mount_unsupported_error();
2541 #endif /* !WITH_FUSE */
2544 wimlib_unmount_image(const tchar *dir, int unmount_flags)
2546 return wimlib_unmount_image_with_progress(dir, unmount_flags, NULL, NULL);