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, 2013, 2014, 2015 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 <attr/xattr.h>
53 #include <sys/types.h>
57 #include "wimlib/blob_table.h"
58 #include "wimlib/dentry.h"
59 #include "wimlib/encoding.h"
60 #include "wimlib/metadata.h"
61 #include "wimlib/paths.h"
62 #include "wimlib/progress.h"
63 #include "wimlib/reparse.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... */
73 #define WIMFS_MQUEUE_NAME_LEN 32
75 #define WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS 0x80000000
77 struct wimfs_unmount_info {
78 unsigned unmount_flags;
79 char mq_name[WIMFS_MQUEUE_NAME_LEN + 1];
82 struct commit_progress_report {
83 enum wimlib_progress_msg msg;
84 union wimlib_progress_info info;
87 /* Description of an open file on a mounted WIM image. Actually, this
88 * represents the open state of a particular data stream of an inode, rather
89 * than the inode itself. (An inode might have multiple named data streams in
90 * addition to the default, unnamed data stream.) At a given time, an inode in
91 * the WIM image might have multiple file descriptors open to it, each to any
92 * one of its data streams. */
95 /* Pointer to the inode of this open file.
96 * 'i_num_opened_fds' of the inode tracks the number of file descriptors
97 * that reference it. */
98 struct wim_inode *f_inode;
100 /* Pointer to the blob descriptor for the data stream that has been
101 * opened. 'num_opened_fds' of the blob descriptor tracks the number of
102 * file descriptors that reference it. Or, this value may be NULL,
103 * which indicates that the opened stream is empty and consequently does
104 * not have a blob descriptor. */
105 struct blob_descriptor *f_blob;
107 /* If valid (filedes_valid(&f_staging_fd)), this contains the
108 * corresponding native file descriptor for the staging file that has
109 * been created for reading from and/or writing to this open stream. A
110 * single staging file might have multiple file descriptors open to it
111 * simultaneously, each used by a different 'struct wimfs_fd'.
113 * Or, if invalid (!filedes_valid(&f_staging_fd)), this 'struct
114 * wimfs_fd' is not associated with a staging file. This is permissible
115 * only if this 'struct wimfs_fd' was opened read-only and the stream
116 * has not yet been extracted to a staging file. */
117 struct filedes f_staging_fd;
119 /* 0-based index of this file descriptor in the file descriptor table of
123 /* Unique ID of the opened stream in the inode. This will stay the same
124 * even if the indices of the inode's streams are changed by a deletion.
129 #define WIMFS_FD(fi) ((struct wimfs_fd *)(uintptr_t)((fi)->fh))
131 /* Context structure for a mounted WIM image. */
132 struct wimfs_context {
133 /* The WIMStruct containing the mounted image. The mounted image is the
134 * currently selected image (wim->current_image). */
137 /* Flags passed to wimlib_mount_image() (WIMLIB_MOUNT_FLAG_*). */
140 /* Default flags for path lookup in the WIM image. */
141 int default_lookup_flags;
143 /* Information about the user who has mounted the WIM image */
147 /* Information about the staging directory for a read-write mount. */
150 char *staging_dir_name;
152 /* For read-write mounts, the inode number to be assigned to the next
153 * created file. Note: since this isn't a persistent filesystem and we
154 * can re-assign the inode numbers just before mounting the image, it's
155 * good enough to just generate inode numbers sequentially. */
158 /* Number of file descriptors open to the mounted WIM image. */
159 unsigned long num_open_fds;
161 /* Original list of blobs in the mounted image, linked by
162 * 'struct blob_descriptor'.orig_blob_list. */
163 struct list_head orig_blob_list;
165 /* Parameters for unmounting the image (can be set via extended
166 * attribute "wimfs.unmount_info"). */
167 struct wimfs_unmount_info unmount_info;
170 #define WIMFS_CTX(fuse_ctx) ((struct wimfs_context*)(fuse_ctx)->private_data)
172 /* Retrieve the context structure for the currently mounted WIM image.
174 * Note: this is a per-thread variable. It is possible for different threads to
175 * mount different images at the same time in the same process, although they
176 * must use different WIMStructs! */
177 static inline struct wimfs_context *
178 wimfs_get_context(void)
180 return WIMFS_CTX(fuse_get_context());
184 wimfs_inc_num_open_fds(void)
186 wimfs_get_context()->num_open_fds++;
190 wimfs_dec_num_open_fds(void)
192 wimfs_get_context()->num_open_fds--;
195 /* Retrieve the WIMStruct for the currently mounted WIM image. */
196 static inline WIMStruct *
197 wimfs_get_WIMStruct(void)
199 return wimfs_get_context()->wim;
202 /* Is write permission requested on the file? */
204 flags_writable(int open_flags)
206 int accmode = (open_flags & O_ACCMODE);
207 return (accmode == O_RDWR || accmode == O_WRONLY);
211 fuse_mask_mode(mode_t mode, const struct fuse_context *fuse_ctx)
213 #if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 8)
214 mode &= ~fuse_ctx->umask;
220 * Allocate a file descriptor to a data stream in the mounted WIM image.
223 * The inode containing the stream being opened
225 * The stream of the inode being opened
227 * On success, a pointer to the new file descriptor will be stored here.
229 * Returns 0 or a -errno code.
232 alloc_wimfs_fd(struct wim_inode *inode,
233 struct wim_inode_stream *strm,
234 struct wimfs_fd **fd_ret)
236 static const u16 min_fds_per_alloc = 8;
237 static const u16 max_fds = 0xffff;
241 if (inode->i_num_opened_fds == inode->i_num_allocated_fds) {
243 struct wimfs_fd **fds;
245 /* Expand this inode's file descriptor table. */
247 num_new_fds = max(min_fds_per_alloc,
248 inode->i_num_allocated_fds / 4);
250 num_new_fds = min(num_new_fds,
251 max_fds - inode->i_num_allocated_fds);
253 if (num_new_fds == 0)
256 fds = REALLOC(inode->i_fds,
257 (inode->i_num_allocated_fds + num_new_fds) *
262 memset(&fds[inode->i_num_allocated_fds], 0,
263 num_new_fds * sizeof(fds[0]));
265 inode->i_num_allocated_fds += num_new_fds;
266 inode->i_next_fd = inode->i_num_opened_fds;
269 /* Allocate the file descriptor in the first available space in the
270 * inode's file descriptor table.
272 * i_next_fd is the lower bound on the next open slot. */
273 for (i = inode->i_next_fd; inode->i_fds[i]; i++)
276 fd = MALLOC(sizeof(*fd));
281 fd->f_blob = stream_blob_resolved(strm);
282 filedes_invalidate(&fd->f_staging_fd);
284 fd->f_stream_id = strm->stream_id;
286 inode->i_fds[i] = fd;
287 inode->i_num_opened_fds++;
289 fd->f_blob->num_opened_fds++;
290 wimfs_inc_num_open_fds();
291 inode->i_next_fd = i + 1;
296 * Close a file descriptor to a data stream in the mounted WIM image.
298 * Returns 0 or a -errno code. The file descriptor is always closed.
301 close_wimfs_fd(struct wimfs_fd *fd)
304 struct wim_inode *inode;
306 /* Close the staging file if open. */
307 if (filedes_valid(&fd->f_staging_fd))
308 if (filedes_close(&fd->f_staging_fd))
311 /* Release this file descriptor from its blob descriptor. */
313 blob_decrement_num_opened_fds(fd->f_blob);
315 wimfs_dec_num_open_fds();
317 /* Release this file descriptor from its inode. */
319 inode->i_fds[fd->f_idx] = NULL;
320 if (fd->f_idx < inode->i_next_fd)
321 inode->i_next_fd = fd->f_idx;
323 inode_dec_num_opened_fds(inode);
328 * Translate a path into the corresponding inode in the mounted WIM image.
330 * See get_dentry() for more information.
332 * Returns a pointer to the resulting inode, or NULL with errno set.
334 static struct wim_inode *
335 wim_pathname_to_inode(WIMStruct *wim, const char *path)
337 struct wim_dentry *dentry;
339 dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
342 return dentry->d_inode;
345 /* Can look up named data stream with colon syntax */
346 #define LOOKUP_FLAG_ADS_OK 0x01
348 /* Can look up directory (otherwise get -ENOTDIR) */
349 #define LOOKUP_FLAG_DIRECTORY_OK 0x02
351 /* Get the data stream of the specified name from the specified inode. Returns
352 * NULL with errno set if not found. */
353 static struct wim_inode_stream *
354 inode_get_data_stream_tstr(const struct wim_inode *inode,
355 const char *stream_name)
357 struct wim_inode_stream *strm;
359 if (!stream_name || !*stream_name) {
360 strm = inode_get_unnamed_stream(inode, STREAM_TYPE_DATA);
362 const utf16lechar *uname;
364 if (tstr_get_utf16le(stream_name, &uname))
366 strm = inode_get_stream(inode, STREAM_TYPE_DATA, uname);
367 tstr_put_utf16le(uname);
375 * Translate a path into the corresponding dentry and stream in the mounted WIM
378 * Returns 0 or a -errno code. @dentry_ret and @strm_ret are both optional.
381 wim_pathname_to_stream(const struct wimfs_context *ctx,
384 struct wim_dentry **dentry_ret,
385 struct wim_inode_stream **strm_ret)
387 WIMStruct *wim = ctx->wim;
388 struct wim_dentry *dentry;
389 struct wim_inode *inode;
390 struct wim_inode_stream *strm;
391 const char *stream_name = NULL;
394 lookup_flags |= ctx->default_lookup_flags;
396 if (lookup_flags & LOOKUP_FLAG_ADS_OK) {
397 stream_name = path_stream_name(path);
399 p = (char *)stream_name - 1;
404 dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
410 inode = dentry->d_inode;
412 if (inode_resolve_streams(inode, wim->blob_table, false))
415 if (!(lookup_flags & LOOKUP_FLAG_DIRECTORY_OK)
416 && inode_is_directory(inode))
419 strm = inode_get_data_stream_tstr(inode, stream_name);
421 /* Force creation of an unnamed data stream */
423 strm = inode_add_stream(inode, STREAM_TYPE_DATA,
424 NO_STREAM_NAME, NULL);
430 *dentry_ret = dentry;
437 * Create a new file in the mounted WIM image.
440 * The FUSE context for the mounted image.
442 * The path at which to create the first link to the new file. If a file
443 * already exists at this path, -EEXIST is returned.
445 * The UNIX mode for the new file. This is only honored if
446 * WIMLIB_MOUNT_FLAG_UNIX_DATA was passed to wimlib_mount_image().
448 * The device ID for the new file, encoding the major and minor device
449 * numbers. This is only honored if WIMLIB_MOUNT_FLAG_UNIX_DATA was passed
450 * to wimlib_mount_image().
452 * Windows file attributes to use for the new file.
454 * On success, a pointer to the new dentry is returned here. Its d_inode
455 * member will point to the new inode that was created for it and added to
456 * the mounted WIM image.
458 * Returns 0 or a -errno code.
461 create_file(struct fuse_context *fuse_ctx, const char *path,
462 mode_t mode, dev_t rdev, u32 attributes,
463 struct wim_dentry **dentry_ret)
465 struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
466 struct wim_dentry *parent;
467 const char *basename;
468 struct wim_dentry *new_dentry;
469 struct wim_inode *new_inode;
471 parent = get_parent_dentry(wimfs_ctx->wim, path, WIMLIB_CASE_SENSITIVE);
475 if (!dentry_is_directory(parent))
478 basename = path_basename(path);
480 if (get_dentry_child_with_name(parent, basename, WIMLIB_CASE_SENSITIVE))
483 if (new_dentry_with_new_inode(basename, true, &new_dentry))
486 new_inode = new_dentry->d_inode;
488 new_inode->i_ino = wimfs_ctx->next_ino++;
489 new_inode->i_attributes = attributes;
491 if (wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) {
492 struct wimlib_unix_data unix_data;
494 unix_data.uid = fuse_ctx->uid;
495 unix_data.gid = fuse_ctx->gid;
496 unix_data.mode = fuse_mask_mode(mode, fuse_ctx);
497 unix_data.rdev = rdev;
498 if (!inode_set_unix_data(new_inode, &unix_data, UNIX_DATA_ALL))
500 free_dentry(new_dentry);
505 list_add_tail(&new_inode->i_list,
506 &wim_get_current_image_metadata(wimfs_ctx->wim)->inode_list);
508 dentry_add_child(parent, new_dentry);
510 *dentry_ret = new_dentry;
515 * Remove a dentry from the mounted WIM image; i.e. remove an alias for an
519 remove_dentry(struct wim_dentry *dentry, struct blob_table *blob_table)
521 /* Drop blob references. */
522 inode_unref_blobs(dentry->d_inode, blob_table);
524 /* Unlink the dentry from the image's dentry tree. */
525 unlink_dentry(dentry);
527 /* Delete the dentry. This will also decrement the link count of the
528 * corresponding inode, and possibly cause it to be deleted as well. */
532 /* Generate UNIX filetype mode bits for the specified WIM inode, based on its
533 * Windows file attributes. */
535 inode_unix_file_type(const struct wim_inode *inode)
537 if (inode_is_symlink(inode))
539 else if (inode_is_directory(inode))
545 /* Generate a default UNIX mode for the specified WIM inode. */
547 inode_default_unix_mode(const struct wim_inode *inode)
549 return inode_unix_file_type(inode) | 0777;
553 * Retrieve standard UNIX metadata ('struct stat') for a WIM inode.
555 * @blob is the blob descriptor for the stream of the inode that is being
556 * queried, or NULL. We mostly return the same information for all streams, but
557 * st_size and st_blocks may be different for different streams.
559 * This always returns 0.
562 inode_to_stbuf(const struct wim_inode *inode,
563 const struct blob_descriptor *blob, struct stat *stbuf)
565 const struct wimfs_context *ctx = wimfs_get_context();
566 struct wimlib_unix_data unix_data;
568 memset(stbuf, 0, sizeof(struct stat));
569 if ((ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) &&
570 inode_get_unix_data(inode, &unix_data))
572 /* Use the user ID, group ID, mode, and device ID from the
573 * inode's extra UNIX metadata information. */
574 stbuf->st_uid = unix_data.uid;
575 stbuf->st_gid = unix_data.gid;
576 stbuf->st_mode = unix_data.mode;
577 stbuf->st_rdev = unix_data.rdev;
579 /* Generate default values for the user ID, group ID, and mode.
581 * Note: in the case of an allow_other mount, fuse_context.uid
582 * may not be the same as wimfs_context.owner_uid! */
583 stbuf->st_uid = ctx->owner_uid;
584 stbuf->st_gid = ctx->owner_gid;
585 stbuf->st_mode = inode_default_unix_mode(inode);
587 stbuf->st_ino = inode->i_ino;
588 stbuf->st_nlink = inode->i_nlink;
590 stbuf->st_size = blob->size;
591 #ifdef HAVE_STAT_NANOSECOND_PRECISION
592 stbuf->st_atim = wim_timestamp_to_timespec(inode->i_last_access_time);
593 stbuf->st_mtim = wim_timestamp_to_timespec(inode->i_last_write_time);
594 stbuf->st_ctim = stbuf->st_mtim;
596 stbuf->st_atime = wim_timestamp_to_time_t(inode->i_last_access_time);
597 stbuf->st_mtime = wim_timestamp_to_time_t(inode->i_last_write_time);
598 stbuf->st_ctime = stbuf->st_mtime;
600 stbuf->st_blocks = DIV_ROUND_UP(stbuf->st_size, 512);
604 /* Update the last access and last write timestamps of a WIM inode. */
606 touch_inode(struct wim_inode *inode)
608 u64 now = now_as_wim_timestamp();
609 inode->i_last_access_time = now;
610 inode->i_last_write_time = now;
614 touch_parent(struct wim_dentry *dentry)
616 touch_inode(dentry->d_parent->d_inode);
620 * Create a new file in the staging directory for a read-write mounted image.
622 * On success, returns the file descriptor for the new staging file, opened for
623 * writing. In addition, stores the allocated name of the staging file in
626 * On failure, returns -1 and sets errno.
629 create_staging_file(const struct wimfs_context *ctx, char **name_ret)
632 static const size_t STAGING_FILE_NAME_LEN = 20;
636 name = MALLOC(STAGING_FILE_NAME_LEN + 1);
639 name[STAGING_FILE_NAME_LEN] = '\0';
642 randomize_char_array_with_alnum(name, STAGING_FILE_NAME_LEN);
643 fd = openat(ctx->staging_dir_fd, name,
644 O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0600);
645 if (unlikely(fd < 0)) {
646 if (unlikely(errno == EEXIST))
647 /* Try again with another name. */
657 * Extract a blob to the staging directory. This is necessary when a stream
658 * using the blob is being opened for writing and the blob has not already been
659 * extracted to the staging directory.
662 * The inode containing the stream being opened for writing.
664 * The stream being opened for writing. The blob descriptor to which the
665 * stream refers will be changed by this function.
667 * Number of bytes of the blob to extract and include in the staging file.
668 * It may be less than the actual blob length, in which case only a prefix
669 * of the blob will be extracted. It may also be more than the actual blob
670 * length, in which case the extra space will be zero-filled.
672 * Returns 0 or a -errno code.
675 extract_blob_to_staging_dir(struct wim_inode *inode,
676 struct wim_inode_stream *strm,
677 off_t size, const struct wimfs_context *ctx)
679 struct blob_descriptor *old_blob;
680 struct blob_descriptor *new_blob;
681 char *staging_file_name;
687 old_blob = stream_blob_resolved(strm);
689 /* Create the staging file. */
690 staging_fd = create_staging_file(ctx, &staging_file_name);
691 if (unlikely(staging_fd < 0))
694 /* Extract the stream to the staging file (possibly truncated). */
698 filedes_init(&fd, staging_fd);
700 extract_size = min(old_blob->size, size);
701 result = extract_blob_to_fd(old_blob, &fd, extract_size);
707 /* In the case of truncate() to more than the file length, extend the
708 * staging file with zeroes by calling ftruncate(). */
709 if (!result && size > extract_size)
710 result = ftruncate(staging_fd, size);
712 /* Close the staging file. */
713 if (close(staging_fd))
716 /* If an error occurred, unlink the staging file. */
717 if (unlikely(result)) {
718 /* extract_blob_to_fd() should set errno, but if it didn't,
719 * set a default value. */
720 ret = errno ? -errno : -EIO;
721 goto out_delete_staging_file;
724 /* Create a blob descriptor for the staging file. */
725 new_blob = new_blob_descriptor();
726 if (unlikely(!new_blob)) {
728 goto out_delete_staging_file;
731 /* There may already be open file descriptors to this stream if it's
732 * previously been opened read-only, but just now we're opening it
733 * read-write. Identify those file descriptors, update them to use the
734 * new blob descriptor, and open staging file descriptors for them. */
735 for (u16 i = 0, j = 0; j < inode->i_num_opened_fds; i++) {
739 fd = inode->i_fds[i];
745 if (fd->f_stream_id != strm->stream_id)
748 /* This is a readonly fd for the same stream. */
749 fd->f_blob = new_blob;
750 new_blob->num_opened_fds++;
751 raw_fd = openat(ctx->staging_dir_fd, staging_file_name,
752 O_RDONLY | O_NOFOLLOW);
753 if (unlikely(raw_fd < 0)) {
755 goto out_revert_fd_changes;
757 filedes_init(&fd->f_staging_fd, raw_fd);
761 old_blob->num_opened_fds -= new_blob->num_opened_fds;
763 new_blob->blob_location = BLOB_IN_STAGING_FILE;
764 new_blob->staging_file_name = staging_file_name;
765 new_blob->staging_dir_fd = ctx->staging_dir_fd;
766 new_blob->size = size;
768 prepare_unhashed_blob(new_blob, inode, strm->stream_id,
769 &wim_get_current_image_metadata(ctx->wim)->unhashed_blobs);
770 inode_replace_stream_blob(inode, strm, new_blob, ctx->wim->blob_table);
773 out_revert_fd_changes:
774 for (u16 i = 0; new_blob->num_opened_fds; i++) {
775 struct wimfs_fd *fd = inode->i_fds[i];
776 if (fd && fd->f_stream_id == strm->stream_id) {
777 fd->f_blob = old_blob;
778 if (filedes_valid(&fd->f_staging_fd)) {
779 filedes_close(&fd->f_staging_fd);
780 filedes_invalidate(&fd->f_staging_fd);
782 new_blob->num_opened_fds--;
785 free_blob_descriptor(new_blob);
786 out_delete_staging_file:
787 unlinkat(ctx->staging_dir_fd, staging_file_name, 0);
788 FREE(staging_file_name);
793 * Create the staging directory for the WIM file.
795 * The staging directory will be created in the directory specified by the open
796 * file descriptor @parent_dir_fd. It will be given a randomly generated name
797 * based on @wim_basename, the name of the WIM file.
799 * On success, returns a file descriptor to the open staging directory with
800 * O_RDONLY access. In addition, stores the allocated name of the staging
801 * directory (relative to @parent_dir_fd) in @staging_dir_name_ret.
802 * On failure, returns -1 and sets errno.
805 make_staging_dir_at(int parent_dir_fd, const char *wim_basename,
806 char **staging_dir_name_ret)
808 static const char common_suffix[8] = ".staging";
809 static const size_t random_suffix_len = 10;
810 size_t wim_basename_len;
811 size_t staging_dir_name_len;
812 char *staging_dir_name;
816 wim_basename_len = strlen(wim_basename);
817 staging_dir_name_len = wim_basename_len + sizeof(common_suffix) +
819 staging_dir_name = MALLOC(staging_dir_name_len + 1);
820 if (!staging_dir_name)
823 p = staging_dir_name;
824 p = mempcpy(p, wim_basename, wim_basename_len);
825 p = mempcpy(p, common_suffix, sizeof(common_suffix));
826 randomize_char_array_with_alnum(p, random_suffix_len);
827 p += random_suffix_len;
830 if (mkdirat(parent_dir_fd, staging_dir_name, 0700))
833 fd = openat(parent_dir_fd, staging_dir_name,
834 O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
838 *staging_dir_name_ret = staging_dir_name;
842 unlinkat(parent_dir_fd, staging_dir_name, AT_REMOVEDIR);
844 FREE(staging_dir_name);
849 * Create the staging directory and set ctx->staging_dir_fd,
850 * ctx->staging_dir_name, and ctx->parent_dir_fd.
853 make_staging_dir(struct wimfs_context *ctx, const char *parent_dir_path)
855 const char *wim_basename;
859 wim_basename = path_basename(ctx->wim->filename);
861 if (!parent_dir_path) {
862 /* The user did not specify a directory. Default to creating
863 * the staging directory alongside the WIM file. */
864 if (wim_basename > ctx->wim->filename) {
865 parent_dir_path = ctx->wim->filename;
866 end = (char *)(wim_basename - 1);
867 /* *end must be a slash. Temporarily overwrite it so we
868 * can open the parent directory. */
871 parent_dir_path = ".";
875 /* Open the parent directory (in which we'll create our staging
877 ctx->parent_dir_fd = open(parent_dir_path, O_RDONLY | O_DIRECTORY);
878 if (ctx->parent_dir_fd < 0) {
879 ERROR_WITH_ERRNO("Can't open directory \"%s\"",
881 ret = WIMLIB_ERR_OPENDIR;
882 goto out_restore_wim_filename;
885 ctx->staging_dir_fd = make_staging_dir_at(ctx->parent_dir_fd,
887 &ctx->staging_dir_name);
888 if (ctx->staging_dir_fd < 0) {
889 ERROR_WITH_ERRNO("Can't create staging directory in \"%s\"",
891 close(ctx->parent_dir_fd);
892 ret = WIMLIB_ERR_MKDIR;
893 goto out_restore_wim_filename;
896 out_restore_wim_filename:
902 /* Deletes the staging directory, undoing the effects of a successful call to
903 * make_staging_dir(). */
905 delete_staging_dir(struct wimfs_context *ctx)
910 dir = fdopendir(ctx->staging_dir_fd);
912 while ((ent = readdir(dir)))
913 unlinkat(ctx->staging_dir_fd, ent->d_name, 0);
916 close(ctx->staging_dir_fd);
918 if (unlinkat(ctx->parent_dir_fd, ctx->staging_dir_name, AT_REMOVEDIR))
919 WARNING_WITH_ERRNO("Could not delete staging directory");
920 FREE(ctx->staging_dir_name);
921 close(ctx->parent_dir_fd);
924 /* Number the inodes in the mounted image sequentially. */
926 reassign_inode_numbers(struct wimfs_context *ctx)
928 struct wim_image_metadata *imd;
929 struct wim_inode *inode;
932 imd = wim_get_current_image_metadata(ctx->wim);
933 image_for_each_inode(inode, imd)
934 inode->i_ino = ctx->next_ino++;
938 release_extra_refcnts(struct wimfs_context *ctx)
940 struct list_head *list = &ctx->orig_blob_list;
941 struct blob_table *blob_table = ctx->wim->blob_table;
942 struct blob_descriptor *blob, *tmp;
944 list_for_each_entry_safe(blob, tmp, list, orig_blob_list)
945 blob_subtract_refcnt(blob, blob_table, blob->out_refcnt);
948 /* Delete the 'struct blob_descriptor' for any stream that was modified
949 * or created in the read-write mounted image and had a final size of 0. */
951 delete_empty_blobs(struct wimfs_context *ctx)
953 struct blob_descriptor *blob, *tmp;
954 struct wim_image_metadata *imd;
956 imd = wim_get_current_image_metadata(ctx->wim);
958 image_for_each_unhashed_blob_safe(blob, tmp, imd) {
960 *retrieve_pointer_to_unhashed_blob(blob) = NULL;
961 list_del(&blob->unhashed_list);
962 free_blob_descriptor(blob);
967 /* Close all file descriptors open to the specified inode.
969 * Note: closing the last file descriptor might free the inode. */
971 inode_close_fds(struct wim_inode *inode)
973 u16 num_open_fds = inode->i_num_opened_fds;
974 for (u16 i = 0; num_open_fds; i++) {
975 if (inode->i_fds[i]) {
976 close_wimfs_fd(inode->i_fds[i]);
982 /* Close all file descriptors open to the mounted image. */
984 close_all_fds(struct wimfs_context *ctx)
986 struct wim_inode *inode, *tmp;
987 struct wim_image_metadata *imd;
989 imd = wim_get_current_image_metadata(ctx->wim);
991 list_for_each_entry_safe(inode, tmp, &imd->inode_list, i_list)
992 inode_close_fds(inode);
995 /* Moves the currently selected image, which may have been modified, to a new
996 * index, and sets the original index to refer to a reset (unmodified) copy of
999 renew_current_image(struct wimfs_context *ctx)
1001 WIMStruct *wim = ctx->wim;
1002 int idx = wim->current_image - 1;
1003 struct wim_image_metadata *imd = wim->image_metadata[idx];
1004 struct wim_image_metadata *replace_imd;
1005 struct blob_descriptor *new_blob;
1008 /* Create 'replace_imd' structure to use for the reset original,
1009 * unmodified image. */
1010 ret = WIMLIB_ERR_NOMEM;
1011 replace_imd = new_image_metadata();
1015 /* Create new blob descriptor for the modified image's metadata
1016 * resource, which doesn't exist yet. */
1017 ret = WIMLIB_ERR_NOMEM;
1018 new_blob = new_blob_descriptor();
1020 goto err_put_replace_imd;
1021 new_blob->refcnt = 1;
1022 new_blob->flags = WIM_RESHDR_FLAG_METADATA;
1023 new_blob->unhashed = 1;
1025 /* Make the image being moved available at a new index. Increments the
1026 * WIM's image count, but does not increment the reference count of the
1027 * 'struct image_metadata'. */
1028 ret = append_image_metadata(wim, imd);
1030 goto err_free_new_blob;
1032 ret = xml_add_image(wim, "");
1034 goto err_undo_append;
1036 replace_imd->metadata_blob = imd->metadata_blob;
1037 imd->metadata_blob = new_blob;
1038 wim->image_metadata[idx] = replace_imd;
1039 wim->current_image = wim->hdr.image_count;
1043 wim->hdr.image_count--;
1045 free_blob_descriptor(new_blob);
1046 err_put_replace_imd:
1047 put_image_metadata(replace_imd, NULL);
1052 static enum wimlib_progress_status
1053 commit_progress_func(enum wimlib_progress_msg msg,
1054 union wimlib_progress_info *info, void *progctx)
1056 mqd_t mq = *(mqd_t *)progctx;
1057 struct commit_progress_report report;
1059 memset(&report, 0, sizeof(report));
1062 report.info = *info;
1063 mq_send(mq, (const char *)&report, sizeof(report), 1);
1064 return WIMLIB_PROGRESS_STATUS_CONTINUE;
1067 /* Commit the mounted image to the underlying WIM file. */
1069 commit_image(struct wimfs_context *ctx, int unmount_flags, mqd_t mq)
1073 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS)
1074 wimlib_register_progress_function(ctx->wim,
1075 commit_progress_func, &mq);
1077 wimlib_register_progress_function(ctx->wim, NULL, NULL);
1079 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_NEW_IMAGE) {
1080 int ret = renew_current_image(ctx);
1084 release_extra_refcnts(ctx);
1086 INIT_LIST_HEAD(&ctx->orig_blob_list);
1087 delete_empty_blobs(ctx);
1088 xml_update_image_info(ctx->wim, ctx->wim->current_image);
1092 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY)
1093 write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
1095 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_REBUILD)
1096 write_flags |= WIMLIB_WRITE_FLAG_REBUILD;
1098 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_RECOMPRESS)
1099 write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
1101 return wimlib_overwrite(ctx->wim, write_flags, 0);
1104 /* In the case of an allow_other mount, only the mount owner and root are
1105 * allowed to unmount the filesystem. */
1107 may_unmount_wimfs(void)
1109 const struct fuse_context *fuse_ctx = fuse_get_context();
1110 const struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1112 return (fuse_ctx->uid == wimfs_ctx->owner_uid ||
1113 fuse_ctx->uid == 0);
1116 /* Unmount the mounted image, called from the daemon process. */
1120 struct fuse_context *fuse_ctx = fuse_get_context();
1121 struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1122 const struct wimfs_unmount_info *info = &wimfs_ctx->unmount_info;
1123 int unmount_flags = info->unmount_flags;
1124 mqd_t mq = (mqd_t)-1;
1127 /* Ignore COMMIT if the image is mounted read-only. */
1128 if (!(wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_READWRITE))
1129 unmount_flags &= ~WIMLIB_UNMOUNT_FLAG_COMMIT;
1131 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS) {
1132 mq = mq_open(info->mq_name, O_WRONLY | O_NONBLOCK);
1133 if (mq == (mqd_t)-1) {
1134 ret = WIMLIB_ERR_MQUEUE;
1139 if (wimfs_ctx->num_open_fds) {
1141 /* There are still open file descriptors to the image. */
1143 /* With COMMIT, refuse to unmount unless FORCE is also
1145 if ((unmount_flags & (WIMLIB_UNMOUNT_FLAG_COMMIT |
1146 WIMLIB_UNMOUNT_FLAG_FORCE))
1147 == WIMLIB_UNMOUNT_FLAG_COMMIT)
1149 ret = WIMLIB_ERR_MOUNTED_IMAGE_IS_BUSY;
1153 /* Force-close all file descriptors. */
1154 close_all_fds(wimfs_ctx);
1157 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_COMMIT)
1158 ret = commit_image(wimfs_ctx, unmount_flags, mq);
1160 ret = 0; /* Read-only mount, or discarding changes to
1161 a read-write mount */
1164 /* Leave the image mounted if commit failed, unless this is a
1165 * forced unmount. The user can retry without COMMIT if they
1167 if (!ret || (unmount_flags & WIMLIB_UNMOUNT_FLAG_FORCE)) {
1168 unlock_wim_for_append(wimfs_ctx->wim);
1169 fuse_exit(fuse_ctx->fuse);
1171 if (mq != (mqd_t)-1)
1177 wimfs_chmod(const char *path, mode_t mask)
1179 const struct wimfs_context *ctx = wimfs_get_context();
1180 struct wim_inode *inode;
1181 struct wimlib_unix_data unix_data;
1183 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
1186 inode = wim_pathname_to_inode(ctx->wim, path);
1190 unix_data.uid = ctx->owner_uid;
1191 unix_data.gid = ctx->owner_gid;
1192 unix_data.mode = mask;
1195 if (!inode_set_unix_data(inode, &unix_data, UNIX_DATA_MODE))
1202 wimfs_chown(const char *path, uid_t uid, gid_t gid)
1204 const struct wimfs_context *ctx = wimfs_get_context();
1205 struct wim_inode *inode;
1206 struct wimlib_unix_data unix_data;
1209 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
1212 inode = wim_pathname_to_inode(ctx->wim, path);
1218 if (uid != (uid_t)-1)
1219 which |= UNIX_DATA_UID;
1221 uid = ctx->owner_uid;
1223 if (gid != (gid_t)-1)
1224 which |= UNIX_DATA_GID;
1226 gid = ctx->owner_gid;
1228 unix_data.uid = uid;
1229 unix_data.gid = gid;
1230 unix_data.mode = inode_default_unix_mode(inode);
1233 if (!inode_set_unix_data(inode, &unix_data, which))
1240 wimfs_fgetattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi)
1242 struct wimfs_fd *fd = WIMFS_FD(fi);
1243 return inode_to_stbuf(fd->f_inode, fd->f_blob, stbuf);
1247 wimfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi)
1249 struct wimfs_fd *fd = WIMFS_FD(fi);
1250 if (ftruncate(fd->f_staging_fd.fd, size))
1252 touch_inode(fd->f_inode);
1253 fd->f_blob->size = size;
1258 wimfs_getattr(const char *path, struct stat *stbuf)
1260 const struct wimfs_context *ctx = wimfs_get_context();
1261 struct wim_dentry *dentry;
1262 struct wim_inode_stream *strm;
1265 ret = wim_pathname_to_stream(ctx, path, LOOKUP_FLAG_DIRECTORY_OK,
1270 return inode_to_stbuf(dentry->d_inode,
1271 stream_blob_resolved(strm), stbuf);
1275 copy_xattr(char *dest, size_t destsize, const void *src, size_t srcsize)
1278 if (destsize < srcsize)
1280 memcpy(dest, src, srcsize);
1286 wimfs_getxattr(const char *path, const char *name, char *value,
1289 const struct wimfs_context *ctx = wimfs_get_context();
1290 struct wim_inode *inode;
1291 struct wim_inode_stream *strm;
1292 struct blob_descriptor *blob;
1294 if (!strncmp(name, "wimfs.", 6)) {
1295 /* Handle some magical extended attributes. These really should
1296 * be ioctls, but directory ioctls aren't supported until
1297 * libfuse 2.9, and even then they are broken. */
1299 if (!strcmp(name, "wim_filename")) {
1300 return copy_xattr(value, size, ctx->wim->filename,
1301 strlen(ctx->wim->filename));
1303 if (!strcmp(name, "wim_info")) {
1304 struct wimlib_wim_info info;
1306 wimlib_get_wim_info(ctx->wim, &info);
1308 return copy_xattr(value, size, &info, sizeof(info));
1310 if (!strcmp(name, "mounted_image")) {
1311 return copy_xattr(value, size,
1312 &ctx->wim->current_image, sizeof(int));
1314 if (!strcmp(name, "mount_flags")) {
1315 return copy_xattr(value, size,
1316 &ctx->mount_flags, sizeof(int));
1318 if (!strcmp(name, "unmount")) {
1319 if (!may_unmount_wimfs())
1324 if (size < sizeof(int))
1326 status = unmount_wimfs();
1327 memcpy(value, &status, sizeof(int));
1334 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1337 if (strncmp(name, "user.", 5))
1344 /* Querying a named data stream */
1346 inode = wim_pathname_to_inode(ctx->wim, path);
1350 strm = inode_get_data_stream_tstr(inode, name);
1352 return (errno == ENOENT) ? -ENOATTR : -errno;
1354 blob = stream_blob_resolved(strm);
1358 if (unlikely(blob->size > INT_MAX))
1362 if (size < blob->size)
1365 if (read_full_blob_into_buf(blob, value))
1366 return errno ? -errno : -EIO;
1372 wimfs_link(const char *existing_path, const char *new_path)
1374 WIMStruct *wim = wimfs_get_WIMStruct();
1375 const char *new_name;
1376 struct wim_inode *inode;
1377 struct wim_dentry *dir;
1378 struct wim_dentry *new_alias;
1380 inode = wim_pathname_to_inode(wim, existing_path);
1384 if (inode->i_attributes & (FILE_ATTRIBUTE_DIRECTORY |
1385 FILE_ATTRIBUTE_REPARSE_POINT))
1388 new_name = path_basename(new_path);
1390 dir = get_parent_dentry(wim, new_path, WIMLIB_CASE_SENSITIVE);
1394 if (!dentry_is_directory(dir))
1397 if (get_dentry_child_with_name(dir, new_name, WIMLIB_CASE_SENSITIVE))
1400 if (new_dentry_with_existing_inode(new_name, inode, &new_alias))
1403 dentry_add_child(dir, new_alias);
1404 touch_inode(dir->d_inode);
1409 wimfs_listxattr(const char *path, char *list, size_t size)
1411 const struct wimfs_context *ctx = wimfs_get_context();
1412 const struct wim_inode *inode;
1414 char *end = list + size;
1417 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1420 /* List named data streams, or get the list size. We report each named
1421 * data stream "X" as an extended attribute "user.X". */
1423 inode = wim_pathname_to_inode(ctx->wim, path);
1427 for (unsigned i = 0; i < inode->i_num_streams; i++) {
1428 const struct wim_inode_stream *strm;
1429 char *stream_name_mbs;
1430 size_t stream_name_mbs_nbytes;
1432 strm = &inode->i_streams[i];
1434 if (!stream_is_named_data_stream(strm))
1437 if (utf16le_to_tstr(strm->stream_name,
1438 utf16le_len_bytes(strm->stream_name),
1440 &stream_name_mbs_nbytes))
1443 if (unlikely(INT_MAX - total_size < stream_name_mbs_nbytes + 6)) {
1444 FREE(stream_name_mbs);
1448 total_size += stream_name_mbs_nbytes + 6;
1450 if (end - p < stream_name_mbs_nbytes + 6) {
1451 FREE(stream_name_mbs);
1454 p = mempcpy(p, "user.", 5);
1455 p = mempcpy(p, stream_name_mbs, stream_name_mbs_nbytes);
1458 FREE(stream_name_mbs);
1464 wimfs_mkdir(const char *path, mode_t mode)
1466 struct wim_dentry *dentry;
1469 /* Note: according to fuse.h, mode may not include S_IFDIR */
1470 ret = create_file(fuse_get_context(), path, mode | S_IFDIR, 0,
1471 FILE_ATTRIBUTE_DIRECTORY, &dentry);
1474 touch_parent(dentry);
1479 wimfs_mknod(const char *path, mode_t mode, dev_t rdev)
1481 struct fuse_context *fuse_ctx = fuse_get_context();
1482 struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1483 const char *stream_name;
1485 if ((wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
1486 && (stream_name = path_stream_name(path)))
1488 struct wim_inode *inode;
1489 struct wim_inode_stream *existing_strm;
1490 struct wim_inode_stream *new_strm;
1492 const utf16lechar *uname;
1494 /* Create a named data stream. */
1499 p = (char *)stream_name - 1;
1502 inode = wim_pathname_to_inode(wimfs_ctx->wim, path);
1507 if (tstr_get_utf16le(stream_name, &uname))
1510 existing_strm = inode_get_stream(inode, STREAM_TYPE_DATA, uname);
1511 if (existing_strm) {
1512 tstr_put_utf16le(uname);
1516 new_strm = inode_add_stream(inode, STREAM_TYPE_DATA, uname, NULL);
1518 tstr_put_utf16le(uname);
1524 /* Create a regular file, device node, named pipe, or socket.
1526 struct wim_dentry *dentry;
1529 if (!S_ISREG(mode) &&
1530 !(wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
1533 /* Note: we still use FILE_ATTRIBUTE_NORMAL for device nodes,
1534 * named pipes, and sockets. The real mode is in the UNIX
1536 ret = create_file(fuse_ctx, path, mode, rdev,
1537 FILE_ATTRIBUTE_NORMAL, &dentry);
1540 touch_parent(dentry);
1546 wimfs_open(const char *path, struct fuse_file_info *fi)
1548 struct wimfs_context *ctx = wimfs_get_context();
1549 struct wim_dentry *dentry;
1550 struct wim_inode *inode;
1551 struct wim_inode_stream *strm;
1552 struct blob_descriptor *blob;
1553 struct wimfs_fd *fd;
1556 ret = wim_pathname_to_stream(ctx, path, 0, &dentry, &strm);
1560 inode = dentry->d_inode;
1561 blob = stream_blob_resolved(strm);
1563 /* The data of the file being opened may be in the staging directory
1564 * (read-write mounts only) or in the WIM. If it's in the staging
1565 * directory, we need to open a native file descriptor for the
1566 * corresponding file. Otherwise, we can read the file data directly
1567 * from the WIM file if we are opening it read-only, but we need to
1568 * extract the data to the staging directory if we are opening it
1571 if (flags_writable(fi->flags) &&
1572 (!blob || blob->blob_location != BLOB_IN_STAGING_FILE)) {
1573 ret = extract_blob_to_staging_dir(inode,
1575 blob ? blob->size : 0,
1579 blob = stream_blob_resolved(strm);
1582 ret = alloc_wimfs_fd(inode, strm, &fd);
1586 if (blob && blob->blob_location == BLOB_IN_STAGING_FILE) {
1589 raw_fd = openat(blob->staging_dir_fd, blob->staging_file_name,
1590 (fi->flags & O_ACCMODE) | O_NOFOLLOW);
1595 filedes_init(&fd->f_staging_fd, raw_fd);
1597 fi->fh = (uintptr_t)fd;
1602 wimfs_opendir(const char *path, struct fuse_file_info *fi)
1604 WIMStruct *wim = wimfs_get_WIMStruct();
1605 struct wim_inode *inode;
1606 struct wim_inode_stream *strm;
1607 struct wimfs_fd *fd;
1610 inode = wim_pathname_to_inode(wim, path);
1613 if (!inode_is_directory(inode))
1615 strm = inode_get_unnamed_stream(inode, STREAM_TYPE_DATA);
1618 ret = alloc_wimfs_fd(inode, strm, &fd);
1621 fi->fh = (uintptr_t)fd;
1626 wimfs_read(const char *path, char *buf, size_t size,
1627 off_t offset, struct fuse_file_info *fi)
1629 struct wimfs_fd *fd = WIMFS_FD(fi);
1630 const struct blob_descriptor *blob;
1637 if (offset >= blob->size)
1640 if (size > blob->size - offset)
1641 size = blob->size - offset;
1646 switch (blob->blob_location) {
1648 if (read_partial_wim_blob_into_buf(blob, size, offset, buf))
1649 ret = errno ? -errno : -EIO;
1653 case BLOB_IN_STAGING_FILE:
1654 ret = raw_pread(&fd->f_staging_fd, buf, size, offset);
1658 case BLOB_IN_ATTACHED_BUFFER:
1659 memcpy(buf, blob->attached_buffer + offset, size);
1670 wimfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
1671 off_t offset, struct fuse_file_info *fi)
1673 struct wimfs_fd *fd = WIMFS_FD(fi);
1674 const struct wim_inode *inode;
1675 const struct wim_dentry *child;
1678 inode = fd->f_inode;
1680 ret = filler(buf, ".", NULL, 0);
1683 ret = filler(buf, "..", NULL, 0);
1687 for_inode_child(child, inode) {
1688 char *file_name_mbs;
1689 size_t file_name_mbs_nbytes;
1691 ret = utf16le_to_tstr(child->file_name,
1692 child->file_name_nbytes,
1694 &file_name_mbs_nbytes);
1698 ret = filler(buf, file_name_mbs, NULL, 0);
1699 FREE(file_name_mbs);
1707 wimfs_readlink(const char *path, char *buf, size_t buf_len)
1709 WIMStruct *wim = wimfs_get_WIMStruct();
1710 const struct wim_inode *inode;
1713 inode = wim_pathname_to_inode(wim, path);
1716 if (!inode_is_symlink(inode))
1720 ret = wim_inode_readlink(inode, buf, buf_len - 1, NULL);
1724 } else if (ret == -ENAMETOOLONG) {
1725 buf[buf_len - 1] = '\0';
1730 /* We use this for both release() and releasedir(), since in both cases we
1731 * simply need to close the file descriptor. */
1733 wimfs_release(const char *path, struct fuse_file_info *fi)
1735 return close_wimfs_fd(WIMFS_FD(fi));
1739 wimfs_removexattr(const char *path, const char *name)
1741 struct wimfs_context *ctx = wimfs_get_context();
1742 struct wim_inode *inode;
1743 struct wim_inode_stream *strm;
1745 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1748 if (strncmp(name, "user.", 5))
1755 /* Removing a named data stream. */
1757 inode = wim_pathname_to_inode(ctx->wim, path);
1761 strm = inode_get_data_stream_tstr(inode, name);
1763 return (errno == ENOENT) ? -ENOATTR : -errno;
1765 inode_remove_stream(inode, strm, ctx->wim->blob_table);
1770 wimfs_rename(const char *from, const char *to)
1772 return rename_wim_path(wimfs_get_WIMStruct(), from, to,
1773 WIMLIB_CASE_SENSITIVE, NULL);
1777 wimfs_rmdir(const char *path)
1779 WIMStruct *wim = wimfs_get_WIMStruct();
1780 struct wim_dentry *dentry;
1782 dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
1786 if (!dentry_is_directory(dentry))
1789 if (dentry_has_children(dentry))
1792 touch_parent(dentry);
1793 remove_dentry(dentry, wim->blob_table);
1798 wimfs_setxattr(const char *path, const char *name,
1799 const char *value, size_t size, int flags)
1801 struct wimfs_context *ctx = wimfs_get_context();
1802 struct wim_inode *inode;
1803 struct wim_inode_stream *strm;
1804 const utf16lechar *uname;
1807 if (!strncmp(name, "wimfs.", 6)) {
1808 /* Handle some magical extended attributes. These really should
1809 * be ioctls, but directory ioctls aren't supported until
1810 * libfuse 2.9, and even then they are broken. [Fixed by
1811 * libfuse commit e3b7d4c278a26520be63d99d6ea84b26906fe73d] */
1813 if (!strcmp(name, "unmount_info")) {
1814 if (!may_unmount_wimfs())
1816 if (size < sizeof(struct wimfs_unmount_info))
1818 memcpy(&ctx->unmount_info, value,
1819 sizeof(struct wimfs_unmount_info));
1825 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1828 if (strncmp(name, "user.", 5))
1835 /* Setting the contents of a named data stream. */
1837 inode = wim_pathname_to_inode(ctx->wim, path);
1841 ret = tstr_get_utf16le(name, &uname);
1845 strm = inode_get_stream(inode, STREAM_TYPE_DATA, uname);
1848 if (flags & XATTR_CREATE)
1852 if (flags & XATTR_REPLACE)
1857 if (!inode_replace_stream_data(inode, strm, value, size,
1858 ctx->wim->blob_table))
1864 if (!inode_add_stream_with_data(inode, STREAM_TYPE_DATA, uname,
1865 value, size, ctx->wim->blob_table))
1874 tstr_put_utf16le(uname);
1879 wimfs_symlink(const char *to, const char *from)
1881 struct fuse_context *fuse_ctx = fuse_get_context();
1882 struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1883 struct wim_dentry *dentry;
1886 ret = create_file(fuse_ctx, from, S_IFLNK | 0777, 0,
1887 FILE_ATTRIBUTE_REPARSE_POINT, &dentry);
1890 dentry->d_inode->i_reparse_tag = WIM_IO_REPARSE_TAG_SYMLINK;
1891 ret = wim_inode_set_symlink(dentry->d_inode, to,
1892 wimfs_ctx->wim->blob_table);
1894 remove_dentry(dentry, wimfs_ctx->wim->blob_table);
1895 if (ret == WIMLIB_ERR_NOMEM)
1900 touch_parent(dentry);
1906 wimfs_truncate(const char *path, off_t size)
1908 const struct wimfs_context *ctx = wimfs_get_context();
1909 struct wim_dentry *dentry;
1910 struct wim_inode_stream *strm;
1911 struct blob_descriptor *blob;
1915 ret = wim_pathname_to_stream(ctx, path, 0, &dentry, &strm);
1919 blob = stream_blob_resolved(strm);
1924 if (!blob || blob->blob_location != BLOB_IN_STAGING_FILE) {
1925 return extract_blob_to_staging_dir(dentry->d_inode,
1929 /* Truncate the staging file. */
1930 fd = openat(blob->staging_dir_fd, blob->staging_file_name,
1931 O_WRONLY | O_NOFOLLOW);
1934 ret = ftruncate(fd, size);
1935 if (close(fd) || ret)
1938 touch_inode(dentry->d_inode);
1943 wimfs_unlink(const char *path)
1945 const struct wimfs_context *ctx = wimfs_get_context();
1946 struct wim_dentry *dentry;
1947 struct wim_inode_stream *strm;
1950 ret = wim_pathname_to_stream(ctx, path, 0, &dentry, &strm);
1954 if (stream_is_named(strm)) {
1955 inode_remove_stream(dentry->d_inode, strm,
1956 ctx->wim->blob_table);
1958 touch_parent(dentry);
1959 remove_dentry(dentry, ctx->wim->blob_table);
1964 #ifdef HAVE_UTIMENSAT
1966 * Change the timestamp on a file dentry.
1968 * Note that alternate data streams do not have their own timestamps.
1971 wimfs_utimens(const char *path, const struct timespec tv[2])
1973 WIMStruct *wim = wimfs_get_WIMStruct();
1974 struct wim_inode *inode;
1976 inode = wim_pathname_to_inode(wim, path);
1980 if (tv[0].tv_nsec != UTIME_OMIT) {
1981 if (tv[0].tv_nsec == UTIME_NOW)
1982 inode->i_last_access_time = now_as_wim_timestamp();
1984 inode->i_last_access_time = timespec_to_wim_timestamp(&tv[0]);
1986 if (tv[1].tv_nsec != UTIME_OMIT) {
1987 if (tv[1].tv_nsec == UTIME_NOW)
1988 inode->i_last_write_time = now_as_wim_timestamp();
1990 inode->i_last_write_time = timespec_to_wim_timestamp(&tv[1]);
1994 #else /* HAVE_UTIMENSAT */
1996 wimfs_utime(const char *path, struct utimbuf *times)
1998 WIMStruct *wim = wimfs_get_WIMStruct();
1999 struct wim_inode *inode;
2001 inode = wim_pathname_to_inode(wim, path);
2005 inode->i_last_access_time = time_t_to_wim_timestamp(times->actime);
2006 inode->i_last_write_time = time_t_to_wim_timestamp(times->modtime);
2009 #endif /* !HAVE_UTIMENSAT */
2012 wimfs_write(const char *path, const char *buf, size_t size,
2013 off_t offset, struct fuse_file_info *fi)
2015 struct wimfs_fd *fd = WIMFS_FD(fi);
2018 ret = raw_pwrite(&fd->f_staging_fd, buf, size, offset);
2022 if (offset + size > fd->f_blob->size)
2023 fd->f_blob->size = offset + size;
2025 touch_inode(fd->f_inode);
2029 static struct fuse_operations wimfs_operations = {
2030 .chmod = wimfs_chmod,
2031 .chown = wimfs_chown,
2032 .fgetattr = wimfs_fgetattr,
2033 .ftruncate = wimfs_ftruncate,
2034 .getattr = wimfs_getattr,
2035 .getxattr = wimfs_getxattr,
2037 .listxattr = wimfs_listxattr,
2038 .mkdir = wimfs_mkdir,
2039 .mknod = wimfs_mknod,
2041 .opendir = wimfs_opendir,
2043 .readdir = wimfs_readdir,
2044 .readlink = wimfs_readlink,
2045 .release = wimfs_release,
2046 .releasedir = wimfs_release,
2047 .removexattr = wimfs_removexattr,
2048 .rename = wimfs_rename,
2049 .rmdir = wimfs_rmdir,
2050 .setxattr = wimfs_setxattr,
2051 .symlink = wimfs_symlink,
2052 .truncate = wimfs_truncate,
2053 .unlink = wimfs_unlink,
2054 #ifdef HAVE_UTIMENSAT
2055 .utimens = wimfs_utimens,
2057 .utime = wimfs_utime,
2059 .write = wimfs_write,
2061 /* We keep track of file descriptor structures (struct wimfs_fd), so
2062 * there is no need to have the file path provided on operations such as
2064 #if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 8)
2065 .flag_nullpath_ok = 1,
2067 #if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 9)
2069 .flag_utime_omit_ok = 1,
2073 /* API function documented in wimlib.h */
2075 wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
2076 int mount_flags, const char *staging_dir)
2079 struct wim_image_metadata *imd;
2080 struct wimfs_context ctx;
2081 char *fuse_argv[16];
2084 if (!wim || !dir || !*dir)
2085 return WIMLIB_ERR_INVALID_PARAM;
2087 if (mount_flags & ~(WIMLIB_MOUNT_FLAG_READWRITE |
2088 WIMLIB_MOUNT_FLAG_DEBUG |
2089 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
2090 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR |
2091 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS |
2092 WIMLIB_MOUNT_FLAG_UNIX_DATA |
2093 WIMLIB_MOUNT_FLAG_ALLOW_OTHER))
2094 return WIMLIB_ERR_INVALID_PARAM;
2096 /* For read-write mount, check for write access to the WIM. */
2097 if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
2099 return WIMLIB_ERR_NO_FILENAME;
2100 ret = can_modify_wim(wim);
2105 /* Select the image to mount. */
2106 ret = select_wim_image(wim, image);
2110 /* Get the metadata for the image to mount. */
2111 imd = wim_get_current_image_metadata(wim);
2113 if (imd->modified) {
2114 /* To avoid complicating things, we don't support mounting
2115 * images to which in-memory modifications have already been
2117 ERROR("Cannot mount a modified WIM image!");
2118 return WIMLIB_ERR_INVALID_PARAM;
2121 if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
2122 ret = lock_wim_for_append(wim);
2127 /* If the user did not specify an interface for accessing named
2128 * data streams, use the default (extended attributes). */
2129 if (!(mount_flags & (WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
2130 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR |
2131 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)))
2132 mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR;
2134 /* Start initializing the wimfs_context. */
2135 memset(&ctx, 0, sizeof(struct wimfs_context));
2137 ctx.mount_flags = mount_flags;
2138 if (mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
2139 ctx.default_lookup_flags = LOOKUP_FLAG_ADS_OK;
2140 /* For read-write mount, create the staging directory. */
2141 if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
2142 ret = make_staging_dir(&ctx, staging_dir);
2146 ctx.owner_uid = getuid();
2147 ctx.owner_gid = getgid();
2149 /* Add each blob referenced by files in the image to a list and
2150 * preemptively double the number of references to each. This is done
2151 * to allow implementing the WIMLIB_UNMOUNT_FLAG_NEW_IMAGE semantics.
2153 INIT_LIST_HEAD(&ctx.orig_blob_list);
2154 if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
2156 struct wim_inode *inode;
2157 struct blob_descriptor *blob;
2159 image_for_each_inode(inode, imd) {
2160 for (i = 0; i < inode->i_num_streams; i++) {
2161 blob = stream_blob(&inode->i_streams[i],
2164 blob->out_refcnt = 0;
2168 image_for_each_inode(inode, imd) {
2169 for (i = 0; i < inode->i_num_streams; i++) {
2170 blob = stream_blob(&inode->i_streams[i],
2173 if (blob->out_refcnt == 0)
2174 list_add(&blob->orig_blob_list,
2175 &ctx.orig_blob_list);
2176 blob->out_refcnt += inode->i_nlink;
2177 blob->refcnt += inode->i_nlink;
2183 /* Assign new inode numbers. */
2184 reassign_inode_numbers(&ctx);
2186 /* If a read-write mount, mark the image as modified. */
2187 if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)
2190 /* Build the FUSE command line. */
2193 fuse_argv[fuse_argc++] = "wimlib";
2194 fuse_argv[fuse_argc++] = (char *)dir;
2196 /* Disable multi-threaded operation. */
2197 fuse_argv[fuse_argc++] = "-s";
2199 /* Enable FUSE debug mode (don't fork) if requested by the user. */
2200 if (mount_flags & WIMLIB_MOUNT_FLAG_DEBUG)
2201 fuse_argv[fuse_argc++] = "-d";
2204 * Build the FUSE mount options:
2207 * FUSE will use the inode numbers we provide. We want this,
2208 * because we have inodes and will number them ourselves.
2211 * Name for our filesystem (main type is "fuse").
2214 * If an open file is unlinked, unlink it for real rather than
2215 * renaming it to a hidden file. Our code supports this; an
2216 * unlinked inode is retained until all its file descriptors have
2219 * default_permissions
2220 * FUSE will perform permission checking. Useful when
2221 * WIMLIB_MOUNT_FLAG_UNIX_DATA is provided and the WIM image
2222 * contains the UNIX permissions for each file.
2225 * Cache the contents of files. This will speed up repeated access
2226 * to files on a mounted WIM image, since they won't need to be
2227 * decompressed repeatedly. This option is valid because data in
2228 * the WIM image should never be changed externally. (Although, if
2229 * someone really wanted to they could modify the WIM file or mess
2230 * with the staging directory; but then they're asking for
2233 * entry_timeout=1000000000
2234 * Cache positive name lookups indefinitely, since names can only
2235 * be added, removed, or modified through the mounted filesystem
2238 * negative_timeout=1000000000
2239 * Cache negative name lookups indefinitely, since names can only
2240 * be added, removed, or modified through the mounted filesystem
2244 * Don't cache file/directory attributes. This is needed as a
2245 * workaround for the fact that when caching attributes, the high
2246 * level interface to libfuse considers a file which has several
2247 * hard-linked names as several different files. (Otherwise, we
2248 * could cache our file/directory attributes indefinitely, since
2249 * they can only be changed through the mounted filesystem itself.)
2251 char optstring[256] =
2255 ",default_permissions"
2257 ",entry_timeout=1000000000"
2258 ",negative_timeout=1000000000"
2261 fuse_argv[fuse_argc++] = "-o";
2262 fuse_argv[fuse_argc++] = optstring;
2263 if (!(mount_flags & WIMLIB_MOUNT_FLAG_READWRITE))
2264 strcat(optstring, ",ro");
2265 if (mount_flags & WIMLIB_MOUNT_FLAG_ALLOW_OTHER)
2266 strcat(optstring, ",allow_other");
2267 fuse_argv[fuse_argc] = NULL;
2269 /* Mount our filesystem. */
2270 ret = fuse_main(fuse_argc, fuse_argv, &wimfs_operations, &ctx);
2272 /* Cleanup and return. */
2274 ret = WIMLIB_ERR_FUSE;
2275 release_extra_refcnts(&ctx);
2276 if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)
2277 delete_staging_dir(&ctx);
2279 unlock_wim_for_append(wim);
2283 struct commit_progress_thread_args {
2285 wimlib_progress_func_t progfunc;
2290 commit_progress_thread_proc(void *_args)
2292 struct commit_progress_thread_args *args = _args;
2293 struct commit_progress_report report;
2297 ret = mq_receive(args->mq,
2298 (char *)&report, sizeof(report), NULL);
2299 if (ret == sizeof(report)) {
2300 call_progress(args->progfunc, report.msg,
2301 &report.info, args->progctx);
2303 if (ret == 0 || (ret < 0 && errno != EINTR))
2311 generate_message_queue_name(char name[WIMFS_MQUEUE_NAME_LEN + 1])
2314 memcpy(name + 1, "wimfs-", 6);
2315 randomize_char_array_with_alnum(name + 7, WIMFS_MQUEUE_NAME_LEN - 7);
2316 name[WIMFS_MQUEUE_NAME_LEN] = '\0';
2320 create_message_queue(const char *name)
2325 struct mq_attr attr;
2328 memset(&attr, 0, sizeof(attr));
2330 attr.mq_msgsize = sizeof(struct commit_progress_report);
2332 am_root = (geteuid() == 0);
2334 /* Filesystem mounted as normal user with --allow-other should
2335 * be able to send messages to root user, if they're doing the
2337 umask_save = umask(0);
2342 mq = mq_open(name, O_RDWR | O_CREAT | O_EXCL, mode, &attr);
2348 /* Unmount a read-only or read-write mounted WIM image. */
2350 do_unmount(const char *dir)
2355 len = getxattr(dir, "wimfs.unmount", &status, sizeof(int));
2356 if (len == sizeof(int))
2358 else if (len < 0 && (errno == EACCES || errno == EPERM))
2359 return WIMLIB_ERR_NOT_PERMITTED_TO_UNMOUNT;
2361 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2365 set_unmount_info(const char *dir, const struct wimfs_unmount_info *unmount_info)
2367 if (!setxattr(dir, "wimfs.unmount_info",
2368 unmount_info, sizeof(struct wimfs_unmount_info), 0))
2370 else if (errno == EROFS)
2372 else if (errno == EACCES || errno == EPERM)
2373 return WIMLIB_ERR_NOT_PERMITTED_TO_UNMOUNT;
2375 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2379 do_unmount_discard(const char *dir)
2382 struct wimfs_unmount_info unmount_info;
2384 memset(&unmount_info, 0, sizeof(unmount_info));
2386 ret = set_unmount_info(dir, &unmount_info);
2389 return do_unmount(dir);
2392 /* Unmount a read-write mounted WIM image, committing the changes. */
2394 do_unmount_commit(const char *dir, int unmount_flags,
2395 wimlib_progress_func_t progfunc, void *progctx)
2397 struct wimfs_unmount_info unmount_info;
2399 struct commit_progress_thread_args args;
2400 pthread_t commit_progress_tid;
2403 memset(&unmount_info, 0, sizeof(unmount_info));
2404 unmount_info.unmount_flags = unmount_flags;
2406 /* The current thread will be stuck in getxattr() until the image is
2407 * committed. Create a thread to handle the progress messages. */
2409 generate_message_queue_name(unmount_info.mq_name);
2411 mq = create_message_queue(unmount_info.mq_name);
2412 if (mq == (mqd_t)-1) {
2413 ERROR_WITH_ERRNO("Can't create POSIX message queue");
2414 return WIMLIB_ERR_MQUEUE;
2417 args.progfunc = progfunc;
2418 args.progctx = progctx;
2419 ret = pthread_create(&commit_progress_tid, NULL,
2420 commit_progress_thread_proc, &args);
2423 ERROR_WITH_ERRNO("Can't create thread");
2424 ret = WIMLIB_ERR_NOMEM;
2427 unmount_info.unmount_flags |= WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS;
2430 ret = set_unmount_info(dir, &unmount_info);
2432 ret = do_unmount(dir);
2434 /* Terminate the progress thread. */
2436 mq_send(mq, empty, 0, 1);
2437 pthread_join(commit_progress_tid, NULL);
2442 mq_unlink(unmount_info.mq_name);
2448 begin_unmount(const char *dir, int unmount_flags, int *mount_flags_ret,
2449 wimlib_progress_func_t progfunc, void *progctx)
2453 int wim_filename_len;
2454 union wimlib_progress_info progress;
2456 if (getxattr(dir, "wimfs.mount_flags",
2457 &mount_flags, sizeof(int)) != sizeof(int))
2458 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2460 *mount_flags_ret = mount_flags;
2465 if (getxattr(dir, "wimfs.mounted_image",
2466 &mounted_image, sizeof(int)) != sizeof(int))
2467 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2469 wim_filename_len = getxattr(dir, "wimfs.wim_filename", NULL, 0);
2470 if (wim_filename_len < 0)
2471 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2473 char wim_filename[wim_filename_len + 1];
2474 if (getxattr(dir, "wimfs.wim_filename",
2475 wim_filename, wim_filename_len) != wim_filename_len)
2476 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2477 wim_filename[wim_filename_len] = '\0';
2479 progress.unmount.mountpoint = dir;
2480 progress.unmount.mounted_wim = wim_filename;
2481 progress.unmount.mounted_image = mounted_image;
2482 progress.unmount.mount_flags = mount_flags;
2483 progress.unmount.unmount_flags = unmount_flags;
2485 return call_progress(progfunc, WIMLIB_PROGRESS_MSG_UNMOUNT_BEGIN,
2486 &progress, progctx);
2489 /* API function documented in wimlib.h */
2491 wimlib_unmount_image_with_progress(const char *dir, int unmount_flags,
2492 wimlib_progress_func_t progfunc, void *progctx)
2497 ret = wimlib_global_init(WIMLIB_INIT_FLAG_ASSUME_UTF8);
2501 if (unmount_flags & ~(WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY |
2502 WIMLIB_UNMOUNT_FLAG_COMMIT |
2503 WIMLIB_UNMOUNT_FLAG_REBUILD |
2504 WIMLIB_UNMOUNT_FLAG_RECOMPRESS |
2505 WIMLIB_UNMOUNT_FLAG_FORCE |
2506 WIMLIB_UNMOUNT_FLAG_NEW_IMAGE))
2507 return WIMLIB_ERR_INVALID_PARAM;
2509 ret = begin_unmount(dir, unmount_flags, &mount_flags,
2514 if ((unmount_flags & WIMLIB_UNMOUNT_FLAG_COMMIT) &&
2515 (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE))
2516 return do_unmount_commit(dir, unmount_flags,
2519 return do_unmount_discard(dir);
2522 #else /* WITH_FUSE */
2526 mount_unsupported_error(void)
2528 #if defined(__WIN32__)
2529 ERROR("Sorry-- Mounting WIM images is not supported on Windows!");
2531 ERROR("wimlib was compiled with --without-fuse, which disables support "
2532 "for mounting WIMs.");
2534 return WIMLIB_ERR_UNSUPPORTED;
2538 wimlib_unmount_image_with_progress(const tchar *dir, int unmount_flags,
2539 wimlib_progress_func_t progfunc, void *progctx)
2541 return mount_unsupported_error();
2545 wimlib_mount_image(WIMStruct *wim, int image, const tchar *dir,
2546 int mount_flags, const tchar *staging_dir)
2548 return mount_unsupported_error();
2551 #endif /* !WITH_FUSE */
2554 wimlib_unmount_image(const tchar *dir, int unmount_flags)
2556 return wimlib_unmount_image_with_progress(dir, unmount_flags, NULL, NULL);