1 /*
2  * mount_image.c
3  *
4  * This file implements mounting of WIM images using FUSE
5  * (Filesystem in Userspace).  See http://fuse.sourceforge.net/.
6  *
7  * Currently it is only expected to work on Linux.
8  */
9 
10 /*
11  * Copyright (C) 2012-2016 Eric Biggers
12  *
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
16  * later version.
17  *
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
21  * details.
22  *
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/.
25  */
26 
27 #ifdef HAVE_CONFIG_H
28 #  include "config.h"
29 #endif
30 
31 #include "wimlib.h"
32 #include "wimlib/error.h"
33 
34 #ifdef WITH_FUSE
35 
36 #ifdef __WIN32__
37 #  error "FUSE mount not supported on Windows!  Please configure --without-fuse"
38 #endif
39 
40 #define FUSE_USE_VERSION 26
41 
42 #include <sys/types.h> /* sometimes required before <sys/xattr.h> */
43 #include <sys/xattr.h>
44 #include <dirent.h>
45 #include <errno.h>
46 #include <fuse.h>
47 #include <limits.h>
48 #include <mqueue.h>
49 #include <pthread.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <sys/stat.h>
53 #include <sys/time.h>
54 #include <unistd.h>
55 #include <utime.h>
56 
57 #include "wimlib/blob_table.h"
58 #include "wimlib/dentry.h"
59 #include "wimlib/encoding.h"
60 #include "wimlib/metadata.h"
61 #include "wimlib/paths.h"
62 #include "wimlib/progress.h"
63 #include "wimlib/reparse.h"
64 #include "wimlib/timestamp.h"
65 #include "wimlib/unix_data.h"
66 #include "wimlib/write.h"
67 #include "wimlib/xml.h"
68 
69 #ifndef O_NOFOLLOW
70 #  define O_NOFOLLOW 0  /* Security only...  */
71 #endif
72 
73 #ifndef ENOATTR
74 #  define ENOATTR ENODATA
75 #endif
76 
77 #define WIMFS_MQUEUE_NAME_LEN 32
78 
79 #define WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS 0x80000000
80 
81 struct wimfs_unmount_info {
82 	unsigned unmount_flags;
83 	char mq_name[WIMFS_MQUEUE_NAME_LEN + 1];
84 };
85 
86 struct commit_progress_report {
87 	enum wimlib_progress_msg msg;
88 	union wimlib_progress_info info;
89 };
90 
91 /* Description of an open file on a mounted WIM image.  Actually, this
92  * represents the open state of a particular data stream of an inode, rather
93  * than the inode itself.  (An inode might have multiple named data streams in
94  * addition to the default, unnamed data stream.)  At a given time, an inode in
95  * the WIM image might have multiple file descriptors open to it, each to any
96  * one of its data streams.  */
97 struct wimfs_fd {
98 
99 	/* Pointer to the inode of this open file.
100 	 * 'i_num_opened_fds' of the inode tracks the number of file descriptors
101 	 * that reference it.  */
102 	struct wim_inode *f_inode;
103 
104 	/* Pointer to the blob descriptor for the data stream that has been
105 	 * opened.  'num_opened_fds' of the blob descriptor tracks the number of
106 	 * file descriptors that reference it.  Or, this value may be NULL,
107 	 * which indicates that the opened stream is empty and consequently does
108 	 * not have a blob descriptor.  */
109 	struct blob_descriptor *f_blob;
110 
111 	/* If valid (filedes_valid(&f_staging_fd)), this contains the
112 	 * corresponding native file descriptor for the staging file that has
113 	 * been created for reading from and/or writing to this open stream.  A
114 	 * single staging file might have multiple file descriptors open to it
115 	 * simultaneously, each used by a different 'struct wimfs_fd'.
116 	 *
117 	 * Or, if invalid (!filedes_valid(&f_staging_fd)), this 'struct
118 	 * wimfs_fd' is not associated with a staging file.  This is permissible
119 	 * only if this 'struct wimfs_fd' was opened read-only and the stream
120 	 * has not yet been extracted to a staging file.  */
121 	struct filedes f_staging_fd;
122 
123 	/* 0-based index of this file descriptor in the file descriptor table of
124 	 * its inode.  */
125 	u16 f_idx;
126 
127 	/* Unique ID of the opened stream in the inode.  This will stay the same
128 	 * even if the indices of the inode's streams are changed by a deletion.
129 	 */
130 	u32 f_stream_id;
131 };
132 
133 #define WIMFS_FD(fi) ((struct wimfs_fd *)(uintptr_t)((fi)->fh))
134 
135 /* Context structure for a mounted WIM image.  */
136 struct wimfs_context {
137 	/* The WIMStruct containing the mounted image.  The mounted image is the
138 	 * currently selected image (wim->current_image).  */
139 	WIMStruct *wim;
140 
141 	/* Flags passed to wimlib_mount_image() (WIMLIB_MOUNT_FLAG_*).  */
142 	int mount_flags;
143 
144 	/* Default flags for path lookup in the WIM image.  */
145 	int default_lookup_flags;
146 
147 	/* Information about the user who has mounted the WIM image  */
148 	uid_t owner_uid;
149 	gid_t owner_gid;
150 
151 	/* Absolute path to the mountpoint directory (may be needed for absolute
152 	 * symbolic link fixups)  */
153 	char *mountpoint_abspath;
154 	size_t mountpoint_abspath_nchars;
155 
156 	/* Information about the staging directory for a read-write mount.  */
157 	int parent_dir_fd;
158 	int staging_dir_fd;
159 	char *staging_dir_name;
160 
161 	/* For read-write mounts, the inode number to be assigned to the next
162 	 * created file.  Note: since this isn't a persistent filesystem and we
163 	 * can re-assign the inode numbers just before mounting the image, it's
164 	 * good enough to just generate inode numbers sequentially.  */
165 	u64 next_ino;
166 
167 	/* Number of file descriptors open to the mounted WIM image.  */
168 	unsigned long num_open_fds;
169 
170 	/* For read-write mounts, the original metadata resource of the mounted
171 	 * image.  */
172 	struct blob_descriptor *metadata_resource;
173 
174 	/* Parameters for unmounting the image (can be set via extended
175 	 * attribute "wimfs.unmount_info").  */
176 	struct wimfs_unmount_info unmount_info;
177 };
178 
179 #define WIMFS_CTX(fuse_ctx) ((struct wimfs_context*)(fuse_ctx)->private_data)
180 
181 /* Retrieve the context structure for the currently mounted WIM image.
182  *
183  * Note: this is a per-thread variable.  It is possible for different threads to
184  * mount different images at the same time in the same process, although they
185  * must use different WIMStructs!  */
186 static inline struct wimfs_context *
wimfs_get_context(void)187 wimfs_get_context(void)
188 {
189 	return WIMFS_CTX(fuse_get_context());
190 }
191 
192 static void
wimfs_inc_num_open_fds(void)193 wimfs_inc_num_open_fds(void)
194 {
195 	wimfs_get_context()->num_open_fds++;
196 }
197 
198 static void
wimfs_dec_num_open_fds(void)199 wimfs_dec_num_open_fds(void)
200 {
201 	wimfs_get_context()->num_open_fds--;
202 }
203 
204 /* Retrieve the WIMStruct for the currently mounted WIM image.  */
205 static inline WIMStruct *
wimfs_get_WIMStruct(void)206 wimfs_get_WIMStruct(void)
207 {
208 	return wimfs_get_context()->wim;
209 }
210 
211 /* Is write permission requested on the file?  */
212 static inline bool
flags_writable(int open_flags)213 flags_writable(int open_flags)
214 {
215 	int accmode = (open_flags & O_ACCMODE);
216 	return (accmode == O_RDWR || accmode == O_WRONLY);
217 }
218 
219 static mode_t
fuse_mask_mode(mode_t mode,const struct fuse_context * fuse_ctx)220 fuse_mask_mode(mode_t mode, const struct fuse_context *fuse_ctx)
221 {
222 #if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 8)
223 	mode &= ~fuse_ctx->umask;
224 #endif
225 	return mode;
226 }
227 
228 /*
229  * Allocate a file descriptor to a data stream in the mounted WIM image.
230  *
231  * @inode
232  *	The inode containing the stream being opened
233  * @strm
234  *	The stream of the inode being opened
235  * @fd_ret
236  *	On success, a pointer to the new file descriptor will be stored here.
237  *
238  * Returns 0 or a -errno code.
239  */
240 static int
alloc_wimfs_fd(struct wim_inode * inode,struct wim_inode_stream * strm,struct wimfs_fd ** fd_ret)241 alloc_wimfs_fd(struct wim_inode *inode,
242 	       struct wim_inode_stream *strm,
243 	       struct wimfs_fd **fd_ret)
244 {
245 	static const u16 min_fds_per_alloc = 8;
246 	static const u16 max_fds = 0xffff;
247 	u16 i;
248 	struct wimfs_fd *fd;
249 
250 	if (inode->i_num_opened_fds == inode->i_num_allocated_fds) {
251 		u16 num_new_fds;
252 		struct wimfs_fd **fds;
253 
254 		/* Expand this inode's file descriptor table.  */
255 
256 		num_new_fds = max(min_fds_per_alloc,
257 				  inode->i_num_allocated_fds / 4);
258 
259 		num_new_fds = min(num_new_fds,
260 				  max_fds - inode->i_num_allocated_fds);
261 
262 		if (num_new_fds == 0)
263 			return -EMFILE;
264 
265 		fds = REALLOC(inode->i_fds,
266 			      (inode->i_num_allocated_fds + num_new_fds) *
267 			        sizeof(fds[0]));
268 		if (!fds)
269 			return -ENOMEM;
270 
271 		memset(&fds[inode->i_num_allocated_fds], 0,
272 		       num_new_fds * sizeof(fds[0]));
273 		inode->i_fds = fds;
274 		inode->i_num_allocated_fds += num_new_fds;
275 		inode->i_next_fd = inode->i_num_opened_fds;
276 	}
277 
278 	/* Allocate the file descriptor in the first available space in the
279 	 * inode's file descriptor table.
280 	 *
281 	 * i_next_fd is the lower bound on the next open slot.  */
282 	for (i = inode->i_next_fd; inode->i_fds[i]; i++)
283 		;
284 
285 	fd = MALLOC(sizeof(*fd));
286 	if (!fd)
287 		return -ENOMEM;
288 
289 	fd->f_inode     = inode;
290 	fd->f_blob      = stream_blob_resolved(strm);
291 	filedes_invalidate(&fd->f_staging_fd);
292 	fd->f_idx       = i;
293 	fd->f_stream_id	= strm->stream_id;
294 	*fd_ret         = fd;
295 	inode->i_fds[i] = fd;
296 	inode->i_num_opened_fds++;
297 	if (fd->f_blob)
298 		fd->f_blob->num_opened_fds++;
299 	wimfs_inc_num_open_fds();
300 	inode->i_next_fd = i + 1;
301 	return 0;
302 }
303 
304 /*
305  * Close a file descriptor to a data stream in the mounted WIM image.
306  *
307  * Returns 0 or a -errno code.  The file descriptor is always closed.
308  */
309 static int
close_wimfs_fd(struct wimfs_fd * fd)310 close_wimfs_fd(struct wimfs_fd *fd)
311 {
312 	int ret = 0;
313 	struct wim_inode *inode;
314 
315 	/* Close the staging file if open.  */
316 	if (filedes_valid(&fd->f_staging_fd))
317 		 if (filedes_close(&fd->f_staging_fd))
318 			 ret = -errno;
319 
320 	/* Release this file descriptor from its blob descriptor.  */
321 	if (fd->f_blob)
322 		blob_decrement_num_opened_fds(fd->f_blob);
323 
324 	wimfs_dec_num_open_fds();
325 
326 	/* Release this file descriptor from its inode.  */
327 	inode = fd->f_inode;
328 	inode->i_fds[fd->f_idx] = NULL;
329 	if (fd->f_idx < inode->i_next_fd)
330 		inode->i_next_fd = fd->f_idx;
331 	FREE(fd);
332 	inode_dec_num_opened_fds(inode);
333 	return ret;
334 }
335 
336 /*
337  * Translate a path into the corresponding inode in the mounted WIM image.
338  *
339  * See get_dentry() for more information.
340  *
341  * Returns a pointer to the resulting inode, or NULL with errno set.
342  */
343 static struct wim_inode *
wim_pathname_to_inode(WIMStruct * wim,const char * path)344 wim_pathname_to_inode(WIMStruct *wim, const char *path)
345 {
346 	struct wim_dentry *dentry;
347 
348 	dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
349 	if (!dentry)
350 		return NULL;
351 	return dentry->d_inode;
352 }
353 
354 /* Can look up named data stream with colon syntax  */
355 #define LOOKUP_FLAG_ADS_OK		0x01
356 
357 /* Can look up directory (otherwise get -ENOTDIR)  */
358 #define LOOKUP_FLAG_DIRECTORY_OK	0x02
359 
360 /* Get the data stream of the specified name from the specified inode.  Returns
361  * NULL with errno set if not found.  */
362 static struct wim_inode_stream *
inode_get_data_stream_tstr(const struct wim_inode * inode,const char * stream_name)363 inode_get_data_stream_tstr(const struct wim_inode *inode,
364 			   const char *stream_name)
365 {
366 	struct wim_inode_stream *strm;
367 
368 	if (!stream_name || !*stream_name) {
369 		strm = inode_get_unnamed_data_stream(inode);
370 	} else {
371 		const utf16lechar *uname;
372 
373 		if (tstr_get_utf16le(stream_name, &uname))
374 			return NULL;
375 		strm = inode_get_stream(inode, STREAM_TYPE_DATA, uname);
376 		tstr_put_utf16le(uname);
377 	}
378 	if (!strm)
379 		errno = ENOENT;
380 	return strm;
381 }
382 
383 /*
384  * Translate a path into the corresponding dentry and stream in the mounted WIM
385  * image.
386  *
387  * Returns 0 or a -errno code.  @dentry_ret and @strm_ret are both optional.
388  */
389 static int
wim_pathname_to_stream(const struct wimfs_context * ctx,const char * path,int lookup_flags,struct wim_dentry ** dentry_ret,struct wim_inode_stream ** strm_ret)390 wim_pathname_to_stream(const struct wimfs_context *ctx,
391 		       const char *path,
392 		       int lookup_flags,
393 		       struct wim_dentry **dentry_ret,
394 		       struct wim_inode_stream **strm_ret)
395 {
396 	WIMStruct *wim = ctx->wim;
397 	struct wim_dentry *dentry;
398 	struct wim_inode *inode;
399 	struct wim_inode_stream *strm;
400 	const char *stream_name = NULL;
401 	char *p = NULL;
402 
403 	lookup_flags |= ctx->default_lookup_flags;
404 
405 	if (lookup_flags & LOOKUP_FLAG_ADS_OK) {
406 		stream_name = path_stream_name(path);
407 		if (stream_name) {
408 			p = (char *)stream_name - 1;
409 			*p = '\0';
410 		}
411 	}
412 
413 	dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
414 	if (p)
415 		*p = ':';
416 	if (!dentry)
417 		return -errno;
418 
419 	inode = dentry->d_inode;
420 
421 	if (inode_resolve_streams(inode, wim->blob_table, false))
422 		return -EIO;
423 
424 	if (!(lookup_flags & LOOKUP_FLAG_DIRECTORY_OK)
425 	      && inode_is_directory(inode))
426 		return -EISDIR;
427 
428 	strm = inode_get_data_stream_tstr(inode, stream_name);
429 	if (!strm) {
430 		/* Force creation of an unnamed data stream  */
431 		if (!stream_name)
432 			strm = inode_add_stream(inode, STREAM_TYPE_DATA,
433 						NO_STREAM_NAME, NULL);
434 		if (!strm)
435 			return -errno;
436 	}
437 
438 	if (dentry_ret)
439 		*dentry_ret = dentry;
440 	if (strm_ret)
441 		*strm_ret = strm;
442 	return 0;
443 }
444 
445 /*
446  * Create a new file in the mounted WIM image.
447  *
448  * @fuse_ctx
449  *	The FUSE context for the mounted image.
450  * @path
451  *	The path at which to create the first link to the new file.  If a file
452  *	already exists at this path, -EEXIST is returned.
453  * @mode
454  *	The UNIX mode for the new file.  This is only fully honored if
455  *	WIMLIB_MOUNT_FLAG_UNIX_DATA was passed to wimlib_mount_image().
456  * @rdev
457  *	The device ID for the new file, encoding the major and minor device
458  *	numbers.  This is only honored if WIMLIB_MOUNT_FLAG_UNIX_DATA was passed
459  *	to wimlib_mount_image().
460  * @dentry_ret
461  *	On success, a pointer to the new dentry is returned here.  Its d_inode
462  *	member will point to the new inode that was created for it and added to
463  *	the mounted WIM image.
464  *
465  * Returns 0 or a -errno code.
466  */
467 static int
create_file(struct fuse_context * fuse_ctx,const char * path,mode_t mode,dev_t rdev,struct wim_dentry ** dentry_ret)468 create_file(struct fuse_context *fuse_ctx, const char *path,
469 	    mode_t mode, dev_t rdev, struct wim_dentry **dentry_ret)
470 {
471 	struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
472 	struct wim_dentry *parent;
473 	const char *basename;
474 	struct wim_dentry *dentry;
475 	struct wim_inode *inode;
476 
477 	parent = get_parent_dentry(wimfs_ctx->wim, path, WIMLIB_CASE_SENSITIVE);
478 	if (!parent)
479 		return -errno;
480 
481 	if (!dentry_is_directory(parent))
482 		return -ENOTDIR;
483 
484 	basename = path_basename(path);
485 
486 	if (get_dentry_child_with_name(parent, basename, WIMLIB_CASE_SENSITIVE))
487 		return -EEXIST;
488 
489 	if (new_dentry_with_new_inode(basename, true, &dentry))
490 		return -ENOMEM;
491 
492 	inode = dentry->d_inode;
493 
494 	inode->i_ino = wimfs_ctx->next_ino++;
495 
496 	/* Note: we still use FILE_ATTRIBUTE_NORMAL for device nodes, named
497 	 * pipes, and sockets.  The real mode is in the UNIX metadata.  */
498 	if (S_ISDIR(mode))
499 		inode->i_attributes = FILE_ATTRIBUTE_DIRECTORY;
500 	else
501 		inode->i_attributes = FILE_ATTRIBUTE_NORMAL;
502 
503 	if (wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) {
504 		struct wimlib_unix_data unix_data;
505 
506 		unix_data.uid = fuse_ctx->uid;
507 		unix_data.gid = fuse_ctx->gid;
508 		unix_data.mode = fuse_mask_mode(mode, fuse_ctx);
509 		unix_data.rdev = rdev;
510 		if (!inode_set_unix_data(inode, &unix_data, UNIX_DATA_ALL))
511 		{
512 			free_dentry(dentry);
513 			return -ENOMEM;
514 		}
515 	}
516 
517 	hlist_add_head(&inode->i_hlist_node,
518 		       &wim_get_current_image_metadata(wimfs_ctx->wim)->inode_list);
519 
520 	dentry_add_child(parent, dentry);
521 
522 	*dentry_ret = dentry;
523 	return 0;
524 }
525 
526 /*
527  * Remove a dentry from the mounted WIM image; i.e. remove an alias for an
528  * inode.
529  */
530 static void
remove_dentry(struct wim_dentry * dentry,struct blob_table * blob_table)531 remove_dentry(struct wim_dentry *dentry, struct blob_table *blob_table)
532 {
533 	/* Drop blob references.  */
534 	inode_unref_blobs(dentry->d_inode, blob_table);
535 
536 	/* Unlink the dentry from the image's dentry tree.  */
537 	unlink_dentry(dentry);
538 
539 	/* Delete the dentry.  This will also decrement the link count of the
540 	 * corresponding inode, and possibly cause it to be deleted as well.  */
541 	free_dentry(dentry);
542 }
543 
544 /* Generate UNIX filetype mode bits for the specified WIM inode, based on its
545  * Windows file attributes.  */
546 static mode_t
inode_unix_file_type(const struct wim_inode * inode)547 inode_unix_file_type(const struct wim_inode *inode)
548 {
549 	if (inode_is_symlink(inode))
550 		return S_IFLNK;
551 	else if (inode_is_directory(inode))
552 		return S_IFDIR;
553 	else
554 		return S_IFREG;
555 }
556 
557 /* Generate a default UNIX mode for the specified WIM inode.  */
558 static mode_t
inode_default_unix_mode(const struct wim_inode * inode)559 inode_default_unix_mode(const struct wim_inode *inode)
560 {
561 	return inode_unix_file_type(inode) | 0777;
562 }
563 
564 static u64
blob_size(const struct blob_descriptor * blob)565 blob_size(const struct blob_descriptor *blob)
566 {
567 	if (!blob)
568 		return 0;
569 	return blob->size;
570 }
571 
572 static u64
blob_stored_size(const struct blob_descriptor * blob)573 blob_stored_size(const struct blob_descriptor *blob)
574 {
575 	if (!blob)
576 		return 0;
577 	if (blob->blob_location == BLOB_IN_WIM &&
578 	    blob->size == blob->rdesc->uncompressed_size)
579 		return blob->rdesc->size_in_wim;
580 	return blob->size;
581 }
582 
583 /*
584  * Retrieve standard UNIX metadata ('struct stat') for a WIM inode.
585  *
586  * @blob is the blob descriptor for the stream of the inode that is being
587  * queried, or NULL.  We mostly return the same information for all streams, but
588  * st_size and st_blocks may be different for different streams.
589  *
590  * This always returns 0.
591  */
592 static int
inode_to_stbuf(const struct wim_inode * inode,const struct blob_descriptor * blob,struct stat * stbuf)593 inode_to_stbuf(const struct wim_inode *inode,
594 	       const struct blob_descriptor *blob, struct stat *stbuf)
595 {
596 	const struct wimfs_context *ctx = wimfs_get_context();
597 	struct wimlib_unix_data unix_data;
598 
599 	memset(stbuf, 0, sizeof(struct stat));
600 	if ((ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) &&
601 	    inode_get_unix_data(inode, &unix_data))
602 	{
603 		/* Use the user ID, group ID, mode, and device ID from the
604 		 * inode's extra UNIX metadata information.  */
605 		stbuf->st_uid = unix_data.uid;
606 		stbuf->st_gid = unix_data.gid;
607 		stbuf->st_mode = unix_data.mode;
608 		stbuf->st_rdev = unix_data.rdev;
609 	} else {
610 		/* Generate default values for the user ID, group ID, and mode.
611 		 *
612 		 * Note: in the case of an allow_other mount, fuse_context.uid
613 		 * may not be the same as wimfs_context.owner_uid!  */
614 		stbuf->st_uid = ctx->owner_uid;
615 		stbuf->st_gid = ctx->owner_gid;
616 		stbuf->st_mode = inode_default_unix_mode(inode);
617 	}
618 	stbuf->st_ino = inode->i_ino;
619 	stbuf->st_nlink = inode->i_nlink;
620 	stbuf->st_size = blob_size(blob);
621 #ifdef HAVE_STAT_NANOSECOND_PRECISION
622 	stbuf->st_atim = wim_timestamp_to_timespec(inode->i_last_access_time);
623 	stbuf->st_mtim = wim_timestamp_to_timespec(inode->i_last_write_time);
624 	stbuf->st_ctim = stbuf->st_mtim;
625 #else
626 	stbuf->st_atime = wim_timestamp_to_time_t(inode->i_last_access_time);
627 	stbuf->st_mtime = wim_timestamp_to_time_t(inode->i_last_write_time);
628 	stbuf->st_ctime = stbuf->st_mtime;
629 #endif
630 	stbuf->st_blocks = DIV_ROUND_UP(blob_stored_size(blob), 512);
631 	return 0;
632 }
633 
634 /* Update the last access and last write timestamps of a WIM inode.  */
635 static void
touch_inode(struct wim_inode * inode)636 touch_inode(struct wim_inode *inode)
637 {
638 	u64 now = now_as_wim_timestamp();
639 	inode->i_last_access_time = now;
640 	inode->i_last_write_time = now;
641 }
642 
643 static void
touch_parent(struct wim_dentry * dentry)644 touch_parent(struct wim_dentry *dentry)
645 {
646 	touch_inode(dentry->d_parent->d_inode);
647 }
648 
649 /*
650  * Create a new file in the staging directory for a read-write mounted image.
651  *
652  * On success, returns the file descriptor for the new staging file, opened for
653  * writing.  In addition, stores the allocated name of the staging file in
654  * @name_ret.
655  *
656  * On failure, returns -1 and sets errno.
657  */
658 static int
create_staging_file(const struct wimfs_context * ctx,char ** name_ret)659 create_staging_file(const struct wimfs_context *ctx, char **name_ret)
660 {
661 
662 	static const size_t STAGING_FILE_NAME_LEN = 20;
663 	char *name;
664 	int fd;
665 
666 	name = MALLOC(STAGING_FILE_NAME_LEN + 1);
667 	if (!name)
668 		return -1;
669 	name[STAGING_FILE_NAME_LEN] = '\0';
670 
671 retry:
672 	get_random_alnum_chars(name, STAGING_FILE_NAME_LEN);
673 	fd = openat(ctx->staging_dir_fd, name,
674 		    O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0600);
675 	if (unlikely(fd < 0)) {
676 		if (unlikely(errno == EEXIST))
677 			/* Try again with another name.  */
678 			goto retry;
679 		FREE(name);
680 	} else {
681 		*name_ret = name;
682 	}
683 	return fd;
684 }
685 
686 /*
687  * Extract a blob to the staging directory.  This is necessary when a stream
688  * using the blob is being opened for writing and the blob has not already been
689  * extracted to the staging directory.
690  *
691  * @inode
692  *	The inode containing the stream being opened for writing.
693  * @strm
694  *	The stream being opened for writing.  The blob descriptor to which the
695  *	stream refers will be changed by this function.
696  * @size
697  *	Number of bytes of the blob to extract and include in the staging file.
698  *	It may be less than the actual blob length, in which case only a prefix
699  *	of the blob will be extracted.  It may also be more than the actual blob
700  *	length, in which case the extra space will be zero-filled.
701  *
702  * Returns 0 or a -errno code.
703  */
704 static int
extract_blob_to_staging_dir(struct wim_inode * inode,struct wim_inode_stream * strm,off_t size,const struct wimfs_context * ctx)705 extract_blob_to_staging_dir(struct wim_inode *inode,
706 			    struct wim_inode_stream *strm,
707 			    off_t size, const struct wimfs_context *ctx)
708 {
709 	struct blob_descriptor *old_blob;
710 	struct blob_descriptor *new_blob;
711 	char *staging_file_name;
712 	int staging_fd;
713 	off_t extract_size;
714 	int result;
715 	int ret;
716 
717 	old_blob = stream_blob_resolved(strm);
718 
719 	/* Create the staging file.  */
720 	staging_fd = create_staging_file(ctx, &staging_file_name);
721 	if (unlikely(staging_fd < 0))
722 		return -errno;
723 
724 	/* Extract the stream to the staging file (possibly truncated).  */
725 	if (old_blob) {
726 		struct filedes fd;
727 
728 		filedes_init(&fd, staging_fd);
729 		errno = 0;
730 		extract_size = min(old_blob->size, size);
731 		result = extract_blob_prefix_to_fd(old_blob, extract_size, &fd);
732 	} else {
733 		extract_size = 0;
734 		result = 0;
735 	}
736 
737 	/* In the case of truncate() to more than the file length, extend the
738 	 * staging file with zeroes by calling ftruncate().  */
739 	if (!result && size > extract_size)
740 		result = ftruncate(staging_fd, size);
741 
742 	/* Close the staging file.  */
743 	if (close(staging_fd))
744 		result = -1;
745 
746 	/* If an error occurred, unlink the staging file.  */
747 	if (unlikely(result)) {
748 		/* extract_blob_to_fd() should set errno, but if it didn't,
749 		 * set a default value.  */
750 		ret = errno ? -errno : -EIO;
751 		goto out_delete_staging_file;
752 	}
753 
754 	/* Create a blob descriptor for the staging file.  */
755 	new_blob = new_blob_descriptor();
756 	if (unlikely(!new_blob)) {
757 		ret = -ENOMEM;
758 		goto out_delete_staging_file;
759 	}
760 
761 	/* There may already be open file descriptors to this stream if it's
762 	 * previously been opened read-only, but just now we're opening it
763 	 * read-write.  Identify those file descriptors, update them to use the
764 	 * new blob descriptor, and open staging file descriptors for them.  */
765 	for (u16 i = 0, j = 0; j < inode->i_num_opened_fds; i++) {
766 		struct wimfs_fd *fd;
767 		int raw_fd;
768 
769 		fd = inode->i_fds[i];
770 		if (!fd)
771 			continue;
772 
773 		j++;
774 
775 		if (fd->f_stream_id != strm->stream_id)
776 			continue;
777 
778 		/* This is a readonly fd for the same stream.  */
779 		fd->f_blob = new_blob;
780 		new_blob->num_opened_fds++;
781 		raw_fd = openat(ctx->staging_dir_fd, staging_file_name,
782 				O_RDONLY | O_NOFOLLOW);
783 		if (unlikely(raw_fd < 0)) {
784 			ret = -errno;
785 			goto out_revert_fd_changes;
786 		}
787 		filedes_init(&fd->f_staging_fd, raw_fd);
788 	}
789 
790 	if (old_blob)
791 		old_blob->num_opened_fds -= new_blob->num_opened_fds;
792 
793 	new_blob->blob_location     = BLOB_IN_STAGING_FILE;
794 	new_blob->staging_file_name = staging_file_name;
795 	new_blob->staging_dir_fd    = ctx->staging_dir_fd;
796 	new_blob->size              = size;
797 
798 	prepare_unhashed_blob(new_blob, inode, strm->stream_id,
799 			      &wim_get_current_image_metadata(ctx->wim)->unhashed_blobs);
800 	inode_replace_stream_blob(inode, strm, new_blob, ctx->wim->blob_table);
801 	return 0;
802 
803 out_revert_fd_changes:
804 	for (u16 i = 0; new_blob->num_opened_fds; i++) {
805 		struct wimfs_fd *fd = inode->i_fds[i];
806 		if (fd && fd->f_stream_id == strm->stream_id) {
807 			fd->f_blob = old_blob;
808 			if (filedes_valid(&fd->f_staging_fd)) {
809 				filedes_close(&fd->f_staging_fd);
810 				filedes_invalidate(&fd->f_staging_fd);
811 			}
812 			new_blob->num_opened_fds--;
813 		}
814 	}
815 	free_blob_descriptor(new_blob);
816 out_delete_staging_file:
817 	unlinkat(ctx->staging_dir_fd, staging_file_name, 0);
818 	FREE(staging_file_name);
819 	return ret;
820 }
821 
822 /*
823  * Create the staging directory for the WIM file.
824  *
825  * The staging directory will be created in the directory specified by the open
826  * file descriptor @parent_dir_fd.  It will be given a randomly generated name
827  * based on @wim_basename, the name of the WIM file.
828  *
829  * On success, returns a file descriptor to the open staging directory with
830  * O_RDONLY access.  In addition, stores the allocated name of the staging
831  * directory (relative to @parent_dir_fd) in @staging_dir_name_ret.
832  * On failure, returns -1 and sets errno.
833  */
834 static int
make_staging_dir_at(int parent_dir_fd,const char * wim_basename,char ** staging_dir_name_ret)835 make_staging_dir_at(int parent_dir_fd, const char *wim_basename,
836 		    char **staging_dir_name_ret)
837 {
838 	static const char common_suffix[8] = ".staging";
839 	static const size_t random_suffix_len = 10;
840 	size_t wim_basename_len;
841 	size_t staging_dir_name_len;
842 	char *staging_dir_name;
843 	char *p;
844 	int fd;
845 
846 	wim_basename_len = strlen(wim_basename);
847 	staging_dir_name_len = wim_basename_len + sizeof(common_suffix) +
848 			       random_suffix_len;
849 	staging_dir_name = MALLOC(staging_dir_name_len + 1);
850 	if (!staging_dir_name)
851 		return -1;
852 
853 	p = staging_dir_name;
854 	p = mempcpy(p, wim_basename, wim_basename_len);
855 	p = mempcpy(p, common_suffix, sizeof(common_suffix));
856 	get_random_alnum_chars(p, random_suffix_len);
857 	p += random_suffix_len;
858 	*p = '\0';
859 
860 	if (mkdirat(parent_dir_fd, staging_dir_name, 0700))
861 		goto err1;
862 
863 	fd = openat(parent_dir_fd, staging_dir_name,
864 		    O_RDONLY | O_DIRECTORY | O_NOFOLLOW);
865 	if (fd < 0)
866 		goto err2;
867 
868 	*staging_dir_name_ret = staging_dir_name;
869 	return fd;
870 
871 err2:
872 	unlinkat(parent_dir_fd, staging_dir_name, AT_REMOVEDIR);
873 err1:
874 	FREE(staging_dir_name);
875 	return -1;
876 }
877 
878 /*
879  * Create the staging directory and set ctx->staging_dir_fd,
880  * ctx->staging_dir_name, and ctx->parent_dir_fd.
881  */
882 static int
make_staging_dir(struct wimfs_context * ctx,const char * parent_dir_path)883 make_staging_dir(struct wimfs_context *ctx, const char *parent_dir_path)
884 {
885 	const char *wim_basename;
886 	char *end = NULL;
887 	int ret;
888 
889 	wim_basename = path_basename(ctx->wim->filename);
890 
891 	if (!parent_dir_path) {
892 		/* The user did not specify a directory.  Default to creating
893 		 * the staging directory alongside the WIM file.  */
894 		if (wim_basename > ctx->wim->filename) {
895 			parent_dir_path = ctx->wim->filename;
896 			end = (char *)(wim_basename - 1);
897 			/* *end must be a slash.  Temporarily overwrite it so we
898 			 * can open the parent directory.  */
899 			*end = '\0';
900 		} else {
901 			parent_dir_path = ".";
902 		}
903 	}
904 
905 	/* Open the parent directory (in which we'll create our staging
906 	 * directory).  */
907 	ctx->parent_dir_fd = open(parent_dir_path, O_RDONLY | O_DIRECTORY);
908 	if (ctx->parent_dir_fd < 0) {
909 		ERROR_WITH_ERRNO("Can't open directory \"%s\"",
910 				 parent_dir_path);
911 		ret = WIMLIB_ERR_OPENDIR;
912 		goto out_restore_wim_filename;
913 	}
914 
915 	ctx->staging_dir_fd = make_staging_dir_at(ctx->parent_dir_fd,
916 						  wim_basename,
917 						  &ctx->staging_dir_name);
918 	if (ctx->staging_dir_fd < 0) {
919 		ERROR_WITH_ERRNO("Can't create staging directory in \"%s\"",
920 				 parent_dir_path);
921 		close(ctx->parent_dir_fd);
922 		ret = WIMLIB_ERR_MKDIR;
923 		goto out_restore_wim_filename;
924 	}
925 	ret = 0;
926 out_restore_wim_filename:
927 	if (end)
928 		*end = '/';
929 	return ret;
930 }
931 
932 /* Deletes the staging directory, undoing the effects of a successful call to
933  * make_staging_dir().  */
934 static void
delete_staging_dir(struct wimfs_context * ctx)935 delete_staging_dir(struct wimfs_context *ctx)
936 {
937 	DIR *dir;
938 	struct dirent *ent;
939 
940 	dir = fdopendir(ctx->staging_dir_fd);
941 	if (dir) {
942 		while ((ent = readdir(dir)))
943 			unlinkat(ctx->staging_dir_fd, ent->d_name, 0);
944 		closedir(dir);
945 	} else {
946 		close(ctx->staging_dir_fd);
947 	}
948 	if (unlinkat(ctx->parent_dir_fd, ctx->staging_dir_name, AT_REMOVEDIR))
949 		WARNING_WITH_ERRNO("Could not delete staging directory");
950 	FREE(ctx->staging_dir_name);
951 	close(ctx->parent_dir_fd);
952 }
953 
954 static void
prepare_inodes(struct wimfs_context * ctx)955 prepare_inodes(struct wimfs_context *ctx)
956 {
957 	struct wim_image_metadata *imd;
958 	struct wim_inode *inode;
959 
960 	ctx->next_ino = 1;
961 	imd = wim_get_current_image_metadata(ctx->wim);
962 	image_for_each_inode(inode, imd) {
963 		inode->i_ino = ctx->next_ino++;
964 		inode->i_num_opened_fds = 0;
965 		inode->i_num_allocated_fds = 0;
966 		inode->i_fds = NULL;
967 	}
968 }
969 
970 /* Delete the 'struct blob_descriptor' for any stream that was modified
971  * or created in the read-write mounted image and had a final size of 0.  */
972 static void
delete_empty_blobs(struct wimfs_context * ctx)973 delete_empty_blobs(struct wimfs_context *ctx)
974 {
975 	struct blob_descriptor *blob, *tmp;
976 	struct wim_image_metadata *imd;
977 
978 	imd = wim_get_current_image_metadata(ctx->wim);
979 
980 	image_for_each_unhashed_blob_safe(blob, tmp, imd) {
981 		if (!blob->size) {
982 			*retrieve_pointer_to_unhashed_blob(blob) = NULL;
983 			list_del(&blob->unhashed_list);
984 			free_blob_descriptor(blob);
985 		}
986 	}
987 }
988 
989 /* Close all file descriptors open to the specified inode.
990  *
991  * Note: closing the last file descriptor might free the inode.  */
992 static void
inode_close_fds(struct wim_inode * inode)993 inode_close_fds(struct wim_inode *inode)
994 {
995 	u16 num_open_fds = inode->i_num_opened_fds;
996 	for (u16 i = 0; num_open_fds; i++) {
997 		if (inode->i_fds[i]) {
998 			close_wimfs_fd(inode->i_fds[i]);
999 			num_open_fds--;
1000 		}
1001 	}
1002 }
1003 
1004 /* Close all file descriptors open to the mounted image.  */
1005 static void
close_all_fds(struct wimfs_context * ctx)1006 close_all_fds(struct wimfs_context *ctx)
1007 {
1008 	struct wim_inode *inode;
1009 	struct hlist_node *tmp;
1010 	struct wim_image_metadata *imd;
1011 
1012 	imd = wim_get_current_image_metadata(ctx->wim);
1013 
1014 	image_for_each_inode_safe(inode, tmp, imd)
1015 		inode_close_fds(inode);
1016 }
1017 
1018 /* Moves the currently selected image, which may have been modified, to a new
1019  * index, and sets the original index to refer to a reset (unmodified) copy of
1020  * the image.  */
1021 static int
renew_current_image(struct wimfs_context * ctx)1022 renew_current_image(struct wimfs_context *ctx)
1023 {
1024 	WIMStruct *wim = ctx->wim;
1025 	int image = wim->current_image;
1026 	struct wim_image_metadata *imd;
1027 	struct wim_inode *inode;
1028 	int ret;
1029 
1030 	ret = WIMLIB_ERR_NOMEM;
1031 	imd = new_unloaded_image_metadata(ctx->metadata_resource);
1032 	if (!imd)
1033 		goto err;
1034 
1035 	ret = append_image_metadata(wim, wim->image_metadata[image - 1]);
1036 	if (ret)
1037 		goto err_put_imd;
1038 
1039 	ret = xml_export_image(wim->xml_info, image,
1040 			       wim->xml_info, NULL, NULL, false);
1041 	if (ret)
1042 		goto err_undo_append;
1043 
1044 	wim->image_metadata[image - 1] = imd;
1045 	wim->current_image = wim->hdr.image_count;
1046 
1047 	ret = select_wim_image(wim, image);
1048 	if (ret)
1049 		goto err_undo_export;
1050 
1051 	image_for_each_inode(inode, imd) {
1052 		for (unsigned i = 0; i < inode->i_num_streams; i++) {
1053 			struct blob_descriptor *blob;
1054 
1055 			blob = stream_blob(&inode->i_streams[i],
1056 					   wim->blob_table);
1057 			if (blob)
1058 				blob->refcnt += inode->i_nlink;
1059 		}
1060 	}
1061 
1062 	select_wim_image(wim, wim->hdr.image_count);
1063 	ctx->metadata_resource = NULL;
1064 	return 0;
1065 
1066 err_undo_export:
1067 	xml_delete_image(wim->xml_info, wim->hdr.image_count);
1068 	wim->image_metadata[image - 1] = wim->image_metadata[wim->hdr.image_count - 1];
1069 	wim->current_image = image;
1070 err_undo_append:
1071 	wim->hdr.image_count--;
1072 err_put_imd:
1073 	imd->metadata_blob = NULL;
1074 	put_image_metadata(imd);
1075 err:
1076 	return ret;
1077 }
1078 
1079 static enum wimlib_progress_status
commit_progress_func(enum wimlib_progress_msg msg,union wimlib_progress_info * info,void * progctx)1080 commit_progress_func(enum wimlib_progress_msg msg,
1081 		     union wimlib_progress_info *info, void *progctx)
1082 {
1083 	mqd_t mq = *(mqd_t *)progctx;
1084 	struct commit_progress_report report;
1085 
1086 	memset(&report, 0, sizeof(report));
1087 	report.msg = msg;
1088 	if (info)
1089 		report.info = *info;
1090 	mq_send(mq, (const char *)&report, sizeof(report), 1);
1091 	return WIMLIB_PROGRESS_STATUS_CONTINUE;
1092 }
1093 
1094 /* Commit the mounted image to the underlying WIM file.  */
1095 static int
commit_image(struct wimfs_context * ctx,int unmount_flags,mqd_t mq)1096 commit_image(struct wimfs_context *ctx, int unmount_flags, mqd_t mq)
1097 {
1098 	int write_flags;
1099 
1100 	if (unmount_flags & WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS)
1101 		wimlib_register_progress_function(ctx->wim,
1102 						  commit_progress_func, &mq);
1103 	else
1104 		wimlib_register_progress_function(ctx->wim, NULL, NULL);
1105 
1106 	if (unmount_flags & WIMLIB_UNMOUNT_FLAG_NEW_IMAGE) {
1107 		int ret = renew_current_image(ctx);
1108 		if (ret)
1109 			return ret;
1110 	}
1111 	delete_empty_blobs(ctx);
1112 
1113 	write_flags = 0;
1114 
1115 	if (unmount_flags & WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY)
1116 		write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
1117 
1118 	if (unmount_flags & WIMLIB_UNMOUNT_FLAG_REBUILD)
1119 		write_flags |= WIMLIB_WRITE_FLAG_REBUILD;
1120 
1121 	if (unmount_flags & WIMLIB_UNMOUNT_FLAG_RECOMPRESS)
1122 		write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
1123 
1124 	return wimlib_overwrite(ctx->wim, write_flags, 0);
1125 }
1126 
1127 /* In the case of an allow_other mount, only the mount owner and root are
1128  * allowed to unmount the filesystem.  */
1129 static bool
may_unmount_wimfs(void)1130 may_unmount_wimfs(void)
1131 {
1132 	const struct fuse_context *fuse_ctx = fuse_get_context();
1133 	const struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1134 
1135 	return (fuse_ctx->uid == wimfs_ctx->owner_uid ||
1136 		fuse_ctx->uid == 0);
1137 }
1138 
1139 /* Unmount the mounted image, called from the daemon process.  */
1140 static int
unmount_wimfs(void)1141 unmount_wimfs(void)
1142 {
1143 	struct fuse_context *fuse_ctx = fuse_get_context();
1144 	struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1145 	const struct wimfs_unmount_info *info = &wimfs_ctx->unmount_info;
1146 	int unmount_flags = info->unmount_flags;
1147 	mqd_t mq = (mqd_t)-1;
1148 	int ret;
1149 
1150 	/* Ignore COMMIT if the image is mounted read-only.  */
1151 	if (!(wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_READWRITE))
1152 		unmount_flags &= ~WIMLIB_UNMOUNT_FLAG_COMMIT;
1153 
1154 	if (unmount_flags & WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS) {
1155 		mq = mq_open(info->mq_name, O_WRONLY | O_NONBLOCK);
1156 		if (mq == (mqd_t)-1) {
1157 			ret = WIMLIB_ERR_MQUEUE;
1158 			goto out;
1159 		}
1160 	}
1161 
1162 	if (wimfs_ctx->num_open_fds) {
1163 
1164 		/* There are still open file descriptors to the image.  */
1165 
1166 		/* With COMMIT, refuse to unmount unless FORCE is also
1167 		 * specified.  */
1168 		if ((unmount_flags & (WIMLIB_UNMOUNT_FLAG_COMMIT |
1169 				      WIMLIB_UNMOUNT_FLAG_FORCE))
1170 				 == WIMLIB_UNMOUNT_FLAG_COMMIT)
1171 		{
1172 			ret = WIMLIB_ERR_MOUNTED_IMAGE_IS_BUSY;
1173 			goto out;
1174 		}
1175 
1176 		/* Force-close all file descriptors.  */
1177 		close_all_fds(wimfs_ctx);
1178 	}
1179 
1180 	if (unmount_flags & WIMLIB_UNMOUNT_FLAG_COMMIT)
1181 		ret = commit_image(wimfs_ctx, unmount_flags, mq);
1182 	else
1183 		ret = 0;  /* Read-only mount, or discarding changes to
1184 			     a read-write mount  */
1185 
1186 out:
1187 	/* Leave the image mounted if commit failed, unless this is a
1188 	 * forced unmount.  The user can retry without COMMIT if they
1189 	 * want.  */
1190 	if (!ret || (unmount_flags & WIMLIB_UNMOUNT_FLAG_FORCE)) {
1191 		unlock_wim_for_append(wimfs_ctx->wim);
1192 		fuse_exit(fuse_ctx->fuse);
1193 	}
1194 	if (mq != (mqd_t)-1)
1195 		mq_close(mq);
1196 	return ret;
1197 }
1198 
1199 static int
wimfs_chmod(const char * path,mode_t mask)1200 wimfs_chmod(const char *path, mode_t mask)
1201 {
1202 	const struct wimfs_context *ctx = wimfs_get_context();
1203 	struct wim_inode *inode;
1204 	struct wimlib_unix_data unix_data;
1205 
1206 	if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
1207 		return -EOPNOTSUPP;
1208 
1209 	inode = wim_pathname_to_inode(ctx->wim, path);
1210 	if (!inode)
1211 		return -errno;
1212 
1213 	unix_data.uid = ctx->owner_uid;
1214 	unix_data.gid = ctx->owner_gid;
1215 	unix_data.mode = mask;
1216 	unix_data.rdev = 0;
1217 
1218 	if (!inode_set_unix_data(inode, &unix_data, UNIX_DATA_MODE))
1219 		return -ENOMEM;
1220 
1221 	return 0;
1222 }
1223 
1224 static int
wimfs_chown(const char * path,uid_t uid,gid_t gid)1225 wimfs_chown(const char *path, uid_t uid, gid_t gid)
1226 {
1227 	const struct wimfs_context *ctx = wimfs_get_context();
1228 	struct wim_inode *inode;
1229 	struct wimlib_unix_data unix_data;
1230 	int which;
1231 
1232 	if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
1233 		return -EOPNOTSUPP;
1234 
1235 	inode = wim_pathname_to_inode(ctx->wim, path);
1236 	if (!inode)
1237 		return -errno;
1238 
1239 	which = 0;
1240 
1241 	if (uid != (uid_t)-1)
1242 		which |= UNIX_DATA_UID;
1243 	else
1244 		uid = ctx->owner_uid;
1245 
1246 	if (gid != (gid_t)-1)
1247 		which |= UNIX_DATA_GID;
1248 	else
1249 		gid = ctx->owner_gid;
1250 
1251 	unix_data.uid = uid;
1252 	unix_data.gid = gid;
1253 	unix_data.mode = inode_default_unix_mode(inode);
1254 	unix_data.rdev = 0;
1255 
1256 	if (!inode_set_unix_data(inode, &unix_data, which))
1257 		return -ENOMEM;
1258 
1259 	return 0;
1260 }
1261 
1262 static int
wimfs_fgetattr(const char * path,struct stat * stbuf,struct fuse_file_info * fi)1263 wimfs_fgetattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi)
1264 {
1265 	struct wimfs_fd *fd = WIMFS_FD(fi);
1266 	return inode_to_stbuf(fd->f_inode, fd->f_blob, stbuf);
1267 }
1268 
1269 static int
wimfs_ftruncate(const char * path,off_t size,struct fuse_file_info * fi)1270 wimfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi)
1271 {
1272 	struct wimfs_fd *fd = WIMFS_FD(fi);
1273 	if (ftruncate(fd->f_staging_fd.fd, size))
1274 		return -errno;
1275 	touch_inode(fd->f_inode);
1276 	fd->f_blob->size = size;
1277 	return 0;
1278 }
1279 
1280 static int
wimfs_getattr(const char * path,struct stat * stbuf)1281 wimfs_getattr(const char *path, struct stat *stbuf)
1282 {
1283 	const struct wimfs_context *ctx = wimfs_get_context();
1284 	struct wim_dentry *dentry;
1285 	struct wim_inode_stream *strm;
1286 	int ret;
1287 
1288 	ret = wim_pathname_to_stream(ctx, path, LOOKUP_FLAG_DIRECTORY_OK,
1289 				     &dentry, &strm);
1290 	if (ret)
1291 		return ret;
1292 
1293 	return inode_to_stbuf(dentry->d_inode,
1294 			      stream_blob_resolved(strm), stbuf);
1295 }
1296 
1297 static int
copy_xattr(char * dest,size_t destsize,const void * src,size_t srcsize)1298 copy_xattr(char *dest, size_t destsize, const void *src, size_t srcsize)
1299 {
1300 	if (destsize) {
1301 		if (destsize < srcsize)
1302 			return -ERANGE;
1303 		memcpy(dest, src, srcsize);
1304 	}
1305 	return srcsize;
1306 }
1307 
1308 static int
wimfs_getxattr(const char * path,const char * name,char * value,size_t size)1309 wimfs_getxattr(const char *path, const char *name, char *value,
1310 	       size_t size)
1311 {
1312 	const struct wimfs_context *ctx = wimfs_get_context();
1313 	const struct wim_inode *inode;
1314 	const struct wim_inode_stream *strm;
1315 	const struct blob_descriptor *blob;
1316 
1317 	if (!strncmp(name, "wimfs.", 6)) {
1318 		/* Handle some magical extended attributes.  These really should
1319 		 * be ioctls, but directory ioctls aren't supported until
1320 		 * libfuse 2.9, and even then they are broken.  */
1321 		name += 6;
1322 		if (!strcmp(name, "wim_filename")) {
1323 			return copy_xattr(value, size, ctx->wim->filename,
1324 					  strlen(ctx->wim->filename));
1325 		}
1326 		if (!strcmp(name, "wim_info")) {
1327 			struct wimlib_wim_info info;
1328 
1329 			wimlib_get_wim_info(ctx->wim, &info);
1330 
1331 			return copy_xattr(value, size, &info, sizeof(info));
1332 		}
1333 		if (!strcmp(name, "mounted_image")) {
1334 			return copy_xattr(value, size,
1335 					  &ctx->wim->current_image, sizeof(int));
1336 		}
1337 		if (!strcmp(name, "mount_flags")) {
1338 			return copy_xattr(value, size,
1339 					  &ctx->mount_flags, sizeof(int));
1340 		}
1341 		if (!strcmp(name, "unmount")) {
1342 			if (!may_unmount_wimfs())
1343 				return -EPERM;
1344 			if (size) {
1345 				int status;
1346 
1347 				if (size < sizeof(int))
1348 					return -ERANGE;
1349 				status = unmount_wimfs();
1350 				memcpy(value, &status, sizeof(int));
1351 			}
1352 			return sizeof(int);
1353 		}
1354 		return -ENOATTR;
1355 	}
1356 
1357 	if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1358 		return -ENOTSUP;
1359 
1360 	if (strncmp(name, "user.", 5))
1361 		return -ENOATTR;
1362 	name += 5;
1363 
1364 	if (!*name)
1365 		return -ENOATTR;
1366 
1367 	/* Querying a named data stream  */
1368 
1369 	inode = wim_pathname_to_inode(ctx->wim, path);
1370 	if (!inode)
1371 		return -errno;
1372 
1373 	strm = inode_get_data_stream_tstr(inode, name);
1374 	if (!strm)
1375 		return (errno == ENOENT) ? -ENOATTR : -errno;
1376 
1377 	blob = stream_blob_resolved(strm);
1378 	if (!blob)
1379 		return 0;
1380 
1381 	if (unlikely(blob->size > INT_MAX))
1382 		return -EFBIG;
1383 
1384 	if (size) {
1385 		if (size < blob->size)
1386 			return -ERANGE;
1387 
1388 		if (read_blob_into_buf(blob, value))
1389 			return errno ? -errno : -EIO;
1390 	}
1391 	return blob->size;
1392 }
1393 
1394 static int
wimfs_link(const char * existing_path,const char * new_path)1395 wimfs_link(const char *existing_path, const char *new_path)
1396 {
1397 	WIMStruct *wim = wimfs_get_WIMStruct();
1398 	const char *new_name;
1399 	struct wim_inode *inode;
1400 	struct wim_dentry *dir;
1401 	struct wim_dentry *new_alias;
1402 
1403 	inode = wim_pathname_to_inode(wim, existing_path);
1404 	if (!inode)
1405 		return -errno;
1406 
1407 	if (inode->i_attributes & (FILE_ATTRIBUTE_DIRECTORY |
1408 				   FILE_ATTRIBUTE_REPARSE_POINT))
1409 		return -EPERM;
1410 
1411 	new_name = path_basename(new_path);
1412 
1413 	dir = get_parent_dentry(wim, new_path, WIMLIB_CASE_SENSITIVE);
1414 	if (!dir)
1415 		return -errno;
1416 
1417 	if (!dentry_is_directory(dir))
1418 		return -ENOTDIR;
1419 
1420 	if (get_dentry_child_with_name(dir, new_name, WIMLIB_CASE_SENSITIVE))
1421 		return -EEXIST;
1422 
1423 	if (new_dentry_with_existing_inode(new_name, inode, &new_alias))
1424 		return -ENOMEM;
1425 
1426 	dentry_add_child(dir, new_alias);
1427 	touch_inode(dir->d_inode);
1428 	return 0;
1429 }
1430 
1431 static int
wimfs_listxattr(const char * path,char * list,size_t size)1432 wimfs_listxattr(const char *path, char *list, size_t size)
1433 {
1434 	const struct wimfs_context *ctx = wimfs_get_context();
1435 	const struct wim_inode *inode;
1436 	char *p = list;
1437 	char *end = list + size;
1438 	int total_size = 0;
1439 
1440 	if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1441 		return -ENOTSUP;
1442 
1443 	/* List named data streams, or get the list size.  We report each named
1444 	 * data stream "X" as an extended attribute "user.X".  */
1445 
1446 	inode = wim_pathname_to_inode(ctx->wim, path);
1447 	if (!inode)
1448 		return -errno;
1449 
1450 	for (unsigned i = 0; i < inode->i_num_streams; i++) {
1451 		const struct wim_inode_stream *strm;
1452 		char *stream_name_mbs;
1453 		size_t stream_name_mbs_nbytes;
1454 
1455 		strm = &inode->i_streams[i];
1456 
1457 		if (!stream_is_named_data_stream(strm))
1458 			continue;
1459 
1460 		if (utf16le_to_tstr(strm->stream_name,
1461 				    utf16le_len_bytes(strm->stream_name),
1462 				    &stream_name_mbs,
1463 				    &stream_name_mbs_nbytes))
1464 			return -errno;
1465 
1466 		if (unlikely(INT_MAX - total_size < stream_name_mbs_nbytes + 6)) {
1467 			FREE(stream_name_mbs);
1468 			return -EFBIG;
1469 		}
1470 
1471 		total_size += stream_name_mbs_nbytes + 6;
1472 		if (size) {
1473 			if (end - p < stream_name_mbs_nbytes + 6) {
1474 				FREE(stream_name_mbs);
1475 				return -ERANGE;
1476 			}
1477 			p = mempcpy(p, "user.", 5);
1478 			p = mempcpy(p, stream_name_mbs, stream_name_mbs_nbytes);
1479 			*p++ = '\0';
1480 		}
1481 		FREE(stream_name_mbs);
1482 	}
1483 	return total_size;
1484 }
1485 
1486 static int
wimfs_mkdir(const char * path,mode_t mode)1487 wimfs_mkdir(const char *path, mode_t mode)
1488 {
1489 	struct wim_dentry *dentry;
1490 	int ret;
1491 
1492 	/* Note: according to fuse.h, mode may not include S_IFDIR  */
1493 	ret = create_file(fuse_get_context(), path, mode | S_IFDIR, 0, &dentry);
1494 	if (ret)
1495 		return ret;
1496 	touch_parent(dentry);
1497 	return 0;
1498 }
1499 
1500 static int
wimfs_mknod(const char * path,mode_t mode,dev_t rdev)1501 wimfs_mknod(const char *path, mode_t mode, dev_t rdev)
1502 {
1503 	struct fuse_context *fuse_ctx = fuse_get_context();
1504 	struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1505 	const char *stream_name;
1506 
1507 	if ((wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
1508 	     && (stream_name = path_stream_name(path)))
1509 	{
1510 		struct wim_inode *inode;
1511 		struct wim_inode_stream *existing_strm;
1512 		struct wim_inode_stream *new_strm;
1513 		char *p;
1514 		const utf16lechar *uname;
1515 
1516 		/* Create a named data stream.  */
1517 
1518 		if (!S_ISREG(mode))
1519 			return -EOPNOTSUPP;
1520 
1521 		p = (char *)stream_name - 1;
1522 
1523 		*p = '\0';
1524 		inode = wim_pathname_to_inode(wimfs_ctx->wim, path);
1525 		*p = ':';
1526 		if (!inode)
1527 			return -errno;
1528 
1529 		if (tstr_get_utf16le(stream_name, &uname))
1530 			return -errno;
1531 
1532 		existing_strm = inode_get_stream(inode, STREAM_TYPE_DATA, uname);
1533 		if (existing_strm) {
1534 			tstr_put_utf16le(uname);
1535 			return -EEXIST;
1536 		}
1537 
1538 		new_strm = inode_add_stream(inode, STREAM_TYPE_DATA, uname, NULL);
1539 
1540 		tstr_put_utf16le(uname);
1541 
1542 		if (!new_strm)
1543 			return -errno;
1544 		return 0;
1545 	} else {
1546 		/* Create a regular file, device node, named pipe, or socket.
1547 		 */
1548 		struct wim_dentry *dentry;
1549 		int ret;
1550 
1551 		if (!S_ISREG(mode) &&
1552 		    !(wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
1553 			return -EPERM;
1554 
1555 		ret = create_file(fuse_ctx, path, mode, rdev, &dentry);
1556 		if (ret)
1557 			return ret;
1558 		touch_parent(dentry);
1559 		return 0;
1560 	}
1561 }
1562 
1563 static int
wimfs_open(const char * path,struct fuse_file_info * fi)1564 wimfs_open(const char *path, struct fuse_file_info *fi)
1565 {
1566 	struct wimfs_context *ctx = wimfs_get_context();
1567 	struct wim_dentry *dentry;
1568 	struct wim_inode *inode;
1569 	struct wim_inode_stream *strm;
1570 	struct blob_descriptor *blob;
1571 	struct wimfs_fd *fd;
1572 	int ret;
1573 
1574 	ret = wim_pathname_to_stream(ctx, path, 0, &dentry, &strm);
1575 	if (ret)
1576 		return ret;
1577 
1578 	inode = dentry->d_inode;
1579 	blob = stream_blob_resolved(strm);
1580 
1581 	/* The data of the file being opened may be in the staging directory
1582 	 * (read-write mounts only) or in the WIM.  If it's in the staging
1583 	 * directory, we need to open a native file descriptor for the
1584 	 * corresponding file.  Otherwise, we can read the file data directly
1585 	 * from the WIM file if we are opening it read-only, but we need to
1586 	 * extract the data to the staging directory if we are opening it
1587 	 * writable.  */
1588 
1589 	if (flags_writable(fi->flags) &&
1590             (!blob || blob->blob_location != BLOB_IN_STAGING_FILE)) {
1591 		ret = extract_blob_to_staging_dir(inode,
1592 						  strm,
1593 						  blob_size(blob),
1594 						  ctx);
1595 		if (ret)
1596 			return ret;
1597 		blob = stream_blob_resolved(strm);
1598 	}
1599 
1600 	ret = alloc_wimfs_fd(inode, strm, &fd);
1601 	if (ret)
1602 		return ret;
1603 
1604 	if (blob && blob->blob_location == BLOB_IN_STAGING_FILE) {
1605 		int raw_fd;
1606 
1607 		raw_fd = openat(blob->staging_dir_fd, blob->staging_file_name,
1608 				(fi->flags & O_ACCMODE) | O_NOFOLLOW);
1609 		if (raw_fd < 0) {
1610 			close_wimfs_fd(fd);
1611 			return -errno;
1612 		}
1613 		filedes_init(&fd->f_staging_fd, raw_fd);
1614 	}
1615 	fi->fh = (uintptr_t)fd;
1616 	return 0;
1617 }
1618 
1619 static int
wimfs_opendir(const char * path,struct fuse_file_info * fi)1620 wimfs_opendir(const char *path, struct fuse_file_info *fi)
1621 {
1622 	WIMStruct *wim = wimfs_get_WIMStruct();
1623 	struct wim_inode *inode;
1624 	struct wim_inode_stream *strm;
1625 	struct wimfs_fd *fd;
1626 	int ret;
1627 
1628 	inode = wim_pathname_to_inode(wim, path);
1629 	if (!inode)
1630 		return -errno;
1631 	if (!inode_is_directory(inode))
1632 		return -ENOTDIR;
1633 	strm = inode_get_unnamed_data_stream(inode);
1634 	if (!strm)
1635 		return -ENOTDIR;
1636 	ret = alloc_wimfs_fd(inode, strm, &fd);
1637 	if (ret)
1638 		return ret;
1639 	fi->fh = (uintptr_t)fd;
1640 	return 0;
1641 }
1642 
1643 static int
wimfs_read(const char * path,char * buf,size_t size,off_t offset,struct fuse_file_info * fi)1644 wimfs_read(const char *path, char *buf, size_t size,
1645 	   off_t offset, struct fuse_file_info *fi)
1646 {
1647 	struct wimfs_fd *fd = WIMFS_FD(fi);
1648 	const struct blob_descriptor *blob;
1649 	ssize_t ret;
1650 
1651 	blob = fd->f_blob;
1652 	if (!blob)
1653 		return 0;
1654 
1655 	if (offset >= blob->size)
1656 		return 0;
1657 
1658 	if (size > blob->size - offset)
1659 		size = blob->size - offset;
1660 
1661 	if (!size)
1662 		return 0;
1663 
1664 	switch (blob->blob_location) {
1665 	case BLOB_IN_WIM:
1666 		if (read_partial_wim_blob_into_buf(blob, offset, size, buf))
1667 			ret = errno ? -errno : -EIO;
1668 		else
1669 			ret = size;
1670 		break;
1671 	case BLOB_IN_STAGING_FILE:
1672 		ret = pread(fd->f_staging_fd.fd, buf, size, offset);
1673 		if (ret < 0)
1674 			ret = -errno;
1675 		break;
1676 	case BLOB_IN_ATTACHED_BUFFER:
1677 		memcpy(buf, blob->attached_buffer + offset, size);
1678 		ret = size;
1679 		break;
1680 	default:
1681 		ret = -EINVAL;
1682 		break;
1683 	}
1684 	return ret;
1685 }
1686 
1687 static int
wimfs_readdir(const char * path,void * buf,fuse_fill_dir_t filler,off_t offset,struct fuse_file_info * fi)1688 wimfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
1689 	      off_t offset, struct fuse_file_info *fi)
1690 {
1691 	struct wimfs_fd *fd = WIMFS_FD(fi);
1692 	const struct wim_inode *inode;
1693 	const struct wim_dentry *child;
1694 	int ret;
1695 
1696 	inode = fd->f_inode;
1697 
1698 	ret = filler(buf, ".", NULL, 0);
1699 	if (ret)
1700 		return ret;
1701 	ret = filler(buf, "..", NULL, 0);
1702 	if (ret)
1703 		return ret;
1704 
1705 	for_inode_child(child, inode) {
1706 		char *name;
1707 		size_t name_nbytes;
1708 
1709 		if (utf16le_to_tstr(child->d_name, child->d_name_nbytes,
1710 				    &name, &name_nbytes))
1711 			return -errno;
1712 
1713 		ret = filler(buf, name, NULL, 0);
1714 		FREE(name);
1715 		if (ret)
1716 			return ret;
1717 	}
1718 	return 0;
1719 }
1720 
1721 static int
wimfs_readlink(const char * path,char * buf,size_t bufsize)1722 wimfs_readlink(const char *path, char *buf, size_t bufsize)
1723 {
1724 	struct wimfs_context *ctx = wimfs_get_context();
1725 	const struct wim_inode *inode;
1726 	int ret;
1727 
1728 	inode = wim_pathname_to_inode(ctx->wim, path);
1729 	if (!inode)
1730 		return -errno;
1731 	if (bufsize <= 0)
1732 		return -EINVAL;
1733 	ret = wim_inode_readlink(inode, buf, bufsize - 1, NULL,
1734 				 ctx->mountpoint_abspath,
1735 				 ctx->mountpoint_abspath_nchars);
1736 	if (ret < 0)
1737 		return ret;
1738 	buf[ret] = '\0';
1739 	return 0;
1740 }
1741 
1742 /* We use this for both release() and releasedir(), since in both cases we
1743  * simply need to close the file descriptor.  */
1744 static int
wimfs_release(const char * path,struct fuse_file_info * fi)1745 wimfs_release(const char *path, struct fuse_file_info *fi)
1746 {
1747 	return close_wimfs_fd(WIMFS_FD(fi));
1748 }
1749 
1750 static int
wimfs_removexattr(const char * path,const char * name)1751 wimfs_removexattr(const char *path, const char *name)
1752 {
1753 	struct wimfs_context *ctx = wimfs_get_context();
1754 	struct wim_inode *inode;
1755 	struct wim_inode_stream *strm;
1756 
1757 	if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1758 		return -ENOTSUP;
1759 
1760 	if (strncmp(name, "user.", 5))
1761 		return -ENOATTR;
1762 	name += 5;
1763 
1764 	if (!*name)
1765 		return -ENOATTR;
1766 
1767 	/* Removing a named data stream.  */
1768 
1769 	inode = wim_pathname_to_inode(ctx->wim, path);
1770 	if (!inode)
1771 		return -errno;
1772 
1773 	strm = inode_get_data_stream_tstr(inode, name);
1774 	if (!strm)
1775 		return (errno == ENOENT) ? -ENOATTR : -errno;
1776 
1777 	inode_remove_stream(inode, strm, ctx->wim->blob_table);
1778 	return 0;
1779 }
1780 
1781 static int
wimfs_rename(const char * from,const char * to)1782 wimfs_rename(const char *from, const char *to)
1783 {
1784 	return rename_wim_path(wimfs_get_WIMStruct(), from, to,
1785 			       WIMLIB_CASE_SENSITIVE, NULL);
1786 }
1787 
1788 static int
wimfs_rmdir(const char * path)1789 wimfs_rmdir(const char *path)
1790 {
1791 	WIMStruct *wim = wimfs_get_WIMStruct();
1792 	struct wim_dentry *dentry;
1793 
1794 	dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
1795 	if (!dentry)
1796 		return -errno;
1797 
1798 	if (!dentry_is_directory(dentry))
1799 		return -ENOTDIR;
1800 
1801 	if (dentry_has_children(dentry))
1802 		return -ENOTEMPTY;
1803 
1804 	touch_parent(dentry);
1805 	remove_dentry(dentry, wim->blob_table);
1806 	return 0;
1807 }
1808 
1809 static int
wimfs_setxattr(const char * path,const char * name,const char * value,size_t size,int flags)1810 wimfs_setxattr(const char *path, const char *name,
1811 	       const char *value, size_t size, int flags)
1812 {
1813 	struct wimfs_context *ctx = wimfs_get_context();
1814 	struct wim_inode *inode;
1815 	struct wim_inode_stream *strm;
1816 	const utf16lechar *uname;
1817 	int ret;
1818 
1819 	if (!strncmp(name, "wimfs.", 6)) {
1820 		/* Handle some magical extended attributes.  These really should
1821 		 * be ioctls, but directory ioctls aren't supported until
1822 		 * libfuse 2.9, and even then they are broken.  [Fixed by
1823 		 * libfuse commit e3b7d4c278a26520be63d99d6ea84b26906fe73d]  */
1824 		name += 6;
1825 		if (!strcmp(name, "unmount_info")) {
1826 			if (!may_unmount_wimfs())
1827 				return -EPERM;
1828 			if (size < sizeof(struct wimfs_unmount_info))
1829 				return -EINVAL;
1830 			memcpy(&ctx->unmount_info, value,
1831 			       sizeof(struct wimfs_unmount_info));
1832 			return 0;
1833 		}
1834 		return -ENOATTR;
1835 	}
1836 
1837 	if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1838 		return -ENOTSUP;
1839 
1840 	if (strncmp(name, "user.", 5))
1841 		return -ENOATTR;
1842 	name += 5;
1843 
1844 	if (!*name)
1845 		return -ENOATTR;
1846 
1847 	/* Setting the contents of a named data stream.  */
1848 
1849 	inode = wim_pathname_to_inode(ctx->wim, path);
1850 	if (!inode)
1851 		return -errno;
1852 
1853 	ret = tstr_get_utf16le(name, &uname);
1854 	if (ret)
1855 		return -errno;
1856 
1857 	strm = inode_get_stream(inode, STREAM_TYPE_DATA, uname);
1858 	if (strm) {
1859 		ret = -EEXIST;
1860 		if (flags & XATTR_CREATE)
1861 			goto out_put_uname;
1862 	} else {
1863 		ret = -ENOATTR;
1864 		if (flags & XATTR_REPLACE)
1865 			goto out_put_uname;
1866 	}
1867 
1868 	if (strm) {
1869 		if (!inode_replace_stream_data(inode, strm, value, size,
1870 					       ctx->wim->blob_table))
1871 		{
1872 			ret = -errno;
1873 			goto out_put_uname;
1874 		}
1875 	} else {
1876 		if (!inode_add_stream_with_data(inode, STREAM_TYPE_DATA, uname,
1877 						value, size, ctx->wim->blob_table))
1878 		{
1879 			ret = -errno;
1880 			goto out_put_uname;
1881 		}
1882 	}
1883 
1884 	ret = 0;
1885 out_put_uname:
1886 	tstr_put_utf16le(uname);
1887 	return ret;
1888 }
1889 
1890 static int
wimfs_symlink(const char * to,const char * from)1891 wimfs_symlink(const char *to, const char *from)
1892 {
1893 	struct fuse_context *fuse_ctx = fuse_get_context();
1894 	struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1895 	struct wim_dentry *dentry;
1896 	int ret;
1897 
1898 	ret = create_file(fuse_ctx, from, S_IFLNK | 0777, 0, &dentry);
1899 	if (ret)
1900 		return ret;
1901 	ret = wim_inode_set_symlink(dentry->d_inode, to,
1902 				    wimfs_ctx->wim->blob_table);
1903 	if (ret) {
1904 		remove_dentry(dentry, wimfs_ctx->wim->blob_table);
1905 		if (ret == WIMLIB_ERR_NOMEM)
1906 			ret = -ENOMEM;
1907 		else
1908 			ret = -EINVAL;
1909 	} else {
1910 		touch_parent(dentry);
1911 	}
1912 	return ret;
1913 }
1914 
1915 static int
wimfs_truncate(const char * path,off_t size)1916 wimfs_truncate(const char *path, off_t size)
1917 {
1918 	const struct wimfs_context *ctx = wimfs_get_context();
1919 	struct wim_dentry *dentry;
1920 	struct wim_inode_stream *strm;
1921 	struct blob_descriptor *blob;
1922 	int ret;
1923 	int fd;
1924 
1925 	ret = wim_pathname_to_stream(ctx, path, 0, &dentry, &strm);
1926 	if (ret)
1927 		return ret;
1928 
1929 	blob = stream_blob_resolved(strm);
1930 
1931 	if (!blob && !size)
1932 		return 0;
1933 
1934 	if (!blob || blob->blob_location != BLOB_IN_STAGING_FILE) {
1935 		return extract_blob_to_staging_dir(dentry->d_inode,
1936 						   strm, size, ctx);
1937 	}
1938 
1939 	/* Truncate the staging file.  */
1940 	fd = openat(blob->staging_dir_fd, blob->staging_file_name,
1941 		    O_WRONLY | O_NOFOLLOW);
1942 	if (fd < 0)
1943 		return -errno;
1944 	ret = ftruncate(fd, size);
1945 	if (close(fd) || ret)
1946 		return -errno;
1947 	blob->size = size;
1948 	touch_inode(dentry->d_inode);
1949 	return 0;
1950 }
1951 
1952 static int
wimfs_unlink(const char * path)1953 wimfs_unlink(const char *path)
1954 {
1955 	const struct wimfs_context *ctx = wimfs_get_context();
1956 	struct wim_dentry *dentry;
1957 	struct wim_inode_stream *strm;
1958 	int ret;
1959 
1960 	ret = wim_pathname_to_stream(ctx, path, 0, &dentry, &strm);
1961 	if (ret)
1962 		return ret;
1963 
1964 	if (stream_is_named(strm)) {
1965 		inode_remove_stream(dentry->d_inode, strm,
1966 				    ctx->wim->blob_table);
1967 	} else {
1968 		touch_parent(dentry);
1969 		remove_dentry(dentry, ctx->wim->blob_table);
1970 	}
1971 	return 0;
1972 }
1973 
1974 #ifdef HAVE_UTIMENSAT
1975 /*
1976  * Change the timestamp on a file dentry.
1977  *
1978  * Note that alternate data streams do not have their own timestamps.
1979  */
1980 static int
wimfs_utimens(const char * path,const struct timespec tv[2])1981 wimfs_utimens(const char *path, const struct timespec tv[2])
1982 {
1983 	WIMStruct *wim = wimfs_get_WIMStruct();
1984 	struct wim_inode *inode;
1985 
1986 	inode = wim_pathname_to_inode(wim, path);
1987 	if (!inode)
1988 		return -errno;
1989 
1990 	if (tv[0].tv_nsec != UTIME_OMIT) {
1991 		if (tv[0].tv_nsec == UTIME_NOW)
1992 			inode->i_last_access_time = now_as_wim_timestamp();
1993 		else
1994 			inode->i_last_access_time = timespec_to_wim_timestamp(&tv[0]);
1995 	}
1996 	if (tv[1].tv_nsec != UTIME_OMIT) {
1997 		if (tv[1].tv_nsec == UTIME_NOW)
1998 			inode->i_last_write_time = now_as_wim_timestamp();
1999 		else
2000 			inode->i_last_write_time = timespec_to_wim_timestamp(&tv[1]);
2001 	}
2002 	return 0;
2003 }
2004 #else /* HAVE_UTIMENSAT */
2005 static int
wimfs_utime(const char * path,struct utimbuf * times)2006 wimfs_utime(const char *path, struct utimbuf *times)
2007 {
2008 	WIMStruct *wim = wimfs_get_WIMStruct();
2009 	struct wim_inode *inode;
2010 
2011 	inode = wim_pathname_to_inode(wim, path);
2012 	if (!inode)
2013 		return -errno;
2014 
2015 	inode->i_last_access_time = time_t_to_wim_timestamp(times->actime);
2016 	inode->i_last_write_time = time_t_to_wim_timestamp(times->modtime);
2017 	return 0;
2018 }
2019 #endif /* !HAVE_UTIMENSAT */
2020 
2021 static int
wimfs_write(const char * path,const char * buf,size_t size,off_t offset,struct fuse_file_info * fi)2022 wimfs_write(const char *path, const char *buf, size_t size,
2023 	    off_t offset, struct fuse_file_info *fi)
2024 {
2025 	struct wimfs_fd *fd = WIMFS_FD(fi);
2026 	ssize_t ret;
2027 
2028 	ret = pwrite(fd->f_staging_fd.fd, buf, size, offset);
2029 	if (ret < 0)
2030 		return -errno;
2031 
2032 	if (offset + size > fd->f_blob->size)
2033 		fd->f_blob->size = offset + size;
2034 
2035 	touch_inode(fd->f_inode);
2036 	return ret;
2037 }
2038 
2039 static const struct fuse_operations wimfs_operations = {
2040 	.chmod       = wimfs_chmod,
2041 	.chown       = wimfs_chown,
2042 	.fgetattr    = wimfs_fgetattr,
2043 	.ftruncate   = wimfs_ftruncate,
2044 	.getattr     = wimfs_getattr,
2045 	.getxattr    = wimfs_getxattr,
2046 	.link        = wimfs_link,
2047 	.listxattr   = wimfs_listxattr,
2048 	.mkdir       = wimfs_mkdir,
2049 	.mknod       = wimfs_mknod,
2050 	.open        = wimfs_open,
2051 	.opendir     = wimfs_opendir,
2052 	.read        = wimfs_read,
2053 	.readdir     = wimfs_readdir,
2054 	.readlink    = wimfs_readlink,
2055 	.release     = wimfs_release,
2056 	.releasedir  = wimfs_release,
2057 	.removexattr = wimfs_removexattr,
2058 	.rename      = wimfs_rename,
2059 	.rmdir       = wimfs_rmdir,
2060 	.setxattr    = wimfs_setxattr,
2061 	.symlink     = wimfs_symlink,
2062 	.truncate    = wimfs_truncate,
2063 	.unlink      = wimfs_unlink,
2064 #ifdef HAVE_UTIMENSAT
2065 	.utimens     = wimfs_utimens,
2066 #else
2067 	.utime       = wimfs_utime,
2068 #endif
2069 	.write       = wimfs_write,
2070 
2071 	/* We keep track of file descriptor structures (struct wimfs_fd), so
2072 	 * there is no need to have the file path provided on operations such as
2073 	 * read().  */
2074 #if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 8)
2075 	.flag_nullpath_ok = 1,
2076 #endif
2077 #if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 9)
2078 	.flag_nopath = 1,
2079 	.flag_utime_omit_ok = 1,
2080 #endif
2081 };
2082 
2083 /* API function documented in wimlib.h  */
2084 WIMLIBAPI int
wimlib_mount_image(WIMStruct * wim,int image,const char * dir,int mount_flags,const char * staging_dir)2085 wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
2086 		   int mount_flags, const char *staging_dir)
2087 {
2088 	int ret;
2089 	struct wim_image_metadata *imd;
2090 	struct wimfs_context ctx;
2091 	char *fuse_argv[16];
2092 	int fuse_argc;
2093 
2094 	if (!wim || !dir || !*dir)
2095 		return WIMLIB_ERR_INVALID_PARAM;
2096 
2097 	if (mount_flags & ~(WIMLIB_MOUNT_FLAG_READWRITE |
2098 			    WIMLIB_MOUNT_FLAG_DEBUG |
2099 			    WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
2100 			    WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR |
2101 			    WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS |
2102 			    WIMLIB_MOUNT_FLAG_UNIX_DATA |
2103 			    WIMLIB_MOUNT_FLAG_ALLOW_OTHER))
2104 		return WIMLIB_ERR_INVALID_PARAM;
2105 
2106 	/* For read-write mount, check for write access to the WIM.  */
2107 	if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
2108 		if (!wim->filename)
2109 			return WIMLIB_ERR_NO_FILENAME;
2110 		ret = can_modify_wim(wim);
2111 		if (ret)
2112 			return ret;
2113 	}
2114 
2115 	/* Select the image to mount.  */
2116 	ret = select_wim_image(wim, image);
2117 	if (ret)
2118 		return ret;
2119 
2120 	/* Get the metadata for the image to mount.  */
2121 	imd = wim_get_current_image_metadata(wim);
2122 
2123 	/* To avoid complicating things, we don't support mounting images to
2124 	 * which in-memory modifications have already been made.  */
2125 	if (is_image_dirty(imd)) {
2126 		ERROR("Cannot mount a modified WIM image!");
2127 		return WIMLIB_ERR_INVALID_PARAM;
2128 	}
2129 
2130 	if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
2131 		if (imd->refcnt > 1)
2132 			return WIMLIB_ERR_IMAGE_HAS_MULTIPLE_REFERENCES;
2133 		ret = lock_wim_for_append(wim);
2134 		if (ret)
2135 			return ret;
2136 	}
2137 
2138 	if (wim_has_solid_resources(wim)) {
2139 		WARNING("Mounting a WIM file containing solid-compressed data; "
2140 			"file access may be slow.");
2141 	}
2142 
2143 	/* If the user did not specify an interface for accessing named
2144 	 * data streams, use the default (extended attributes).  */
2145 	if (!(mount_flags & (WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
2146 			     WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR |
2147 			     WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)))
2148 		mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR;
2149 
2150 	/* Start initializing the wimfs_context.  */
2151 	memset(&ctx, 0, sizeof(struct wimfs_context));
2152 	ctx.wim = wim;
2153 	ctx.mount_flags = mount_flags;
2154 	if (mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
2155 		ctx.default_lookup_flags = LOOKUP_FLAG_ADS_OK;
2156 
2157 	/* For read-write mounts, create the staging directory, save a reference
2158 	 * to the image's metadata resource, and mark the image dirty.  */
2159 	if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
2160 		ret = make_staging_dir(&ctx, staging_dir);
2161 		if (ret)
2162 			goto out;
2163 		ret = WIMLIB_ERR_NOMEM;
2164 		ctx.metadata_resource = clone_blob_descriptor(
2165 							imd->metadata_blob);
2166 		if (!ctx.metadata_resource)
2167 			goto out;
2168 		mark_image_dirty(imd);
2169 	}
2170 	ctx.owner_uid = getuid();
2171 	ctx.owner_gid = getgid();
2172 
2173 	/* Number the inodes in the mounted image sequentially and initialize
2174 	 * the file descriptor arrays  */
2175 	prepare_inodes(&ctx);
2176 
2177 	/* Save the absolute path to the mountpoint directory.  */
2178 	ctx.mountpoint_abspath = realpath(dir, NULL);
2179 	if (ctx.mountpoint_abspath)
2180 		ctx.mountpoint_abspath_nchars = strlen(ctx.mountpoint_abspath);
2181 
2182 	/* Build the FUSE command line.  */
2183 
2184 	fuse_argc = 0;
2185 	fuse_argv[fuse_argc++] = "wimlib";
2186 	fuse_argv[fuse_argc++] = (char *)dir;
2187 
2188 	/* Disable multi-threaded operation.  */
2189 	fuse_argv[fuse_argc++] = "-s";
2190 
2191 	/* Enable FUSE debug mode (don't fork) if requested by the user.  */
2192 	if (mount_flags & WIMLIB_MOUNT_FLAG_DEBUG)
2193 		fuse_argv[fuse_argc++] = "-d";
2194 
2195 	/*
2196 	 * Build the FUSE mount options:
2197 	 *
2198 	 * use_ino
2199 	 *	FUSE will use the inode numbers we provide.  We want this,
2200 	 *	because we have inodes and will number them ourselves.
2201 	 *
2202 	 * subtype=wimfs
2203 	 *	Name for our filesystem (main type is "fuse").
2204 	 *
2205 	 * hard_remove
2206 	 *	If an open file is unlinked, unlink it for real rather than
2207 	 *	renaming it to a hidden file.  Our code supports this; an
2208 	 *	unlinked inode is retained until all its file descriptors have
2209 	 *	been closed.
2210 	 *
2211 	 * default_permissions
2212 	 *	FUSE will perform permission checking.  Useful when
2213 	 *	WIMLIB_MOUNT_FLAG_UNIX_DATA is provided and the WIM image
2214 	 *	contains the UNIX permissions for each file.
2215 	 *
2216 	 * kernel_cache
2217 	 *	Cache the contents of files.  This will speed up repeated access
2218 	 *	to files on a mounted WIM image, since they won't need to be
2219 	 *	decompressed repeatedly.  This option is valid because data in
2220 	 *	the WIM image should never be changed externally.  (Although, if
2221 	 *	someone really wanted to they could modify the WIM file or mess
2222 	 *	with the staging directory; but then they're asking for
2223 	 *	trouble.)
2224 	 *
2225 	 * entry_timeout=1000000000
2226 	 *	Cache positive name lookups indefinitely, since names can only
2227 	 *	be added, removed, or modified through the mounted filesystem
2228 	 *	itself.
2229 	 *
2230 	 * negative_timeout=1000000000
2231 	 *	Cache negative name lookups indefinitely, since names can only
2232 	 *	be added, removed, or modified through the mounted filesystem
2233 	 *	itself.
2234 	 *
2235 	 * attr_timeout=0
2236 	 *	Don't cache file/directory attributes.  This is needed as a
2237 	 *	workaround for the fact that when caching attributes, the high
2238 	 *	level interface to libfuse considers a file which has several
2239 	 *	hard-linked names as several different files.  (Otherwise, we
2240 	 *	could cache our file/directory attributes indefinitely, since
2241 	 *	they can only be changed through the mounted filesystem itself.)
2242 	 */
2243 	char optstring[256] =
2244 		"use_ino"
2245 		",subtype=wimfs"
2246 		",hard_remove"
2247 		",default_permissions"
2248 		",kernel_cache"
2249 		",entry_timeout=1000000000"
2250 		",negative_timeout=1000000000"
2251 		",attr_timeout=0"
2252 		;
2253 	fuse_argv[fuse_argc++] = "-o";
2254 	fuse_argv[fuse_argc++] = optstring;
2255 	if (!(mount_flags & WIMLIB_MOUNT_FLAG_READWRITE))
2256 		strcat(optstring, ",ro");
2257 	if (mount_flags & WIMLIB_MOUNT_FLAG_ALLOW_OTHER)
2258 		strcat(optstring, ",allow_other");
2259 	fuse_argv[fuse_argc] = NULL;
2260 
2261 	/* Mount our filesystem.  */
2262 	ret = fuse_main(fuse_argc, fuse_argv, &wimfs_operations, &ctx);
2263 
2264 	/* Cleanup and return.  */
2265 	if (ret)
2266 		ret = WIMLIB_ERR_FUSE;
2267 out:
2268 	FREE(ctx.mountpoint_abspath);
2269 	free_blob_descriptor(ctx.metadata_resource);
2270 	if (ctx.staging_dir_name)
2271 		delete_staging_dir(&ctx);
2272 	unlock_wim_for_append(wim);
2273 	return ret;
2274 }
2275 
2276 struct commit_progress_thread_args {
2277 	mqd_t mq;
2278 	wimlib_progress_func_t progfunc;
2279 	void *progctx;
2280 };
2281 
2282 static void *
commit_progress_thread_proc(void * _args)2283 commit_progress_thread_proc(void *_args)
2284 {
2285 	struct commit_progress_thread_args *args = _args;
2286 	struct commit_progress_report report;
2287 	ssize_t ret;
2288 
2289 	for (;;) {
2290 		ret = mq_receive(args->mq,
2291 				 (char *)&report, sizeof(report), NULL);
2292 		if (ret == sizeof(report)) {
2293 			call_progress(args->progfunc, report.msg,
2294 				      &report.info, args->progctx);
2295 		} else {
2296 			if (ret == 0 || (ret < 0 && errno != EINTR))
2297 				break;
2298 		}
2299 	}
2300 	return NULL;
2301 }
2302 
2303 static void
generate_message_queue_name(char name[WIMFS_MQUEUE_NAME_LEN+1])2304 generate_message_queue_name(char name[WIMFS_MQUEUE_NAME_LEN + 1])
2305 {
2306 	name[0] = '/';
2307 	memcpy(name + 1, "wimfs-", 6);
2308 	get_random_alnum_chars(name + 7, WIMFS_MQUEUE_NAME_LEN - 7);
2309 	name[WIMFS_MQUEUE_NAME_LEN] = '\0';
2310 }
2311 
2312 static mqd_t
create_message_queue(const char * name)2313 create_message_queue(const char *name)
2314 {
2315 	bool am_root;
2316 	mode_t umask_save;
2317 	mode_t mode;
2318 	struct mq_attr attr;
2319 	mqd_t mq;
2320 
2321 	memset(&attr, 0, sizeof(attr));
2322 	attr.mq_maxmsg = 8;
2323 	attr.mq_msgsize = sizeof(struct commit_progress_report);
2324 
2325 	am_root = (geteuid() == 0);
2326 	if (am_root) {
2327 		/* Filesystem mounted as normal user with --allow-other should
2328 		 * be able to send messages to root user, if they're doing the
2329 		 * unmount.  */
2330 		umask_save = umask(0);
2331 		mode = 0666;
2332 	} else {
2333 		mode = 0600;
2334 	}
2335 	mq = mq_open(name, O_RDWR | O_CREAT | O_EXCL, mode, &attr);
2336 	if (am_root)
2337 		umask(umask_save);
2338 	return mq;
2339 }
2340 
2341 /* Unmount a read-only or read-write mounted WIM image.  */
2342 static int
do_unmount(const char * dir)2343 do_unmount(const char *dir)
2344 {
2345 	int status;
2346 	ssize_t len;
2347 
2348 	len = getxattr(dir, "wimfs.unmount", &status, sizeof(int));
2349 	if (len == sizeof(int))
2350 		return status;
2351 	else if (len < 0 && (errno == EACCES || errno == EPERM))
2352 		return WIMLIB_ERR_NOT_PERMITTED_TO_UNMOUNT;
2353 	else
2354 		return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2355 }
2356 
2357 static int
set_unmount_info(const char * dir,const struct wimfs_unmount_info * unmount_info)2358 set_unmount_info(const char *dir, const struct wimfs_unmount_info *unmount_info)
2359 {
2360 	if (!setxattr(dir, "wimfs.unmount_info",
2361 		      unmount_info, sizeof(struct wimfs_unmount_info), 0))
2362 		return 0;
2363 	else if (errno == EROFS)
2364 		return 0;
2365 	else if (errno == EACCES || errno == EPERM)
2366 		return WIMLIB_ERR_NOT_PERMITTED_TO_UNMOUNT;
2367 	else
2368 		return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2369 }
2370 
2371 static int
do_unmount_discard(const char * dir)2372 do_unmount_discard(const char *dir)
2373 {
2374 	int ret;
2375 	struct wimfs_unmount_info unmount_info;
2376 
2377 	memset(&unmount_info, 0, sizeof(unmount_info));
2378 
2379 	ret = set_unmount_info(dir, &unmount_info);
2380 	if (ret)
2381 		return ret;
2382 	return do_unmount(dir);
2383 }
2384 
2385 /* Unmount a read-write mounted WIM image, committing the changes.  */
2386 static int
do_unmount_commit(const char * dir,int unmount_flags,wimlib_progress_func_t progfunc,void * progctx)2387 do_unmount_commit(const char *dir, int unmount_flags,
2388 		  wimlib_progress_func_t progfunc, void *progctx)
2389 {
2390 	struct wimfs_unmount_info unmount_info;
2391 	mqd_t mq;
2392 	struct commit_progress_thread_args args;
2393 	pthread_t commit_progress_tid;
2394 	int ret;
2395 
2396 	memset(&unmount_info, 0, sizeof(unmount_info));
2397 	unmount_info.unmount_flags = unmount_flags;
2398 
2399 	/* The current thread will be stuck in getxattr() until the image is
2400 	 * committed.  Create a thread to handle the progress messages.  */
2401 	if (progfunc) {
2402 		generate_message_queue_name(unmount_info.mq_name);
2403 
2404 		mq = create_message_queue(unmount_info.mq_name);
2405 		if (mq == (mqd_t)-1) {
2406 			ERROR_WITH_ERRNO("Can't create POSIX message queue");
2407 			return WIMLIB_ERR_MQUEUE;
2408 		}
2409 		args.mq = mq;
2410 		args.progfunc = progfunc;
2411 		args.progctx = progctx;
2412 		ret = pthread_create(&commit_progress_tid, NULL,
2413 				     commit_progress_thread_proc, &args);
2414 		if (ret) {
2415 			errno = ret;
2416 			ERROR_WITH_ERRNO("Can't create thread");
2417 			ret = WIMLIB_ERR_NOMEM;
2418 			goto out_delete_mq;
2419 		}
2420 		unmount_info.unmount_flags |= WIMLIB_UNMOUNT_FLAG_SEND_PROGRESS;
2421 	}
2422 
2423 	ret = set_unmount_info(dir, &unmount_info);
2424 	if (!ret)
2425 		ret = do_unmount(dir);
2426 	if (progfunc) {
2427 		/* Terminate the progress thread.  */
2428 		char empty[1];
2429 		mq_send(mq, empty, 0, 1);
2430 		pthread_join(commit_progress_tid, NULL);
2431 	}
2432 out_delete_mq:
2433 	if (progfunc) {
2434 		mq_close(mq);
2435 		mq_unlink(unmount_info.mq_name);
2436 	}
2437 	return ret;
2438 }
2439 
2440 static int
begin_unmount(const char * dir,int unmount_flags,int * mount_flags_ret,wimlib_progress_func_t progfunc,void * progctx)2441 begin_unmount(const char *dir, int unmount_flags, int *mount_flags_ret,
2442 	      wimlib_progress_func_t progfunc, void *progctx)
2443 {
2444 	int mount_flags;
2445 	int mounted_image;
2446 	int wim_filename_len;
2447 	union wimlib_progress_info progress;
2448 
2449 	if (getxattr(dir, "wimfs.mount_flags",
2450 		     &mount_flags, sizeof(int)) != sizeof(int))
2451 		return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2452 
2453 	*mount_flags_ret = mount_flags;
2454 
2455 	if (!progfunc)
2456 		return 0;
2457 
2458 	if (getxattr(dir, "wimfs.mounted_image",
2459 		     &mounted_image, sizeof(int)) != sizeof(int))
2460 		return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2461 
2462 	wim_filename_len = getxattr(dir, "wimfs.wim_filename", NULL, 0);
2463 	if (wim_filename_len < 0)
2464 		return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2465 
2466 	char wim_filename[wim_filename_len + 1];
2467 	if (getxattr(dir, "wimfs.wim_filename",
2468 		     wim_filename, wim_filename_len) != wim_filename_len)
2469 		return WIMLIB_ERR_NOT_A_MOUNTPOINT;
2470 	wim_filename[wim_filename_len] = '\0';
2471 
2472 	progress.unmount.mountpoint = dir;
2473 	progress.unmount.mounted_wim = wim_filename;
2474 	progress.unmount.mounted_image = mounted_image;
2475 	progress.unmount.mount_flags = mount_flags;
2476 	progress.unmount.unmount_flags = unmount_flags;
2477 
2478 	return call_progress(progfunc, WIMLIB_PROGRESS_MSG_UNMOUNT_BEGIN,
2479 			     &progress, progctx);
2480 }
2481 
2482 /* API function documented in wimlib.h  */
2483 WIMLIBAPI int
wimlib_unmount_image_with_progress(const char * dir,int unmount_flags,wimlib_progress_func_t progfunc,void * progctx)2484 wimlib_unmount_image_with_progress(const char *dir, int unmount_flags,
2485 				   wimlib_progress_func_t progfunc, void *progctx)
2486 {
2487 	int mount_flags;
2488 	int ret;
2489 
2490 	ret = wimlib_global_init(0);
2491 	if (ret)
2492 		return ret;
2493 
2494 	if (unmount_flags & ~(WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY |
2495 			      WIMLIB_UNMOUNT_FLAG_COMMIT |
2496 			      WIMLIB_UNMOUNT_FLAG_REBUILD |
2497 			      WIMLIB_UNMOUNT_FLAG_RECOMPRESS |
2498 			      WIMLIB_UNMOUNT_FLAG_FORCE |
2499 			      WIMLIB_UNMOUNT_FLAG_NEW_IMAGE))
2500 		return WIMLIB_ERR_INVALID_PARAM;
2501 
2502 	ret = begin_unmount(dir, unmount_flags, &mount_flags,
2503 			    progfunc, progctx);
2504 	if (ret)
2505 		return ret;
2506 
2507 	if ((unmount_flags & WIMLIB_UNMOUNT_FLAG_COMMIT) &&
2508 	    (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE))
2509 		return do_unmount_commit(dir, unmount_flags,
2510 					 progfunc, progctx);
2511 	else
2512 		return do_unmount_discard(dir);
2513 }
2514 
2515 #else /* WITH_FUSE */
2516 
2517 
2518 static int
mount_unsupported_error(void)2519 mount_unsupported_error(void)
2520 {
2521 #if defined(__WIN32__)
2522 	ERROR("Sorry-- Mounting WIM images is not supported on Windows!");
2523 #else
2524 	ERROR("wimlib was compiled with --without-fuse, which disables support "
2525 	      "for mounting WIMs.");
2526 #endif
2527 	return WIMLIB_ERR_UNSUPPORTED;
2528 }
2529 
2530 WIMLIBAPI int
wimlib_unmount_image_with_progress(const tchar * dir,int unmount_flags,wimlib_progress_func_t progfunc,void * progctx)2531 wimlib_unmount_image_with_progress(const tchar *dir, int unmount_flags,
2532 				   wimlib_progress_func_t progfunc, void *progctx)
2533 {
2534 	return mount_unsupported_error();
2535 }
2536 
2537 WIMLIBAPI int
wimlib_mount_image(WIMStruct * wim,int image,const tchar * dir,int mount_flags,const tchar * staging_dir)2538 wimlib_mount_image(WIMStruct *wim, int image, const tchar *dir,
2539 		   int mount_flags, const tchar *staging_dir)
2540 {
2541 	return mount_unsupported_error();
2542 }
2543 
2544 #endif /* !WITH_FUSE */
2545 
2546 WIMLIBAPI int
wimlib_unmount_image(const tchar * dir,int unmount_flags)2547 wimlib_unmount_image(const tchar *dir, int unmount_flags)
2548 {
2549 	return wimlib_unmount_image_with_progress(dir, unmount_flags, NULL, NULL);
2550 }
2551