4 * This file implements mounting of WIM images using FUSE
5 * (Filesystem in Userspace). See https://github.com/libfuse/libfuse
7 * Currently it is only expected to work on Linux.
11 * Copyright 2012-2023 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 https://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 30
42 #include <sys/types.h> /* sometimes required before <sys/xattr.h> */
43 #include <sys/xattr.h>
56 #include "wimlib/blob_table.h"
57 #include "wimlib/dentry.h"
58 #include "wimlib/encoding.h"
59 #include "wimlib/metadata.h"
60 #include "wimlib/paths.h"
61 #include "wimlib/progress.h"
62 #include "wimlib/reparse.h"
63 #include "wimlib/threads.h"
64 #include "wimlib/timestamp.h"
65 #include "wimlib/unix_data.h"
66 #include "wimlib/write.h"
67 #include "wimlib/xml.h"
70 # define O_NOFOLLOW 0 /* Security only... */
74 # define ENOATTR ENODATA
77 #ifndef RENAME_NOREPLACE
78 # define RENAME_NOREPLACE (1 << 0)
80 #ifndef RENAME_EXCHANGE
81 # define RENAME_EXCHANGE (1 << 1)
84 #define WIMFS_MQUEUE_NAME_LEN 32
86 #define WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS 0x80000000
88 struct wimfs_unmount_info {
89 unsigned unmount_flags;
90 char mq_name[WIMFS_MQUEUE_NAME_LEN + 1];
93 struct commit_progress_report {
94 enum wimlib_progress_msg msg;
95 union wimlib_progress_info info;
98 /* Description of an open file on a mounted WIM image. Actually, this
99 * represents the open state of a particular data stream of an inode, rather
100 * than the inode itself. (An inode might have multiple named data streams in
101 * addition to the default, unnamed data stream.) At a given time, an inode in
102 * the WIM image might have multiple file descriptors open to it, each to any
103 * one of its data streams. */
106 /* Pointer to the inode of this open file.
107 * 'i_num_opened_fds' of the inode tracks the number of file descriptors
108 * that reference it. */
109 struct wim_inode *f_inode;
111 /* Pointer to the blob descriptor for the data stream that has been
112 * opened. 'num_opened_fds' of the blob descriptor tracks the number of
113 * file descriptors that reference it. Or, this value may be NULL,
114 * which indicates that the opened stream is empty and consequently does
115 * not have a blob descriptor. */
116 struct blob_descriptor *f_blob;
118 /* If valid (filedes_valid(&f_staging_fd)), this contains the
119 * corresponding native file descriptor for the staging file that has
120 * been created for reading from and/or writing to this open stream. A
121 * single staging file might have multiple file descriptors open to it
122 * simultaneously, each used by a different 'struct wimfs_fd'.
124 * Or, if invalid (!filedes_valid(&f_staging_fd)), this 'struct
125 * wimfs_fd' is not associated with a staging file. This is permissible
126 * only if this 'struct wimfs_fd' was opened read-only and the stream
127 * has not yet been extracted to a staging file. */
128 struct filedes f_staging_fd;
130 /* 0-based index of this file descriptor in the file descriptor table of
134 /* Unique ID of the opened stream in the inode. This will stay the same
135 * even if the indices of the inode's streams are changed by a deletion.
140 #define WIMFS_FD(fi) ((struct wimfs_fd *)(uintptr_t)((fi)->fh))
142 /* Context structure for a mounted WIM image. */
143 struct wimfs_context {
144 /* The WIMStruct containing the mounted image. The mounted image is the
145 * currently selected image (wim->current_image). */
148 /* Flags passed to wimlib_mount_image() (WIMLIB_MOUNT_FLAG_*). */
151 /* Default flags for path lookup in the WIM image. */
152 int default_lookup_flags;
154 /* Information about the user who has mounted the WIM image */
158 /* Absolute path to the mountpoint directory (may be needed for absolute
159 * symbolic link fixups) */
160 char *mountpoint_abspath;
161 size_t mountpoint_abspath_nchars;
163 /* Information about the staging directory for a read-write mount. */
166 char *staging_dir_name;
168 /* For read-write mounts, the inode number to be assigned to the next
169 * created file. Note: since this isn't a persistent filesystem and we
170 * can re-assign the inode numbers just before mounting the image, it's
171 * good enough to just generate inode numbers sequentially. */
174 /* Number of file descriptors open to the mounted WIM image. */
175 unsigned long num_open_fds;
177 /* For read-write mounts, the original metadata resource of the mounted
179 struct blob_descriptor *metadata_resource;
181 /* Parameters for unmounting the image (can be set via extended
182 * attribute "wimfs.unmount_info"). */
183 struct wimfs_unmount_info unmount_info;
186 #define WIMFS_CTX(fuse_ctx) ((struct wimfs_context*)(fuse_ctx)->private_data)
188 /* Retrieve the context structure for the currently mounted WIM image.
190 * Note: this is a per-thread variable. It is possible for different threads to
191 * mount different images at the same time in the same process, although they
192 * must use different WIMStructs! */
193 static inline struct wimfs_context *
194 wimfs_get_context(void)
196 return WIMFS_CTX(fuse_get_context());
200 wimfs_inc_num_open_fds(void)
202 wimfs_get_context()->num_open_fds++;
206 wimfs_dec_num_open_fds(void)
208 wimfs_get_context()->num_open_fds--;
211 /* Retrieve the WIMStruct for the currently mounted WIM image. */
212 static inline WIMStruct *
213 wimfs_get_WIMStruct(void)
215 return wimfs_get_context()->wim;
218 /* Is write permission requested on the file? */
220 flags_writable(int open_flags)
222 int accmode = (open_flags & O_ACCMODE);
223 return (accmode == O_RDWR || accmode == O_WRONLY);
227 fuse_mask_mode(mode_t mode, const struct fuse_context *fuse_ctx)
229 return mode & ~fuse_ctx->umask;
233 * Allocate a file descriptor to a data stream in the mounted WIM image.
236 * The inode containing the stream being opened
238 * The stream of the inode being opened
240 * On success, a pointer to the new file descriptor will be stored here.
242 * Returns 0 or a -errno code.
245 alloc_wimfs_fd(struct wim_inode *inode,
246 struct wim_inode_stream *strm,
247 struct wimfs_fd **fd_ret)
249 static const u16 min_fds_per_alloc = 8;
250 static const u16 max_fds = 0xffff;
254 if (inode->i_num_opened_fds == inode->i_num_allocated_fds) {
256 struct wimfs_fd **fds;
258 /* Expand this inode's file descriptor table. */
260 num_new_fds = max(min_fds_per_alloc,
261 inode->i_num_allocated_fds / 4);
263 num_new_fds = min(num_new_fds,
264 max_fds - inode->i_num_allocated_fds);
266 if (num_new_fds == 0)
269 fds = REALLOC(inode->i_fds,
270 (inode->i_num_allocated_fds + num_new_fds) *
275 memset(&fds[inode->i_num_allocated_fds], 0,
276 num_new_fds * sizeof(fds[0]));
278 inode->i_num_allocated_fds += num_new_fds;
279 inode->i_next_fd = inode->i_num_opened_fds;
282 /* Allocate the file descriptor in the first available space in the
283 * inode's file descriptor table.
285 * i_next_fd is the lower bound on the next open slot. */
286 for (i = inode->i_next_fd; inode->i_fds[i]; i++)
289 fd = MALLOC(sizeof(*fd));
294 fd->f_blob = stream_blob_resolved(strm);
295 filedes_invalidate(&fd->f_staging_fd);
297 fd->f_stream_id = strm->stream_id;
299 inode->i_fds[i] = fd;
300 inode->i_num_opened_fds++;
302 fd->f_blob->num_opened_fds++;
303 wimfs_inc_num_open_fds();
304 inode->i_next_fd = i + 1;
309 * Close a file descriptor to a data stream in the mounted WIM image.
311 * Returns 0 or a -errno code. The file descriptor is always closed.
314 close_wimfs_fd(struct wimfs_fd *fd)
317 struct wim_inode *inode;
319 /* Close the staging file if open. */
320 if (filedes_valid(&fd->f_staging_fd))
321 if (filedes_close(&fd->f_staging_fd))
324 /* Release this file descriptor from its blob descriptor. */
326 blob_decrement_num_opened_fds(fd->f_blob);
328 wimfs_dec_num_open_fds();
330 /* Release this file descriptor from its inode. */
332 inode->i_fds[fd->f_idx] = NULL;
333 if (fd->f_idx < inode->i_next_fd)
334 inode->i_next_fd = fd->f_idx;
336 inode_dec_num_opened_fds(inode);
341 * Translate a path into the corresponding inode in the mounted WIM image.
343 * See get_dentry() for more information.
345 * Returns a pointer to the resulting inode, or NULL with errno set.
347 static struct wim_inode *
348 wim_pathname_to_inode(WIMStruct *wim, const char *path)
350 struct wim_dentry *dentry;
352 dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
355 return dentry->d_inode;
358 /* Can look up named data stream with colon syntax */
359 #define LOOKUP_FLAG_ADS_OK 0x01
361 /* Can look up directory (otherwise get -ENOTDIR) */
362 #define LOOKUP_FLAG_DIRECTORY_OK 0x02
364 /* Get the data stream of the specified name from the specified inode. Returns
365 * NULL with errno set if not found. */
366 static struct wim_inode_stream *
367 inode_get_data_stream_tstr(const struct wim_inode *inode,
368 const char *stream_name)
370 struct wim_inode_stream *strm;
372 if (!stream_name || !*stream_name) {
373 strm = inode_get_unnamed_data_stream(inode);
375 const utf16lechar *uname;
377 if (tstr_get_utf16le(stream_name, &uname))
379 strm = inode_get_stream(inode, STREAM_TYPE_DATA, uname);
380 tstr_put_utf16le(uname);
388 * Translate a path into the corresponding dentry and stream in the mounted WIM
391 * Returns 0 or a -errno code. @dentry_ret and @strm_ret are both optional.
394 wim_pathname_to_stream(const struct wimfs_context *ctx,
397 struct wim_dentry **dentry_ret,
398 struct wim_inode_stream **strm_ret)
400 WIMStruct *wim = ctx->wim;
401 struct wim_dentry *dentry;
402 struct wim_inode *inode;
403 struct wim_inode_stream *strm;
404 const char *stream_name = NULL;
407 lookup_flags |= ctx->default_lookup_flags;
409 if (lookup_flags & LOOKUP_FLAG_ADS_OK) {
410 stream_name = path_stream_name(path);
412 p = (char *)stream_name - 1;
417 dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
423 inode = dentry->d_inode;
425 if (inode_resolve_streams(inode, wim->blob_table, false))
428 if (!(lookup_flags & LOOKUP_FLAG_DIRECTORY_OK)
429 && inode_is_directory(inode))
432 strm = inode_get_data_stream_tstr(inode, stream_name);
434 /* Force creation of an unnamed data stream */
436 strm = inode_add_stream(inode, STREAM_TYPE_DATA,
437 NO_STREAM_NAME, NULL);
443 *dentry_ret = dentry;
450 * Create a new file in the mounted WIM image.
453 * The FUSE context for the mounted image.
455 * The path at which to create the first link to the new file. If a file
456 * already exists at this path, -EEXIST is returned.
458 * The UNIX mode for the new file. This is only fully honored if
459 * WIMLIB_MOUNT_FLAG_UNIX_DATA was passed to wimlib_mount_image().
461 * The device ID for the new file, encoding the major and minor device
462 * numbers. This is only honored if WIMLIB_MOUNT_FLAG_UNIX_DATA was passed
463 * to wimlib_mount_image().
465 * On success, a pointer to the new dentry is returned here. Its d_inode
466 * member will point to the new inode that was created for it and added to
467 * the mounted WIM image.
469 * Returns 0 or a -errno code.
472 create_file(struct fuse_context *fuse_ctx, const char *path,
473 mode_t mode, dev_t rdev, struct wim_dentry **dentry_ret)
475 struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
476 struct wim_dentry *parent;
477 const char *basename;
478 struct wim_dentry *dentry;
479 struct wim_inode *inode;
481 parent = get_parent_dentry(wimfs_ctx->wim, path, WIMLIB_CASE_SENSITIVE);
485 if (!dentry_is_directory(parent))
488 basename = path_basename(path);
490 if (get_dentry_child_with_name(parent, basename, WIMLIB_CASE_SENSITIVE))
493 if (new_dentry_with_new_inode(basename, true, &dentry))
496 inode = dentry->d_inode;
498 inode->i_ino = wimfs_ctx->next_ino++;
500 /* Note: we still use FILE_ATTRIBUTE_NORMAL for device nodes, named
501 * pipes, and sockets. The real mode is in the UNIX metadata. */
503 inode->i_attributes = FILE_ATTRIBUTE_DIRECTORY;
505 inode->i_attributes = FILE_ATTRIBUTE_NORMAL;
507 if (wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) {
508 struct wimlib_unix_data unix_data;
510 unix_data.uid = fuse_ctx->uid;
511 unix_data.gid = fuse_ctx->gid;
512 unix_data.mode = fuse_mask_mode(mode, fuse_ctx);
513 unix_data.rdev = rdev;
514 if (!inode_set_unix_data(inode, &unix_data, UNIX_DATA_ALL))
521 hlist_add_head(&inode->i_hlist_node,
522 &wim_get_current_image_metadata(wimfs_ctx->wim)->inode_list);
524 dentry_add_child(parent, dentry);
526 *dentry_ret = dentry;
531 * Remove a dentry from the mounted WIM image; i.e. remove an alias for an
535 remove_dentry(struct wim_dentry *dentry, struct blob_table *blob_table)
537 /* Drop blob references. */
538 inode_unref_blobs(dentry->d_inode, blob_table);
540 /* Unlink the dentry from the image's dentry tree. */
541 unlink_dentry(dentry);
543 /* Delete the dentry. This will also decrement the link count of the
544 * corresponding inode, and possibly cause it to be deleted as well. */
548 /* Generate UNIX filetype mode bits for the specified WIM inode, based on its
549 * Windows file attributes. */
551 inode_unix_file_type(const struct wim_inode *inode)
553 if (inode_is_symlink(inode))
555 else if (inode_is_directory(inode))
561 /* Generate a default UNIX mode for the specified WIM inode. */
563 inode_default_unix_mode(const struct wim_inode *inode)
565 return inode_unix_file_type(inode) | 0777;
569 blob_size(const struct blob_descriptor *blob)
577 blob_stored_size(const struct blob_descriptor *blob)
581 if (blob->blob_location == BLOB_IN_WIM &&
582 blob->size == blob->rdesc->uncompressed_size)
583 return blob->rdesc->size_in_wim;
588 * Retrieve standard UNIX metadata ('struct stat') for a WIM inode.
590 * @blob is the blob descriptor for the stream of the inode that is being
591 * queried, or NULL. We mostly return the same information for all streams, but
592 * st_size and st_blocks may be different for different streams.
594 * This always returns 0.
597 inode_to_stbuf(const struct wim_inode *inode,
598 const struct blob_descriptor *blob, struct stat *stbuf)
600 const struct wimfs_context *ctx = wimfs_get_context();
601 struct wimlib_unix_data unix_data;
603 memset(stbuf, 0, sizeof(struct stat));
604 if ((ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) &&
605 inode_get_unix_data(inode, &unix_data))
607 /* Use the user ID, group ID, mode, and device ID from the
608 * inode's extra UNIX metadata information. */
609 stbuf->st_uid = unix_data.uid;
610 stbuf->st_gid = unix_data.gid;
611 stbuf->st_mode = unix_data.mode;
612 stbuf->st_rdev = unix_data.rdev;
614 /* Generate default values for the user ID, group ID, and mode.
616 * Note: in the case of an allow_other mount, fuse_context.uid
617 * may not be the same as wimfs_context.owner_uid! */
618 stbuf->st_uid = ctx->owner_uid;
619 stbuf->st_gid = ctx->owner_gid;
620 stbuf->st_mode = inode_default_unix_mode(inode);
622 stbuf->st_ino = inode->i_ino;
623 stbuf->st_nlink = inode->i_nlink;
624 stbuf->st_size = blob_size(blob);
625 #ifdef HAVE_STAT_NANOSECOND_PRECISION
626 stbuf->st_atim = wim_timestamp_to_timespec(inode->i_last_access_time);
627 stbuf->st_mtim = wim_timestamp_to_timespec(inode->i_last_write_time);
628 stbuf->st_ctim = stbuf->st_mtim;
630 stbuf->st_atime = wim_timestamp_to_time_t(inode->i_last_access_time);
631 stbuf->st_mtime = wim_timestamp_to_time_t(inode->i_last_write_time);
632 stbuf->st_ctime = stbuf->st_mtime;
634 stbuf->st_blocks = DIV_ROUND_UP(blob_stored_size(blob), 512);
638 /* Update the last access and last write timestamps of a WIM inode. */
640 touch_inode(struct wim_inode *inode)
642 u64 now = now_as_wim_timestamp();
643 inode->i_last_access_time = now;
644 inode->i_last_write_time = now;
648 touch_parent(struct wim_dentry *dentry)
650 touch_inode(dentry->d_parent->d_inode);
654 * Update inode metadata after a regular file's contents have changed:
656 * - Update the timestamps
657 * - Clear the setuid and setgid bits
660 file_contents_changed(struct wim_inode *inode)
662 struct wimlib_unix_data unix_data;
667 if (inode_get_unix_data(inode, &unix_data)) {
668 unix_data.mode &= ~(S_ISUID | S_ISGID);
669 ok = inode_set_unix_data(inode, &unix_data, UNIX_DATA_MODE);
671 * This cannot fail because no memory allocation should have
672 * been required, as the UNIX data already exists.
675 } /* Else, set[ug]id can't be set, so there's nothing to do. */
679 * Create a new file in the staging directory for a read-write mounted image.
681 * On success, returns the file descriptor for the new staging file, opened for
682 * writing. In addition, stores the allocated name of the staging file in
685 * On failure, returns -1 and sets errno.
688 create_staging_file(const struct wimfs_context *ctx, char **name_ret)
691 static const size_t STAGING_FILE_NAME_LEN = 20;
695 name = MALLOC(STAGING_FILE_NAME_LEN + 1);
698 name[STAGING_FILE_NAME_LEN] = '\0';
701 get_random_alnum_chars(name, STAGING_FILE_NAME_LEN);
702 fd = openat(ctx->staging_dir_fd, name,
703 O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0600);
704 if (unlikely(fd < 0)) {
705 if (unlikely(errno == EEXIST))
706 /* Try again with another name. */
716 * Extract a blob to the staging directory. This is necessary when a stream
717 * using the blob is being opened for writing and the blob has not already been
718 * extracted to the staging directory.
721 * The inode containing the stream being opened for writing.
723 * The stream being opened for writing. The blob descriptor to which the
724 * stream refers will be changed by this function.
726 * Number of bytes of the blob to extract and include in the staging file.
727 * It may be less than the actual blob length, in which case only a prefix
728 * of the blob will be extracted. It may also be more than the actual blob
729 * length, in which case the extra space will be zero-filled.
731 * Returns 0 or a -errno code.
734 extract_blob_to_staging_dir(struct wim_inode *inode,
735 struct wim_inode_stream *strm,
736 off_t size, const struct wimfs_context *ctx)
738 struct blob_descriptor *old_blob;
739 struct blob_descriptor *new_blob;
740 char *staging_file_name;
746 old_blob = stream_blob_resolved(strm);
748 /* Create the staging file. */
749 staging_fd = create_staging_file(ctx, &staging_file_name);
750 if (unlikely(staging_fd < 0))
753 /* Extract the stream to the staging file (possibly truncated). */
757 filedes_init(&fd, staging_fd);
759 extract_size = min(old_blob->size, size);
760 result = extract_blob_prefix_to_fd(old_blob, extract_size, &fd);
766 /* In the case of truncate() to more than the file length, extend the
767 * staging file with zeroes by calling ftruncate(). */
768 if (!result && size > extract_size)
769 result = ftruncate(staging_fd, size);
771 /* Close the staging file. */
772 if (close(staging_fd))
775 /* If an error occurred, unlink the staging file. */
776 if (unlikely(result)) {
777 /* extract_blob_to_fd() should set errno, but if it didn't,
778 * set a default value. */
779 ret = errno ? -errno : -EIO;
780 goto out_delete_staging_file;
783 /* Create a blob descriptor for the staging file. */
784 new_blob = new_blob_descriptor();
785 if (unlikely(!new_blob)) {
787 goto out_delete_staging_file;
790 /* There may already be open file descriptors to this stream if it's
791 * previously been opened read-only, but just now we're opening it
792 * read-write. Identify those file descriptors, update them to use the
793 * new blob descriptor, and open staging file descriptors for them. */
794 for (u16 i = 0, j = 0; j < inode->i_num_opened_fds; i++) {
798 fd = inode->i_fds[i];
804 if (fd->f_stream_id != strm->stream_id)
807 /* This is a readonly fd for the same stream. */
808 fd->f_blob = new_blob;
809 new_blob->num_opened_fds++;
810 raw_fd = openat(ctx->staging_dir_fd, staging_file_name,
811 O_RDONLY | O_NOFOLLOW);
812 if (unlikely(raw_fd < 0)) {
814 goto out_revert_fd_changes;
816 filedes_init(&fd->f_staging_fd, raw_fd);
820 old_blob->num_opened_fds -= new_blob->num_opened_fds;
822 new_blob->blob_location = BLOB_IN_STAGING_FILE;
823 new_blob->staging_file_name = staging_file_name;
824 new_blob->staging_dir_fd = ctx->staging_dir_fd;
825 new_blob->size = size;
827 prepare_unhashed_blob(new_blob, inode, strm->stream_id,
828 &wim_get_current_image_metadata(ctx->wim)->unhashed_blobs);
829 inode_replace_stream_blob(inode, strm, new_blob, ctx->wim->blob_table);
830 if (size != blob_size(old_blob))
831 file_contents_changed(inode);
834 out_revert_fd_changes:
835 for (u16 i = 0; new_blob->num_opened_fds; i++) {
836 struct wimfs_fd *fd = inode->i_fds[i];
837 if (fd && fd->f_stream_id == strm->stream_id) {
838 fd->f_blob = old_blob;
839 if (filedes_valid(&fd->f_staging_fd)) {
840 filedes_close(&fd->f_staging_fd);
841 filedes_invalidate(&fd->f_staging_fd);
843 new_blob->num_opened_fds--;
846 free_blob_descriptor(new_blob);
847 out_delete_staging_file:
848 unlinkat(ctx->staging_dir_fd, staging_file_name, 0);
849 FREE(staging_file_name);
854 * Create the staging directory for the WIM file.
856 * The staging directory will be created in the directory specified by the open
857 * file descriptor @parent_dir_fd. It will be given a randomly generated name
858 * based on @wim_basename, the name of the WIM file.
860 * On success, returns a file descriptor to the open staging directory with
861 * O_RDONLY access. In addition, stores the allocated name of the staging
862 * directory (relative to @parent_dir_fd) in @staging_dir_name_ret.
863 * On failure, returns -1 and sets errno.
866 make_staging_dir_at(int parent_dir_fd, const char *wim_basename,
867 char **staging_dir_name_ret)
869 static const char common_suffix[8] = ".staging";
870 static const size_t random_suffix_len = 10;
871 size_t wim_basename_len;
872 size_t staging_dir_name_len;
873 char *staging_dir_name;
877 wim_basename_len = strlen(wim_basename);
878 staging_dir_name_len = wim_basename_len + sizeof(common_suffix) +
880 staging_dir_name = MALLOC(staging_dir_name_len + 1);
881 if (!staging_dir_name)
884 p = staging_dir_name;
885 p = mempcpy(p, wim_basename, wim_basename_len);
886 p = mempcpy(p, common_suffix, sizeof(common_suffix));
887 get_random_alnum_chars(p, random_suffix_len);
888 p += random_suffix_len;
891 if (mkdirat(parent_dir_fd, staging_dir_name, 0700))
894 fd = openat(parent_dir_fd, staging_dir_name,
895 O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
899 *staging_dir_name_ret = staging_dir_name;
903 unlinkat(parent_dir_fd, staging_dir_name, AT_REMOVEDIR);
905 FREE(staging_dir_name);
910 * Create the staging directory and set ctx->staging_dir_fd,
911 * ctx->staging_dir_name, and ctx->parent_dir_fd.
914 make_staging_dir(struct wimfs_context *ctx, const char *parent_dir_path)
916 const char *wim_basename;
920 wim_basename = path_basename(ctx->wim->filename);
922 if (!parent_dir_path) {
923 /* The user did not specify a directory. Default to creating
924 * the staging directory alongside the WIM file. */
925 if (wim_basename > ctx->wim->filename) {
926 parent_dir_path = ctx->wim->filename;
927 end = (char *)(wim_basename - 1);
928 /* *end must be a slash. Temporarily overwrite it so we
929 * can open the parent directory. */
932 parent_dir_path = ".";
936 /* Open the parent directory (in which we'll create our staging
938 ctx->parent_dir_fd = open(parent_dir_path, O_RDONLY | O_DIRECTORY);
939 if (ctx->parent_dir_fd < 0) {
940 ERROR_WITH_ERRNO("Can't open directory \"%s\"",
942 ret = WIMLIB_ERR_OPENDIR;
943 goto out_restore_wim_filename;
946 ctx->staging_dir_fd = make_staging_dir_at(ctx->parent_dir_fd,
948 &ctx->staging_dir_name);
949 if (ctx->staging_dir_fd < 0) {
950 ERROR_WITH_ERRNO("Can't create staging directory in \"%s\"",
952 close(ctx->parent_dir_fd);
953 ret = WIMLIB_ERR_MKDIR;
954 goto out_restore_wim_filename;
957 out_restore_wim_filename:
963 /* Deletes the staging directory, undoing the effects of a successful call to
964 * make_staging_dir(). */
966 delete_staging_dir(struct wimfs_context *ctx)
971 dir = fdopendir(ctx->staging_dir_fd);
973 while ((ent = readdir(dir)))
974 unlinkat(ctx->staging_dir_fd, ent->d_name, 0);
977 close(ctx->staging_dir_fd);
979 if (unlinkat(ctx->parent_dir_fd, ctx->staging_dir_name, AT_REMOVEDIR))
980 WARNING_WITH_ERRNO("Could not delete staging directory");
981 FREE(ctx->staging_dir_name);
982 close(ctx->parent_dir_fd);
986 prepare_inodes(struct wimfs_context *ctx)
988 struct wim_image_metadata *imd;
989 struct wim_inode *inode;
992 imd = wim_get_current_image_metadata(ctx->wim);
993 image_for_each_inode(inode, imd) {
994 inode->i_ino = ctx->next_ino++;
995 inode->i_num_opened_fds = 0;
996 inode->i_num_allocated_fds = 0;
1001 /* Delete the 'struct blob_descriptor' for any stream that was modified
1002 * or created in the read-write mounted image and had a final size of 0. */
1004 delete_empty_blobs(struct wimfs_context *ctx)
1006 struct blob_descriptor *blob, *tmp;
1007 struct wim_image_metadata *imd;
1009 imd = wim_get_current_image_metadata(ctx->wim);
1011 image_for_each_unhashed_blob_safe(blob, tmp, imd) {
1013 *retrieve_pointer_to_unhashed_blob(blob) = NULL;
1014 list_del(&blob->unhashed_list);
1015 free_blob_descriptor(blob);
1020 /* Close all file descriptors open to the specified inode.
1022 * Note: closing the last file descriptor might free the inode. */
1024 inode_close_fds(struct wim_inode *inode)
1026 u16 num_open_fds = inode->i_num_opened_fds;
1027 for (u16 i = 0; num_open_fds; i++) {
1028 if (inode->i_fds[i]) {
1029 close_wimfs_fd(inode->i_fds[i]);
1035 /* Close all file descriptors open to the mounted image. */
1037 close_all_fds(struct wimfs_context *ctx)
1039 struct wim_inode *inode;
1040 struct hlist_node *tmp;
1041 struct wim_image_metadata *imd;
1043 imd = wim_get_current_image_metadata(ctx->wim);
1045 image_for_each_inode_safe(inode, tmp, imd)
1046 inode_close_fds(inode);
1049 /* Moves the currently selected image, which may have been modified, to a new
1050 * index, and sets the original index to refer to a reset (unmodified) copy of
1053 renew_current_image(struct wimfs_context *ctx)
1055 WIMStruct *wim = ctx->wim;
1056 int image = wim->current_image;
1057 struct wim_image_metadata *imd;
1058 struct wim_inode *inode;
1061 ret = WIMLIB_ERR_NOMEM;
1062 imd = new_unloaded_image_metadata(ctx->metadata_resource);
1066 ret = append_image_metadata(wim, wim->image_metadata[image - 1]);
1070 ret = xml_export_image(wim->xml_info, image,
1071 wim->xml_info, NULL, NULL, false);
1073 goto err_undo_append;
1075 wim->image_metadata[image - 1] = imd;
1076 wim->current_image = wim->hdr.image_count;
1078 ret = select_wim_image(wim, image);
1080 goto err_undo_export;
1082 image_for_each_inode(inode, imd) {
1083 for (unsigned i = 0; i < inode->i_num_streams; i++) {
1084 struct blob_descriptor *blob;
1086 blob = stream_blob(&inode->i_streams[i],
1089 blob->refcnt += inode->i_nlink;
1093 select_wim_image(wim, wim->hdr.image_count);
1094 ctx->metadata_resource = NULL;
1098 xml_delete_image(wim->xml_info, wim->hdr.image_count);
1099 wim->image_metadata[image - 1] = wim->image_metadata[wim->hdr.image_count - 1];
1100 wim->current_image = image;
1102 wim->hdr.image_count--;
1104 imd->metadata_blob = NULL;
1105 put_image_metadata(imd);
1110 static enum wimlib_progress_status
1111 commit_progress_func(enum wimlib_progress_msg msg,
1112 union wimlib_progress_info *info, void *progctx)
1114 mqd_t mq = *(mqd_t *)progctx;
1115 struct commit_progress_report report;
1117 memset(&report, 0, sizeof(report));
1120 report.info = *info;
1121 mq_send(mq, (const char *)&report, sizeof(report), 1);
1122 return WIMLIB_PROGRESS_STATUS_CONTINUE;
1125 /* Commit the mounted image to the underlying WIM file. */
1127 commit_image(struct wimfs_context *ctx, int unmount_flags, mqd_t mq)
1131 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS)
1132 wimlib_register_progress_function(ctx->wim,
1133 commit_progress_func, &mq);
1135 wimlib_register_progress_function(ctx->wim, NULL, NULL);
1137 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_NEW_IMAGE) {
1138 int ret = renew_current_image(ctx);
1142 delete_empty_blobs(ctx);
1146 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY)
1147 write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
1149 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_REBUILD)
1150 write_flags |= WIMLIB_WRITE_FLAG_REBUILD;
1152 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_RECOMPRESS)
1153 write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
1155 return wimlib_overwrite(ctx->wim, write_flags, 0);
1158 /* In the case of an allow_other mount, only the mount owner and root are
1159 * allowed to unmount the filesystem. */
1161 may_unmount_wimfs(void)
1163 const struct fuse_context *fuse_ctx = fuse_get_context();
1164 const struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1166 return (fuse_ctx->uid == wimfs_ctx->owner_uid ||
1167 fuse_ctx->uid == 0);
1170 /* Unmount the mounted image, called from the daemon process. */
1174 struct fuse_context *fuse_ctx = fuse_get_context();
1175 struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1176 const struct wimfs_unmount_info *info = &wimfs_ctx->unmount_info;
1177 int unmount_flags = info->unmount_flags;
1178 mqd_t mq = (mqd_t)-1;
1181 /* Ignore COMMIT if the image is mounted read-only. */
1182 if (!(wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_READWRITE))
1183 unmount_flags &= ~WIMLIB_UNMOUNT_FLAG_COMMIT;
1185 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS) {
1186 mq = mq_open(info->mq_name, O_WRONLY | O_NONBLOCK);
1187 if (mq == (mqd_t)-1) {
1188 ret = WIMLIB_ERR_MQUEUE;
1193 if (wimfs_ctx->num_open_fds) {
1195 /* There are still open file descriptors to the image. */
1197 /* With COMMIT, refuse to unmount unless FORCE is also
1199 if ((unmount_flags & (WIMLIB_UNMOUNT_FLAG_COMMIT |
1200 WIMLIB_UNMOUNT_FLAG_FORCE))
1201 == WIMLIB_UNMOUNT_FLAG_COMMIT)
1203 ret = WIMLIB_ERR_MOUNTED_IMAGE_IS_BUSY;
1207 /* Force-close all file descriptors. */
1208 close_all_fds(wimfs_ctx);
1211 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_COMMIT)
1212 ret = commit_image(wimfs_ctx, unmount_flags, mq);
1214 ret = 0; /* Read-only mount, or discarding changes to
1215 a read-write mount */
1218 /* Leave the image mounted if commit failed, unless this is a
1219 * forced unmount. The user can retry without COMMIT if they
1221 if (!ret || (unmount_flags & WIMLIB_UNMOUNT_FLAG_FORCE)) {
1222 unlock_wim_for_append(wimfs_ctx->wim);
1223 fuse_exit(fuse_ctx->fuse);
1225 if (mq != (mqd_t)-1)
1231 wimfs_init(struct fuse_conn_info *conn, struct fuse_config *cfg)
1234 * Cache positive name lookups indefinitely, since names can only be
1235 * added, removed, or modified through the mounted filesystem itself.
1237 cfg->entry_timeout = 1000000000;
1240 * Cache negative name lookups indefinitely, since names can only be
1241 * added, removed, or modified through the mounted filesystem itself.
1243 cfg->negative_timeout = 1000000000;
1246 * Don't cache file/directory attributes. This is needed as a
1247 * workaround for the fact that when caching attributes, the high level
1248 * interface to libfuse considers a file which has several hard-linked
1249 * names as several different files. (Otherwise, we could cache our
1250 * file/directory attributes indefinitely, since they can only be
1251 * changed through the mounted filesystem itself.)
1253 cfg->attr_timeout = 0;
1256 * If an open file is unlinked, unlink it for real rather than renaming
1257 * it to a hidden file. Our code supports this; an unlinked inode is
1258 * retained until all its file descriptors have been closed.
1260 cfg->hard_remove = 1;
1263 * Make FUSE use the inode numbers we provide. We want this, because we
1264 * have inodes and will number them ourselves.
1269 * Cache the contents of files. This will speed up repeated access to
1270 * files on a mounted WIM image, since they won't need to be
1271 * decompressed repeatedly. This option is valid because data in the
1272 * WIM image should never be changed externally. (Although, if someone
1273 * really wanted to they could modify the WIM file or mess with the
1274 * staging directory; but then they're asking for trouble.)
1276 cfg->kernel_cache = 1;
1279 * We keep track of file descriptor structures (struct wimfs_fd), so
1280 * there is no need to have the file path provided on operations such as
1283 cfg->nullpath_ok = 1;
1285 return wimfs_get_context();
1289 wimfs_chmod(const char *path, mode_t mask, struct fuse_file_info *fi)
1291 const struct wimfs_context *ctx = wimfs_get_context();
1292 struct wim_inode *inode;
1293 struct wimlib_unix_data unix_data;
1295 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
1299 inode = WIMFS_FD(fi)->f_inode;
1301 inode = wim_pathname_to_inode(ctx->wim, path);
1305 unix_data.uid = ctx->owner_uid;
1306 unix_data.gid = ctx->owner_gid;
1307 unix_data.mode = mask;
1310 if (!inode_set_unix_data(inode, &unix_data, UNIX_DATA_MODE))
1317 wimfs_chown(const char *path, uid_t uid, gid_t gid, struct fuse_file_info *fi)
1319 const struct wimfs_context *ctx = wimfs_get_context();
1320 struct wim_inode *inode;
1321 struct wimlib_unix_data unix_data;
1324 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
1328 inode = WIMFS_FD(fi)->f_inode;
1330 inode = wim_pathname_to_inode(ctx->wim, path);
1337 if (uid != (uid_t)-1)
1338 which |= UNIX_DATA_UID;
1340 uid = ctx->owner_uid;
1342 if (gid != (gid_t)-1)
1343 which |= UNIX_DATA_GID;
1345 gid = ctx->owner_gid;
1347 unix_data.uid = uid;
1348 unix_data.gid = gid;
1349 unix_data.mode = inode_default_unix_mode(inode);
1352 if (!inode_set_unix_data(inode, &unix_data, which))
1359 wimfs_getattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi)
1361 const struct wimfs_context *ctx = wimfs_get_context();
1362 const struct wim_inode *inode;
1363 const struct blob_descriptor *blob;
1367 const struct wimfs_fd *fd = WIMFS_FD(fi);
1369 inode = fd->f_inode;
1372 struct wim_dentry *dentry;
1373 struct wim_inode_stream *strm;
1375 ret = wim_pathname_to_stream(ctx, path,
1376 LOOKUP_FLAG_DIRECTORY_OK,
1380 inode = dentry->d_inode;
1381 blob = stream_blob_resolved(strm);
1384 return inode_to_stbuf(inode, blob, stbuf);
1388 copy_xattr(char *dest, size_t destsize, const void *src, size_t srcsize)
1391 if (destsize < srcsize)
1393 memcpy(dest, src, srcsize);
1399 wimfs_getxattr(const char *path, const char *name, char *value,
1402 const struct wimfs_context *ctx = wimfs_get_context();
1403 const struct wim_inode *inode;
1404 const struct wim_inode_stream *strm;
1405 const struct blob_descriptor *blob;
1407 if (!strncmp(name, "wimfs.", 6)) {
1408 /* Handle some magical extended attributes. These really should
1409 * be ioctls, but directory ioctls aren't supported until
1410 * libfuse 2.9, and even then they are broken. */
1412 if (!strcmp(name, "wim_filename")) {
1413 return copy_xattr(value, size, ctx->wim->filename,
1414 strlen(ctx->wim->filename));
1416 if (!strcmp(name, "wim_info")) {
1417 struct wimlib_wim_info info;
1419 wimlib_get_wim_info(ctx->wim, &info);
1421 return copy_xattr(value, size, &info, sizeof(info));
1423 if (!strcmp(name, "mounted_image")) {
1424 return copy_xattr(value, size,
1425 &ctx->wim->current_image, sizeof(int));
1427 if (!strcmp(name, "mount_flags")) {
1428 return copy_xattr(value, size,
1429 &ctx->mount_flags, sizeof(int));
1431 if (!strcmp(name, "unmount")) {
1432 if (!may_unmount_wimfs())
1437 if (size < sizeof(int))
1439 status = unmount_wimfs();
1440 memcpy(value, &status, sizeof(int));
1447 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1450 if (strncmp(name, "user.", 5))
1457 /* Querying a named data stream */
1459 inode = wim_pathname_to_inode(ctx->wim, path);
1463 strm = inode_get_data_stream_tstr(inode, name);
1465 return (errno == ENOENT) ? -ENOATTR : -errno;
1467 blob = stream_blob_resolved(strm);
1471 if (unlikely(blob->size > INT_MAX))
1475 if (size < blob->size)
1478 if (read_blob_into_buf(blob, value))
1479 return errno ? -errno : -EIO;
1485 wimfs_link(const char *existing_path, const char *new_path)
1487 WIMStruct *wim = wimfs_get_WIMStruct();
1488 const char *new_name;
1489 struct wim_inode *inode;
1490 struct wim_dentry *dir;
1491 struct wim_dentry *new_alias;
1493 inode = wim_pathname_to_inode(wim, existing_path);
1497 if (inode->i_attributes & (FILE_ATTRIBUTE_DIRECTORY |
1498 FILE_ATTRIBUTE_REPARSE_POINT))
1501 new_name = path_basename(new_path);
1503 dir = get_parent_dentry(wim, new_path, WIMLIB_CASE_SENSITIVE);
1507 if (!dentry_is_directory(dir))
1510 if (get_dentry_child_with_name(dir, new_name, WIMLIB_CASE_SENSITIVE))
1513 if (new_dentry_with_existing_inode(new_name, inode, &new_alias))
1516 dentry_add_child(dir, new_alias);
1517 touch_inode(dir->d_inode);
1522 wimfs_listxattr(const char *path, char *list, size_t size)
1524 const struct wimfs_context *ctx = wimfs_get_context();
1525 const struct wim_inode *inode;
1529 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1532 /* List named data streams, or get the list size. We report each named
1533 * data stream "X" as an extended attribute "user.X". */
1535 inode = wim_pathname_to_inode(ctx->wim, path);
1539 for (unsigned i = 0; i < inode->i_num_streams; i++) {
1540 const struct wim_inode_stream *strm;
1541 char *stream_name_mbs;
1542 size_t stream_name_mbs_nbytes;
1544 strm = &inode->i_streams[i];
1546 if (!stream_is_named_data_stream(strm))
1549 if (utf16le_to_tstr(strm->stream_name,
1550 utf16le_len_bytes(strm->stream_name),
1552 &stream_name_mbs_nbytes))
1555 if (unlikely(INT_MAX - total_size < stream_name_mbs_nbytes + 6)) {
1556 FREE(stream_name_mbs);
1560 total_size += stream_name_mbs_nbytes + 6;
1562 if (list + size - p < stream_name_mbs_nbytes + 6) {
1563 FREE(stream_name_mbs);
1566 p = mempcpy(p, "user.", 5);
1567 p = mempcpy(p, stream_name_mbs, stream_name_mbs_nbytes);
1570 FREE(stream_name_mbs);
1576 wimfs_mkdir(const char *path, mode_t mode)
1578 struct wim_dentry *dentry;
1581 /* Note: according to fuse.h, mode may not include S_IFDIR */
1582 ret = create_file(fuse_get_context(), path, mode | S_IFDIR, 0, &dentry);
1585 touch_parent(dentry);
1590 wimfs_mknod(const char *path, mode_t mode, dev_t rdev)
1592 struct fuse_context *fuse_ctx = fuse_get_context();
1593 struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1594 const char *stream_name;
1596 if ((wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
1597 && (stream_name = path_stream_name(path)))
1599 struct wim_inode *inode;
1600 struct wim_inode_stream *existing_strm;
1601 struct wim_inode_stream *new_strm;
1603 const utf16lechar *uname;
1605 /* Create a named data stream. */
1610 p = (char *)stream_name - 1;
1613 inode = wim_pathname_to_inode(wimfs_ctx->wim, path);
1618 if (tstr_get_utf16le(stream_name, &uname))
1621 existing_strm = inode_get_stream(inode, STREAM_TYPE_DATA, uname);
1622 if (existing_strm) {
1623 tstr_put_utf16le(uname);
1627 new_strm = inode_add_stream(inode, STREAM_TYPE_DATA, uname, NULL);
1629 tstr_put_utf16le(uname);
1635 /* Create a regular file, device node, named pipe, or socket.
1637 struct wim_dentry *dentry;
1640 if (!S_ISREG(mode) &&
1641 !(wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
1644 ret = create_file(fuse_ctx, path, mode, rdev, &dentry);
1647 touch_parent(dentry);
1653 wimfs_open(const char *path, struct fuse_file_info *fi)
1655 struct wimfs_context *ctx = wimfs_get_context();
1656 struct wim_dentry *dentry;
1657 struct wim_inode *inode;
1658 struct wim_inode_stream *strm;
1659 struct blob_descriptor *blob;
1660 struct wimfs_fd *fd;
1663 ret = wim_pathname_to_stream(ctx, path, 0, &dentry, &strm);
1667 inode = dentry->d_inode;
1668 blob = stream_blob_resolved(strm);
1670 /* The data of the file being opened may be in the staging directory
1671 * (read-write mounts only) or in the WIM. If it's in the staging
1672 * directory, we need to open a native file descriptor for the
1673 * corresponding file. Otherwise, we can read the file data directly
1674 * from the WIM file if we are opening it read-only, but we need to
1675 * extract the data to the staging directory if we are opening it
1678 if (flags_writable(fi->flags) &&
1679 (!blob || blob->blob_location != BLOB_IN_STAGING_FILE)) {
1680 ret = extract_blob_to_staging_dir(inode,
1686 blob = stream_blob_resolved(strm);
1689 ret = alloc_wimfs_fd(inode, strm, &fd);
1693 if (blob && blob->blob_location == BLOB_IN_STAGING_FILE) {
1696 raw_fd = openat(blob->staging_dir_fd, blob->staging_file_name,
1697 (fi->flags & (O_ACCMODE | O_TRUNC)) |
1703 filedes_init(&fd->f_staging_fd, raw_fd);
1704 if (fi->flags & O_TRUNC) {
1706 file_contents_changed(inode);
1709 fi->fh = (uintptr_t)fd;
1714 wimfs_opendir(const char *path, struct fuse_file_info *fi)
1716 WIMStruct *wim = wimfs_get_WIMStruct();
1717 struct wim_inode *inode;
1718 struct wim_inode_stream *strm;
1719 struct wimfs_fd *fd;
1722 inode = wim_pathname_to_inode(wim, path);
1725 if (!inode_is_directory(inode))
1727 strm = inode_get_unnamed_data_stream(inode);
1730 ret = alloc_wimfs_fd(inode, strm, &fd);
1733 fi->fh = (uintptr_t)fd;
1738 wimfs_read(const char *path, char *buf, size_t size,
1739 off_t offset, struct fuse_file_info *fi)
1741 struct wimfs_fd *fd = WIMFS_FD(fi);
1742 const struct blob_descriptor *blob;
1749 if (offset >= blob->size)
1752 if (size > blob->size - offset)
1753 size = blob->size - offset;
1758 switch (blob->blob_location) {
1760 if (read_partial_wim_blob_into_buf(blob, offset, size, buf))
1761 ret = errno ? -errno : -EIO;
1765 case BLOB_IN_STAGING_FILE:
1766 ret = pread(fd->f_staging_fd.fd, buf, size, offset);
1770 case BLOB_IN_ATTACHED_BUFFER:
1771 memcpy(buf, blob->attached_buffer + offset, size);
1782 wimfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
1783 off_t offset, struct fuse_file_info *fi,
1784 enum fuse_readdir_flags flags)
1786 struct wimfs_fd *fd = WIMFS_FD(fi);
1787 const struct wim_inode *inode;
1788 const struct wim_dentry *child;
1791 inode = fd->f_inode;
1793 ret = filler(buf, ".", NULL, 0, 0);
1796 ret = filler(buf, "..", NULL, 0, 0);
1800 for_inode_child(child, inode) {
1804 if (utf16le_to_tstr(child->d_name, child->d_name_nbytes,
1805 &name, &name_nbytes))
1808 ret = filler(buf, name, NULL, 0, 0);
1817 wimfs_readlink(const char *path, char *buf, size_t bufsize)
1819 struct wimfs_context *ctx = wimfs_get_context();
1820 const struct wim_inode *inode;
1823 inode = wim_pathname_to_inode(ctx->wim, path);
1828 ret = wim_inode_readlink(inode, buf, bufsize - 1, NULL,
1829 ctx->mountpoint_abspath,
1830 ctx->mountpoint_abspath_nchars);
1837 /* We use this for both release() and releasedir(), since in both cases we
1838 * simply need to close the file descriptor. */
1840 wimfs_release(const char *path, struct fuse_file_info *fi)
1842 return close_wimfs_fd(WIMFS_FD(fi));
1846 wimfs_removexattr(const char *path, const char *name)
1848 struct wimfs_context *ctx = wimfs_get_context();
1849 struct wim_inode *inode;
1850 struct wim_inode_stream *strm;
1852 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1855 if (strncmp(name, "user.", 5))
1862 /* Removing a named data stream. */
1864 inode = wim_pathname_to_inode(ctx->wim, path);
1868 strm = inode_get_data_stream_tstr(inode, name);
1870 return (errno == ENOENT) ? -ENOATTR : -errno;
1872 inode_remove_stream(inode, strm, ctx->wim->blob_table);
1877 wimfs_rename(const char *from, const char *to, unsigned int flags)
1879 if (flags & RENAME_EXCHANGE)
1881 return rename_wim_path(wimfs_get_WIMStruct(), from, to,
1882 WIMLIB_CASE_SENSITIVE,
1883 (flags & RENAME_NOREPLACE), NULL);
1887 wimfs_rmdir(const char *path)
1889 WIMStruct *wim = wimfs_get_WIMStruct();
1890 struct wim_dentry *dentry;
1892 dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
1896 if (!dentry_is_directory(dentry))
1899 if (dentry_has_children(dentry))
1902 touch_parent(dentry);
1903 remove_dentry(dentry, wim->blob_table);
1908 wimfs_setxattr(const char *path, const char *name,
1909 const char *value, size_t size, int flags)
1911 struct wimfs_context *ctx = wimfs_get_context();
1912 struct wim_inode *inode;
1913 struct wim_inode_stream *strm;
1914 const utf16lechar *uname;
1917 if (!strncmp(name, "wimfs.", 6)) {
1918 /* Handle some magical extended attributes. These really should
1919 * be ioctls, but directory ioctls aren't supported until
1920 * libfuse 2.9, and even then they are broken. [Fixed by
1921 * libfuse commit e3b7d4c278a26520be63d99d6ea84b26906fe73d] */
1923 if (!strcmp(name, "unmount_info")) {
1924 if (!may_unmount_wimfs())
1926 if (size < sizeof(struct wimfs_unmount_info))
1928 memcpy(&ctx->unmount_info, value,
1929 sizeof(struct wimfs_unmount_info));
1935 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1938 if (strncmp(name, "user.", 5))
1945 /* Setting the contents of a named data stream. */
1947 inode = wim_pathname_to_inode(ctx->wim, path);
1951 ret = tstr_get_utf16le(name, &uname);
1955 strm = inode_get_stream(inode, STREAM_TYPE_DATA, uname);
1958 if (flags & XATTR_CREATE)
1962 if (flags & XATTR_REPLACE)
1967 if (!inode_replace_stream_data(inode, strm, value, size,
1968 ctx->wim->blob_table))
1974 if (!inode_add_stream_with_data(inode, STREAM_TYPE_DATA, uname,
1975 value, size, ctx->wim->blob_table))
1984 tstr_put_utf16le(uname);
1989 wimfs_symlink(const char *to, const char *from)
1991 struct fuse_context *fuse_ctx = fuse_get_context();
1992 struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1993 struct wim_dentry *dentry;
1996 ret = create_file(fuse_ctx, from, S_IFLNK | 0777, 0, &dentry);
1999 ret = wim_inode_set_symlink(dentry->d_inode, to,
2000 wimfs_ctx->wim->blob_table);
2002 remove_dentry(dentry, wimfs_ctx->wim->blob_table);
2003 if (ret == WIMLIB_ERR_NOMEM)
2008 touch_parent(dentry);
2014 do_truncate(int staging_fd, off_t size,
2015 struct wim_inode *inode, struct blob_descriptor *blob)
2017 if (ftruncate(staging_fd, size))
2019 file_contents_changed(inode);
2025 wimfs_truncate(const char *path, off_t size, struct fuse_file_info *fi)
2027 const struct wimfs_context *ctx = wimfs_get_context();
2028 struct wim_dentry *dentry;
2029 struct wim_inode_stream *strm;
2030 struct blob_descriptor *blob;
2035 struct wimfs_fd *fd = WIMFS_FD(fi);
2037 return do_truncate(fd->f_staging_fd.fd, size, fd->f_inode,
2041 ret = wim_pathname_to_stream(ctx, path, 0, &dentry, &strm);
2045 blob = stream_blob_resolved(strm);
2050 if (!blob || blob->blob_location != BLOB_IN_STAGING_FILE) {
2051 return extract_blob_to_staging_dir(dentry->d_inode,
2055 /* Truncate the staging file. */
2056 staging_fd = openat(blob->staging_dir_fd, blob->staging_file_name,
2057 O_WRONLY | O_NOFOLLOW);
2060 ret = do_truncate(staging_fd, size, dentry->d_inode, blob);
2061 if (close(staging_fd) && !ret)
2067 wimfs_unlink(const char *path)
2069 const struct wimfs_context *ctx = wimfs_get_context();
2070 struct wim_dentry *dentry;
2071 struct wim_inode_stream *strm;
2074 ret = wim_pathname_to_stream(ctx, path, 0, &dentry, &strm);
2078 if (stream_is_named(strm)) {
2079 inode_remove_stream(dentry->d_inode, strm,
2080 ctx->wim->blob_table);
2082 touch_parent(dentry);
2083 remove_dentry(dentry, ctx->wim->blob_table);
2089 * Change the timestamp on a file dentry.
2091 * Note that alternate data streams do not have their own timestamps.
2094 wimfs_utimens(const char *path, const struct timespec tv[2],
2095 struct fuse_file_info *fi)
2097 struct wim_inode *inode;
2100 inode = WIMFS_FD(fi)->f_inode;
2102 inode = wim_pathname_to_inode(wimfs_get_WIMStruct(), path);
2107 if (tv[0].tv_nsec != UTIME_OMIT) {
2108 if (tv[0].tv_nsec == UTIME_NOW)
2109 inode->i_last_access_time = now_as_wim_timestamp();
2111 inode->i_last_access_time = timespec_to_wim_timestamp(&tv[0]);
2113 if (tv[1].tv_nsec != UTIME_OMIT) {
2114 if (tv[1].tv_nsec == UTIME_NOW)
2115 inode->i_last_write_time = now_as_wim_timestamp();
2117 inode->i_last_write_time = timespec_to_wim_timestamp(&tv[1]);
2123 wimfs_write(const char *path, const char *buf, size_t size,
2124 off_t offset, struct fuse_file_info *fi)
2126 struct wimfs_fd *fd = WIMFS_FD(fi);
2129 ret = pwrite(fd->f_staging_fd.fd, buf, size, offset);
2133 if (offset + size > fd->f_blob->size)
2134 fd->f_blob->size = offset + size;
2136 file_contents_changed(fd->f_inode);
2140 static const struct fuse_operations wimfs_operations = {
2142 .chmod = wimfs_chmod,
2143 .chown = wimfs_chown,
2144 .getattr = wimfs_getattr,
2145 .getxattr = wimfs_getxattr,
2147 .listxattr = wimfs_listxattr,
2148 .mkdir = wimfs_mkdir,
2149 .mknod = wimfs_mknod,
2151 .opendir = wimfs_opendir,
2153 .readdir = wimfs_readdir,
2154 .readlink = wimfs_readlink,
2155 .release = wimfs_release,
2156 .releasedir = wimfs_release,
2157 .removexattr = wimfs_removexattr,
2158 .rename = wimfs_rename,
2159 .rmdir = wimfs_rmdir,
2160 .setxattr = wimfs_setxattr,
2161 .symlink = wimfs_symlink,
2162 .truncate = wimfs_truncate,
2163 .unlink = wimfs_unlink,
2164 .utimens = wimfs_utimens,
2165 .write = wimfs_write,
2169 /* API function documented in wimlib.h */
2171 wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
2172 int mount_flags, const char *staging_dir)
2175 struct wim_image_metadata *imd;
2176 struct wimfs_context ctx;
2177 char *fuse_argv[16];
2180 if (!wim || !dir || !*dir)
2181 return WIMLIB_ERR_INVALID_PARAM;
2183 if (mount_flags & ~(WIMLIB_MOUNT_FLAG_READWRITE |
2184 WIMLIB_MOUNT_FLAG_DEBUG |
2185 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
2186 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR |
2187 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS |
2188 WIMLIB_MOUNT_FLAG_UNIX_DATA |
2189 WIMLIB_MOUNT_FLAG_ALLOW_OTHER))
2190 return WIMLIB_ERR_INVALID_PARAM;
2192 /* For read-write mount, check for write access to the WIM. */
2193 if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
2195 return WIMLIB_ERR_NO_FILENAME;
2196 ret = can_modify_wim(wim);
2201 /* Select the image to mount. */
2202 ret = select_wim_image(wim, image);
2206 /* Get the metadata for the image to mount. */
2207 imd = wim_get_current_image_metadata(wim);
2209 /* To avoid complicating things, we don't support mounting images to
2210 * which in-memory modifications have already been made. */
2211 if (is_image_dirty(imd)) {
2212 ERROR("Cannot mount a modified WIM image!");
2213 return WIMLIB_ERR_INVALID_PARAM;
2216 if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
2217 if (imd->refcnt > 1)
2218 return WIMLIB_ERR_IMAGE_HAS_MULTIPLE_REFERENCES;
2219 ret = lock_wim_for_append(wim);
2224 if (wim_has_solid_resources(wim)) {
2225 WARNING("Mounting a WIM file containing solid-compressed data; "
2226 "file access may be slow.");
2229 /* If the user did not specify an interface for accessing named
2230 * data streams, use the default (extended attributes). */
2231 if (!(mount_flags & (WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
2232 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR |
2233 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)))
2234 mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR;
2236 /* Start initializing the wimfs_context. */
2237 memset(&ctx, 0, sizeof(struct wimfs_context));
2239 ctx.mount_flags = mount_flags;
2240 if (mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
2241 ctx.default_lookup_flags = LOOKUP_FLAG_ADS_OK;
2243 /* For read-write mounts, create the staging directory, save a reference
2244 * to the image's metadata resource, and mark the image dirty. */
2245 if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
2246 ret = make_staging_dir(&ctx, staging_dir);
2249 ret = WIMLIB_ERR_NOMEM;
2250 ctx.metadata_resource = clone_blob_descriptor(
2251 imd->metadata_blob);
2252 if (!ctx.metadata_resource)
2254 mark_image_dirty(imd);
2256 ctx.owner_uid = getuid();
2257 ctx.owner_gid = getgid();
2259 /* Number the inodes in the mounted image sequentially and initialize
2260 * the file descriptor arrays */
2261 prepare_inodes(&ctx);
2263 /* Save the absolute path to the mountpoint directory. */
2264 ctx.mountpoint_abspath = realpath(dir, NULL);
2265 if (ctx.mountpoint_abspath)
2266 ctx.mountpoint_abspath_nchars = strlen(ctx.mountpoint_abspath);
2268 /* Build the FUSE command line. */
2271 fuse_argv[fuse_argc++] = "wimlib";
2272 fuse_argv[fuse_argc++] = (char *)dir;
2274 /* Disable multi-threaded operation. */
2275 fuse_argv[fuse_argc++] = "-s";
2277 /* Enable FUSE debug mode (don't fork) if requested by the user. */
2278 if (mount_flags & WIMLIB_MOUNT_FLAG_DEBUG)
2279 fuse_argv[fuse_argc++] = "-d";
2282 * Build the FUSE mount options:
2285 * Name for our filesystem (main type is "fuse").
2287 * default_permissions
2288 * FUSE will perform permission checking. Useful when
2289 * WIMLIB_MOUNT_FLAG_UNIX_DATA is provided and the WIM image
2290 * contains the UNIX permissions for each file.
2292 char optstring[128] = "subtype=wimfs,default_permissions";
2293 fuse_argv[fuse_argc++] = "-o";
2294 fuse_argv[fuse_argc++] = optstring;
2295 if (!(mount_flags & WIMLIB_MOUNT_FLAG_READWRITE))
2296 strcat(optstring, ",ro");
2297 if (mount_flags & WIMLIB_MOUNT_FLAG_ALLOW_OTHER)
2298 strcat(optstring, ",allow_other");
2299 fuse_argv[fuse_argc] = NULL;
2301 /* Mount our filesystem. */
2302 ret = fuse_main(fuse_argc, fuse_argv, &wimfs_operations, &ctx);
2304 /* Cleanup and return. */
2306 ret = WIMLIB_ERR_FUSE;
2308 FREE(ctx.mountpoint_abspath);
2309 free_blob_descriptor(ctx.metadata_resource);
2310 if (ctx.staging_dir_name)
2311 delete_staging_dir(&ctx);
2312 unlock_wim_for_append(wim);
2316 struct commit_progress_thread_args {
2318 wimlib_progress_func_t progfunc;
2323 commit_progress_thread_proc(void *_args)
2325 struct commit_progress_thread_args *args = _args;
2326 struct commit_progress_report report;
2330 ret = mq_receive(args->mq,
2331 (char *)&report, sizeof(report), NULL);
2332 if (ret == sizeof(report)) {
2333 call_progress(args->progfunc, report.msg,
2334 &report.info, args->progctx);
2336 if (ret == 0 || (ret < 0 && errno != EINTR))
2344 generate_message_queue_name(char name[WIMFS_MQUEUE_NAME_LEN + 1])
2347 memcpy(name + 1, "wimfs-", 6);
2348 get_random_alnum_chars(name + 7, WIMFS_MQUEUE_NAME_LEN - 7);
2349 name[WIMFS_MQUEUE_NAME_LEN] = '\0';
2353 create_message_queue(const char *name)
2358 struct mq_attr attr;
2361 memset(&attr, 0, sizeof(attr));
2363 attr.mq_msgsize = sizeof(struct commit_progress_report);
2365 am_root = (geteuid() == 0);
2367 /* Filesystem mounted as normal user with --allow-other should
2368 * be able to send messages to root user, if they're doing the
2370 umask_save = umask(0);
2375 mq = mq_open(name, O_RDWR | O_CREAT | O_EXCL, mode, &attr);
2381 /* Unmount a read-only or read-write mounted WIM image. */
2383 do_unmount(const char *dir)
2388 len = getxattr(dir, "wimfs.unmount", &status, sizeof(int));
2389 if (len == sizeof(int))
2391 else if (len < 0 && (errno == EACCES || errno == EPERM))
2392 return WIMLIB_ERR_NOT_PERMITTED_TO_UNMOUNT;
2394 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2398 set_unmount_info(const char *dir, const struct wimfs_unmount_info *unmount_info)
2400 if (!setxattr(dir, "wimfs.unmount_info",
2401 unmount_info, sizeof(struct wimfs_unmount_info), 0))
2403 else if (errno == EROFS)
2405 else if (errno == EACCES || errno == EPERM)
2406 return WIMLIB_ERR_NOT_PERMITTED_TO_UNMOUNT;
2408 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2412 do_unmount_discard(const char *dir)
2415 struct wimfs_unmount_info unmount_info;
2417 memset(&unmount_info, 0, sizeof(unmount_info));
2419 ret = set_unmount_info(dir, &unmount_info);
2422 return do_unmount(dir);
2425 /* Unmount a read-write mounted WIM image, committing the changes. */
2427 do_unmount_commit(const char *dir, int unmount_flags,
2428 wimlib_progress_func_t progfunc, void *progctx)
2430 struct wimfs_unmount_info unmount_info;
2431 mqd_t mq = (mqd_t)-1;
2432 struct commit_progress_thread_args args;
2433 struct thread commit_progress_tid;
2436 memset(&unmount_info, 0, sizeof(unmount_info));
2437 unmount_info.unmount_flags = unmount_flags;
2439 /* The current thread will be stuck in getxattr() until the image is
2440 * committed. Create a thread to handle the progress messages. */
2442 generate_message_queue_name(unmount_info.mq_name);
2444 mq = create_message_queue(unmount_info.mq_name);
2445 if (mq == (mqd_t)-1) {
2446 ERROR_WITH_ERRNO("Can't create POSIX message queue");
2447 return WIMLIB_ERR_MQUEUE;
2450 args.progfunc = progfunc;
2451 args.progctx = progctx;
2452 if (!thread_create(&commit_progress_tid,
2453 commit_progress_thread_proc, &args)) {
2454 ret = WIMLIB_ERR_NOMEM;
2457 unmount_info.unmount_flags |= WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS;
2460 ret = set_unmount_info(dir, &unmount_info);
2462 ret = do_unmount(dir);
2464 /* Terminate the progress thread. */
2466 mq_send(mq, empty, 0, 1);
2467 thread_join(&commit_progress_tid);
2472 mq_unlink(unmount_info.mq_name);
2478 begin_unmount(const char *dir, int unmount_flags, int *mount_flags_ret,
2479 wimlib_progress_func_t progfunc, void *progctx)
2483 int wim_filename_len;
2484 union wimlib_progress_info progress;
2486 if (getxattr(dir, "wimfs.mount_flags",
2487 &mount_flags, sizeof(int)) != sizeof(int))
2488 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2490 *mount_flags_ret = mount_flags;
2495 if (getxattr(dir, "wimfs.mounted_image",
2496 &mounted_image, sizeof(int)) != sizeof(int))
2497 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2499 wim_filename_len = getxattr(dir, "wimfs.wim_filename", NULL, 0);
2500 if (wim_filename_len < 0)
2501 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2503 char wim_filename[wim_filename_len + 1];
2504 if (getxattr(dir, "wimfs.wim_filename",
2505 wim_filename, wim_filename_len) != wim_filename_len)
2506 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2507 wim_filename[wim_filename_len] = '\0';
2509 progress.unmount.mountpoint = dir;
2510 progress.unmount.mounted_wim = wim_filename;
2511 progress.unmount.mounted_image = mounted_image;
2512 progress.unmount.mount_flags = mount_flags;
2513 progress.unmount.unmount_flags = unmount_flags;
2515 return call_progress(progfunc, WIMLIB_PROGRESS_MSG_UNMOUNT_BEGIN,
2516 &progress, progctx);
2519 /* API function documented in wimlib.h */
2521 wimlib_unmount_image_with_progress(const char *dir, int unmount_flags,
2522 wimlib_progress_func_t progfunc, void *progctx)
2527 ret = wimlib_global_init(0);
2531 if (unmount_flags & ~(WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY |
2532 WIMLIB_UNMOUNT_FLAG_COMMIT |
2533 WIMLIB_UNMOUNT_FLAG_REBUILD |
2534 WIMLIB_UNMOUNT_FLAG_RECOMPRESS |
2535 WIMLIB_UNMOUNT_FLAG_FORCE |
2536 WIMLIB_UNMOUNT_FLAG_NEW_IMAGE))
2537 return WIMLIB_ERR_INVALID_PARAM;
2539 ret = begin_unmount(dir, unmount_flags, &mount_flags,
2544 if ((unmount_flags & WIMLIB_UNMOUNT_FLAG_COMMIT) &&
2545 (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE))
2546 return do_unmount_commit(dir, unmount_flags,
2549 return do_unmount_discard(dir);
2552 #else /* WITH_FUSE */
2556 mount_unsupported_error(void)
2559 ERROR("Sorry-- Mounting WIM images is not supported on Windows!");
2561 ERROR("wimlib was compiled with --without-fuse, which disables support "
2562 "for mounting WIMs.");
2564 return WIMLIB_ERR_UNSUPPORTED;
2568 wimlib_unmount_image_with_progress(const tchar *dir, int unmount_flags,
2569 wimlib_progress_func_t progfunc, void *progctx)
2571 return mount_unsupported_error();
2575 wimlib_mount_image(WIMStruct *wim, int image, const tchar *dir,
2576 int mount_flags, const tchar *staging_dir)
2578 return mount_unsupported_error();
2581 #endif /* !WITH_FUSE */
2584 wimlib_unmount_image(const tchar *dir, int unmount_flags)
2586 return wimlib_unmount_image_with_progress(dir, unmount_flags, NULL, NULL);