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 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 #include "wimlib/dentry.h"
41 #include "wimlib/encoding.h"
42 #include "wimlib/metadata.h"
43 #include "wimlib/paths.h"
44 #include "wimlib/progress.h"
45 #include "wimlib/reparse.h"
46 #include "wimlib/timestamp.h"
47 #include "wimlib/unix_data.h"
48 #include "wimlib/write.h"
49 #include "wimlib/xml.h"
60 #include <sys/types.h>
64 #define FUSE_USE_VERSION 26
66 #include <attr/xattr.h>
69 # define O_NOFOLLOW 0 /* Security only... */
72 #define WIMFS_MQUEUE_NAME_LEN 32
74 #define WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS 0x80000000
76 struct wimfs_unmount_info {
77 unsigned unmount_flags;
78 char mq_name[WIMFS_MQUEUE_NAME_LEN + 1];
81 struct commit_progress_report {
82 enum wimlib_progress_msg msg;
83 union wimlib_progress_info info;
86 /* Description of an open file on a mounted WIM image. Actually, this
87 * represents the open state of a particular data stream of an inode, rather
88 * than the inode itself. (An inode might have multiple named data streams in
89 * addition to the default, unnamed data stream.) At a given time, an inode in
90 * the WIM image might have multiple file descriptors open to it, each to any
91 * one of its data streams. */
94 /* Pointer to the inode of this open file.
95 * 'i_num_opened_fds' of the inode tracks the number of file descriptors
96 * that reference it. */
97 struct wim_inode *f_inode;
99 /* Pointer to the lookup table entry for the data stream that has been
100 * opened. 'num_opened_fds' of the lookup table entry tracks the number
101 * of file descriptors that reference it. Or, this value may be NULL,
102 * which indicates that the opened stream is empty and consequently does
103 * not have a lookup table entry. */
104 struct wim_lookup_table_entry *f_lte;
106 /* If valid (filedes_valid(&f_staging_fd)), this contains the
107 * corresponding native file descriptor for the staging file that has
108 * been created for reading from and/or writing to this open stream. A
109 * single staging file might have multiple file descriptors open to it
110 * simultaneously, each used by a different 'struct wimfs_fd'.
112 * Or, if invalid (!filedes_valid(&f_staging_fd)), this 'struct
113 * wimfs_fd' is not associated with a staging file. This is permissible
114 * only if this 'struct wimfs_fd' was opened read-only and the stream
115 * has not yet been extracted to a staging file. */
116 struct filedes f_staging_fd;
118 /* 0-based index of this file descriptor in the file descriptor table of
122 /* Unique ID of the opened stream in the inode. This will stay the same
123 * even if the indices of the inode's alternate data streams are changed
128 #define WIMFS_FD(fi) ((struct wimfs_fd *)(uintptr_t)((fi)->fh))
130 /* Context structure for a mounted WIM image. */
131 struct wimfs_context {
132 /* The WIMStruct containing the mounted image. The mounted image is the
133 * currently selected image (wim->current_image). */
136 /* Flags passed to wimlib_mount_image() (WIMLIB_MOUNT_FLAG_*). */
139 /* Default flags for path lookup in the WIM image. */
140 int default_lookup_flags;
142 /* Information about the user who has mounted the WIM image */
146 /* Information about the staging directory for a read-write mount. */
149 char *staging_dir_name;
151 /* For read-write mounts, the inode number to be assigned to the next
152 * created file. Note: since this isn't a persistent filesystem and we
153 * can re-assign the inode numbers just before mounting the image, it's
154 * good enough to just generate inode numbers sequentially. */
157 /* Number of file descriptors open to the mounted WIM image. */
158 unsigned long num_open_fds;
160 /* Original list of single-instance streams in the mounted image, linked
161 * by 'struct wim_lookup_table_entry'.orig_stream_list. */
162 struct list_head orig_stream_list;
164 /* Parameters for unmounting the image (can be set via extended
165 * attribute "wimfs.unmount_info"). */
166 struct wimfs_unmount_info unmount_info;
169 #define WIMFS_CTX(fuse_ctx) ((struct wimfs_context*)(fuse_ctx)->private_data)
171 /* Retrieve the context structure for the currently mounted WIM image.
173 * Note: this is a per-thread variable. It is possible for different threads to
174 * mount different images at the same time in the same process, although they
175 * must use different WIMStructs! */
176 static inline struct wimfs_context *
177 wimfs_get_context(void)
179 return WIMFS_CTX(fuse_get_context());
183 wimfs_inc_num_open_fds(void)
185 wimfs_get_context()->num_open_fds++;
189 wimfs_dec_num_open_fds(void)
191 wimfs_get_context()->num_open_fds--;
194 /* Retrieve the WIMStruct for the currently mounted WIM image. */
195 static inline WIMStruct *
196 wimfs_get_WIMStruct(void)
198 return wimfs_get_context()->wim;
201 /* Is write permission requested on the file? */
203 flags_writable(int open_flags)
205 int accmode = (open_flags & O_ACCMODE);
206 return (accmode == O_RDWR || accmode == O_WRONLY);
210 fuse_mask_mode(mode_t mode, const struct fuse_context *fuse_ctx)
212 #if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 8)
213 mode &= ~fuse_ctx->umask;
219 * Allocate a file descriptor to a data stream in the mounted WIM image.
222 * A pointer to the inode containing the stream being opened.
224 * The ID of the data stream being opened within the inode.
226 * A pointer to the lookup table entry for the stream data. Or, for a
227 * 0-byte stream, this may be NULL.
229 * On success, a pointer to the new file descriptor will be stored here.
231 * Returns 0 or a -errno code.
234 alloc_wimfs_fd(struct wim_inode *inode,
236 struct wim_lookup_table_entry *lte,
237 struct wimfs_fd **fd_ret)
239 static const u16 min_fds_per_alloc = 8;
240 static const u16 max_fds = 0xffff;
244 if (inode->i_num_opened_fds == inode->i_num_allocated_fds) {
246 struct wimfs_fd **fds;
248 /* Expand this inode's file descriptor table. */
250 num_new_fds = max(min_fds_per_alloc,
251 inode->i_num_allocated_fds / 4);
253 num_new_fds = min(num_new_fds,
254 max_fds - inode->i_num_allocated_fds);
256 if (num_new_fds == 0)
259 fds = REALLOC(inode->i_fds,
260 (inode->i_num_allocated_fds + num_new_fds) *
265 memset(&fds[inode->i_num_allocated_fds], 0,
266 num_new_fds * sizeof(fds[0]));
268 inode->i_num_allocated_fds += num_new_fds;
269 inode->i_next_fd = inode->i_num_opened_fds;
272 /* Allocate the file descriptor in the first available space in the
273 * inode's file descriptor table.
275 * i_next_fd is the lower bound on the next open slot. */
276 for (i = inode->i_next_fd; inode->i_fds[i]; i++)
279 fd = MALLOC(sizeof(*fd));
285 filedes_invalidate(&fd->f_staging_fd);
287 fd->f_stream_id = stream_id;
289 inode->i_fds[i] = fd;
290 inode->i_num_opened_fds++;
292 lte->num_opened_fds++;
293 wimfs_inc_num_open_fds();
294 inode->i_next_fd = i + 1;
299 * Close a file descriptor to a data stream in the mounted WIM image.
301 * Returns 0 or a -errno code. The file descriptor is always closed.
304 close_wimfs_fd(struct wimfs_fd *fd)
307 struct wim_inode *inode;
309 /* Close the staging file if open. */
310 if (filedes_valid(&fd->f_staging_fd))
311 if (filedes_close(&fd->f_staging_fd))
314 /* Release this file descriptor from its lookup table entry. */
316 lte_decrement_num_opened_fds(fd->f_lte);
318 wimfs_dec_num_open_fds();
320 /* Release this file descriptor from its inode. */
322 inode->i_fds[fd->f_idx] = NULL;
323 if (fd->f_idx < inode->i_next_fd)
324 inode->i_next_fd = fd->f_idx;
326 if (--inode->i_num_opened_fds == 0) {
327 /* The last file descriptor to this inode was closed. */
330 inode->i_num_allocated_fds = 0;
331 if (inode->i_nlink == 0)
332 /* No links to this inode remain. Get rid of it. */
339 * Translate a path into the corresponding inode in the mounted WIM image.
341 * See get_dentry() for more information.
343 * Returns a pointer to the resulting inode, or NULL with errno set.
345 static struct wim_inode *
346 wim_pathname_to_inode(WIMStruct *wim, const char *path)
348 struct wim_dentry *dentry;
350 dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
353 return dentry->d_inode;
356 /* Can look up named data stream with colon syntax */
357 #define LOOKUP_FLAG_ADS_OK 0x01
359 /* Can look up directory (otherwise get -ENOTDIR) */
360 #define LOOKUP_FLAG_DIRECTORY_OK 0x02
363 * Translate a path into the corresponding dentry, lookup table entry, and
364 * stream index in the mounted WIM image.
366 * Returns 0 or a -errno code. All of @dentry_ret, @lte_ret, and
367 * @stream_idx_ret are optional.
370 wim_pathname_to_stream(const struct wimfs_context *ctx, const char *path,
372 struct wim_dentry **dentry_ret,
373 struct wim_lookup_table_entry **lte_ret,
376 WIMStruct *wim = ctx->wim;
377 struct wim_dentry *dentry;
378 struct wim_lookup_table_entry *lte;
380 const char *stream_name = NULL;
381 struct wim_inode *inode;
384 lookup_flags |= ctx->default_lookup_flags;
386 if (lookup_flags & LOOKUP_FLAG_ADS_OK) {
387 stream_name = path_stream_name(path);
389 p = (char *)stream_name - 1;
394 dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
400 inode = dentry->d_inode;
402 if (inode_resolve_streams(inode, wim->lookup_table, false))
405 if (!(lookup_flags & LOOKUP_FLAG_DIRECTORY_OK)
406 && inode_is_directory(inode))
410 struct wim_ads_entry *ads_entry;
412 ads_entry = inode_get_ads_entry(inode, stream_name);
416 stream_idx = ads_entry - inode->i_ads_entries + 1;
417 lte = ads_entry->lte;
419 lte = inode_unnamed_stream_resolved(inode, &stream_idx);
422 *dentry_ret = dentry;
426 *stream_idx_ret = stream_idx;
431 * Create a new file in the mounted WIM image.
434 * The FUSE context for the mounted image.
436 * The path at which to create the first link to the new file. If a file
437 * already exists at this path, -EEXIST is returned.
439 * The UNIX mode for the new file. This is only honored if
440 * WIMLIB_MOUNT_FLAG_UNIX_DATA was passed to wimlib_mount_image().
442 * The device ID for the new file, encoding the major and minor device
443 * numbers. This is only honored if WIMLIB_MOUNT_FLAG_UNIX_DATA was passed
444 * to wimlib_mount_image().
446 * Windows file attributes to use for the new file.
448 * On success, a pointer to the new dentry is returned here. Its d_inode
449 * member will point to the new inode that was created for it and added to
450 * the mounted WIM image.
452 * Returns 0 or a -errno code.
455 create_dentry(struct fuse_context *fuse_ctx, const char *path,
456 mode_t mode, dev_t rdev, u32 attributes,
457 struct wim_dentry **dentry_ret)
459 struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
460 struct wim_dentry *parent;
461 const char *basename;
462 struct wim_dentry *new_dentry;
463 struct wim_inode *new_inode;
465 parent = get_parent_dentry(wimfs_ctx->wim, path, WIMLIB_CASE_SENSITIVE);
469 if (!dentry_is_directory(parent))
472 basename = path_basename(path);
474 if (get_dentry_child_with_name(parent, basename, WIMLIB_CASE_SENSITIVE))
477 if (new_dentry_with_inode(basename, &new_dentry))
480 new_inode = new_dentry->d_inode;
482 new_inode->i_resolved = 1;
483 new_inode->i_ino = wimfs_ctx->next_ino++;
484 new_inode->i_attributes = attributes;
486 if (wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) {
487 struct wimlib_unix_data unix_data;
489 unix_data.uid = fuse_ctx->uid;
490 unix_data.gid = fuse_ctx->gid;
491 unix_data.mode = fuse_mask_mode(mode, fuse_ctx);
492 unix_data.rdev = rdev;
493 if (!inode_set_unix_data(new_inode, &unix_data, UNIX_DATA_ALL))
495 free_dentry(new_dentry);
500 list_add_tail(&new_inode->i_list,
501 &wim_get_current_image_metadata(wimfs_ctx->wim)->inode_list);
503 dentry_add_child(parent, new_dentry);
505 *dentry_ret = new_dentry;
510 * Remove a dentry from the mounted WIM image; i.e. remove an alias for an
514 remove_dentry(struct wim_dentry *dentry,
515 struct wim_lookup_table *lookup_table)
517 /* Drop the reference to each stream the inode contains. */
518 inode_unref_streams(dentry->d_inode, lookup_table);
520 /* Unlink the dentry from the image's dentry tree. */
521 unlink_dentry(dentry);
523 /* Delete the dentry. This will also decrement the link count of the
524 * corresponding inode, and possibly cause it to be deleted as well. */
528 /* Generate UNIX filetype mode bits for the specified WIM inode, based on its
529 * Windows file attributes. */
531 inode_unix_file_type(const struct wim_inode *inode)
533 if (inode_is_symlink(inode))
535 else if (inode_is_directory(inode))
541 /* Generate a default UNIX mode for the specified WIM inode. */
543 inode_default_unix_mode(const struct wim_inode *inode)
545 return inode_unix_file_type(inode) | 0777;
549 * Retrieve standard UNIX metadata ('struct stat') for a WIM inode.
551 * @lte specifies the stream of the inode that is being queried. We mostly
552 * return the same information for all streams, but st_size and st_blocks may be
553 * different for different streams.
555 * This always returns 0.
558 inode_to_stbuf(const struct wim_inode *inode,
559 const struct wim_lookup_table_entry *lte,
562 const struct wimfs_context *ctx = wimfs_get_context();
563 struct wimlib_unix_data unix_data;
565 memset(stbuf, 0, sizeof(struct stat));
566 if ((ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) &&
567 inode_get_unix_data(inode, &unix_data))
569 /* Use the user ID, group ID, mode, and device ID from the
570 * inode's extra UNIX metadata information. */
571 stbuf->st_uid = unix_data.uid;
572 stbuf->st_gid = unix_data.gid;
573 stbuf->st_mode = unix_data.mode;
574 stbuf->st_rdev = unix_data.rdev;
576 /* Generate default values for the user ID, group ID, and mode.
578 * Note: in the case of an allow_other mount, fuse_context.uid
579 * may not be the same as wimfs_context.owner_uid! */
580 stbuf->st_uid = ctx->owner_uid;
581 stbuf->st_gid = ctx->owner_gid;
582 stbuf->st_mode = inode_default_unix_mode(inode);
584 stbuf->st_ino = inode->i_ino;
585 stbuf->st_nlink = inode->i_nlink;
587 stbuf->st_size = lte->size;
588 #ifdef HAVE_STAT_NANOSECOND_PRECISION
589 stbuf->st_atim = wim_timestamp_to_timespec(inode->i_last_access_time);
590 stbuf->st_mtim = wim_timestamp_to_timespec(inode->i_last_write_time);
591 stbuf->st_ctim = stbuf->st_mtim;
593 stbuf->st_atime = wim_timestamp_to_time_t(inode->i_last_access_time);
594 stbuf->st_mtime = wim_timestamp_to_time_t(inode->i_last_write_time);
595 stbuf->st_ctime = stbuf->st_mtime;
597 stbuf->st_blocks = DIV_ROUND_UP(stbuf->st_size, 512);
601 /* Update the last access and last write timestamps of a WIM inode. */
603 touch_inode(struct wim_inode *inode)
605 u64 now = now_as_wim_timestamp();
606 inode->i_last_access_time = now;
607 inode->i_last_write_time = now;
611 touch_parent(struct wim_dentry *dentry)
613 touch_inode(dentry->d_parent->d_inode);
617 * Create a new file in the staging directory for a read-write mounted image.
619 * On success, returns the file descriptor for the new staging file, opened for
620 * writing. In addition, stores the allocated name of the staging file in
623 * On failure, returns -1 and sets errno.
626 create_staging_file(const struct wimfs_context *ctx, char **name_ret)
629 static const size_t STAGING_FILE_NAME_LEN = 20;
633 name = MALLOC(STAGING_FILE_NAME_LEN + 1);
636 name[STAGING_FILE_NAME_LEN] = '\0';
639 randomize_char_array_with_alnum(name, STAGING_FILE_NAME_LEN);
640 fd = openat(ctx->staging_dir_fd, name,
641 O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0600);
642 if (unlikely(fd < 0)) {
643 if (unlikely(errno == EEXIST))
644 /* Try again with another name. */
654 * Extract a WIM resource to the staging directory.
655 * This is necessary if a stream using the resource is being opened for writing.
658 * The inode containing the stream being opened for writing.
661 * The index of the stream in @inode being opened for writing.
664 * *lte_ptr is the lookup table entry for the stream being extracted, or
665 * NULL if the stream does not have a lookup table entry (which is possible
666 * if the stream is empty). On success, *lte_ptr will be set to point to a
667 * lookup table entry that represents the resource in its new location in a
668 * staging file. This may be the same as the old entry in the case that it
669 * was reused, or it may be a new entry.
672 * Number of bytes of the stream to extract and include in the staging file
673 * resource. It may be less than the actual stream length, in which case
674 * only a prefix of the resource will be extracted. It may also be more
675 * than the actual stream length, in which case the extra space will be
678 * Returns 0 or a -errno code.
681 extract_resource_to_staging_dir(struct wim_inode *inode,
683 struct wim_lookup_table_entry **lte_ptr,
685 const struct wimfs_context *ctx)
687 struct wim_lookup_table_entry *old_lte;
688 struct wim_lookup_table_entry *new_lte;
689 char *staging_file_name;
698 /* Create the staging file. */
699 staging_fd = create_staging_file(ctx, &staging_file_name);
700 if (unlikely(staging_fd < 0))
703 /* Extract the stream to the staging file (possibly truncated). */
707 filedes_init(&fd, staging_fd);
709 extract_size = min(old_lte->size, size);
710 result = extract_stream_to_fd(old_lte, &fd, extract_size);
716 /* In the case of truncate() to more than the file length, extend the
717 * staging file with zeroes by calling ftruncate(). */
718 if (!result && size > extract_size)
719 result = ftruncate(staging_fd, size);
721 /* Close the staging file. */
722 if (close(staging_fd))
725 /* If an error occurred, unlink the staging file. */
726 if (unlikely(result)) {
727 /* extract_stream_to_fd() should set errno, but if it didn't,
728 * set a default value. */
729 ret = errno ? -errno : -EIO;
730 goto out_delete_staging_file;
733 /* Now deal with the lookup table entries. We may be able to re-use the
734 * existing entry, but we may have to create a new one instead. */
736 stream_id = inode_stream_idx_to_id(inode, stream_idx);
738 if (old_lte && inode->i_nlink == old_lte->refcnt) {
739 /* The reference count of the existing lookup table entry is the
740 * same as the link count of the inode that contains the stream
741 * we're opening. Therefore, all the references to the lookup
742 * table entry correspond to the stream we're trying to extract,
743 * so the lookup table entry can be re-used. */
744 lookup_table_unlink(ctx->wim->lookup_table, old_lte);
745 lte_put_resource(old_lte);
748 /* We need to split the old lookup table entry because it also
749 * has other references. Or, there was no old lookup table
750 * entry, so we need to create a new one anyway. */
752 new_lte = new_lookup_table_entry();
753 if (unlikely(!new_lte)) {
755 goto out_delete_staging_file;
758 /* There may already be open file descriptors to this stream if
759 * it's previously been opened read-only, but just now we're
760 * opening it read-write. Identify those file descriptors and
761 * change their lookup table entry pointers to point to the new
762 * lookup table entry, and open staging file descriptors for
765 * At the same time, we need to count the number of these opened
766 * file descriptors to the new lookup table entry. If there's
767 * an old lookup table entry, this number needs to be subtracted
768 * from the fd's opened to the old entry. */
769 for (u16 i = 0, j = 0; j < inode->i_num_opened_fds; i++) {
773 fd = inode->i_fds[i];
779 if (fd->f_stream_id != stream_id)
782 /* This is a readonly fd for the same stream. */
784 new_lte->num_opened_fds++;
785 raw_fd = openat(ctx->staging_dir_fd, staging_file_name,
786 O_RDONLY | O_NOFOLLOW);
787 if (unlikely(raw_fd < 0)) {
789 goto out_revert_fd_changes;
791 filedes_init(&fd->f_staging_fd, raw_fd);
794 old_lte->num_opened_fds -= new_lte->num_opened_fds;
795 old_lte->refcnt -= inode->i_nlink;
799 new_lte->refcnt = inode->i_nlink;
800 new_lte->resource_location = RESOURCE_IN_STAGING_FILE;
801 new_lte->staging_file_name = staging_file_name;
802 new_lte->staging_dir_fd = ctx->staging_dir_fd;
803 new_lte->size = size;
805 add_unhashed_stream(new_lte, inode, stream_id,
806 &wim_get_current_image_metadata(ctx->wim)->unhashed_streams);
808 inode->i_lte = new_lte;
810 inode->i_ads_entries[stream_idx - 1].lte = new_lte;
814 out_revert_fd_changes:
815 for (u16 i = 0; new_lte->num_opened_fds; i++) {
816 struct wimfs_fd *fd = inode->i_fds[i];
817 if (fd && fd->f_stream_id == stream_id) {
819 if (filedes_valid(&fd->f_staging_fd)) {
820 filedes_close(&fd->f_staging_fd);
821 filedes_invalidate(&fd->f_staging_fd);
823 new_lte->num_opened_fds--;
826 free_lookup_table_entry(new_lte);
827 out_delete_staging_file:
828 unlinkat(ctx->staging_dir_fd, staging_file_name, 0);
829 FREE(staging_file_name);
834 * Create the staging directory for the WIM file.
836 * The staging directory will be created in the directory specified by the open
837 * file descriptor @parent_dir_fd. It will be given a randomly generated name
838 * based on @wim_basename, the name of the WIM file.
840 * On success, returns a file descriptor to the open staging directory with
841 * O_RDONLY access. In addition, stores the allocated name of the staging
842 * directory (relative to @parent_dir_fd) in @staging_dir_name_ret.
843 * On failure, returns -1 and sets errno.
846 make_staging_dir_at(int parent_dir_fd, const char *wim_basename,
847 char **staging_dir_name_ret)
849 static const char common_suffix[8] = ".staging";
850 static const size_t random_suffix_len = 10;
851 size_t wim_basename_len;
852 size_t staging_dir_name_len;
853 char *staging_dir_name;
857 wim_basename_len = strlen(wim_basename);
858 staging_dir_name_len = wim_basename_len + sizeof(common_suffix) +
860 staging_dir_name = MALLOC(staging_dir_name_len + 1);
861 if (!staging_dir_name)
864 p = staging_dir_name;
865 p = mempcpy(p, wim_basename, wim_basename_len);
866 p = mempcpy(p, common_suffix, sizeof(common_suffix));
867 randomize_char_array_with_alnum(p, random_suffix_len);
868 p += random_suffix_len;
871 if (mkdirat(parent_dir_fd, staging_dir_name, 0700))
874 fd = openat(parent_dir_fd, staging_dir_name,
875 O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
879 *staging_dir_name_ret = staging_dir_name;
883 unlinkat(parent_dir_fd, staging_dir_name, AT_REMOVEDIR);
885 FREE(staging_dir_name);
890 * Create the staging directory and set ctx->staging_dir_fd,
891 * ctx->staging_dir_name, and ctx->parent_dir_fd.
894 make_staging_dir(struct wimfs_context *ctx, const char *parent_dir_path)
896 const char *wim_basename;
900 wim_basename = path_basename(ctx->wim->filename);
902 if (!parent_dir_path) {
903 /* The user did not specify a directory. Default to creating
904 * the staging directory alongside the WIM file. */
905 if (wim_basename > ctx->wim->filename) {
906 parent_dir_path = ctx->wim->filename;
907 end = (char *)(wim_basename - 1);
908 /* *end must be a slash. Temporarily overwrite it so we
909 * can open the parent directory. */
912 parent_dir_path = ".";
916 /* Open the parent directory (in which we'll create our staging
918 ctx->parent_dir_fd = open(parent_dir_path, O_RDONLY | O_DIRECTORY);
919 if (ctx->parent_dir_fd < 0) {
920 ERROR_WITH_ERRNO("Can't open directory \"%s\"",
922 ret = WIMLIB_ERR_OPENDIR;
923 goto out_restore_wim_filename;
926 ctx->staging_dir_fd = make_staging_dir_at(ctx->parent_dir_fd,
928 &ctx->staging_dir_name);
929 if (ctx->staging_dir_fd < 0) {
930 ERROR_WITH_ERRNO("Can't create staging directory in \"%s\"",
932 close(ctx->parent_dir_fd);
933 ret = WIMLIB_ERR_MKDIR;
934 goto out_restore_wim_filename;
937 out_restore_wim_filename:
943 /* Deletes the staging directory, undoing the effects of a successful call to
944 * make_staging_dir(). */
946 delete_staging_dir(struct wimfs_context *ctx)
951 dir = fdopendir(ctx->staging_dir_fd);
953 while ((ent = readdir(dir)))
954 unlinkat(ctx->staging_dir_fd, ent->d_name, 0);
957 close(ctx->staging_dir_fd);
959 if (unlinkat(ctx->parent_dir_fd, ctx->staging_dir_name, AT_REMOVEDIR))
960 WARNING_WITH_ERRNO("Could not delete staging directory");
961 FREE(ctx->staging_dir_name);
962 close(ctx->parent_dir_fd);
965 /* Number the inodes in the mounted image sequentially. */
967 reassign_inode_numbers(struct wimfs_context *ctx)
969 struct wim_image_metadata *imd;
970 struct wim_inode *inode;
973 imd = wim_get_current_image_metadata(ctx->wim);
974 image_for_each_inode(inode, imd)
975 inode->i_ino = ctx->next_ino++;
979 release_extra_refcnts(struct wimfs_context *ctx)
981 struct list_head *list = &ctx->orig_stream_list;
982 struct wim_lookup_table *lookup_table = ctx->wim->lookup_table;
983 struct wim_lookup_table_entry *lte, *tmp;
985 list_for_each_entry_safe(lte, tmp, list, orig_stream_list) {
986 u32 n = lte->out_refcnt;
988 lte_decrement_refcnt(lte, lookup_table);
992 /* Delete the 'struct wim_lookup_table_entry' for any stream that was modified
993 * or created in the read-write mounted image and had a final size of 0. */
995 delete_empty_streams(struct wimfs_context *ctx)
997 struct wim_lookup_table_entry *lte, *tmp;
998 struct wim_image_metadata *imd;
1000 imd = wim_get_current_image_metadata(ctx->wim);
1002 image_for_each_unhashed_stream_safe(lte, tmp, imd) {
1004 *retrieve_lte_pointer(lte) = NULL;
1005 list_del(<e->unhashed_list);
1006 free_lookup_table_entry(lte);
1011 /* Close all file descriptors open to the specified inode.
1013 * Note: closing the last file descriptor might free the inode. */
1015 inode_close_fds(struct wim_inode *inode)
1017 u16 num_open_fds = inode->i_num_opened_fds;
1018 for (u16 i = 0; num_open_fds; i++) {
1019 if (inode->i_fds[i]) {
1020 close_wimfs_fd(inode->i_fds[i]);
1026 /* Close all file descriptors open to the mounted image. */
1028 close_all_fds(struct wimfs_context *ctx)
1030 struct wim_inode *inode, *tmp;
1031 struct wim_image_metadata *imd;
1033 imd = wim_get_current_image_metadata(ctx->wim);
1035 list_for_each_entry_safe(inode, tmp, &imd->inode_list, i_list)
1036 inode_close_fds(inode);
1039 /* Moves the currently selected image, which may have been modified, to a new
1040 * index, and sets the original index to refer to a reset (unmodified) copy of
1043 renew_current_image(struct wimfs_context *ctx)
1045 WIMStruct *wim = ctx->wim;
1046 int idx = wim->current_image - 1;
1047 struct wim_image_metadata *imd = wim->image_metadata[idx];
1048 struct wim_image_metadata *replace_imd;
1049 struct wim_lookup_table_entry *new_lte;
1052 /* Create 'replace_imd' structure to use for the reset original,
1053 * unmodified image. */
1054 ret = WIMLIB_ERR_NOMEM;
1055 replace_imd = new_image_metadata();
1059 /* Create new stream reference for the modified image's metadata
1060 * resource, which doesn't exist yet. */
1061 ret = WIMLIB_ERR_NOMEM;
1062 new_lte = new_lookup_table_entry();
1064 goto err_put_replace_imd;
1065 new_lte->flags = WIM_RESHDR_FLAG_METADATA;
1066 new_lte->unhashed = 1;
1068 /* Make the image being moved available at a new index. Increments the
1069 * WIM's image count, but does not increment the reference count of the
1070 * 'struct image_metadata'. */
1071 ret = append_image_metadata(wim, imd);
1073 goto err_free_new_lte;
1075 ret = xml_add_image(wim, "");
1077 goto err_undo_append;
1079 replace_imd->metadata_lte = imd->metadata_lte;
1080 imd->metadata_lte = new_lte;
1081 wim->image_metadata[idx] = replace_imd;
1082 wim->current_image = wim->hdr.image_count;
1086 wim->hdr.image_count--;
1088 free_lookup_table_entry(new_lte);
1089 err_put_replace_imd:
1090 put_image_metadata(replace_imd, NULL);
1095 static enum wimlib_progress_status
1096 commit_progress_func(enum wimlib_progress_msg msg,
1097 union wimlib_progress_info *info, void *progctx)
1099 mqd_t mq = *(mqd_t *)progctx;
1100 struct commit_progress_report report;
1102 memset(&report, 0, sizeof(report));
1105 report.info = *info;
1106 mq_send(mq, (const char *)&report, sizeof(report), 1);
1107 return WIMLIB_PROGRESS_STATUS_CONTINUE;
1110 /* Commit the mounted image to the underlying WIM file. */
1112 commit_image(struct wimfs_context *ctx, int unmount_flags, mqd_t mq)
1116 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS)
1117 wimlib_register_progress_function(ctx->wim,
1118 commit_progress_func, &mq);
1120 wimlib_register_progress_function(ctx->wim, NULL, NULL);
1122 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_NEW_IMAGE) {
1123 int ret = renew_current_image(ctx);
1127 release_extra_refcnts(ctx);
1129 INIT_LIST_HEAD(&ctx->orig_stream_list);
1130 delete_empty_streams(ctx);
1131 xml_update_image_info(ctx->wim, ctx->wim->current_image);
1135 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY)
1136 write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
1138 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_REBUILD)
1139 write_flags |= WIMLIB_WRITE_FLAG_REBUILD;
1141 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_RECOMPRESS)
1142 write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
1144 return wimlib_overwrite(ctx->wim, write_flags, 0);
1147 /* In the case of an allow_other mount, only the mount owner and root are
1148 * allowed to unmount the filesystem. */
1150 may_unmount_wimfs(void)
1152 const struct fuse_context *fuse_ctx = fuse_get_context();
1153 const struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1155 return (fuse_ctx->uid == wimfs_ctx->owner_uid ||
1156 fuse_ctx->uid == 0);
1159 /* Unmount the mounted image, called from the daemon process. */
1163 struct fuse_context *fuse_ctx = fuse_get_context();
1164 struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1165 const struct wimfs_unmount_info *info = &wimfs_ctx->unmount_info;
1166 int unmount_flags = info->unmount_flags;
1167 mqd_t mq = (mqd_t)-1;
1170 /* Ignore COMMIT if the image is mounted read-only. */
1171 if (!(wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_READWRITE))
1172 unmount_flags &= ~WIMLIB_UNMOUNT_FLAG_COMMIT;
1174 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS) {
1175 mq = mq_open(info->mq_name, O_WRONLY | O_NONBLOCK);
1176 if (mq == (mqd_t)-1) {
1177 ret = WIMLIB_ERR_MQUEUE;
1182 if (wimfs_ctx->num_open_fds) {
1184 /* There are still open file descriptors to the image. */
1186 /* With COMMIT, refuse to unmount unless FORCE is also
1188 if ((unmount_flags & (WIMLIB_UNMOUNT_FLAG_COMMIT |
1189 WIMLIB_UNMOUNT_FLAG_FORCE))
1190 == WIMLIB_UNMOUNT_FLAG_COMMIT)
1192 ret = WIMLIB_ERR_MOUNTED_IMAGE_IS_BUSY;
1196 /* Force-close all file descriptors. */
1197 close_all_fds(wimfs_ctx);
1200 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_COMMIT)
1201 ret = commit_image(wimfs_ctx, unmount_flags, mq);
1203 ret = 0; /* Read-only mount, or discarding changes to
1204 a read-write mount */
1207 /* Leave the image mounted if commit failed, unless this is a
1208 * forced unmount. The user can retry without COMMIT if they
1210 if (!ret || (unmount_flags & WIMLIB_UNMOUNT_FLAG_FORCE)) {
1211 unlock_wim_for_append(wimfs_ctx->wim);
1212 fuse_exit(fuse_ctx->fuse);
1214 if (mq != (mqd_t)-1)
1220 wimfs_chmod(const char *path, mode_t mask)
1222 const struct wimfs_context *ctx = wimfs_get_context();
1223 struct wim_inode *inode;
1224 struct wimlib_unix_data unix_data;
1226 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
1229 inode = wim_pathname_to_inode(ctx->wim, path);
1233 unix_data.uid = ctx->owner_uid;
1234 unix_data.gid = ctx->owner_gid;
1235 unix_data.mode = mask;
1238 if (!inode_set_unix_data(inode, &unix_data, UNIX_DATA_MODE))
1245 wimfs_chown(const char *path, uid_t uid, gid_t gid)
1247 const struct wimfs_context *ctx = wimfs_get_context();
1248 struct wim_inode *inode;
1249 struct wimlib_unix_data unix_data;
1252 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
1255 inode = wim_pathname_to_inode(ctx->wim, path);
1261 if (uid != (uid_t)-1)
1262 which |= UNIX_DATA_UID;
1264 uid = ctx->owner_uid;
1266 if (gid != (gid_t)-1)
1267 which |= UNIX_DATA_GID;
1269 gid = ctx->owner_gid;
1271 unix_data.uid = uid;
1272 unix_data.gid = gid;
1273 unix_data.mode = inode_default_unix_mode(inode);
1276 if (!inode_set_unix_data(inode, &unix_data, which))
1283 wimfs_fgetattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi)
1285 struct wimfs_fd *fd = WIMFS_FD(fi);
1286 return inode_to_stbuf(fd->f_inode, fd->f_lte, stbuf);
1290 wimfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi)
1292 struct wimfs_fd *fd = WIMFS_FD(fi);
1293 if (ftruncate(fd->f_staging_fd.fd, size))
1295 touch_inode(fd->f_inode);
1296 fd->f_lte->size = size;
1301 wimfs_getattr(const char *path, struct stat *stbuf)
1303 const struct wimfs_context *ctx = wimfs_get_context();
1304 struct wim_dentry *dentry;
1305 struct wim_lookup_table_entry *lte;
1308 ret = wim_pathname_to_stream(ctx, path, LOOKUP_FLAG_DIRECTORY_OK,
1309 &dentry, <e, NULL);
1312 return inode_to_stbuf(dentry->d_inode, lte, stbuf);
1316 copy_xattr(char *dest, size_t destsize, const void *src, size_t srcsize)
1319 if (destsize < srcsize)
1321 memcpy(dest, src, srcsize);
1327 wimfs_getxattr(const char *path, const char *name, char *value,
1330 const struct wimfs_context *ctx = wimfs_get_context();
1331 struct wim_inode *inode;
1332 struct wim_ads_entry *ads_entry;
1333 struct wim_lookup_table_entry *lte;
1335 if (!strncmp(name, "wimfs.", 6)) {
1336 /* Handle some magical extended attributes. These really should
1337 * be ioctls, but directory ioctls aren't supported until
1338 * libfuse 2.9, and even then they are broken. */
1340 if (!strcmp(name, "wim_filename")) {
1341 return copy_xattr(value, size, ctx->wim->filename,
1342 strlen(ctx->wim->filename));
1344 if (!strcmp(name, "wim_info")) {
1345 struct wimlib_wim_info info;
1347 wimlib_get_wim_info(ctx->wim, &info);
1349 return copy_xattr(value, size, &info, sizeof(info));
1351 if (!strcmp(name, "mounted_image")) {
1352 return copy_xattr(value, size,
1353 &ctx->wim->current_image, sizeof(int));
1355 if (!strcmp(name, "mount_flags")) {
1356 return copy_xattr(value, size,
1357 &ctx->mount_flags, sizeof(int));
1359 if (!strcmp(name, "unmount")) {
1360 if (!may_unmount_wimfs())
1365 if (size < sizeof(int))
1367 status = unmount_wimfs();
1368 memcpy(value, &status, sizeof(int));
1375 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1378 if (strncmp(name, "user.", 5))
1382 /* Querying a named data stream */
1384 inode = wim_pathname_to_inode(ctx->wim, path);
1388 ads_entry = inode_get_ads_entry(inode, name);
1390 return (errno == ENOENT) ? -ENOATTR : -errno;
1392 lte = ads_entry->lte;
1396 if (unlikely(lte->size > INT_MAX))
1400 if (size < lte->size)
1403 if (read_full_stream_into_buf(lte, value))
1404 return errno ? -errno : -EIO;
1410 wimfs_link(const char *existing_path, const char *new_path)
1412 WIMStruct *wim = wimfs_get_WIMStruct();
1413 const char *new_name;
1414 struct wim_inode *inode;
1415 struct wim_dentry *dir;
1416 struct wim_dentry *new_alias;
1418 inode = wim_pathname_to_inode(wim, existing_path);
1422 if (inode->i_attributes & (FILE_ATTRIBUTE_DIRECTORY |
1423 FILE_ATTRIBUTE_REPARSE_POINT))
1426 new_name = path_basename(new_path);
1428 dir = get_parent_dentry(wim, new_path, WIMLIB_CASE_SENSITIVE);
1432 if (!dentry_is_directory(dir))
1435 if (get_dentry_child_with_name(dir, new_name, WIMLIB_CASE_SENSITIVE))
1438 if (new_dentry(new_name, &new_alias))
1441 new_alias->d_inode = inode;
1442 inode_add_dentry(new_alias, inode);
1443 dentry_add_child(dir, new_alias);
1444 touch_inode(dir->d_inode);
1446 inode_ref_streams(inode);
1451 wimfs_listxattr(const char *path, char *list, size_t size)
1453 const struct wimfs_context *ctx = wimfs_get_context();
1454 const struct wim_inode *inode;
1456 char *end = list + size;
1459 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1462 /* List named data streams, or get the list size. We report each named
1463 * data stream "X" as an extended attribute "user.X". */
1465 inode = wim_pathname_to_inode(ctx->wim, path);
1469 for (u16 i = 0; i < inode->i_num_ads; i++) {
1470 const struct wim_ads_entry *entry;
1471 char *stream_name_mbs;
1472 size_t stream_name_mbs_nbytes;
1474 entry = &inode->i_ads_entries[i];
1476 if (!entry->stream_name_nbytes)
1479 if (utf16le_to_tstr(entry->stream_name,
1480 entry->stream_name_nbytes,
1482 &stream_name_mbs_nbytes))
1485 if (unlikely(INT_MAX - total_size < stream_name_mbs_nbytes + 6)) {
1486 FREE(stream_name_mbs);
1490 total_size += stream_name_mbs_nbytes + 6;
1492 if (end - p < stream_name_mbs_nbytes + 6) {
1493 FREE(stream_name_mbs);
1496 p = mempcpy(p, "user.", 5);
1497 p = mempcpy(p, stream_name_mbs, stream_name_mbs_nbytes);
1500 FREE(stream_name_mbs);
1506 wimfs_mkdir(const char *path, mode_t mode)
1508 struct wim_dentry *dentry;
1511 /* Note: according to fuse.h, mode may not include S_IFDIR */
1512 ret = create_dentry(fuse_get_context(), path, mode | S_IFDIR, 0,
1513 FILE_ATTRIBUTE_DIRECTORY, &dentry);
1516 touch_parent(dentry);
1521 wimfs_mknod(const char *path, mode_t mode, dev_t rdev)
1523 struct fuse_context *fuse_ctx = fuse_get_context();
1524 struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1525 const char *stream_name;
1527 if ((wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
1528 && (stream_name = path_stream_name(path)))
1530 struct wim_ads_entry *old_entry;
1531 struct wim_ads_entry *new_entry;
1532 struct wim_inode *inode;
1535 /* Create a named data stream. */
1540 p = (char *)stream_name - 1;
1543 inode = wim_pathname_to_inode(wimfs_ctx->wim, path);
1548 old_entry = inode_get_ads_entry(inode, stream_name);
1551 if (errno != ENOENT)
1554 new_entry = inode_add_ads(inode, stream_name);
1559 /* Create a regular file, device node, named pipe, or socket.
1561 struct wim_dentry *dentry;
1564 if (!S_ISREG(mode) &&
1565 !(wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
1568 /* Note: we still use FILE_ATTRIBUTE_NORMAL for device nodes,
1569 * named pipes, and sockets. The real mode is in the UNIX
1571 ret = create_dentry(fuse_ctx, path, mode, rdev,
1572 FILE_ATTRIBUTE_NORMAL, &dentry);
1575 touch_parent(dentry);
1581 wimfs_open(const char *path, struct fuse_file_info *fi)
1583 struct wimfs_context *ctx = wimfs_get_context();
1584 struct wim_dentry *dentry;
1585 struct wim_inode *inode;
1586 struct wim_lookup_table_entry *lte;
1588 struct wimfs_fd *fd;
1591 ret = wim_pathname_to_stream(ctx, path, 0, &dentry, <e, &stream_idx);
1595 inode = dentry->d_inode;
1597 /* The file resource may be in the staging directory (read-write mounts
1598 * only) or in the WIM. If it's in the staging directory, we need to
1599 * open a native file descriptor for the corresponding file. Otherwise,
1600 * we can read the file resource directly from the WIM file if we are
1601 * opening it read-only, but we need to extract the resource to the
1602 * staging directory if we are opening it writable. */
1604 if (flags_writable(fi->flags) &&
1605 (!lte || lte->resource_location != RESOURCE_IN_STAGING_FILE)) {
1606 ret = extract_resource_to_staging_dir(inode,
1609 lte ? lte->size : 0,
1615 ret = alloc_wimfs_fd(inode, inode_stream_idx_to_id(inode, stream_idx),
1620 if (lte && lte->resource_location == RESOURCE_IN_STAGING_FILE) {
1623 raw_fd = openat(lte->staging_dir_fd, lte->staging_file_name,
1624 (fi->flags & O_ACCMODE) | O_NOFOLLOW);
1629 filedes_init(&fd->f_staging_fd, raw_fd);
1631 fi->fh = (uintptr_t)fd;
1636 wimfs_opendir(const char *path, struct fuse_file_info *fi)
1638 WIMStruct *wim = wimfs_get_WIMStruct();
1639 struct wim_inode *inode;
1640 struct wimfs_fd *fd;
1643 inode = wim_pathname_to_inode(wim, path);
1646 if (!inode_is_directory(inode))
1648 ret = alloc_wimfs_fd(inode, 0, NULL, &fd);
1651 fi->fh = (uintptr_t)fd;
1656 wimfs_read(const char *path, char *buf, size_t size,
1657 off_t offset, struct fuse_file_info *fi)
1659 struct wimfs_fd *fd = WIMFS_FD(fi);
1660 const struct wim_lookup_table_entry *lte;
1667 if (offset >= lte->size)
1670 if (size > lte->size - offset)
1671 size = lte->size - offset;
1676 switch (lte->resource_location) {
1677 case RESOURCE_IN_WIM:
1678 if (read_partial_wim_stream_into_buf(lte, size, offset, buf))
1679 ret = errno ? -errno : -EIO;
1683 case RESOURCE_IN_STAGING_FILE:
1684 ret = raw_pread(&fd->f_staging_fd, buf, size, offset);
1688 case RESOURCE_IN_ATTACHED_BUFFER:
1689 memcpy(buf, lte->attached_buffer + offset, size);
1700 wimfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
1701 off_t offset, struct fuse_file_info *fi)
1703 struct wimfs_fd *fd = WIMFS_FD(fi);
1704 const struct wim_inode *inode;
1705 const struct wim_dentry *child;
1708 inode = fd->f_inode;
1710 ret = filler(buf, ".", NULL, 0);
1713 ret = filler(buf, "..", NULL, 0);
1717 for_inode_child(child, inode) {
1718 char *file_name_mbs;
1719 size_t file_name_mbs_nbytes;
1721 ret = utf16le_to_tstr(child->file_name,
1722 child->file_name_nbytes,
1724 &file_name_mbs_nbytes);
1728 ret = filler(buf, file_name_mbs, NULL, 0);
1729 FREE(file_name_mbs);
1737 wimfs_readlink(const char *path, char *buf, size_t buf_len)
1739 WIMStruct *wim = wimfs_get_WIMStruct();
1740 const struct wim_inode *inode;
1743 inode = wim_pathname_to_inode(wim, path);
1746 if (!inode_is_symlink(inode))
1750 ret = wim_inode_readlink(inode, buf, buf_len - 1, NULL);
1754 } else if (ret == -ENAMETOOLONG) {
1755 buf[buf_len - 1] = '\0';
1760 /* We use this for both release() and releasedir(), since in both cases we
1761 * simply need to close the file descriptor. */
1763 wimfs_release(const char *path, struct fuse_file_info *fi)
1765 return close_wimfs_fd(WIMFS_FD(fi));
1769 wimfs_removexattr(const char *path, const char *name)
1771 struct wimfs_context *ctx = wimfs_get_context();
1772 struct wim_inode *inode;
1773 struct wim_ads_entry *ads_entry;
1775 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1778 if (strncmp(name, "user.", 5))
1782 /* Removing a named data stream. */
1784 inode = wim_pathname_to_inode(ctx->wim, path);
1788 ads_entry = inode_get_ads_entry(inode, name);
1790 return (errno == ENOENT) ? -ENOATTR : -errno;
1792 inode_remove_ads(inode, ads_entry, ctx->wim->lookup_table);
1797 wimfs_rename(const char *from, const char *to)
1799 return rename_wim_path(wimfs_get_WIMStruct(), from, to,
1800 WIMLIB_CASE_SENSITIVE, NULL);
1804 wimfs_rmdir(const char *path)
1806 WIMStruct *wim = wimfs_get_WIMStruct();
1807 struct wim_dentry *dentry;
1809 dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
1813 if (!dentry_is_directory(dentry))
1816 if (dentry_has_children(dentry))
1819 touch_parent(dentry);
1820 remove_dentry(dentry, wim->lookup_table);
1825 wimfs_setxattr(const char *path, const char *name,
1826 const char *value, size_t size, int flags)
1828 struct wimfs_context *ctx = wimfs_get_context();
1829 struct wim_inode *inode;
1830 struct wim_ads_entry *existing_entry;
1832 if (!strncmp(name, "wimfs.", 6)) {
1833 /* Handle some magical extended attributes. These really should
1834 * be ioctls, but directory ioctls aren't supported until
1835 * libfuse 2.9, and even then they are broken. [Fixed by
1836 * libfuse commit e3b7d4c278a26520be63d99d6ea84b26906fe73d] */
1838 if (!strcmp(name, "unmount_info")) {
1839 if (!may_unmount_wimfs())
1841 if (size < sizeof(struct wimfs_unmount_info))
1843 memcpy(&ctx->unmount_info, value,
1844 sizeof(struct wimfs_unmount_info));
1850 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1853 if (strncmp(name, "user.", 5))
1857 /* Setting the contents of a named data stream. */
1859 inode = wim_pathname_to_inode(ctx->wim, path);
1863 existing_entry = inode_get_ads_entry(inode, name);
1864 if (existing_entry) {
1865 if (flags & XATTR_CREATE)
1868 if (errno != ENOENT)
1870 if (flags & XATTR_REPLACE)
1874 if (!inode_add_ads_with_data(inode, name, value,
1875 size, ctx->wim->lookup_table))
1878 inode_remove_ads(inode, existing_entry, ctx->wim->lookup_table);
1883 wimfs_symlink(const char *to, const char *from)
1885 struct fuse_context *fuse_ctx = fuse_get_context();
1886 struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1887 struct wim_dentry *dentry;
1890 ret = create_dentry(fuse_ctx, from, S_IFLNK | 0777, 0,
1891 FILE_ATTRIBUTE_REPARSE_POINT, &dentry);
1894 dentry->d_inode->i_reparse_tag = WIM_IO_REPARSE_TAG_SYMLINK;
1895 ret = wim_inode_set_symlink(dentry->d_inode, to,
1896 wimfs_ctx->wim->lookup_table);
1898 remove_dentry(dentry, wimfs_ctx->wim->lookup_table);
1899 if (ret == WIMLIB_ERR_NOMEM)
1904 touch_parent(dentry);
1910 wimfs_truncate(const char *path, off_t size)
1912 const struct wimfs_context *ctx = wimfs_get_context();
1913 struct wim_dentry *dentry;
1914 struct wim_lookup_table_entry *lte;
1919 ret = wim_pathname_to_stream(ctx, path, 0, &dentry, <e, &stream_idx);
1926 if (!lte || lte->resource_location != RESOURCE_IN_STAGING_FILE) {
1927 return extract_resource_to_staging_dir(dentry->d_inode,
1932 /* Truncate the staging file. */
1933 fd = openat(lte->staging_dir_fd, lte->staging_file_name,
1934 O_WRONLY | O_NOFOLLOW);
1937 ret = ftruncate(fd, size);
1938 if (close(fd) || ret)
1945 wimfs_unlink(const char *path)
1947 const struct wimfs_context *ctx = wimfs_get_context();
1948 struct wim_dentry *dentry;
1952 ret = wim_pathname_to_stream(ctx, path, 0, &dentry, NULL, &stream_idx);
1956 if (inode_stream_name_nbytes(dentry->d_inode, stream_idx) == 0) {
1957 touch_parent(dentry);
1958 remove_dentry(dentry, ctx->wim->lookup_table);
1960 inode_remove_ads(dentry->d_inode,
1961 &dentry->d_inode->i_ads_entries[stream_idx - 1],
1962 ctx->wim->lookup_table);
1967 #ifdef HAVE_UTIMENSAT
1969 * Change the timestamp on a file dentry.
1971 * Note that alternate data streams do not have their own timestamps.
1974 wimfs_utimens(const char *path, const struct timespec tv[2])
1976 WIMStruct *wim = wimfs_get_WIMStruct();
1977 struct wim_inode *inode;
1979 inode = wim_pathname_to_inode(wim, path);
1983 if (tv[0].tv_nsec != UTIME_OMIT) {
1984 if (tv[0].tv_nsec == UTIME_NOW)
1985 inode->i_last_access_time = now_as_wim_timestamp();
1987 inode->i_last_access_time = timespec_to_wim_timestamp(&tv[0]);
1989 if (tv[1].tv_nsec != UTIME_OMIT) {
1990 if (tv[1].tv_nsec == UTIME_NOW)
1991 inode->i_last_write_time = now_as_wim_timestamp();
1993 inode->i_last_write_time = timespec_to_wim_timestamp(&tv[1]);
1997 #else /* HAVE_UTIMENSAT */
1999 wimfs_utime(const char *path, struct utimbuf *times)
2001 WIMStruct *wim = wimfs_get_WIMStruct();
2002 struct wim_inode *inode;
2004 inode = wim_pathname_to_inode(wim, path);
2008 inode->i_last_access_time = time_t_to_wim_timestamp(times->actime);
2009 inode->i_last_write_time = time_t_to_wim_timestamp(times->modtime);
2012 #endif /* !HAVE_UTIMENSAT */
2015 wimfs_write(const char *path, const char *buf, size_t size,
2016 off_t offset, struct fuse_file_info *fi)
2018 struct wimfs_fd *fd = WIMFS_FD(fi);
2021 ret = raw_pwrite(&fd->f_staging_fd, buf, size, offset);
2025 if (offset + size > fd->f_lte->size)
2026 fd->f_lte->size = offset + size;
2028 touch_inode(fd->f_inode);
2032 static struct fuse_operations wimfs_operations = {
2033 .chmod = wimfs_chmod,
2034 .chown = wimfs_chown,
2035 .fgetattr = wimfs_fgetattr,
2036 .ftruncate = wimfs_ftruncate,
2037 .getattr = wimfs_getattr,
2038 .getxattr = wimfs_getxattr,
2040 .listxattr = wimfs_listxattr,
2041 .mkdir = wimfs_mkdir,
2042 .mknod = wimfs_mknod,
2044 .opendir = wimfs_opendir,
2046 .readdir = wimfs_readdir,
2047 .readlink = wimfs_readlink,
2048 .release = wimfs_release,
2049 .releasedir = wimfs_release,
2050 .removexattr = wimfs_removexattr,
2051 .rename = wimfs_rename,
2052 .rmdir = wimfs_rmdir,
2053 .setxattr = wimfs_setxattr,
2054 .symlink = wimfs_symlink,
2055 .truncate = wimfs_truncate,
2056 .unlink = wimfs_unlink,
2057 #ifdef HAVE_UTIMENSAT
2058 .utimens = wimfs_utimens,
2060 .utime = wimfs_utime,
2062 .write = wimfs_write,
2064 /* We keep track of file descriptor structures (struct wimfs_fd), so
2065 * there is no need to have the file path provided on operations such as
2067 #if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 8)
2068 .flag_nullpath_ok = 1,
2070 #if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 9)
2072 .flag_utime_omit_ok = 1,
2076 /* API function documented in wimlib.h */
2078 wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
2079 int mount_flags, const char *staging_dir)
2082 struct wim_image_metadata *imd;
2083 struct wimfs_context ctx;
2084 char *fuse_argv[16];
2087 if (!wim || !dir || !*dir)
2088 return WIMLIB_ERR_INVALID_PARAM;
2090 if (mount_flags & ~(WIMLIB_MOUNT_FLAG_READWRITE |
2091 WIMLIB_MOUNT_FLAG_DEBUG |
2092 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
2093 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR |
2094 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS |
2095 WIMLIB_MOUNT_FLAG_UNIX_DATA |
2096 WIMLIB_MOUNT_FLAG_ALLOW_OTHER))
2097 return WIMLIB_ERR_INVALID_PARAM;
2099 /* For read-write mount, check for write access to the WIM. */
2100 if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
2102 return WIMLIB_ERR_NO_FILENAME;
2103 ret = can_modify_wim(wim);
2108 /* Select the image to mount. */
2109 ret = select_wim_image(wim, image);
2113 /* Get the metadata for the image to mount. */
2114 imd = wim_get_current_image_metadata(wim);
2116 if (imd->modified) {
2117 /* To avoid complicating things, we don't support mounting
2118 * images to which in-memory modifications have already been
2120 ERROR("Cannot mount a modified WIM image!");
2121 return WIMLIB_ERR_INVALID_PARAM;
2124 if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
2125 ret = lock_wim_for_append(wim);
2130 /* If the user did not specify an interface for accessing named
2131 * data streams, use the default (extended attributes). */
2132 if (!(mount_flags & (WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
2133 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR |
2134 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)))
2135 mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR;
2137 /* Start initializing the wimfs_context. */
2138 memset(&ctx, 0, sizeof(struct wimfs_context));
2140 ctx.mount_flags = mount_flags;
2141 if (mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
2142 ctx.default_lookup_flags = LOOKUP_FLAG_ADS_OK;
2143 /* For read-write mount, create the staging directory. */
2144 if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
2145 ret = make_staging_dir(&ctx, staging_dir);
2149 ctx.owner_uid = getuid();
2150 ctx.owner_gid = getgid();
2152 /* Add each stream referenced by files in the image to a list and
2153 * preemptively double the number of references to each. This is done
2154 * to allow implementing the WIMLIB_UNMOUNT_FLAG_NEW_IMAGE semantics.
2156 INIT_LIST_HEAD(&ctx.orig_stream_list);
2157 if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
2159 struct wim_inode *inode;
2160 struct wim_lookup_table_entry *lte;
2162 image_for_each_inode(inode, imd) {
2163 for (i = 0; i <= inode->i_num_ads; i++) {
2164 lte = inode_stream_lte(inode, i,
2167 lte->out_refcnt = 0;
2171 image_for_each_inode(inode, imd) {
2172 for (i = 0; i <= inode->i_num_ads; i++) {
2173 lte = inode_stream_lte(inode, i,
2176 if (lte->out_refcnt == 0)
2177 list_add(<e->orig_stream_list,
2178 &ctx.orig_stream_list);
2179 lte->out_refcnt += inode->i_nlink;
2180 lte->refcnt += inode->i_nlink;
2186 /* Assign new inode numbers. */
2187 reassign_inode_numbers(&ctx);
2189 /* If a read-write mount, mark the image as modified. */
2190 if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)
2193 /* Build the FUSE command line. */
2196 fuse_argv[fuse_argc++] = "wimlib";
2197 fuse_argv[fuse_argc++] = (char *)dir;
2199 /* Disable multi-threaded operation. */
2200 fuse_argv[fuse_argc++] = "-s";
2202 /* Enable FUSE debug mode (don't fork) if requested by the user. */
2203 if (mount_flags & WIMLIB_MOUNT_FLAG_DEBUG)
2204 fuse_argv[fuse_argc++] = "-d";
2207 * Build the FUSE mount options:
2210 * FUSE will use the inode numbers we provide. We want this,
2211 * because we have inodes and will number them ourselves.
2214 * Name for our filesystem (main type is "fuse").
2217 * If an open file is unlinked, unlink it for real rather than
2218 * renaming it to a hidden file. Our code supports this; an
2219 * unlinked inode is retained until all its file descriptors have
2222 * default_permissions
2223 * FUSE will perform permission checking. Useful when
2224 * WIMLIB_MOUNT_FLAG_UNIX_DATA is provided and the WIM image
2225 * contains the UNIX permissions for each file.
2228 * Cache the contents of files. This will speed up repeated access
2229 * to files on a mounted WIM image, since they won't need to be
2230 * decompressed repeatedly. This option is valid because data in
2231 * the WIM image should never be changed externally. (Although, if
2232 * someone really wanted to they could modify the WIM file or mess
2233 * with the staging directory; but then they're asking for
2236 * entry_timeout=1000000000
2237 * Cache positive name lookups indefinitely, since names can only
2238 * be added, removed, or modified through the mounted filesystem
2241 * negative_timeout=1000000000
2242 * Cache negative name lookups indefinitely, since names can only
2243 * be added, removed, or modified through the mounted filesystem
2247 * Don't cache file/directory attributes. This is needed as a
2248 * workaround for the fact that when caching attributes, the high
2249 * level interface to libfuse considers a file which has several
2250 * hard-linked names as several different files. (Otherwise, we
2251 * could cache our file/directory attributes indefinitely, since
2252 * they can only be changed through the mounted filesystem itself.)
2254 char optstring[256] =
2258 ",default_permissions"
2260 ",entry_timeout=1000000000"
2261 ",negative_timeout=1000000000"
2264 fuse_argv[fuse_argc++] = "-o";
2265 fuse_argv[fuse_argc++] = optstring;
2266 if (!(mount_flags & WIMLIB_MOUNT_FLAG_READWRITE))
2267 strcat(optstring, ",ro");
2268 if (mount_flags & WIMLIB_MOUNT_FLAG_ALLOW_OTHER)
2269 strcat(optstring, ",allow_other");
2270 fuse_argv[fuse_argc] = NULL;
2272 /* Mount our filesystem. */
2273 ret = fuse_main(fuse_argc, fuse_argv, &wimfs_operations, &ctx);
2275 /* Cleanup and return. */
2277 ret = WIMLIB_ERR_FUSE;
2278 release_extra_refcnts(&ctx);
2279 if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)
2280 delete_staging_dir(&ctx);
2282 unlock_wim_for_append(wim);
2286 struct commit_progress_thread_args {
2288 wimlib_progress_func_t progfunc;
2293 commit_progress_thread_proc(void *_args)
2295 struct commit_progress_thread_args *args = _args;
2296 struct commit_progress_report report;
2300 ret = mq_receive(args->mq,
2301 (char *)&report, sizeof(report), NULL);
2302 if (ret == sizeof(report)) {
2303 call_progress(args->progfunc, report.msg,
2304 &report.info, args->progctx);
2306 if (ret == 0 || (ret < 0 && errno != EINTR))
2314 generate_message_queue_name(char name[WIMFS_MQUEUE_NAME_LEN + 1])
2317 memcpy(name + 1, "wimfs-", 6);
2318 randomize_char_array_with_alnum(name + 7, WIMFS_MQUEUE_NAME_LEN - 7);
2319 name[WIMFS_MQUEUE_NAME_LEN] = '\0';
2323 create_message_queue(const char *name)
2328 struct mq_attr attr;
2331 memset(&attr, 0, sizeof(attr));
2333 attr.mq_msgsize = sizeof(struct commit_progress_report);
2335 am_root = (geteuid() == 0);
2337 /* Filesystem mounted as normal user with --allow-other should
2338 * be able to send messages to root user, if they're doing the
2340 umask_save = umask(0);
2345 mq = mq_open(name, O_RDWR | O_CREAT | O_EXCL, mode, &attr);
2351 /* Unmount a read-only or read-write mounted WIM image. */
2353 do_unmount(const char *dir)
2358 len = getxattr(dir, "wimfs.unmount", &status, sizeof(int));
2359 if (len == sizeof(int))
2361 else if (len < 0 && (errno == EACCES || errno == EPERM))
2362 return WIMLIB_ERR_NOT_PERMITTED_TO_UNMOUNT;
2364 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2368 set_unmount_info(const char *dir, const struct wimfs_unmount_info *unmount_info)
2370 if (!setxattr(dir, "wimfs.unmount_info",
2371 unmount_info, sizeof(struct wimfs_unmount_info), 0))
2373 else if (errno == EROFS)
2375 else if (errno == EACCES || errno == EPERM)
2376 return WIMLIB_ERR_NOT_PERMITTED_TO_UNMOUNT;
2378 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2382 do_unmount_discard(const char *dir)
2385 struct wimfs_unmount_info unmount_info;
2387 memset(&unmount_info, 0, sizeof(unmount_info));
2389 ret = set_unmount_info(dir, &unmount_info);
2392 return do_unmount(dir);
2395 /* Unmount a read-write mounted WIM image, committing the changes. */
2397 do_unmount_commit(const char *dir, int unmount_flags,
2398 wimlib_progress_func_t progfunc, void *progctx)
2400 struct wimfs_unmount_info unmount_info;
2402 struct commit_progress_thread_args args;
2403 pthread_t commit_progress_tid;
2406 memset(&unmount_info, 0, sizeof(unmount_info));
2407 unmount_info.unmount_flags = unmount_flags;
2409 /* The current thread will be stuck in getxattr() until the image is
2410 * committed. Create a thread to handle the progress messages. */
2412 generate_message_queue_name(unmount_info.mq_name);
2414 mq = create_message_queue(unmount_info.mq_name);
2415 if (mq == (mqd_t)-1) {
2416 ERROR_WITH_ERRNO("Can't create POSIX message queue");
2417 return WIMLIB_ERR_MQUEUE;
2420 args.progfunc = progfunc;
2421 args.progctx = progctx;
2422 ret = pthread_create(&commit_progress_tid, NULL,
2423 commit_progress_thread_proc, &args);
2426 ERROR_WITH_ERRNO("Can't create thread");
2427 ret = WIMLIB_ERR_NOMEM;
2430 unmount_info.unmount_flags |= WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS;
2433 ret = set_unmount_info(dir, &unmount_info);
2435 ret = do_unmount(dir);
2437 /* Terminate the progress thread. */
2439 mq_send(mq, empty, 0, 1);
2440 pthread_join(commit_progress_tid, NULL);
2445 mq_unlink(unmount_info.mq_name);
2451 begin_unmount(const char *dir, int unmount_flags, int *mount_flags_ret,
2452 wimlib_progress_func_t progfunc, void *progctx)
2456 int wim_filename_len;
2457 union wimlib_progress_info progress;
2459 if (getxattr(dir, "wimfs.mount_flags",
2460 &mount_flags, sizeof(int)) != sizeof(int))
2461 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2463 *mount_flags_ret = mount_flags;
2468 if (getxattr(dir, "wimfs.mounted_image",
2469 &mounted_image, sizeof(int)) != sizeof(int))
2470 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2472 wim_filename_len = getxattr(dir, "wimfs.wim_filename", NULL, 0);
2473 if (wim_filename_len < 0)
2474 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2476 char wim_filename[wim_filename_len + 1];
2477 if (getxattr(dir, "wimfs.wim_filename",
2478 wim_filename, wim_filename_len) != wim_filename_len)
2479 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2480 wim_filename[wim_filename_len] = '\0';
2482 progress.unmount.mountpoint = dir;
2483 progress.unmount.mounted_wim = wim_filename;
2484 progress.unmount.mounted_image = mounted_image;
2485 progress.unmount.mount_flags = mount_flags;
2486 progress.unmount.unmount_flags = unmount_flags;
2488 return call_progress(progfunc, WIMLIB_PROGRESS_MSG_UNMOUNT_BEGIN,
2489 &progress, progctx);
2492 /* API function documented in wimlib.h */
2494 wimlib_unmount_image_with_progress(const char *dir, int unmount_flags,
2495 wimlib_progress_func_t progfunc, void *progctx)
2500 ret = wimlib_global_init(WIMLIB_INIT_FLAG_ASSUME_UTF8);
2504 if (unmount_flags & ~(WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY |
2505 WIMLIB_UNMOUNT_FLAG_COMMIT |
2506 WIMLIB_UNMOUNT_FLAG_REBUILD |
2507 WIMLIB_UNMOUNT_FLAG_RECOMPRESS |
2508 WIMLIB_UNMOUNT_FLAG_FORCE |
2509 WIMLIB_UNMOUNT_FLAG_NEW_IMAGE))
2510 return WIMLIB_ERR_INVALID_PARAM;
2512 ret = begin_unmount(dir, unmount_flags, &mount_flags,
2517 if ((unmount_flags & WIMLIB_UNMOUNT_FLAG_COMMIT) &&
2518 (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE))
2519 return do_unmount_commit(dir, unmount_flags,
2522 return do_unmount_discard(dir);
2525 #else /* WITH_FUSE */
2529 mount_unsupported_error(void)
2531 #if defined(__WIN32__)
2532 ERROR("Sorry-- Mounting WIM images is not supported on Windows!");
2534 ERROR("wimlib was compiled with --without-fuse, which disables support "
2535 "for mounting WIMs.");
2537 return WIMLIB_ERR_UNSUPPORTED;
2541 wimlib_unmount_image_with_progress(const tchar *dir, int unmount_flags,
2542 wimlib_progress_func_t progfunc, void *progctx)
2544 return mount_unsupported_error();
2548 wimlib_mount_image(WIMStruct *wim, int image, const tchar *dir,
2549 int mount_flags, const tchar *staging_dir)
2551 return mount_unsupported_error();
2554 #endif /* !WITH_FUSE */
2557 wimlib_unmount_image(const tchar *dir, int unmount_flags)
2559 return wimlib_unmount_image_with_progress(dir, unmount_flags, NULL, NULL);