4 * This file implements mounting of WIM files using FUSE, which stands for
5 * Filesystem in Userspace. FUSE allows a filesystem to be implemented in a
6 * userspace process by implementing the filesystem primitives--- read(),
7 * write(), readdir(), etc.
11 * Copyright (C) 2012, 2013, 2014 Eric Biggers
13 * This file is part of wimlib, a library for working with WIM files.
15 * wimlib is free software; you can redistribute it and/or modify it under the
16 * terms of the GNU General Public License as published by the Free
17 * Software Foundation; either version 3 of the License, or (at your option)
20 * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
21 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
22 * A PARTICULAR PURPOSE. See the GNU General Public License for more
25 * You should have received a copy of the GNU General Public License
26 * along with wimlib; if not, see http://www.gnu.org/licenses/.
38 # error "FUSE mount not supported on Windows! Please configure --without-fuse"
41 #include "wimlib/dentry.h"
42 #include "wimlib/encoding.h"
43 #include "wimlib/metadata.h"
44 #include "wimlib/paths.h"
45 #include "wimlib/progress.h"
46 #include "wimlib/reparse.h"
47 #include "wimlib/timestamp.h"
48 #include "wimlib/unix_data.h"
49 #include "wimlib/write.h"
50 #include "wimlib/xml.h"
61 #include <sys/types.h>
65 #define FUSE_USE_VERSION 26
67 #include <attr/xattr.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 lookup table entry for the data stream that has been
101 * opened. 'num_opened_fds' of the lookup table entry tracks the number
102 * of 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 lookup table entry. */
105 struct wim_lookup_table_entry *f_lte;
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 alternate data streams are changed
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 single-instance streams in the mounted image, linked
162 * by 'struct wim_lookup_table_entry'.orig_stream_list. */
163 struct list_head orig_stream_list;
166 #define WIMFS_CTX(fuse_ctx) ((struct wimfs_context*)(fuse_ctx)->private_data)
168 /* Retrieve the context structure for the currently mounted WIM image.
170 * Note: this is a per-thread variable. It is possible for different threads to
171 * mount different images at the same time in the same process, although they
172 * must use different WIMStructs! */
173 static inline struct wimfs_context *
174 wimfs_get_context(void)
176 return WIMFS_CTX(fuse_get_context());
180 wimfs_inc_num_open_fds(void)
182 wimfs_get_context()->num_open_fds++;
186 wimfs_dec_num_open_fds(void)
188 wimfs_get_context()->num_open_fds--;
191 /* Retrieve the WIMStruct for the currently mounted WIM image. */
192 static inline WIMStruct *
193 wimfs_get_WIMStruct(void)
195 return wimfs_get_context()->wim;
199 get_lookup_flags(const struct wimfs_context *ctx)
201 return ctx->default_lookup_flags;
204 /* Is write permission requested on the file? */
206 flags_writable(int open_flags)
208 int accmode = (open_flags & O_ACCMODE);
209 return (accmode == O_RDWR || accmode == O_WRONLY);
213 fuse_mask_mode(mode_t mode, const struct fuse_context *fuse_ctx)
215 #if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 8)
216 mode &= ~fuse_ctx->umask;
222 * Allocate a file descriptor to a data stream in the mounted WIM image.
225 * A pointer to the inode containing the stream being opened.
227 * The ID of the data stream being opened within the inode.
229 * A pointer to the lookup table entry for the stream data. Or, for a
230 * 0-byte stream, this may be NULL.
232 * On success, a pointer to the new file descriptor will be stored here.
234 * Returns 0 or a -errno code.
237 alloc_wimfs_fd(struct wim_inode *inode,
239 struct wim_lookup_table_entry *lte,
240 struct wimfs_fd **fd_ret)
242 static const u16 min_fds_per_alloc = 8;
243 static const u16 max_fds = 0xffff;
247 if (inode->i_num_opened_fds == inode->i_num_allocated_fds) {
249 struct wimfs_fd **fds;
251 /* Expand this inode's file descriptor table. */
253 num_new_fds = max(min_fds_per_alloc,
254 inode->i_num_allocated_fds / 4);
256 num_new_fds = min(num_new_fds,
257 max_fds - inode->i_num_allocated_fds);
259 if (num_new_fds == 0)
262 fds = REALLOC(inode->i_fds,
263 (inode->i_num_allocated_fds + num_new_fds) *
268 memset(&fds[inode->i_num_allocated_fds], 0,
269 num_new_fds * sizeof(fds[0]));
271 inode->i_num_allocated_fds += num_new_fds;
272 inode->i_next_fd = inode->i_num_opened_fds;
275 /* Allocate the file descriptor in the first available space in the
276 * inode's file descriptor table.
278 * i_next_fd is the lower bound on the next open slot. */
279 for (i = inode->i_next_fd; inode->i_fds[i]; i++)
282 fd = MALLOC(sizeof(*fd));
288 filedes_invalidate(&fd->f_staging_fd);
290 fd->f_stream_id = stream_id;
292 inode->i_fds[i] = fd;
293 inode->i_num_opened_fds++;
295 lte->num_opened_fds++;
296 wimfs_inc_num_open_fds();
297 inode->i_next_fd = i + 1;
302 * Close a file descriptor to a data stream in the mounted WIM image.
304 * Returns 0 or a -errno code. The file descriptor is always closed.
307 close_wimfs_fd(struct wimfs_fd *fd)
310 struct wim_inode *inode;
312 /* Close the staging file if open. */
313 if (filedes_valid(&fd->f_staging_fd))
314 if (filedes_close(&fd->f_staging_fd))
317 /* Release this file descriptor from its lookup table entry. */
319 lte_decrement_num_opened_fds(fd->f_lte);
321 wimfs_dec_num_open_fds();
323 /* Release this file descriptor from its inode. */
325 inode->i_fds[fd->f_idx] = NULL;
326 if (fd->f_idx < inode->i_next_fd)
327 inode->i_next_fd = fd->f_idx;
329 if (--inode->i_num_opened_fds == 0) {
330 /* The last file descriptor to this inode was closed. */
333 inode->i_num_allocated_fds = 0;
334 if (inode->i_nlink == 0)
335 /* No links to this inode remain. Get rid of it. */
342 * Translate a path into the corresponding inode in the mounted WIM image.
344 * See get_dentry() for more information.
346 * Returns a pointer to the resulting inode, or NULL with errno set.
348 static struct wim_inode *
349 wim_pathname_to_inode(WIMStruct *wim, const char *path)
351 struct wim_dentry *dentry;
353 dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
356 return dentry->d_inode;
360 * Create a new file in the mounted WIM image.
363 * The FUSE context for the mounted image.
365 * The path at which to create the first link to the new file. If a file
366 * already exists at this path, -EEXIST is returned.
368 * The UNIX mode for the new file. This is only honored if
369 * WIMLIB_MOUNT_FLAG_UNIX_DATA was passed to wimlib_mount_image().
371 * The device ID for the new file, encoding the major and minor device
372 * numbers. This is only honored if WIMLIB_MOUNT_FLAG_UNIX_DATA was passed
373 * to wimlib_mount_image().
375 * Windows file attributes to use for the new file.
377 * On success, a pointer to the new dentry is returned here. Its d_inode
378 * member will point to the new inode that was created for it and added to
379 * the mounted WIM image.
381 * Returns 0 or a -errno code.
384 create_dentry(struct fuse_context *fuse_ctx, const char *path,
385 mode_t mode, dev_t rdev, u32 attributes,
386 struct wim_dentry **dentry_ret)
388 struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
389 struct wim_dentry *parent;
390 const char *basename;
391 struct wim_dentry *new_dentry;
392 struct wim_inode *new_inode;
394 parent = get_parent_dentry(wimfs_ctx->wim, path, WIMLIB_CASE_SENSITIVE);
398 if (!dentry_is_directory(parent))
401 basename = path_basename(path);
403 if (get_dentry_child_with_name(parent, basename, WIMLIB_CASE_SENSITIVE))
406 if (new_dentry_with_inode(basename, &new_dentry))
409 new_inode = new_dentry->d_inode;
411 new_inode->i_resolved = 1;
412 new_inode->i_ino = wimfs_ctx->next_ino++;
413 new_inode->i_attributes = attributes;
415 if (wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) {
416 struct wimlib_unix_data unix_data;
418 unix_data.uid = fuse_ctx->uid;
419 unix_data.gid = fuse_ctx->gid;
420 unix_data.mode = fuse_mask_mode(mode, fuse_ctx);
421 unix_data.rdev = rdev;
422 if (!inode_set_unix_data(new_inode, &unix_data, UNIX_DATA_ALL))
424 free_dentry(new_dentry);
429 list_add_tail(&new_inode->i_list,
430 &wim_get_current_image_metadata(wimfs_ctx->wim)->inode_list);
432 dentry_add_child(parent, new_dentry);
435 *dentry_ret = new_dentry;
440 * Remove a dentry from the mounted WIM image; i.e. remove an alias for an
444 remove_dentry(struct wim_dentry *dentry,
445 struct wim_lookup_table *lookup_table)
447 /* Drop the reference to each stream the inode contains. */
448 inode_unref_streams(dentry->d_inode, lookup_table);
450 /* Unlink the dentry from the image's dentry tree. */
451 unlink_dentry(dentry);
453 /* Delete the dentry. This will also decrement the link count of the
454 * corresponding inode, and possibly cause it to be deleted as well. */
458 /* Generate UNIX filetype mode bits for the specified WIM inode, based on its
459 * Windows file attributes. */
461 inode_unix_file_type(const struct wim_inode *inode)
463 if (inode_is_symlink(inode))
465 else if (inode_is_directory(inode))
471 /* Generate a default UNIX mode for the specified WIM inode. */
473 inode_default_unix_mode(const struct wim_inode *inode)
475 return inode_unix_file_type(inode) | 0777;
479 * Retrieve standard UNIX metadata ('struct stat') for a WIM inode.
481 * @lte specifies the stream of the inode that is being queried. We mostly
482 * return the same information for all streams, but st_size and st_blocks may be
483 * different for different streams.
485 * This always returns 0.
488 inode_to_stbuf(const struct wim_inode *inode,
489 const struct wim_lookup_table_entry *lte,
492 const struct wimfs_context *ctx = wimfs_get_context();
493 struct wimlib_unix_data unix_data;
495 memset(stbuf, 0, sizeof(struct stat));
496 if ((ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) &&
497 inode_get_unix_data(inode, &unix_data))
499 /* Use the user ID, group ID, mode, and device ID from the
500 * inode's extra UNIX metadata information. */
501 stbuf->st_uid = unix_data.uid;
502 stbuf->st_gid = unix_data.gid;
503 stbuf->st_mode = unix_data.mode;
504 stbuf->st_rdev = unix_data.rdev;
506 /* Generate default values for the user ID, group ID, and mode.
508 * Note: in the case of an allow_other mount, fuse_context.uid
509 * may not be the same as wimfs_context.owner_uid! */
510 stbuf->st_uid = ctx->owner_uid;
511 stbuf->st_gid = ctx->owner_gid;
512 stbuf->st_mode = inode_default_unix_mode(inode);
514 stbuf->st_ino = inode->i_ino;
515 stbuf->st_nlink = inode->i_nlink;
517 stbuf->st_size = lte->size;
518 #ifdef HAVE_STAT_NANOSECOND_PRECISION
519 stbuf->st_atim = wim_timestamp_to_timespec(inode->i_last_access_time);
520 stbuf->st_mtim = wim_timestamp_to_timespec(inode->i_last_write_time);
521 stbuf->st_ctim = stbuf->st_mtim;
523 stbuf->st_atime = wim_timestamp_to_unix(inode->i_last_access_time);
524 stbuf->st_mtime = wim_timestamp_to_unix(inode->i_last_write_time);
525 stbuf->st_ctime = stbuf->st_mtime;
527 stbuf->st_blocks = (stbuf->st_size + 511) / 512;
531 /* Update the last access and last write timestamps of a WIM inode. */
533 touch_inode(struct wim_inode *inode)
535 u64 now = get_wim_timestamp();
536 inode->i_last_access_time = now;
537 inode->i_last_write_time = now;
541 * Create a new file in the staging directory for a read-write mounted image.
543 * On success, returns the file descriptor for the new staging file, opened for
544 * writing. In addition, stores the allocated name of the staging file in
547 * On failure, returns -1 and sets errno.
550 create_staging_file(const struct wimfs_context *ctx, char **name_ret)
553 static const size_t STAGING_FILE_NAME_LEN = 20;
557 name = MALLOC(STAGING_FILE_NAME_LEN + 1);
560 name[STAGING_FILE_NAME_LEN] = '\0';
563 randomize_char_array_with_alnum(name, STAGING_FILE_NAME_LEN);
564 fd = openat(ctx->staging_dir_fd, name,
565 O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0600);
566 if (unlikely(fd < 0)) {
567 if (unlikely(errno == EEXIST))
568 /* Try again with another name. */
578 * Extract a WIM resource to the staging directory.
579 * This is necessary if a stream using the resource is being opened for writing.
582 * The inode containing the stream being opened for writing.
585 * The index of the stream in @inode being opened for writing.
588 * *lte_ptr is the lookup table entry for the stream being extracted, or
589 * NULL if the stream does not have a lookup table entry (which is possible
590 * if the stream is empty). On success, *lte_ptr will be set to point to a
591 * lookup table entry that represents the resource in its new location in a
592 * staging file. This may be the same as the old entry in the case that it
593 * was reused, or it may be a new entry.
596 * Number of bytes of the stream to extract and include in the staging file
597 * resource. It may be less than the actual stream length, in which case
598 * only a prefix of the resource will be extracted. It may also be more
599 * than the actual stream length, in which case the extra space will be
602 * Returns 0 or a -errno code.
605 extract_resource_to_staging_dir(struct wim_inode *inode,
607 struct wim_lookup_table_entry **lte_ptr,
609 const struct wimfs_context *ctx)
611 struct wim_lookup_table_entry *old_lte;
612 struct wim_lookup_table_entry *new_lte;
613 char *staging_file_name;
622 /* Create the staging file. */
623 staging_fd = create_staging_file(ctx, &staging_file_name);
624 if (unlikely(staging_fd < 0))
627 /* Extract the stream to the staging file (possibly truncated). */
631 filedes_init(&fd, staging_fd);
633 extract_size = min(old_lte->size, size);
634 result = extract_stream_to_fd(old_lte, &fd, extract_size);
640 /* In the case of truncate() to more than the file length, extend the
641 * staging file with zeroes by calling ftruncate(). */
642 if (!result && size > extract_size)
643 result = ftruncate(staging_fd, size);
645 /* Close the staging file. */
646 if (close(staging_fd))
649 /* If an error occurred, unlink the staging file. */
650 if (unlikely(result)) {
651 /* extract_stream_to_fd() should set errno, but if it didn't,
652 * set a default value. */
653 ret = errno ? -errno : -EIO;
654 goto out_delete_staging_file;
657 /* Now deal with the lookup table entries. We may be able to re-use the
658 * existing entry, but we may have to create a new one instead. */
660 stream_id = inode_stream_idx_to_id(inode, stream_idx);
662 if (old_lte && inode->i_nlink == old_lte->refcnt) {
663 /* The reference count of the existing lookup table entry is the
664 * same as the link count of the inode that contains the stream
665 * we're opening. Therefore, all the references to the lookup
666 * table entry correspond to the stream we're trying to extract,
667 * so the lookup table entry can be re-used. */
668 lookup_table_unlink(ctx->wim->lookup_table, old_lte);
669 lte_put_resource(old_lte);
672 /* We need to split the old lookup table entry because it also
673 * has other references. Or, there was no old lookup table
674 * entry, so we need to create a new one anyway. */
676 new_lte = new_lookup_table_entry();
677 if (unlikely(!new_lte)) {
679 goto out_delete_staging_file;
682 /* There may already be open file descriptors to this stream if
683 * it's previously been opened read-only, but just now we're
684 * opening it read-write. Identify those file descriptors and
685 * change their lookup table entry pointers to point to the new
686 * lookup table entry, and open staging file descriptors for
689 * At the same time, we need to count the number of these opened
690 * file descriptors to the new lookup table entry. If there's
691 * an old lookup table entry, this number needs to be subtracted
692 * from the fd's opened to the old entry. */
693 for (u16 i = 0, j = 0; j < inode->i_num_opened_fds; i++) {
697 fd = inode->i_fds[i];
703 if (fd->f_stream_id != stream_id)
706 /* This is a readonly fd for the same stream. */
708 new_lte->num_opened_fds++;
709 raw_fd = openat(ctx->staging_dir_fd, staging_file_name,
710 O_RDONLY | O_NOFOLLOW);
711 if (unlikely(raw_fd < 0)) {
713 goto out_revert_fd_changes;
715 filedes_init(&fd->f_staging_fd, raw_fd);
718 old_lte->num_opened_fds -= new_lte->num_opened_fds;
719 old_lte->refcnt -= inode->i_nlink;
723 new_lte->refcnt = inode->i_nlink;
724 new_lte->resource_location = RESOURCE_IN_STAGING_FILE;
725 new_lte->staging_file_name = staging_file_name;
726 new_lte->staging_dir_fd = ctx->staging_dir_fd;
727 new_lte->size = size;
729 add_unhashed_stream(new_lte, inode, stream_id,
730 &wim_get_current_image_metadata(ctx->wim)->unhashed_streams);
732 inode->i_lte = new_lte;
734 inode->i_ads_entries[stream_idx - 1].lte = new_lte;
738 out_revert_fd_changes:
739 for (u16 i = 0; new_lte->num_opened_fds; i++) {
740 struct wimfs_fd *fd = inode->i_fds[i];
741 if (fd && fd->f_stream_id == stream_id) {
743 if (filedes_valid(&fd->f_staging_fd)) {
744 filedes_close(&fd->f_staging_fd);
745 filedes_invalidate(&fd->f_staging_fd);
747 new_lte->num_opened_fds--;
750 free_lookup_table_entry(new_lte);
751 out_delete_staging_file:
752 unlinkat(ctx->staging_dir_fd, staging_file_name, 0);
753 FREE(staging_file_name);
758 * Create the staging directory for the WIM file.
760 * The staging directory will be created in the directory specified by the open
761 * file descriptor @parent_dir_fd. It will be given a randomly generated name
762 * based on @wim_basename, the name of the WIM file.
764 * On success, returns a file descriptor to the open staging directory with
765 * O_RDONLY access. In addition, stores the allocated name of the staging
766 * directory (relative to @parent_dir_fd) in @staging_dir_name_ret.
767 * On failure, returns -1 and sets errno.
770 make_staging_dir_at(int parent_dir_fd, const char *wim_basename,
771 char **staging_dir_name_ret)
773 static const char common_suffix[8] = ".staging";
774 static const size_t random_suffix_len = 10;
775 size_t wim_basename_len;
776 size_t staging_dir_name_len;
777 char *staging_dir_name;
781 wim_basename_len = strlen(wim_basename);
782 staging_dir_name_len = wim_basename_len + sizeof(common_suffix) +
784 staging_dir_name = MALLOC(staging_dir_name_len + 1);
785 if (!staging_dir_name)
788 p = staging_dir_name;
789 p = mempcpy(p, wim_basename, wim_basename_len);
790 p = mempcpy(p, common_suffix, sizeof(common_suffix));
791 randomize_char_array_with_alnum(p, random_suffix_len);
792 p += random_suffix_len;
795 if (mkdirat(parent_dir_fd, staging_dir_name, 0700))
798 fd = openat(parent_dir_fd, staging_dir_name,
799 O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
803 *staging_dir_name_ret = staging_dir_name;
807 unlinkat(parent_dir_fd, staging_dir_name, AT_REMOVEDIR);
809 FREE(staging_dir_name);
814 * Create the staging directory and set ctx->staging_dir_fd,
815 * ctx->staging_dir_name, and ctx->parent_dir_fd.
818 make_staging_dir(struct wimfs_context *ctx, const char *parent_dir_path)
820 const char *wim_basename;
824 wim_basename = path_basename(ctx->wim->filename);
826 if (!parent_dir_path) {
827 /* The user did not specify a directory. Default to creating
828 * the staging directory alongside the WIM file. */
829 if (wim_basename > ctx->wim->filename) {
830 parent_dir_path = ctx->wim->filename;
831 end = (char *)(wim_basename - 1);
832 /* *end must be a slash. Temporarily overwrite it so we
833 * can open the parent directory. */
836 parent_dir_path = ".";
840 /* Open the parent directory (in which we'll create our staging
842 ctx->parent_dir_fd = open(parent_dir_path, O_RDONLY | O_DIRECTORY);
843 if (ctx->parent_dir_fd < 0) {
844 ERROR_WITH_ERRNO("Can't open directory \"%s\"",
846 ret = WIMLIB_ERR_OPENDIR;
847 goto out_restore_wim_filename;
850 ctx->staging_dir_fd = make_staging_dir_at(ctx->parent_dir_fd,
852 &ctx->staging_dir_name);
853 if (ctx->staging_dir_fd < 0) {
854 ERROR_WITH_ERRNO("Can't create staging directory in \"%s\"",
856 close(ctx->parent_dir_fd);
857 ret = WIMLIB_ERR_MKDIR;
858 goto out_restore_wim_filename;
861 out_restore_wim_filename:
867 /* Deletes the staging directory, undoing the effects of a succesful call to
868 * make_staging_dir(). */
870 delete_staging_dir(struct wimfs_context *ctx)
875 dir = fdopendir(ctx->staging_dir_fd);
877 while ((ent = readdir(dir)))
878 unlinkat(ctx->staging_dir_fd, ent->d_name, 0);
881 close(ctx->staging_dir_fd);
883 if (unlinkat(ctx->parent_dir_fd, ctx->staging_dir_name, AT_REMOVEDIR))
884 WARNING_WITH_ERRNO("Could not delete staging directory");
885 FREE(ctx->staging_dir_name);
886 close(ctx->parent_dir_fd);
890 reassign_inode_numbers(struct wimfs_context *ctx)
892 struct wim_image_metadata *imd;
893 struct wim_inode *inode;
896 imd = wim_get_current_image_metadata(ctx->wim);
897 image_for_each_inode(inode, imd)
898 inode->i_ino = ctx->next_ino++;
902 release_extra_refcnts(struct wimfs_context *ctx)
904 struct list_head *list = &ctx->orig_stream_list;
905 struct wim_lookup_table *lookup_table = ctx->wim->lookup_table;
906 struct wim_lookup_table_entry *lte, *tmp;
908 list_for_each_entry_safe(lte, tmp, list, orig_stream_list) {
909 u32 n = lte->out_refcnt;
911 lte_decrement_refcnt(lte, lookup_table);
916 delete_empty_streams(struct wimfs_context *ctx)
918 struct wim_lookup_table_entry *lte, *tmp;
919 struct wim_image_metadata *imd;
921 imd = wim_get_current_image_metadata(ctx->wim);
923 image_for_each_unhashed_stream_safe(lte, tmp, imd) {
925 *retrieve_lte_pointer(lte) = NULL;
926 list_del(<e->unhashed_list);
927 free_lookup_table_entry(lte);
933 inode_close_fds(struct wim_inode *inode)
935 u16 num_open_fds = inode->i_num_opened_fds;
936 for (u16 i = 0; num_open_fds; i++) {
937 if (inode->i_fds[i]) {
938 close_wimfs_fd(inode->i_fds[i]);
945 close_all_fds(struct wimfs_context *ctx)
947 struct wim_inode *inode, *tmp;
948 struct wim_image_metadata *imd;
950 imd = wim_get_current_image_metadata(ctx->wim);
952 list_for_each_entry_safe(inode, tmp, &imd->inode_list, i_list)
953 inode_close_fds(inode);
956 /* Moves the currently selected image, which may have been modified, to a new
957 * index, and sets the original index to refer to a reset (unmodified) copy of
960 renew_current_image(struct wimfs_context *ctx)
962 WIMStruct *wim = ctx->wim;
963 int idx = wim->current_image - 1;
964 struct wim_image_metadata *imd = wim->image_metadata[idx];
965 struct wim_image_metadata *replace_imd;
966 struct wim_lookup_table_entry *new_lte;
969 /* Create 'replace_imd' structure to use for the reset original,
970 * unmodified image. */
971 ret = WIMLIB_ERR_NOMEM;
972 replace_imd = new_image_metadata();
976 /* Create new stream reference for the modified image's metadata
977 * resource, which doesn't exist yet. */
978 ret = WIMLIB_ERR_NOMEM;
979 new_lte = new_lookup_table_entry();
981 goto err_put_replace_imd;
982 new_lte->flags = WIM_RESHDR_FLAG_METADATA;
983 new_lte->unhashed = 1;
985 /* Make the image being moved available at a new index. Increments the
986 * WIM's image count, but does not increment the reference count of the
987 * 'struct image_metadata'. */
988 ret = append_image_metadata(wim, imd);
990 goto err_free_new_lte;
992 ret = xml_add_image(wim, T(""));
994 goto err_undo_append;
996 replace_imd->metadata_lte = imd->metadata_lte;
997 imd->metadata_lte = new_lte;
998 wim->image_metadata[idx] = replace_imd;
999 wim->current_image = wim->hdr.image_count;
1003 wim->hdr.image_count--;
1005 free_lookup_table_entry(new_lte);
1006 err_put_replace_imd:
1007 put_image_metadata(replace_imd, NULL);
1012 static enum wimlib_progress_status
1013 commit_progress_func(enum wimlib_progress_msg msg,
1014 union wimlib_progress_info *info, void *progctx)
1016 mqd_t mq = *(mqd_t *)progctx;
1017 struct commit_progress_report report;
1019 memset(&report, 0, sizeof(report));
1022 report.info = *info;
1023 mq_send(mq, (const char *)&report, sizeof(report), 1);
1024 return WIMLIB_PROGRESS_STATUS_CONTINUE;
1027 /* Commit the mounted image to the underlying WIM file. */
1029 commit_image(struct wimfs_context *ctx, int unmount_flags, mqd_t mq)
1033 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS)
1034 wimlib_register_progress_function(ctx->wim,
1035 commit_progress_func, &mq);
1037 wimlib_register_progress_function(ctx->wim, NULL, NULL);
1039 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_NEW_IMAGE) {
1040 int ret = renew_current_image(ctx);
1044 release_extra_refcnts(ctx);
1046 INIT_LIST_HEAD(&ctx->orig_stream_list);
1047 delete_empty_streams(ctx);
1048 xml_update_image_info(ctx->wim, ctx->wim->current_image);
1051 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY)
1052 write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
1053 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_REBUILD)
1054 write_flags |= WIMLIB_WRITE_FLAG_REBUILD;
1055 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_RECOMPRESS)
1056 write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
1057 return wimlib_overwrite(ctx->wim, write_flags, 0);
1061 unmount_wimfs(const struct wimfs_unmount_info *info)
1063 struct fuse_context *fuse_ctx = fuse_get_context();
1064 struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1065 int unmount_flags = info->unmount_flags;
1066 mqd_t mq = (mqd_t)-1;
1069 if (fuse_ctx->uid != wimfs_ctx->owner_uid &&
1073 if (info->mq_name[0]) {
1074 mq = mq_open(info->mq_name, O_WRONLY | O_NONBLOCK);
1075 if (mq == (mqd_t)-1)
1079 /* Ignore COMMIT if the image is mounted read-only. */
1080 if (!(wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_READWRITE))
1081 unmount_flags &= ~WIMLIB_UNMOUNT_FLAG_COMMIT;
1083 if (wimfs_ctx->num_open_fds) {
1084 if ((unmount_flags & (WIMLIB_UNMOUNT_FLAG_COMMIT |
1085 WIMLIB_UNMOUNT_FLAG_FORCE))
1086 == WIMLIB_UNMOUNT_FLAG_COMMIT)
1088 status = WIMLIB_ERR_MOUNTED_IMAGE_IS_BUSY;
1089 goto out_send_status;
1091 close_all_fds(wimfs_ctx);
1094 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_COMMIT)
1095 status = commit_image(wimfs_ctx, unmount_flags, mq);
1098 fuse_exit(fuse_ctx->fuse);
1100 if (mq != (mqd_t)-1) {
1101 mq_send(mq, (const char *)&status, sizeof(int), 1);
1108 wimfs_chmod(const char *path, mode_t mask)
1110 const struct wimfs_context *ctx = wimfs_get_context();
1111 struct wim_inode *inode;
1112 struct wimlib_unix_data unix_data;
1114 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
1117 inode = wim_pathname_to_inode(ctx->wim, path);
1121 unix_data.uid = ctx->owner_uid;
1122 unix_data.gid = ctx->owner_gid;
1123 unix_data.mode = mask;
1126 if (!inode_set_unix_data(inode, &unix_data, UNIX_DATA_MODE))
1133 wimfs_chown(const char *path, uid_t uid, gid_t gid)
1135 const struct wimfs_context *ctx = wimfs_get_context();
1136 struct wim_inode *inode;
1137 struct wimlib_unix_data unix_data;
1140 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
1143 inode = wim_pathname_to_inode(ctx->wim, path);
1149 if (uid != (uid_t)-1)
1150 which |= UNIX_DATA_UID;
1152 uid = ctx->owner_uid;
1154 if (gid != (gid_t)-1)
1155 which |= UNIX_DATA_GID;
1157 gid = ctx->owner_gid;
1159 unix_data.uid = uid;
1160 unix_data.gid = gid;
1161 unix_data.mode = inode_default_unix_mode(inode);
1164 if (!inode_set_unix_data(inode, &unix_data, which))
1171 wimfs_fgetattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi)
1173 struct wimfs_fd *fd = WIMFS_FD(fi);
1174 return inode_to_stbuf(fd->f_inode, fd->f_lte, stbuf);
1178 wimfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi)
1180 struct wimfs_fd *fd = WIMFS_FD(fi);
1181 if (ftruncate(fd->f_staging_fd.fd, size))
1183 touch_inode(fd->f_inode);
1184 fd->f_lte->size = size;
1189 wimfs_getattr(const char *path, struct stat *stbuf)
1191 const struct wimfs_context *ctx = wimfs_get_context();
1192 struct wim_dentry *dentry;
1193 struct wim_lookup_table_entry *lte;
1196 ret = wim_pathname_to_stream(ctx->wim, path,
1197 get_lookup_flags(ctx) |
1198 LOOKUP_FLAG_DIRECTORY_OK,
1199 &dentry, <e, NULL);
1202 return inode_to_stbuf(dentry->d_inode, lte, stbuf);
1206 copy_xattr(char *dest, size_t destsize, const void *src, size_t srcsize)
1210 if (destsize < srcsize)
1212 memcpy(dest, src, srcsize);
1217 wimfs_getxattr(const char *path, const char *name, char *value,
1220 struct fuse_context *fuse_ctx = fuse_get_context();
1221 const struct wimfs_context *ctx = WIMFS_CTX(fuse_ctx);
1222 struct wim_inode *inode;
1223 struct wim_ads_entry *ads_entry;
1224 struct wim_lookup_table_entry *lte;
1226 if (!strncmp(name, "wimfs.", 6)) {
1227 /* Handle some magical extended attributes. These really should
1228 * be ioctls, but directory ioctls aren't supported until
1229 * libfuse 2.9, and even then they are broken. */
1231 if (!strcmp(name, "wim_filename")) {
1232 return copy_xattr(value, size, ctx->wim->filename,
1233 strlen(ctx->wim->filename));
1235 if (!strcmp(name, "wim_info")) {
1236 struct wimlib_wim_info info;
1238 wimlib_get_wim_info(ctx->wim, &info);
1240 return copy_xattr(value, size, &info, sizeof(info));
1242 if (!strcmp(name, "mounted_image")) {
1243 return copy_xattr(value, size,
1244 &ctx->wim->current_image, sizeof(int));
1246 if (!strcmp(name, "mount_flags")) {
1247 return copy_xattr(value, size,
1248 &ctx->mount_flags, sizeof(int));
1250 if (!strcmp(name, "unmount")) {
1251 struct wimfs_unmount_info info;
1252 memset(&info, 0, sizeof(info));
1253 return unmount_wimfs(&info);
1258 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1261 if (strncmp(name, "user.", 5))
1265 /* Querying a named data stream */
1267 inode = wim_pathname_to_inode(ctx->wim, path);
1271 ads_entry = inode_get_ads_entry(inode, name);
1273 return (errno == ENOENT) ? -ENOATTR : -errno;
1275 lte = ads_entry->lte;
1279 if (unlikely(lte->size > INT_MAX))
1283 if (lte->size > size)
1286 if (read_full_stream_into_buf(lte, value))
1293 wimfs_link(const char *existing_path, const char *new_path)
1295 WIMStruct *wim = wimfs_get_WIMStruct();
1296 const char *new_name;
1297 struct wim_inode *inode;
1298 struct wim_dentry *dir;
1299 struct wim_dentry *new_alias;
1301 inode = wim_pathname_to_inode(wim, existing_path);
1305 if (inode->i_attributes & (FILE_ATTRIBUTE_DIRECTORY |
1306 FILE_ATTRIBUTE_REPARSE_POINT))
1309 new_name = path_basename(new_path);
1311 dir = get_parent_dentry(wim, new_path, WIMLIB_CASE_SENSITIVE);
1315 if (!dentry_is_directory(dir))
1318 if (get_dentry_child_with_name(dir, new_name, WIMLIB_CASE_SENSITIVE))
1321 if (new_dentry(new_name, &new_alias))
1324 new_alias->d_inode = inode;
1325 inode_add_dentry(new_alias, inode);
1326 dentry_add_child(dir, new_alias);
1328 inode_ref_streams(inode);
1333 wimfs_listxattr(const char *path, char *list, size_t size)
1335 const struct wimfs_context *ctx = wimfs_get_context();
1336 const struct wim_inode *inode;
1338 char *end = list + size;
1341 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1344 /* List named data streams, or get the list size. We report each named
1345 * data stream "X" as an extended attribute "user.X". */
1347 inode = wim_pathname_to_inode(ctx->wim, path);
1351 for (u16 i = 0; i < inode->i_num_ads; i++) {
1352 const struct wim_ads_entry *entry;
1353 char *stream_name_mbs;
1354 size_t stream_name_mbs_nbytes;
1356 entry = &inode->i_ads_entries[i];
1358 if (!entry->stream_name_nbytes)
1361 if (utf16le_to_tstr(entry->stream_name,
1362 entry->stream_name_nbytes,
1364 &stream_name_mbs_nbytes))
1367 if (unlikely(INT_MAX - total_size < stream_name_mbs_nbytes + 6)) {
1368 FREE(stream_name_mbs);
1372 total_size += stream_name_mbs_nbytes + 6;
1374 if (end - p < stream_name_mbs_nbytes + 6) {
1375 FREE(stream_name_mbs);
1378 p = mempcpy(p, "user.", 5);
1379 p = mempcpy(p, stream_name_mbs, stream_name_mbs_nbytes);
1382 FREE(stream_name_mbs);
1388 wimfs_mkdir(const char *path, mode_t mode)
1390 /* Note: according to fuse.h, mode may not include S_IFDIR */
1391 return create_dentry(fuse_get_context(), path, mode | S_IFDIR, 0,
1392 FILE_ATTRIBUTE_DIRECTORY, NULL);
1396 wimfs_mknod(const char *path, mode_t mode, dev_t rdev)
1398 struct fuse_context *fuse_ctx = fuse_get_context();
1399 struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1400 const char *stream_name;
1402 if ((wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
1403 && (stream_name = path_stream_name(path)))
1405 struct wim_ads_entry *old_entry;
1406 struct wim_ads_entry *new_entry;
1407 struct wim_inode *inode;
1410 /* Create a named data stream. */
1415 p = (char *)stream_name - 1;
1418 inode = wim_pathname_to_inode(wimfs_ctx->wim, path);
1423 old_entry = inode_get_ads_entry(inode, stream_name);
1426 if (errno != ENOENT)
1429 new_entry = inode_add_ads(inode, stream_name);
1434 /* Create a regular file, device node, named pipe, or socket.
1437 if (!S_ISREG(mode) &&
1438 !(wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
1441 /* Note: we still use FILE_ATTRIBUTE_NORMAL for device nodes,
1442 * named pipes, and sockets. The real mode is in the UNIX
1444 return create_dentry(fuse_ctx, path, mode, rdev,
1445 FILE_ATTRIBUTE_NORMAL, NULL);
1450 wimfs_open(const char *path, struct fuse_file_info *fi)
1452 struct wimfs_context *ctx = wimfs_get_context();
1453 struct wim_dentry *dentry;
1454 struct wim_inode *inode;
1455 struct wim_lookup_table_entry *lte;
1457 struct wimfs_fd *fd;
1460 ret = wim_pathname_to_stream(ctx->wim, path, get_lookup_flags(ctx),
1461 &dentry, <e, &stream_idx);
1465 inode = dentry->d_inode;
1467 /* The file resource may be in the staging directory (read-write mounts
1468 * only) or in the WIM. If it's in the staging directory, we need to
1469 * open a native file descriptor for the corresponding file. Otherwise,
1470 * we can read the file resource directly from the WIM file if we are
1471 * opening it read-only, but we need to extract the resource to the
1472 * staging directory if we are opening it writable. */
1474 if (flags_writable(fi->flags) &&
1475 (!lte || lte->resource_location != RESOURCE_IN_STAGING_FILE)) {
1476 ret = extract_resource_to_staging_dir(inode,
1479 lte ? lte->size : 0,
1485 ret = alloc_wimfs_fd(inode, inode_stream_idx_to_id(inode, stream_idx),
1490 if (lte && lte->resource_location == RESOURCE_IN_STAGING_FILE) {
1493 raw_fd = openat(lte->staging_dir_fd, lte->staging_file_name,
1494 (fi->flags & O_ACCMODE) | O_NOFOLLOW);
1499 filedes_init(&fd->f_staging_fd, raw_fd);
1501 fi->fh = (uintptr_t)fd;
1506 wimfs_opendir(const char *path, struct fuse_file_info *fi)
1508 WIMStruct *wim = wimfs_get_WIMStruct();
1509 struct wim_inode *inode;
1510 struct wimfs_fd *fd;
1513 inode = wim_pathname_to_inode(wim, path);
1516 if (!inode_is_directory(inode))
1518 ret = alloc_wimfs_fd(inode, 0, NULL, &fd);
1521 fi->fh = (uintptr_t)fd;
1526 wimfs_read(const char *path, char *buf, size_t size,
1527 off_t offset, struct fuse_file_info *fi)
1529 struct wimfs_fd *fd = WIMFS_FD(fi);
1530 const struct wim_lookup_table_entry *lte;
1537 if (offset >= lte->size)
1540 if (size > lte->size - offset)
1541 size = lte->size - offset;
1546 switch (lte->resource_location) {
1547 case RESOURCE_IN_WIM:
1548 if (read_partial_wim_stream_into_buf(lte, size, offset, buf))
1553 case RESOURCE_IN_STAGING_FILE:
1554 ret = raw_pread(&fd->f_staging_fd, buf, size, offset);
1558 case RESOURCE_IN_ATTACHED_BUFFER:
1559 memcpy(buf, lte->attached_buffer + offset, size);
1570 wimfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
1571 off_t offset, struct fuse_file_info *fi)
1573 struct wimfs_fd *fd = WIMFS_FD(fi);
1574 const struct wim_inode *inode;
1575 const struct wim_dentry *child;
1578 inode = fd->f_inode;
1580 ret = filler(buf, ".", NULL, 0);
1583 ret = filler(buf, "..", NULL, 0);
1587 for_inode_child(child, inode) {
1588 char *file_name_mbs;
1589 size_t file_name_mbs_nbytes;
1591 ret = utf16le_to_tstr(child->file_name,
1592 child->file_name_nbytes,
1594 &file_name_mbs_nbytes);
1598 ret = filler(buf, file_name_mbs, NULL, 0);
1599 FREE(file_name_mbs);
1607 wimfs_readlink(const char *path, char *buf, size_t buf_len)
1609 WIMStruct *wim = wimfs_get_WIMStruct();
1610 const struct wim_inode *inode;
1613 inode = wim_pathname_to_inode(wim, path);
1616 if (!inode_is_symlink(inode))
1620 ret = wim_inode_readlink(inode, buf, buf_len - 1, NULL);
1624 } else if (ret == -ENAMETOOLONG) {
1625 buf[buf_len - 1] = '\0';
1630 /* We use this for both release() and releasedir(), since in both cases we
1631 * simply need to close the file descriptor. */
1633 wimfs_release(const char *path, struct fuse_file_info *fi)
1635 return close_wimfs_fd(WIMFS_FD(fi));
1639 wimfs_removexattr(const char *path, const char *name)
1641 struct wimfs_context *ctx = wimfs_get_context();
1642 struct wim_inode *inode;
1643 struct wim_ads_entry *ads_entry;
1645 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1648 if (strncmp(name, "user.", 5))
1652 /* Removing a named data stream. */
1654 inode = wim_pathname_to_inode(ctx->wim, path);
1658 ads_entry = inode_get_ads_entry(inode, name);
1660 return (errno == ENOENT) ? -ENOATTR : -errno;
1662 inode_remove_ads(inode, ads_entry, ctx->wim->lookup_table);
1667 wimfs_rename(const char *from, const char *to)
1669 return rename_wim_path(wimfs_get_WIMStruct(), from, to,
1670 WIMLIB_CASE_SENSITIVE, NULL);
1674 wimfs_rmdir(const char *path)
1676 WIMStruct *wim = wimfs_get_WIMStruct();
1677 struct wim_dentry *dentry;
1679 dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
1683 if (!dentry_is_directory(dentry))
1686 if (dentry_has_children(dentry))
1689 remove_dentry(dentry, wim->lookup_table);
1694 wimfs_setxattr(const char *path, const char *name,
1695 const char *value, size_t size, int flags)
1697 struct wimfs_context *ctx = wimfs_get_context();
1698 struct wim_inode *inode;
1699 struct wim_ads_entry *existing_entry;
1701 if (!strncmp(name, "wimfs.", 6)) {
1702 /* Handle some magical extended attributes. These really should
1703 * be ioctls, but directory ioctls aren't supported until
1704 * libfuse 2.9, and even then they are broken. */
1706 if (!strcmp(name, "unmount")) {
1707 if (size < sizeof(struct wimfs_unmount_info))
1709 return unmount_wimfs((const void *)value);
1714 if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1717 if (strncmp(name, "user.", 5))
1721 /* Setting the contents of a named data stream. */
1723 inode = wim_pathname_to_inode(ctx->wim, path);
1727 existing_entry = inode_get_ads_entry(inode, name);
1728 if (existing_entry) {
1729 if (flags & XATTR_CREATE)
1732 if (errno != ENOENT)
1734 if (flags & XATTR_REPLACE)
1738 if (!inode_add_ads_with_data(inode, name, value,
1739 size, ctx->wim->lookup_table))
1742 inode_remove_ads(inode, existing_entry, ctx->wim->lookup_table);
1747 wimfs_symlink(const char *to, const char *from)
1749 struct fuse_context *fuse_ctx = fuse_get_context();
1750 struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1751 struct wim_dentry *dentry;
1754 ret = create_dentry(fuse_ctx, from, S_IFLNK | 0777, 0,
1755 FILE_ATTRIBUTE_REPARSE_POINT, &dentry);
1758 dentry->d_inode->i_reparse_tag = WIM_IO_REPARSE_TAG_SYMLINK;
1759 ret = wim_inode_set_symlink(dentry->d_inode, to,
1760 wimfs_ctx->wim->lookup_table);
1762 remove_dentry(dentry, wimfs_ctx->wim->lookup_table);
1763 if (ret == WIMLIB_ERR_NOMEM)
1772 wimfs_truncate(const char *path, off_t size)
1774 const struct wimfs_context *ctx = wimfs_get_context();
1775 struct wim_dentry *dentry;
1776 struct wim_lookup_table_entry *lte;
1781 ret = wim_pathname_to_stream(ctx->wim, path, get_lookup_flags(ctx),
1782 &dentry, <e, &stream_idx);
1790 if (!lte || lte->resource_location != RESOURCE_IN_STAGING_FILE) {
1791 return extract_resource_to_staging_dir(dentry->d_inode,
1796 /* Truncate the staging file. */
1797 fd = openat(lte->staging_dir_fd, lte->staging_file_name,
1798 O_WRONLY | O_NOFOLLOW);
1801 ret = ftruncate(fd, size);
1802 if (close(fd) || ret)
1809 wimfs_unlink(const char *path)
1811 const struct wimfs_context *ctx = wimfs_get_context();
1812 struct wim_dentry *dentry;
1816 ret = wim_pathname_to_stream(ctx->wim, path, get_lookup_flags(ctx),
1817 &dentry, NULL, &stream_idx);
1822 if (inode_stream_name_nbytes(dentry->d_inode, stream_idx) == 0)
1823 remove_dentry(dentry, ctx->wim->lookup_table);
1825 inode_remove_ads(dentry->d_inode,
1826 &dentry->d_inode->i_ads_entries[stream_idx - 1],
1827 ctx->wim->lookup_table);
1831 #ifdef HAVE_UTIMENSAT
1833 * Change the timestamp on a file dentry.
1835 * Note that alternate data streams do not have their own timestamps.
1838 wimfs_utimens(const char *path, const struct timespec tv[2])
1840 WIMStruct *wim = wimfs_get_WIMStruct();
1841 struct wim_inode *inode;
1843 inode = wim_pathname_to_inode(wim, path);
1847 if (tv[0].tv_nsec != UTIME_OMIT) {
1848 if (tv[0].tv_nsec == UTIME_NOW)
1849 inode->i_last_access_time = get_wim_timestamp();
1851 inode->i_last_access_time = timespec_to_wim_timestamp(tv[0]);
1853 if (tv[1].tv_nsec != UTIME_OMIT) {
1854 if (tv[1].tv_nsec == UTIME_NOW)
1855 inode->i_last_write_time = get_wim_timestamp();
1857 inode->i_last_write_time = timespec_to_wim_timestamp(tv[1]);
1861 #else /* HAVE_UTIMENSAT */
1863 wimfs_utime(const char *path, struct utimbuf *times)
1865 WIMStruct *wim = wimfs_get_WIMStruct();
1866 struct wim_inode *inode;
1868 inode = wim_pathname_to_inode(wim, path);
1872 inode->i_last_access_time = unix_timestamp_to_wim(times->actime);
1873 inode->i_last_write_time = unix_timestamp_to_wim(times->modtime);
1876 #endif /* !HAVE_UTIMENSAT */
1879 wimfs_write(const char *path, const char *buf, size_t size,
1880 off_t offset, struct fuse_file_info *fi)
1882 struct wimfs_fd *fd = WIMFS_FD(fi);
1885 ret = raw_pwrite(&fd->f_staging_fd, buf, size, offset);
1889 if (offset + size > fd->f_lte->size)
1890 fd->f_lte->size = offset + size;
1892 touch_inode(fd->f_inode);
1896 static struct fuse_operations wimfs_operations = {
1897 .chmod = wimfs_chmod,
1898 .chown = wimfs_chown,
1899 .fgetattr = wimfs_fgetattr,
1900 .ftruncate = wimfs_ftruncate,
1901 .getattr = wimfs_getattr,
1902 .getxattr = wimfs_getxattr,
1904 .listxattr = wimfs_listxattr,
1905 .mkdir = wimfs_mkdir,
1906 .mknod = wimfs_mknod,
1908 .opendir = wimfs_opendir,
1910 .readdir = wimfs_readdir,
1911 .readlink = wimfs_readlink,
1912 .release = wimfs_release,
1913 .releasedir = wimfs_release,
1914 .removexattr = wimfs_removexattr,
1915 .rename = wimfs_rename,
1916 .rmdir = wimfs_rmdir,
1917 .setxattr = wimfs_setxattr,
1918 .symlink = wimfs_symlink,
1919 .truncate = wimfs_truncate,
1920 .unlink = wimfs_unlink,
1921 #ifdef HAVE_UTIMENSAT
1922 .utimens = wimfs_utimens,
1924 .utime = wimfs_utime,
1926 .write = wimfs_write,
1928 /* We keep track of file descriptor structures (struct wimfs_fd), so
1929 * there is no need to have the file path provided on operations such as
1931 #if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 8)
1932 .flag_nullpath_ok = 1,
1934 #if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 9)
1936 .flag_utime_omit_ok = 1,
1940 /* API function documented in wimlib.h */
1942 wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
1943 int mount_flags, const char *staging_dir)
1946 struct wim_image_metadata *imd;
1947 struct wimfs_context ctx;
1948 char *fuse_argv[16];
1951 if (!wim || !dir || !*dir)
1952 return WIMLIB_ERR_INVALID_PARAM;
1954 if (mount_flags & ~(WIMLIB_MOUNT_FLAG_READWRITE |
1955 WIMLIB_MOUNT_FLAG_DEBUG |
1956 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
1957 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR |
1958 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS |
1959 WIMLIB_MOUNT_FLAG_UNIX_DATA |
1960 WIMLIB_MOUNT_FLAG_ALLOW_OTHER))
1961 return WIMLIB_ERR_INVALID_PARAM;
1963 /* For read-write mount, check for write access to the WIM. */
1964 if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
1965 ret = can_delete_from_wim(wim);
1970 /* Select the image to mount. */
1971 ret = select_wim_image(wim, image);
1975 /* Get the metadata for the image to mount. */
1976 imd = wim_get_current_image_metadata(wim);
1978 if (imd->modified) {
1979 /* To avoid complicating things, we don't support mounting
1980 * images to which in-memory modifications have already been
1982 ERROR("Cannot mount a modified WIM image!");
1983 return WIMLIB_ERR_INVALID_PARAM;
1986 ret = lock_wim_for_append(wim, wim->in_fd.fd);
1990 /* If the user did not specify an interface for accessing named
1991 * data streams, use the default (extended attributes). */
1992 if (!(mount_flags & (WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
1993 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR |
1994 WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)))
1995 mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR;
1997 /* Start initializing the wimfs_context. */
1998 memset(&ctx, 0, sizeof(struct wimfs_context));
2000 ctx.mount_flags = mount_flags;
2001 if (mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
2002 ctx.default_lookup_flags = LOOKUP_FLAG_ADS_OK;
2003 /* For read-write mount, create the staging directory. */
2004 if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
2005 ret = make_staging_dir(&ctx, staging_dir);
2009 ctx.owner_uid = getuid();
2010 ctx.owner_gid = getgid();
2012 /* Add each stream referenced by files in the image to a list and
2013 * preemptively double the number of references to each. The latter is
2014 * done to allow implementing the WIMLIB_UNMOUNT_FLAG_NEW_IMAGE
2016 INIT_LIST_HEAD(&ctx.orig_stream_list);
2017 if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
2019 struct wim_inode *inode;
2020 struct wim_lookup_table_entry *lte;
2022 image_for_each_inode(inode, imd) {
2023 for (i = 0; i <= inode->i_num_ads; i++) {
2024 lte = inode_stream_lte(inode, i,
2027 lte->out_refcnt = 0;
2031 image_for_each_inode(inode, imd) {
2032 for (i = 0; i <= inode->i_num_ads; i++) {
2033 lte = inode_stream_lte(inode, i,
2036 if (lte->out_refcnt == 0)
2037 list_add(<e->orig_stream_list,
2038 &ctx.orig_stream_list);
2039 lte->out_refcnt += inode->i_nlink;
2040 lte->refcnt += inode->i_nlink;
2046 /* Assign new inode numbers. */
2047 reassign_inode_numbers(&ctx);
2049 /* If a read-write mount, mark the image as modified. */
2050 if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)
2053 /* Build the FUSE command line. */
2056 fuse_argv[fuse_argc++] = "wimlib";
2057 fuse_argv[fuse_argc++] = (char *)dir;
2059 /* Disable multi-threaded operation. */
2060 fuse_argv[fuse_argc++] = "-s";
2062 /* Enable FUSE debug mode (don't fork) if requested by the user. */
2063 if (mount_flags & WIMLIB_MOUNT_FLAG_DEBUG)
2064 fuse_argv[fuse_argc++] = "-d";
2067 * Build the FUSE mount options:
2070 * FUSE will use the inode numbers we provide. We want this,
2071 * because we have inodes and will number them ourselves.
2074 * Name for our filesystem (main type is "fuse").
2077 * If an open file is unlinked, unlink it for real rather than
2078 * renaming it to a hidden file. Our code supports this; an
2079 * unlinked inode is retained until all its file descriptors have
2082 * default_permissions
2083 * FUSE will perform permission checking. Useful when
2084 * WIMLIB_MOUNT_FLAG_UNIX_DATA is provided and the WIM image
2085 * contains the UNIX permissions for each file.
2088 * Cache the contents of files. This will speed up repeated access
2089 * to files on a mounted WIM image, since they won't need to be
2090 * decompressed repeatedly. This option is valid because data in
2091 * the WIM image should never be changed externally. (Although, if
2092 * someone really wanted to they could modify the WIM file or mess
2093 * with the staging directory; but then they're asking for
2096 * entry_timeout=1000000000
2097 * Cache positive name lookups indefinitely, since names can only
2098 * be added, removed, or modified through the mounted filesystem
2101 * negative_timeout=1000000000
2102 * Cache negative name lookups indefinitely, since names can only
2103 * be added, removed, or modified through the mounted filesystem
2107 * Don't cache file/directory attributes. This is needed as a
2108 * workaround for the fact that when caching attributes, the high
2109 * level interface to libfuse considers a file which has several
2110 * hard-linked names as several different files. (Otherwise, we
2111 * could cache our file/directory attributes indefinitely, since
2112 * they can only be changed through the mounted filesystem itself.)
2114 char optstring[256] =
2119 ",default_permissions"
2121 ",entry_timeout=1000000000"
2122 ",negative_timeout=1000000000"
2125 fuse_argv[fuse_argc++] = "-o";
2126 fuse_argv[fuse_argc++] = optstring;
2127 if (!(mount_flags & WIMLIB_MOUNT_FLAG_READWRITE))
2128 strcat(optstring, ",ro");
2129 if (mount_flags & WIMLIB_MOUNT_FLAG_ALLOW_OTHER)
2130 strcat(optstring, ",allow_other");
2131 fuse_argv[fuse_argc] = NULL;
2133 /* Mount our filesystem. */
2134 ret = fuse_main(fuse_argc, fuse_argv, &wimfs_operations, &ctx);
2136 /* Cleanup and return. */
2138 ret = WIMLIB_ERR_FUSE;
2139 release_extra_refcnts(&ctx);
2140 if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)
2141 delete_staging_dir(&ctx);
2143 unlock_wim_for_append(wim, wim->in_fd.fd);
2147 struct commit_progress_thread_args {
2149 wimlib_progress_func_t progfunc;
2155 commit_progress_thread_proc(void *_args)
2157 struct commit_progress_thread_args *args = _args;
2158 struct commit_progress_report report;
2161 args->status = WIMLIB_ERR_NOT_A_MOUNTPOINT;
2163 ret = mq_receive(args->mq,
2164 (char *)&report, sizeof(report), NULL);
2170 if (ret == sizeof(int)) {
2171 args->status = *(int *)&report;
2174 if (ret < sizeof(report))
2176 call_progress(args->progfunc, report.msg,
2177 &report.info, args->progctx);
2183 generate_message_queue_name(char name[WIMFS_MQUEUE_NAME_LEN + 1])
2186 memcpy(name + 1, "wimfs-", 6);
2187 randomize_char_array_with_alnum(name + 7, WIMFS_MQUEUE_NAME_LEN - 7);
2188 name[WIMFS_MQUEUE_NAME_LEN] = '\0';
2192 create_message_queue(const char *name, bool have_progfunc)
2194 bool am_root = (getuid() == 0);
2195 mode_t umask_save = 0;
2197 struct mq_attr attr;
2200 memset(&attr, 0, sizeof(attr));
2203 attr.mq_msgsize = sizeof(struct commit_progress_report);
2205 attr.mq_msgsize = sizeof(int);
2208 /* Filesystem mounted as normal user with --allow-other should
2209 * be able to send messages to root user, if they're doing the
2211 umask_save = umask(0);
2214 mq = mq_open(name, O_RDWR | O_CREAT | O_EXCL, mode, &attr);
2220 /* Unmount a read-write mounted WIM image, committing the changes. */
2222 do_unmount_commit(const char *dir, int unmount_flags,
2223 wimlib_progress_func_t progfunc, void *progctx)
2225 struct wimfs_unmount_info unmount_info;
2227 struct commit_progress_thread_args args;
2228 pthread_t commit_progress_tid;
2231 memset(&unmount_info, 0, sizeof(unmount_info));
2232 unmount_info.unmount_flags = unmount_flags;
2233 generate_message_queue_name(unmount_info.mq_name);
2235 mq = create_message_queue(unmount_info.mq_name, progfunc != NULL);
2236 if (mq == (mqd_t)-1) {
2237 ERROR_WITH_ERRNO("Can't create POSIX message queue");
2238 return WIMLIB_ERR_MQUEUE;
2241 /* The current thread will be stuck in setxattr() until the image is
2242 * committed. Create a thread to handle the progress messages. */
2245 args.progfunc = progfunc;
2246 args.progctx = progctx;
2247 ret = pthread_create(&commit_progress_tid, NULL,
2248 commit_progress_thread_proc, &args);
2251 ERROR_WITH_ERRNO("Can't create thread");
2252 ret = WIMLIB_ERR_NOMEM;
2255 unmount_info.unmount_flags |= WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS;
2258 if (!setxattr(dir, "wimfs.unmount",
2259 (const char *)&unmount_info, sizeof(unmount_info), 0))
2261 else if (errno == EACCES || errno == EPERM)
2262 ret = WIMLIB_ERR_NOT_PERMITTED_TO_UNMOUNT;
2264 ret = WIMLIB_ERR_NOT_A_MOUNTPOINT;
2267 /* Terminate the progress thread and retrieve final unmount
2271 mq_send(mq, (const char *)&tmp, sizeof(int), 1);
2273 pthread_join(commit_progress_tid, NULL);
2274 if (!ret && args.status != -1)
2277 /* Retrieve the final unmount status. */
2282 mq_send(mq, (const char *)&tmp, sizeof(int), 1);
2283 len = mq_receive(mq, (char *)&tmp, sizeof(int), NULL);
2285 if (len == 4 && tmp != -1)
2288 ret = WIMLIB_ERR_NOT_A_MOUNTPOINT;
2292 mq_unlink(unmount_info.mq_name);
2296 /* Unmount a read-only or read-write mounted WIM image, discarding any changes.
2299 do_unmount_discard(const char *dir)
2301 if (!getxattr(dir, "wimfs.unmount", NULL, 0))
2303 else if (errno == EACCES || errno == EPERM)
2304 return WIMLIB_ERR_NOT_PERMITTED_TO_UNMOUNT;
2306 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2310 begin_unmount(const char *dir, int unmount_flags, int *mount_flags_ret,
2311 wimlib_progress_func_t progfunc, void *progctx)
2315 int wim_filename_len;
2316 union wimlib_progress_info progress;
2318 if (getxattr(dir, "wimfs.mount_flags",
2319 &mount_flags, sizeof(int)) != sizeof(int))
2320 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2322 *mount_flags_ret = mount_flags;
2327 if (getxattr(dir, "wimfs.mounted_image",
2328 &mounted_image, sizeof(int)) != sizeof(int))
2329 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2331 wim_filename_len = getxattr(dir, "wimfs.wim_filename", NULL, 0);
2332 if (wim_filename_len < 0)
2333 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2335 char wim_filename[wim_filename_len + 1];
2336 if (getxattr(dir, "wimfs.wim_filename",
2337 wim_filename, wim_filename_len) != wim_filename_len)
2338 return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2339 wim_filename[wim_filename_len] = '\0';
2341 progress.unmount.mountpoint = dir;
2342 progress.unmount.mounted_wim = wim_filename;
2343 progress.unmount.mounted_image = mounted_image;
2344 progress.unmount.mount_flags = mount_flags;
2345 progress.unmount.unmount_flags = unmount_flags;
2347 return call_progress(progfunc, WIMLIB_PROGRESS_MSG_UNMOUNT_BEGIN,
2348 &progress, progctx);
2351 /* API function documented in wimlib.h */
2353 wimlib_unmount_image_with_progress(const char *dir, int unmount_flags,
2354 wimlib_progress_func_t progfunc, void *progctx)
2359 wimlib_global_init(WIMLIB_INIT_FLAG_ASSUME_UTF8);
2361 if (unmount_flags & ~(WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY |
2362 WIMLIB_UNMOUNT_FLAG_COMMIT |
2363 WIMLIB_UNMOUNT_FLAG_REBUILD |
2364 WIMLIB_UNMOUNT_FLAG_RECOMPRESS |
2365 WIMLIB_UNMOUNT_FLAG_FORCE |
2366 WIMLIB_UNMOUNT_FLAG_NEW_IMAGE))
2367 return WIMLIB_ERR_INVALID_PARAM;
2369 ret = begin_unmount(dir, unmount_flags, &mount_flags,
2374 if ((unmount_flags & WIMLIB_UNMOUNT_FLAG_COMMIT) &&
2375 (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE))
2376 return do_unmount_commit(dir, unmount_flags,
2379 return do_unmount_discard(dir);
2382 #else /* WITH_FUSE */
2386 mount_unsupported_error(void)
2388 #if defined(__WIN32__)
2389 ERROR("Sorry-- Mounting WIM images is not supported on Windows!");
2391 ERROR("wimlib was compiled with --without-fuse, which disables support "
2392 "for mounting WIMs.");
2394 return WIMLIB_ERR_UNSUPPORTED;
2398 wimlib_unmount_image_with_progress(const tchar *dir, int unmount_flags,
2399 wimlib_progress_func_t progfunc, void *progctx)
2401 return mount_unsupported_error();
2405 wimlib_mount_image(WIMStruct *wim, int image, const tchar *dir,
2406 int mount_flags, const tchar *staging_dir)
2408 return mount_unsupported_error();
2411 #endif /* !WITH_FUSE */
2414 wimlib_unmount_image(const tchar *dir, int unmount_flags)
2416 return wimlib_unmount_image_with_progress(dir, unmount_flags, NULL, NULL);