]> wimlib.net Git - wimlib/blob - src/mount_image.c
Clean up headers
[wimlib] / src / mount_image.c
1 /*
2  * mount_image.c
3  *
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.
8  */
9
10 /*
11  * Copyright (C) 2012, 2013 Eric Biggers
12  *
13  * This file is part of wimlib, a library for working with WIM files.
14  *
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)
18  * any later version.
19  *
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
23  * details.
24  *
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/.
27  */
28
29 #include "wimlib_internal.h"
30
31 #ifdef WITH_FUSE
32
33 #include "buffer_io.h"
34 #include "lookup_table.h"
35 #include "sha1.h"
36 #include "timestamp.h"
37 #include "xml.h"
38
39 #include <errno.h>
40 #include <ftw.h>
41 #include <limits.h>
42 #include <mqueue.h>
43 #include <signal.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <sys/stat.h>
47 #include <sys/time.h>
48 #include <sys/types.h>
49 #include <sys/wait.h>
50 #include <unistd.h>
51 #include <utime.h>
52
53 #define FUSE_USE_VERSION 26
54 #include <fuse.h>
55
56 #ifdef ENABLE_XATTR
57 #include <attr/xattr.h>
58 #endif
59
60 #define MSG_VERSION_TOO_HIGH    -1
61 #define MSG_BREAK_LOOP          -2
62
63 /* File descriptor to a file open on the WIM filesystem. */
64 struct wimfs_fd {
65         struct wim_inode *f_inode;
66         struct wim_lookup_table_entry *f_lte;
67         int staging_fd;
68         u16 idx;
69         u32 stream_id;
70 };
71
72 struct wimfs_context {
73         /* The WIMStruct for the mounted WIM. */
74         WIMStruct *wim;
75
76         /* Name of the staging directory for a read-write mount.  Whenever a new file is
77          * created, it is done so in the staging directory.  Furthermore, whenever a
78          * file in the WIM is modified, it is extracted to the staging directory.  If
79          * changes are commited when the WIM is unmounted, the file resources are merged
80          * in from the staging directory when writing the new WIM. */
81         char *staging_dir_name;
82         size_t staging_dir_name_len;
83
84         /* Flags passed to wimlib_mount(). */
85         int mount_flags;
86
87         /* Default flags to use when looking up a WIM dentry (depends on whether
88          * the Windows interface to alternate data streams is being used or
89          * not). */
90         int default_lookup_flags;
91
92         /* Next inode number to be assigned.  Note: I didn't bother with a
93          * bitmap of free inode numbers since this isn't even a "real"
94          * filesystem anyway. */
95         u64 next_ino;
96
97         /* List of lookup table entries for files in the staging directory */
98         struct list_head staging_list;
99
100         /* List of inodes in the mounted image */
101         struct hlist_head *image_inode_list;
102
103         /* Name and message queue descriptors for message queues between the
104          * filesystem daemon process and the unmount process.  These are used
105          * when the filesystem is unmounted and the process running
106          * wimlib_unmount_image() (i.e. the `imagex unmount' command) needs to
107          * communicate with the filesystem daemon running fuse_main() (i.e. the
108          * daemon created by the `imagex mount' or `imagex mountrw' commands */
109         char *unmount_to_daemon_mq_name;
110         char *daemon_to_unmount_mq_name;
111         mqd_t unmount_to_daemon_mq;
112         mqd_t daemon_to_unmount_mq;
113
114         uid_t default_uid;
115         gid_t default_gid;
116
117         int status;
118         bool have_status;
119 };
120
121 static void init_wimfs_context(struct wimfs_context *ctx)
122 {
123         memset(ctx, 0, sizeof(*ctx));
124         ctx->unmount_to_daemon_mq = (mqd_t)-1;
125         ctx->daemon_to_unmount_mq = (mqd_t)-1;
126         INIT_LIST_HEAD(&ctx->staging_list);
127 }
128
129 #define WIMFS_CTX(fuse_ctx) ((struct wimfs_context*)(fuse_ctx)->private_data)
130
131 static inline struct wimfs_context *wimfs_get_context()
132 {
133         return WIMFS_CTX(fuse_get_context());
134 }
135
136 static inline WIMStruct *wimfs_get_WIMStruct()
137 {
138         return wimfs_get_context()->wim;
139 }
140
141 static inline bool wimfs_ctx_readonly(const struct wimfs_context *ctx)
142 {
143         return (ctx->mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) == 0;
144 }
145
146 static inline int get_lookup_flags(const struct wimfs_context *ctx)
147 {
148         return ctx->default_lookup_flags;
149 }
150
151 /* Returns nonzero if write permission is requested on the file open flags */
152 static inline int flags_writable(int open_flags)
153 {
154         return open_flags & (O_RDWR | O_WRONLY);
155 }
156
157 /*
158  * Allocate a file descriptor for a stream.
159  *
160  * @inode:      inode containing the stream we're opening
161  * @stream_id:  ID of the stream we're opening
162  * @lte:        Lookup table entry for the stream (may be NULL)
163  * @fd_ret:     Return the allocated file descriptor if successful.
164  * @readonly:   True if this is a read-only mount.
165  *
166  * Return 0 iff successful or error code if unsuccessful.
167  */
168 static int alloc_wimfs_fd(struct wim_inode *inode,
169                           u32 stream_id,
170                           struct wim_lookup_table_entry *lte,
171                           struct wimfs_fd **fd_ret,
172                           bool readonly)
173 {
174         static const u16 fds_per_alloc = 8;
175         static const u16 max_fds = 0xffff;
176         int ret;
177
178         pthread_mutex_lock(&inode->i_mutex);
179
180         DEBUG("Allocating fd for stream ID %u from inode %#"PRIx64" "
181               "(open = %u, allocated = %u)",
182               stream_id, inode->i_ino, inode->i_num_opened_fds,
183               inode->i_num_allocated_fds);
184
185         if (inode->i_num_opened_fds == inode->i_num_allocated_fds) {
186                 struct wimfs_fd **fds;
187                 u16 num_new_fds;
188
189                 if (inode->i_num_allocated_fds == max_fds) {
190                         ret = -EMFILE;
191                         goto out;
192                 }
193                 num_new_fds = min(fds_per_alloc,
194                                   max_fds - inode->i_num_allocated_fds);
195
196                 fds = REALLOC(inode->i_fds,
197                               (inode->i_num_allocated_fds + num_new_fds) *
198                                 sizeof(inode->i_fds[0]));
199                 if (!fds) {
200                         ret = -ENOMEM;
201                         goto out;
202                 }
203                 memset(&fds[inode->i_num_allocated_fds], 0,
204                        num_new_fds * sizeof(fds[0]));
205                 inode->i_fds = fds;
206                 inode->i_num_allocated_fds += num_new_fds;
207         }
208         for (u16 i = 0; ; i++) {
209                 if (!inode->i_fds[i]) {
210                         struct wimfs_fd *fd = CALLOC(1, sizeof(*fd));
211                         if (!fd) {
212                                 ret = -ENOMEM;
213                                 break;
214                         }
215                         fd->f_inode    = inode;
216                         fd->f_lte      = lte;
217                         fd->staging_fd = -1;
218                         fd->idx        = i;
219                         fd->stream_id  = stream_id;
220                         *fd_ret        = fd;
221                         inode->i_fds[i]  = fd;
222                         inode->i_num_opened_fds++;
223                         if (lte && !readonly)
224                                 lte->num_opened_fds++;
225                         DEBUG("Allocated fd (idx = %u)", fd->idx);
226                         ret = 0;
227                         break;
228                 }
229         }
230 out:
231         pthread_mutex_unlock(&inode->i_mutex);
232         return ret;
233 }
234
235 static void inode_put_fd(struct wim_inode *inode, struct wimfs_fd *fd)
236 {
237         wimlib_assert(inode != NULL);
238
239         pthread_mutex_lock(&inode->i_mutex);
240
241         wimlib_assert(fd->f_inode == inode);
242         wimlib_assert(inode->i_num_opened_fds != 0);
243         wimlib_assert(fd->idx < inode->i_num_allocated_fds);
244         wimlib_assert(inode->i_fds[fd->idx] == fd);
245
246         inode->i_fds[fd->idx] = NULL;
247         FREE(fd);
248         if (--inode->i_num_opened_fds == 0 && inode->i_nlink == 0) {
249                 pthread_mutex_unlock(&inode->i_mutex);
250                 free_inode(inode);
251         } else {
252                 pthread_mutex_unlock(&inode->i_mutex);
253         }
254 }
255
256 static int lte_put_fd(struct wim_lookup_table_entry *lte, struct wimfs_fd *fd)
257 {
258         wimlib_assert(fd->f_lte == lte);
259
260         if (!lte) /* Empty stream with no lookup table entry */
261                 return 0;
262
263         /* Close staging file descriptor if needed. */
264
265         if (lte->resource_location == RESOURCE_IN_STAGING_FILE
266              && fd->staging_fd != -1)
267         {
268                 if (close(fd->staging_fd) != 0) {
269                         ERROR_WITH_ERRNO("Failed to close staging file");
270                         return -errno;
271                 }
272         }
273         lte_decrement_num_opened_fds(lte);
274         return 0;
275 }
276
277 /* Close a file descriptor. */
278 static int close_wimfs_fd(struct wimfs_fd *fd)
279 {
280         int ret;
281         DEBUG("Closing fd (ino = %#"PRIx64", opened = %u, allocated = %u)",
282               fd->f_inode->i_ino, fd->f_inode->i_num_opened_fds,
283               fd->f_inode->i_num_allocated_fds);
284         ret = lte_put_fd(fd->f_lte, fd);
285         if (ret != 0)
286                 return ret;
287
288         inode_put_fd(fd->f_inode, fd);
289         return 0;
290 }
291
292 /*
293  * Add a new dentry with a new inode to a WIM image.
294  *
295  * Returns 0 on success, or negative error number on failure.
296  */
297 static int create_dentry(struct fuse_context *fuse_ctx,const char *path,
298                          mode_t mode, int attributes,
299                          struct wim_dentry **dentry_ret)
300 {
301         struct wim_dentry *parent;
302         struct wim_dentry *new;
303         const char *basename;
304         struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
305
306         parent = get_parent_dentry(wimfs_ctx->wim, path);
307         if (!parent)
308                 return -errno;
309
310         if (!dentry_is_directory(parent))
311                 return -ENOTDIR;
312
313         basename = path_basename(path);
314         if (get_dentry_child_with_name(parent, basename))
315                 return -EEXIST;
316
317         new = new_dentry_with_inode(basename);
318         if (!new)
319                 return -errno;
320
321         new->d_inode->i_resolved = 1;
322         new->d_inode->i_ino = wimfs_ctx->next_ino++;
323         new->d_inode->i_attributes = attributes;
324
325         if (wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) {
326                 if (inode_set_unix_data(new->d_inode,
327                                         fuse_ctx->uid,
328                                         fuse_ctx->gid,
329                                         mode & ~fuse_ctx->umask,
330                                         wimfs_ctx->wim->lookup_table,
331                                         UNIX_DATA_ALL | UNIX_DATA_CREATE))
332                 {
333                         free_dentry(new);
334                         return -ENOMEM;
335                 }
336         }
337         dentry_add_child(parent, new);
338         hlist_add_head(&new->d_inode->i_hlist, wimfs_ctx->image_inode_list);
339         if (dentry_ret)
340                 *dentry_ret = new;
341         return 0;
342 }
343
344 /* Remove a dentry from a mounted WIM image; i.e. remove an alias for the
345  * corresponding inode.
346  *
347  * If there are no remaining references to the inode either through dentries or
348  * open file descriptors, the inode is freed.  Otherwise, the inode is not
349  * removed, but the dentry is unlinked and freed.
350  *
351  * Either way, all lookup table entries referenced by the inode have their
352  * reference count decremented.  If a lookup table entry has no open file
353  * descriptors and no references remaining, it is freed, and the corresponding
354  * staging file is unlinked.
355  */
356 static void remove_dentry(struct wim_dentry *dentry,
357                           struct wim_lookup_table *lookup_table)
358 {
359         struct wim_inode *inode = dentry->d_inode;
360         struct wim_lookup_table_entry *lte;
361         unsigned i;
362
363         for (i = 0; i <= inode->i_num_ads; i++) {
364                 lte = inode_stream_lte_resolved(inode, i);
365                 if (lte)
366                         lte_decrement_refcnt(lte, lookup_table);
367         }
368         unlink_dentry(dentry);
369         put_dentry(dentry);
370 }
371
372 static mode_t inode_default_unix_mode(const struct wim_inode *inode)
373 {
374         if (inode_is_symlink(inode))
375                 return S_IFLNK | 0777;
376         else if (inode_is_directory(inode))
377                 return S_IFDIR | 0777;
378         else
379                 return S_IFREG | 0777;
380 }
381
382 /* Transfers file attributes from a struct wim_inode to a `stat' buffer.
383  *
384  * The lookup table entry tells us which stream in the inode we are statting.
385  * For a named data stream, everything returned is the same as the unnamed data
386  * stream except possibly the size and block count. */
387 static int inode_to_stbuf(const struct wim_inode *inode,
388                           const struct wim_lookup_table_entry *lte,
389                           struct stat *stbuf)
390 {
391         const struct wimfs_context *ctx = wimfs_get_context();
392
393         memset(stbuf, 0, sizeof(struct stat));
394         stbuf->st_mode = inode_default_unix_mode(inode);
395         stbuf->st_uid = ctx->default_uid;
396         stbuf->st_gid = ctx->default_gid;
397         if (ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) {
398                 struct wimlib_unix_data unix_data;
399                 if (inode_get_unix_data(inode, &unix_data, NULL) == 0) {
400                         stbuf->st_uid = unix_data.uid;
401                         stbuf->st_gid = unix_data.gid;
402                         stbuf->st_mode = unix_data.mode;
403                 }
404         }
405         stbuf->st_ino = (ino_t)inode->i_ino;
406         stbuf->st_nlink = inode->i_nlink;
407         if (lte) {
408                 if (lte->resource_location == RESOURCE_IN_STAGING_FILE) {
409                         struct stat native_stat;
410                         if (stat(lte->staging_file_name, &native_stat) != 0) {
411                                 DEBUG("Failed to stat `%s': %m",
412                                       lte->staging_file_name);
413                                 return -errno;
414                         }
415                         stbuf->st_size = native_stat.st_size;
416                 } else {
417                         stbuf->st_size = wim_resource_size(lte);
418                 }
419         } else {
420                 stbuf->st_size = 0;
421         }
422
423         stbuf->st_atime = wim_timestamp_to_unix(inode->i_last_access_time);
424         stbuf->st_mtime = wim_timestamp_to_unix(inode->i_last_write_time);
425         stbuf->st_ctime = wim_timestamp_to_unix(inode->i_creation_time);
426         stbuf->st_blocks = (stbuf->st_size + 511) / 512;
427         return 0;
428 }
429
430 /* Creates a new staging file and returns its file descriptor opened for
431  * writing.
432  *
433  * @name_ret: A location into which the a pointer to the newly allocated name of
434  *            the staging file is stored.
435  *
436  * @ctx:      Context for the WIM filesystem; this provides the name of the
437  *            staging directory.
438  *
439  * On success, returns the file descriptor for the staging file, opened for
440  * writing.  On failure, returns -1 and sets errno.
441  */
442 static int create_staging_file(char **name_ret, struct wimfs_context *ctx)
443 {
444         size_t name_len;
445         char *name;
446         struct stat stbuf;
447         int fd;
448         int errno_save;
449
450         static const size_t STAGING_FILE_NAME_LEN = 20;
451
452         name_len = ctx->staging_dir_name_len + 1 + STAGING_FILE_NAME_LEN;
453         name = MALLOC(name_len + 1);
454         if (!name) {
455                 errno = ENOMEM;
456                 return -1;
457         }
458
459         do {
460
461                 memcpy(name, ctx->staging_dir_name, ctx->staging_dir_name_len);
462                 name[ctx->staging_dir_name_len] = '/';
463                 randomize_char_array_with_alnum(name + ctx->staging_dir_name_len + 1,
464                                                 STAGING_FILE_NAME_LEN);
465                 name[name_len] = '\0';
466
467
468         /* Just in case, verify that the randomly generated name doesn't name an
469          * existing file, and try again if so  */
470         } while (stat(name, &stbuf) == 0);
471
472         if (errno != ENOENT) /* other error?! */
473                 return -1;
474
475         /* doesn't exist--- ok */
476
477         DEBUG("Creating staging file `%s'", name);
478
479         fd = open(name, O_WRONLY | O_CREAT | O_EXCL, 0600);
480         if (fd == -1) {
481                 errno_save = errno;
482                 FREE(name);
483                 errno = errno_save;
484         } else {
485                 *name_ret = name;
486         }
487         return fd;
488 }
489
490 /*
491  * Extract a WIM resource to the staging directory.
492  *
493  * @inode:  Inode that contains the stream we are extracting
494  *
495  * @stream_id: Identifier for the stream (it stays constant even if the indices
496  * of the stream entries are changed)
497  *
498  * @lte: Pointer to pointer to the lookup table entry for the stream we need to
499  * extract, or NULL if there was no lookup table entry present for the stream
500  *
501  * @size:  Number of bytes of the stream we want to extract (this supports the
502  * wimfs_truncate() function).  It may be more than the actual stream length, in
503  * which case the extra space is filled with zeroes.
504  *
505  * @ctx:  Context for the WIM filesystem.
506  *
507  * Returns 0 on success or a negative error code on failure.
508  */
509 static int extract_resource_to_staging_dir(struct wim_inode *inode,
510                                            u32 stream_id,
511                                            struct wim_lookup_table_entry **lte,
512                                            off_t size,
513                                            struct wimfs_context *ctx)
514 {
515         char *staging_file_name;
516         int ret;
517         int fd;
518         struct wim_lookup_table_entry *old_lte, *new_lte;
519         off_t extract_size;
520
521         DEBUG("Extracting resource to staging dir: inode %"PRIu64", "
522               "stream id %"PRIu32, inode->i_ino, stream_id);
523
524         old_lte = *lte;
525
526         wimlib_assert(old_lte == NULL ||
527                       old_lte->resource_location != RESOURCE_IN_STAGING_FILE);
528
529         /* Create the staging file */
530         fd = create_staging_file(&staging_file_name, ctx);
531         if (fd == -1)
532                 return -errno;
533
534         /* Extract the stream to the staging file (possibly truncated) */
535         if (old_lte) {
536                 extract_size = min(wim_resource_size(old_lte), size);
537                 ret = extract_wim_resource_to_fd(old_lte, fd, extract_size);
538         } else {
539                 ret = 0;
540                 extract_size = 0;
541         }
542
543         /* In the case of truncate() to more than the file length, extend the
544          * file with zeroes by calling ftruncate() on the underlying staging
545          * file */
546         if (ret == 0 && size > extract_size)
547                 ret = ftruncate(fd, size);
548
549         /* Close the staging file descriptor and check for errors.  If there's
550          * an error, unlink the staging file. */
551         if (ret != 0 || close(fd) != 0) {
552                 if (errno != 0)
553                         ret = -errno;
554                 else
555                         ret = -EIO;
556                 close(fd);
557                 goto out_delete_staging_file;
558         }
559
560         /* Now deal with the lookup table entries.  We may be able to re-use the
561          * existing entry, but we may have to create a new one instead. */
562
563         if (old_lte && inode->i_nlink == old_lte->refcnt) {
564                 /* The reference count of the existing lookup table entry is the
565                  * same as the link count of the inode that contains the stream
566                  * we're opening.  Therefore, ALL the references to the lookup
567                  * table entry correspond to the stream we're trying to extract,
568                  * so the lookup table entry can be re-used.  */
569                 DEBUG("Re-using lookup table entry");
570                 lookup_table_unlink(ctx->wim->lookup_table, old_lte);
571                 new_lte = old_lte;
572         } else {
573                 if (old_lte) {
574                         /* There's an existing lookup table entry, but its
575                          * reference count is greater than the link count for
576                          * the inode containing a stream we're opening.
577                          * Therefore, we need to split the lookup table entry.
578                          */
579                         wimlib_assert(old_lte->refcnt > inode->i_nlink);
580                         DEBUG("Splitting lookup table entry "
581                               "(inode->i_nlink = %u, old_lte->refcnt = %u)",
582                               inode->i_nlink, old_lte->refcnt);
583                 }
584
585                 new_lte = new_lookup_table_entry();
586                 if (!new_lte) {
587                         ret = -ENOMEM;
588                         goto out_delete_staging_file;
589                 }
590
591                 /* There may already be open file descriptors to this stream if
592                  * it's previously been opened read-only, but just now we're
593                  * opening it read-write.  Identify those file descriptors and
594                  * change their lookup table entry pointers to point to the new
595                  * lookup table entry, and open staging file descriptors for
596                  * them.
597                  *
598                  * At the same time, we need to count the number of these opened
599                  * file descriptors to the new lookup table entry.  If there's
600                  * an old lookup table entry, this number needs to be subtracted
601                  * from the fd's opened to the old entry. */
602                 for (u16 i = 0, j = 0; j < inode->i_num_opened_fds; i++) {
603                         struct wimfs_fd *fd = inode->i_fds[i];
604                         if (fd) {
605                                 if (fd->stream_id == stream_id) {
606                                         wimlib_assert(fd->f_lte == old_lte);
607                                         wimlib_assert(fd->staging_fd == -1);
608                                         fd->f_lte = new_lte;
609                                         new_lte->num_opened_fds++;
610                                         fd->staging_fd = open(staging_file_name, O_RDONLY);
611                                         if (fd->staging_fd == -1) {
612                                                 ret = -errno;
613                                                 goto out_revert_fd_changes;
614                                         }
615                                 }
616                                 j++;
617                         }
618                 }
619                 DEBUG("%hu fd's were already opened to the file we extracted",
620                       new_lte->num_opened_fds);
621                 if (old_lte) {
622                         old_lte->num_opened_fds -= new_lte->num_opened_fds;
623                         old_lte->refcnt -= inode->i_nlink;
624                 }
625         }
626
627         new_lte->refcnt                       = inode->i_nlink;
628         new_lte->resource_location            = RESOURCE_IN_STAGING_FILE;
629         new_lte->staging_file_name            = staging_file_name;
630         new_lte->lte_inode                    = inode;
631         random_hash(new_lte->hash);
632
633         if (stream_id == 0)
634                 inode->i_lte = new_lte;
635         else
636                 for (u16 i = 0; i < inode->i_num_ads; i++)
637                         if (inode->i_ads_entries[i].stream_id == stream_id)
638                                 inode->i_ads_entries[i].lte = new_lte;
639
640         lookup_table_insert(ctx->wim->lookup_table, new_lte);
641         list_add(&new_lte->staging_list, &ctx->staging_list);
642         *lte = new_lte;
643         return 0;
644 out_revert_fd_changes:
645         for (u16 i = 0, j = 0; j < new_lte->num_opened_fds; i++) {
646                 struct wimfs_fd *fd = inode->i_fds[i];
647                 if (fd && fd->stream_id == stream_id && fd->f_lte == new_lte) {
648                         fd->f_lte = old_lte;
649                         if (fd->staging_fd != -1) {
650                                 close(fd->staging_fd);
651                                 fd->staging_fd = -1;
652                         }
653                         j++;
654                 }
655         }
656         free_lookup_table_entry(new_lte);
657 out_delete_staging_file:
658         unlink(staging_file_name);
659         FREE(staging_file_name);
660         return ret;
661 }
662
663 /*
664  * Creates a randomly named staging directory and saves its name in the
665  * filesystem context structure.
666  */
667 static int make_staging_dir(struct wimfs_context *ctx, const char *user_prefix)
668 {
669         static const size_t random_suffix_len = 10;
670         static const char *common_suffix = ".staging";
671         static const size_t common_suffix_len = 8;
672
673         char *staging_dir_name = NULL;
674         size_t staging_dir_name_len;
675         size_t prefix_len;
676         const char *wim_basename;
677         char *real_user_prefix = NULL;
678         int ret;
679
680         if (user_prefix) {
681                 real_user_prefix = realpath(user_prefix, NULL);
682                 if (!real_user_prefix) {
683                         ERROR_WITH_ERRNO("Could not resolve `%s'",
684                                          real_user_prefix);
685                         ret = WIMLIB_ERR_NOTDIR;
686                         goto out;
687                 }
688                 wim_basename = path_basename(ctx->wim->filename);
689                 prefix_len = strlen(real_user_prefix) + 1 + strlen(wim_basename);
690         } else {
691                 prefix_len = strlen(ctx->wim->filename);
692         }
693
694         staging_dir_name_len = prefix_len + common_suffix_len + random_suffix_len;
695
696         staging_dir_name = MALLOC(staging_dir_name_len + 1);
697         if (!staging_dir_name) {
698                 ret = WIMLIB_ERR_NOMEM;
699                 goto out;
700         }
701
702         if (real_user_prefix)
703                 sprintf(staging_dir_name, "%s/%s", real_user_prefix, wim_basename);
704         else
705                 strcpy(staging_dir_name, ctx->wim->filename);
706
707         strcat(staging_dir_name, common_suffix);
708
709         randomize_char_array_with_alnum(staging_dir_name + prefix_len + common_suffix_len,
710                                         random_suffix_len);
711
712         staging_dir_name[staging_dir_name_len] = '\0';
713
714         if (mkdir(staging_dir_name, 0700) != 0) {
715                 ERROR_WITH_ERRNO("Failed to create temporary directory `%s'",
716                                  staging_dir_name);
717                 ret = WIMLIB_ERR_MKDIR;
718         } else {
719                 ret = 0;
720         }
721 out:
722         FREE(real_user_prefix);
723         if (ret == 0) {
724                 ctx->staging_dir_name = staging_dir_name;
725                 ctx->staging_dir_name_len = staging_dir_name_len;
726         } else {
727                 FREE(staging_dir_name);
728         }
729         return ret;
730 }
731
732 static int remove_file_or_directory(const char *fpath, const struct stat *sb,
733                                     int typeflag, struct FTW *ftwbuf)
734 {
735         if (remove(fpath) == 0)
736                 return 0;
737         else {
738                 ERROR_WITH_ERRNO("Cannot remove `%s'", fpath);
739                 return WIMLIB_ERR_DELETE_STAGING_DIR;
740         }
741 }
742
743 /*
744  * Deletes the staging directory and all the files contained in it.
745  */
746 static int delete_staging_dir(struct wimfs_context *ctx)
747 {
748         int ret;
749         ret = nftw(ctx->staging_dir_name, remove_file_or_directory,
750                    10, FTW_DEPTH);
751         FREE(ctx->staging_dir_name);
752         ctx->staging_dir_name = NULL;
753         return ret;
754 }
755
756 static void inode_update_lte_ptr(struct wim_inode *inode,
757                                  struct wim_lookup_table_entry *old_lte,
758                                  struct wim_lookup_table_entry *new_lte)
759 {
760         if (inode->i_lte == old_lte) {
761                 inode->i_lte = new_lte;
762         } else {
763                 for (unsigned i = 0; i < inode->i_num_ads; i++) {
764                         if (inode->i_ads_entries[i].lte == old_lte) {
765                                 inode->i_ads_entries[i].lte = new_lte;
766                                 break;
767                         }
768                 }
769         }
770 }
771
772 static int update_lte_of_staging_file(struct wim_lookup_table_entry *lte,
773                                       struct wim_lookup_table *table)
774 {
775         struct wim_lookup_table_entry *duplicate_lte;
776         int ret;
777         u8 hash[SHA1_HASH_SIZE];
778         struct stat stbuf;
779
780         ret = sha1sum(lte->staging_file_name, hash);
781         if (ret != 0)
782                 return ret;
783         lookup_table_unlink(table, lte);
784         duplicate_lte = __lookup_resource(table, hash);
785         if (duplicate_lte) {
786                 /* Merge duplicate lookup table entries */
787                 duplicate_lte->refcnt += lte->refcnt;
788                 inode_update_lte_ptr(lte->lte_inode, lte, duplicate_lte);
789                 free_lookup_table_entry(lte);
790         } else {
791                 if (stat(lte->staging_file_name, &stbuf) != 0) {
792                         ERROR_WITH_ERRNO("Failed to stat `%s'", lte->staging_file_name);
793                         return WIMLIB_ERR_STAT;
794                 }
795                 if (stbuf.st_size == 0) {
796                         /* Zero-length stream.  No lookup table entry needed. */
797                         inode_update_lte_ptr(lte->lte_inode, lte, NULL);
798                         free_lookup_table_entry(lte);
799                 } else {
800                         BUILD_BUG_ON(&lte->file_on_disk != &lte->staging_file_name);
801                         lte->resource_entry.original_size = stbuf.st_size;
802                         lte->resource_entry.size = stbuf.st_size;
803                         lte->resource_location = RESOURCE_IN_FILE_ON_DISK;
804                         lte->file_on_disk_fp = NULL;
805                         copy_hash(lte->hash, hash);
806                         lookup_table_insert(table, lte);
807                 }
808         }
809         return 0;
810 }
811
812 static int inode_close_fds(struct wim_inode *inode)
813 {
814         u16 num_opened_fds = inode->i_num_opened_fds;
815         for (u16 i = 0, j = 0; j < num_opened_fds; i++) {
816                 struct wimfs_fd *fd = inode->i_fds[i];
817                 if (fd) {
818                         wimlib_assert(fd->f_inode == inode);
819                         int ret = close_wimfs_fd(fd);
820                         if (ret != 0)
821                                 return ret;
822                         j++;
823                 }
824         }
825         return 0;
826 }
827
828 /* Overwrites the WIM file, with changes saved. */
829 static int rebuild_wim(struct wimfs_context *ctx, int write_flags,
830                        wimlib_progress_func_t progress_func)
831 {
832         int ret;
833         struct wim_lookup_table_entry *lte, *tmp;
834         WIMStruct *w = ctx->wim;
835
836         DEBUG("Closing all staging file descriptors.");
837         list_for_each_entry_safe(lte, tmp, &ctx->staging_list, staging_list) {
838                 ret = inode_close_fds(lte->lte_inode);
839                 if (ret != 0)
840                         return ret;
841         }
842
843         DEBUG("Calculating SHA1 checksums for all new staging files.");
844         list_for_each_entry_safe(lte, tmp, &ctx->staging_list, staging_list) {
845                 ret = update_lte_of_staging_file(lte, w->lookup_table);
846                 if (ret != 0)
847                         return ret;
848         }
849
850         xml_update_image_info(w, w->current_image);
851         ret = wimlib_overwrite(w, write_flags, 0, progress_func);
852         if (ret != 0)
853                 ERROR("Failed to commit changes to mounted WIM image");
854         return ret;
855 }
856
857
858
859 /* Simple function that returns the concatenation of 2 strings. */
860 static char *strcat_dup(const char *s1, const char *s2, size_t max_len)
861 {
862         size_t len = strlen(s1) + strlen(s2);
863         if (len > max_len)
864                 len = max_len;
865         char *p = MALLOC(len + 1);
866         if (!p)
867                 return NULL;
868         snprintf(p, len + 1, "%s%s", s1, s2);
869         return p;
870 }
871
872 static int set_message_queue_names(struct wimfs_context *ctx,
873                                    const char *mount_dir)
874 {
875         static const char *u2d_prefix = "/wimlib-unmount-to-daemon-mq";
876         static const char *d2u_prefix = "/wimlib-daemon-to-unmount-mq";
877         char *dir_path;
878         char *p;
879         int ret;
880
881         dir_path = realpath(mount_dir, NULL);
882         if (!dir_path) {
883                 ERROR_WITH_ERRNO("Failed to resolve path \"%s\"", mount_dir);
884                 if (errno == ENOMEM)
885                         return WIMLIB_ERR_NOMEM;
886                 else
887                         return WIMLIB_ERR_NOTDIR;
888         }
889
890         for (p = dir_path; *p; p++)
891                 if (*p == '/')
892                         *p = 0xff;
893
894         ctx->unmount_to_daemon_mq_name = strcat_dup(u2d_prefix, dir_path,
895                                                     NAME_MAX);
896         if (!ctx->unmount_to_daemon_mq_name) {
897                 ret = WIMLIB_ERR_NOMEM;
898                 goto out_free_dir_path;
899         }
900         ctx->daemon_to_unmount_mq_name = strcat_dup(d2u_prefix, dir_path,
901                                                     NAME_MAX);
902         if (!ctx->daemon_to_unmount_mq_name) {
903                 ret = WIMLIB_ERR_NOMEM;
904                 goto out_free_unmount_to_daemon_mq_name;
905         }
906
907         ret = 0;
908         goto out_free_dir_path;
909 out_free_unmount_to_daemon_mq_name:
910         FREE(ctx->unmount_to_daemon_mq_name);
911         ctx->unmount_to_daemon_mq_name = NULL;
912 out_free_dir_path:
913         FREE(dir_path);
914         return ret;
915 }
916
917 static void free_message_queue_names(struct wimfs_context *ctx)
918 {
919         FREE(ctx->unmount_to_daemon_mq_name);
920         FREE(ctx->daemon_to_unmount_mq_name);
921         ctx->unmount_to_daemon_mq_name = NULL;
922         ctx->daemon_to_unmount_mq_name = NULL;
923 }
924
925 /*
926  * Opens two POSIX message queue: one for sending messages from the unmount
927  * process to the daemon process, and one to go the other way.  The names of the
928  * message queues, which must be system-wide unique, are be based on the mount
929  * point.
930  *
931  * @daemon specifies whether the calling process is the filesystem daemon or the
932  * unmount process.
933  */
934 static int open_message_queues(struct wimfs_context *ctx, bool daemon)
935 {
936         int unmount_to_daemon_mq_flags = O_WRONLY | O_CREAT;
937         int daemon_to_unmount_mq_flags = O_RDONLY | O_CREAT;
938         mode_t mode;
939         mode_t orig_umask;
940         int ret;
941
942         if (daemon) {
943                 swap(unmount_to_daemon_mq_flags, daemon_to_unmount_mq_flags);
944                 mode = 0600;
945         } else {
946                 mode = 0666;
947         }
948
949         orig_umask = umask(0000);
950         DEBUG("Opening message queue \"%s\"", ctx->unmount_to_daemon_mq_name);
951         ctx->unmount_to_daemon_mq = mq_open(ctx->unmount_to_daemon_mq_name,
952                                             unmount_to_daemon_mq_flags, mode, NULL);
953
954         if (ctx->unmount_to_daemon_mq == (mqd_t)-1) {
955                 ERROR_WITH_ERRNO("mq_open()");
956                 ret = WIMLIB_ERR_MQUEUE;
957                 goto out;
958         }
959
960         DEBUG("Opening message queue \"%s\"", ctx->daemon_to_unmount_mq_name);
961         ctx->daemon_to_unmount_mq = mq_open(ctx->daemon_to_unmount_mq_name,
962                                             daemon_to_unmount_mq_flags, mode, NULL);
963
964         if (ctx->daemon_to_unmount_mq == (mqd_t)-1) {
965                 ERROR_WITH_ERRNO("mq_open()");
966                 mq_close(ctx->unmount_to_daemon_mq);
967                 mq_unlink(ctx->unmount_to_daemon_mq_name);
968                 ctx->unmount_to_daemon_mq = (mqd_t)-1;
969                 ret = WIMLIB_ERR_MQUEUE;
970                 goto out;
971         }
972         ret = 0;
973 out:
974         umask(orig_umask);
975         return ret;
976 }
977
978 /* Try to determine the maximum message size of a message queue.  The return
979  * value is the maximum message size, or a guess of 8192 bytes if it cannot be
980  * determined. */
981 static long mq_get_msgsize(mqd_t mq)
982 {
983         static const char *msgsize_max_file = "/proc/sys/fs/mqueue/msgsize_max";
984         FILE *fp;
985         struct mq_attr attr;
986         long msgsize;
987
988         if (mq_getattr(mq, &attr) == 0) {
989                 msgsize = attr.mq_msgsize;
990         } else {
991                 ERROR_WITH_ERRNO("mq_getattr()");
992                 ERROR("Attempting to read %s", msgsize_max_file);
993                 fp = fopen(msgsize_max_file, "rb");
994                 if (fp) {
995                         if (fscanf(fp, "%ld", &msgsize) != 1) {
996                                 ERROR("Assuming message size of 8192");
997                                 msgsize = 8192;
998                         }
999                         fclose(fp);
1000                 } else {
1001                         ERROR_WITH_ERRNO("Failed to open the file `%s'",
1002                                          msgsize_max_file);
1003                         ERROR("Assuming message size of 8192");
1004                         msgsize = 8192;
1005                 }
1006         }
1007         return msgsize;
1008 }
1009
1010 static int get_mailbox(mqd_t mq, long needed_msgsize, long *msgsize_ret,
1011                        void **mailbox_ret)
1012 {
1013         long msgsize;
1014         char *mailbox;
1015
1016         msgsize = mq_get_msgsize(mq);
1017
1018         if (msgsize < needed_msgsize) {
1019                 ERROR("Message queue max size must be at least %ld!",
1020                       needed_msgsize);
1021                 return WIMLIB_ERR_MQUEUE;
1022         }
1023
1024         mailbox = MALLOC(msgsize);
1025         if (!mailbox) {
1026                 ERROR("Failed to allocate %ld bytes for mailbox", msgsize);
1027                 return WIMLIB_ERR_NOMEM;
1028         }
1029         *msgsize_ret = msgsize;
1030         *mailbox_ret = mailbox;
1031         return 0;
1032 }
1033
1034 static void unlink_message_queues(struct wimfs_context *ctx)
1035 {
1036         mq_unlink(ctx->unmount_to_daemon_mq_name);
1037         mq_unlink(ctx->daemon_to_unmount_mq_name);
1038 }
1039
1040 /* Closes the message queues, which are allocated in static variables */
1041 static void close_message_queues(struct wimfs_context *ctx)
1042 {
1043         DEBUG("Closing message queues");
1044         mq_close(ctx->unmount_to_daemon_mq);
1045         ctx->unmount_to_daemon_mq = (mqd_t)(-1);
1046         mq_close(ctx->daemon_to_unmount_mq);
1047         ctx->daemon_to_unmount_mq = (mqd_t)(-1);
1048         unlink_message_queues(ctx);
1049 }
1050
1051
1052 struct unmount_msg_hdr {
1053         u32 min_version;
1054         u32 cur_version;
1055         u32 msg_type;
1056         u32 msg_size;
1057 } PACKED;
1058
1059 struct msg_unmount_request {
1060         struct unmount_msg_hdr hdr;
1061         u32 unmount_flags;
1062         u8 want_progress_messages;
1063 } PACKED;
1064
1065 struct msg_daemon_info {
1066         struct unmount_msg_hdr hdr;
1067         pid_t daemon_pid;
1068         u32 mount_flags;
1069 } PACKED;
1070
1071 struct msg_unmount_finished {
1072         struct unmount_msg_hdr hdr;
1073         int32_t status;
1074 } PACKED;
1075
1076 struct msg_write_streams_progress {
1077         struct unmount_msg_hdr hdr;
1078         union wimlib_progress_info info;
1079 } PACKED;
1080
1081 enum {
1082         MSG_TYPE_UNMOUNT_REQUEST,
1083         MSG_TYPE_DAEMON_INFO,
1084         MSG_TYPE_WRITE_STREAMS_PROGRESS,
1085         MSG_TYPE_UNMOUNT_FINISHED,
1086         MSG_TYPE_MAX,
1087 };
1088
1089 struct msg_handler_context_hdr {
1090         int timeout_seconds;
1091 };
1092
1093 struct unmount_msg_handler_context {
1094         struct msg_handler_context_hdr hdr;
1095         pid_t daemon_pid;
1096         int mount_flags;
1097         int status;
1098         wimlib_progress_func_t progress_func;
1099 };
1100
1101 struct daemon_msg_handler_context {
1102         struct msg_handler_context_hdr hdr;
1103         struct wimfs_context *wimfs_ctx;
1104 };
1105
1106 static int send_unmount_request_msg(mqd_t mq, int unmount_flags,
1107                                     u8 want_progress_messages)
1108 {
1109         DEBUG("Sending unmount request msg");
1110         struct msg_unmount_request msg = {
1111                 .hdr = {
1112                         .min_version = WIMLIB_MAKEVERSION(1, 2, 1),
1113                         .cur_version = WIMLIB_VERSION_CODE,
1114                         .msg_type    = MSG_TYPE_UNMOUNT_REQUEST,
1115                         .msg_size    = sizeof(msg),
1116                 },
1117                 .unmount_flags = unmount_flags,
1118                 .want_progress_messages = want_progress_messages,
1119         };
1120
1121         if (mq_send(mq, (void*)&msg, sizeof(msg), 1)) {
1122                 ERROR_WITH_ERRNO("Failed to communicate with filesystem daemon");
1123                 return WIMLIB_ERR_MQUEUE;
1124         }
1125         return 0;
1126 }
1127
1128 static int send_daemon_info_msg(mqd_t mq, pid_t pid, int mount_flags)
1129 {
1130         DEBUG("Sending daemon info msg (pid = %d, mount_flags=%x)",
1131               pid, mount_flags);
1132
1133         struct msg_daemon_info msg = {
1134                 .hdr = {
1135                         .min_version = WIMLIB_MAKEVERSION(1, 2, 1),
1136                         .cur_version = WIMLIB_VERSION_CODE,
1137                         .msg_type = MSG_TYPE_DAEMON_INFO,
1138                         .msg_size = sizeof(msg),
1139                 },
1140                 .daemon_pid = pid,
1141                 .mount_flags = mount_flags,
1142         };
1143         if (mq_send(mq, (void*)&msg, sizeof(msg), 1)) {
1144                 ERROR_WITH_ERRNO("Failed to send daemon info to unmount process");
1145                 return WIMLIB_ERR_MQUEUE;
1146         }
1147         return 0;
1148 }
1149
1150 static void send_unmount_finished_msg(mqd_t mq, int status)
1151 {
1152         DEBUG("Sending unmount finished msg");
1153         struct msg_unmount_finished msg = {
1154                 .hdr = {
1155                         .min_version = WIMLIB_MAKEVERSION(1, 2, 1),
1156                         .cur_version = WIMLIB_VERSION_CODE,
1157                         .msg_type = MSG_TYPE_UNMOUNT_FINISHED,
1158                         .msg_size = sizeof(msg),
1159                 },
1160                 .status = status,
1161         };
1162         if (mq_send(mq, (void*)&msg, sizeof(msg), 1))
1163                 ERROR_WITH_ERRNO("Failed to send status to unmount process");
1164 }
1165
1166 static int unmount_progress_func(enum wimlib_progress_msg msg,
1167                                  const union wimlib_progress_info *info)
1168 {
1169         if (msg == WIMLIB_PROGRESS_MSG_WRITE_STREAMS) {
1170                 struct msg_write_streams_progress msg = {
1171                         .hdr = {
1172                                 .min_version = WIMLIB_MAKEVERSION(1, 2, 1),
1173                                 .cur_version = WIMLIB_VERSION_CODE,
1174                                 .msg_type = MSG_TYPE_WRITE_STREAMS_PROGRESS,
1175                                 .msg_size = sizeof(msg),
1176                         },
1177                         .info = *info,
1178                 };
1179                 if (mq_send(wimfs_get_context()->daemon_to_unmount_mq,
1180                             (void*)&msg, sizeof(msg), 1))
1181                 {
1182                         ERROR_WITH_ERRNO("Failed to send progress information "
1183                                          "to unmount process");
1184                 }
1185         }
1186         return 0;
1187 }
1188
1189 static int msg_unmount_request_handler(const void *_msg, void *_handler_ctx)
1190 {
1191         const struct msg_unmount_request *msg = _msg;
1192         struct daemon_msg_handler_context *handler_ctx = _handler_ctx;
1193         struct wimfs_context *wimfs_ctx;
1194         int status = 0;
1195         int ret;
1196         int unmount_flags;
1197         wimlib_progress_func_t progress_func;
1198
1199         DEBUG("Handling unmount request msg");
1200
1201         wimfs_ctx = handler_ctx->wimfs_ctx;
1202         if (msg->hdr.msg_size < sizeof(*msg)) {
1203                 status = WIMLIB_ERR_INVALID_UNMOUNT_MESSAGE;
1204                 goto out;
1205         }
1206
1207         unmount_flags = msg->unmount_flags;
1208         if (msg->want_progress_messages)
1209                 progress_func = unmount_progress_func;
1210         else
1211                 progress_func = NULL;
1212
1213         ret = send_daemon_info_msg(wimfs_ctx->daemon_to_unmount_mq, getpid(),
1214                                    wimfs_ctx->mount_flags);
1215         if (ret != 0) {
1216                 status = ret;
1217                 goto out;
1218         }
1219
1220         if (wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
1221                 if (unmount_flags & WIMLIB_UNMOUNT_FLAG_COMMIT) {
1222                         int write_flags = 0;
1223                         if (unmount_flags & WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY)
1224                                 write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
1225                         if (unmount_flags & WIMLIB_UNMOUNT_FLAG_REBUILD)
1226                                 write_flags |= WIMLIB_WRITE_FLAG_REBUILD;
1227                         if (unmount_flags & WIMLIB_UNMOUNT_FLAG_RECOMPRESS)
1228                                 write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
1229                         status = rebuild_wim(wimfs_ctx, write_flags,
1230                                              progress_func);
1231                 }
1232         } else {
1233                 DEBUG("Read-only mount");
1234                 status = 0;
1235         }
1236
1237 out:
1238         if (wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
1239                 ret = delete_staging_dir(wimfs_ctx);
1240                 if (ret != 0) {
1241                         ERROR("Failed to delete the staging directory");
1242                         if (status == 0)
1243                                 status = ret;
1244                 }
1245         }
1246         wimfs_ctx->status = status;
1247         wimfs_ctx->have_status = true;
1248         return MSG_BREAK_LOOP;
1249 }
1250
1251 static int msg_daemon_info_handler(const void *_msg, void *_handler_ctx)
1252 {
1253         const struct msg_daemon_info *msg = _msg;
1254         struct unmount_msg_handler_context *handler_ctx = _handler_ctx;
1255
1256         DEBUG("Handling daemon info msg");
1257         if (msg->hdr.msg_size < sizeof(*msg))
1258                 return WIMLIB_ERR_INVALID_UNMOUNT_MESSAGE;
1259         handler_ctx->daemon_pid = msg->daemon_pid;
1260         handler_ctx->mount_flags = msg->mount_flags;
1261         handler_ctx->hdr.timeout_seconds = 1;
1262         DEBUG("pid of daemon is %d; mount flags were %#x",
1263               handler_ctx->daemon_pid,
1264               handler_ctx->mount_flags);
1265         return 0;
1266 }
1267
1268 static int msg_write_streams_progress_handler(const void *_msg,
1269                                               void *_handler_ctx)
1270 {
1271         const struct msg_write_streams_progress *msg = _msg;
1272         struct unmount_msg_handler_context *handler_ctx = _handler_ctx;
1273
1274         if (msg->hdr.msg_size < sizeof(*msg))
1275                 return WIMLIB_ERR_INVALID_UNMOUNT_MESSAGE;
1276         if (handler_ctx->progress_func) {
1277                 handler_ctx->progress_func(WIMLIB_PROGRESS_MSG_WRITE_STREAMS,
1278                                            &msg->info);
1279         }
1280         return 0;
1281 }
1282
1283 static int msg_unmount_finished_handler(const void *_msg, void *_handler_ctx)
1284 {
1285         const struct msg_unmount_finished *msg = _msg;
1286         struct unmount_msg_handler_context *handler_ctx = _handler_ctx;
1287
1288         DEBUG("Handling unmount finished message");
1289         if (msg->hdr.msg_size < sizeof(*msg))
1290                 return WIMLIB_ERR_INVALID_UNMOUNT_MESSAGE;
1291         handler_ctx->status = msg->status;
1292         DEBUG("status is %d", handler_ctx->status);
1293         return MSG_BREAK_LOOP;
1294 }
1295
1296 static int unmount_timed_out_cb(void *_handler_ctx)
1297 {
1298         struct unmount_msg_handler_context *handler_ctx = _handler_ctx;
1299
1300         if (handler_ctx->daemon_pid == 0) {
1301                 goto out_crashed;
1302         } else {
1303                 kill(handler_ctx->daemon_pid, 0);
1304                 if (errno == ESRCH) {
1305                         goto out_crashed;
1306                 } else {
1307                         DEBUG("Filesystem daemon is still alive... "
1308                               "Waiting another %d seconds\n",
1309                               handler_ctx->hdr.timeout_seconds);
1310                         return 0;
1311                 }
1312         }
1313 out_crashed:
1314         ERROR("The filesystem daemon has crashed!  Changes to the "
1315               "WIM may not have been commited.");
1316         return WIMLIB_ERR_FILESYSTEM_DAEMON_CRASHED;
1317 }
1318
1319 static int daemon_timed_out_cb(void *_handler_ctx)
1320 {
1321         ERROR("Timed out waiting for unmount request! "
1322               "Changes to the mounted WIM will not be committed.");
1323         return WIMLIB_ERR_TIMEOUT;
1324 }
1325
1326 typedef int (*msg_handler_t)(const void *_msg, void *_handler_ctx);
1327
1328 struct msg_handler_callbacks {
1329         int (*timed_out)(void * _handler_ctx);
1330         msg_handler_t msg_handlers[MSG_TYPE_MAX];
1331 };
1332
1333 static const struct msg_handler_callbacks unmount_msg_handler_callbacks = {
1334         .timed_out = unmount_timed_out_cb,
1335         .msg_handlers = {
1336                 [MSG_TYPE_DAEMON_INFO] = msg_daemon_info_handler,
1337                 [MSG_TYPE_WRITE_STREAMS_PROGRESS] = msg_write_streams_progress_handler,
1338                 [MSG_TYPE_UNMOUNT_FINISHED] = msg_unmount_finished_handler,
1339         },
1340 };
1341
1342 static const struct msg_handler_callbacks daemon_msg_handler_callbacks = {
1343         .timed_out = daemon_timed_out_cb,
1344         .msg_handlers = {
1345                 [MSG_TYPE_UNMOUNT_REQUEST] = msg_unmount_request_handler,
1346         },
1347 };
1348
1349 static int receive_message(mqd_t mq,
1350                            struct msg_handler_context_hdr *handler_ctx,
1351                            const msg_handler_t msg_handlers[],
1352                            long mailbox_size, void *mailbox)
1353 {
1354         struct timeval now;
1355         struct timespec timeout;
1356         ssize_t bytes_received;
1357         struct unmount_msg_hdr *hdr;
1358         int ret;
1359
1360         gettimeofday(&now, NULL);
1361         timeout.tv_sec = now.tv_sec + handler_ctx->timeout_seconds;
1362         timeout.tv_nsec = now.tv_usec * 1000;
1363
1364         bytes_received = mq_timedreceive(mq, mailbox,
1365                                          mailbox_size, NULL, &timeout);
1366         hdr = mailbox;
1367         if (bytes_received == -1) {
1368                 if (errno == ETIMEDOUT) {
1369                         ret = WIMLIB_ERR_TIMEOUT;
1370                 } else {
1371                         ERROR_WITH_ERRNO("mq_timedreceive()");
1372                         ret = WIMLIB_ERR_MQUEUE;
1373                 }
1374         } else if (bytes_received < sizeof(*hdr) ||
1375                    bytes_received != hdr->msg_size) {
1376                 ret = WIMLIB_ERR_INVALID_UNMOUNT_MESSAGE;
1377         } else if (WIMLIB_VERSION_CODE < hdr->min_version) {
1378                 /*ERROR("Cannot understand the received message. "*/
1379                       /*"Please upgrade wimlib to at least v%d.%d.%d",*/
1380                       /*WIMLIB_GET_MAJOR_VERSION(hdr->min_version),*/
1381                       /*WIMLIB_GET_MINOR_VERSION(hdr->min_version),*/
1382                       /*WIMLIB_GET_PATCH_VERSION(hdr->min_version));*/
1383                 ret = MSG_VERSION_TOO_HIGH;
1384         } else if (hdr->msg_type >= MSG_TYPE_MAX) {
1385                 ret = WIMLIB_ERR_INVALID_UNMOUNT_MESSAGE;
1386         } else if (msg_handlers[hdr->msg_type] == NULL) {
1387                 ret = WIMLIB_ERR_INVALID_UNMOUNT_MESSAGE;
1388         } else {
1389                 ret = msg_handlers[hdr->msg_type](mailbox, handler_ctx);
1390         }
1391         return ret;
1392 }
1393
1394 static int message_loop(mqd_t mq,
1395                         const struct msg_handler_callbacks *callbacks,
1396                         struct msg_handler_context_hdr *handler_ctx)
1397 {
1398         static const size_t MAX_MSG_SIZE = 512;
1399         long msgsize;
1400         void *mailbox;
1401         int ret;
1402
1403         DEBUG("Entering message loop");
1404
1405         ret = get_mailbox(mq, MAX_MSG_SIZE, &msgsize, &mailbox);
1406         if (ret != 0)
1407                 return ret;
1408         while (1) {
1409                 ret = receive_message(mq, handler_ctx,
1410                                       callbacks->msg_handlers,
1411                                       msgsize, mailbox);
1412                 if (ret == 0 || ret == MSG_VERSION_TOO_HIGH) {
1413                         continue;
1414                 } else if (ret == MSG_BREAK_LOOP) {
1415                         ret = 0;
1416                         break;
1417                 } else if (ret == WIMLIB_ERR_TIMEOUT) {
1418                         if (callbacks->timed_out)
1419                                 ret = callbacks->timed_out(handler_ctx);
1420                         if (ret == 0)
1421                                 continue;
1422                         else
1423                                 break;
1424                 } else {
1425                         ERROR_WITH_ERRNO("Error communicating with "
1426                                          "filesystem daemon");
1427                         break;
1428                 }
1429         }
1430         FREE(mailbox);
1431         DEBUG("Exiting message loop");
1432         return ret;
1433 }
1434
1435 /* Execute `fusermount -u', which is installed setuid root, to unmount the WIM.
1436  *
1437  * FUSE does not yet implement synchronous unmounts.  This means that fusermount
1438  * -u will return before the filesystem daemon returns from wimfs_destroy().
1439  *  This is partly what we want, because we need to send a message from this
1440  *  process to the filesystem daemon telling whether --commit was specified or
1441  *  not.  However, after that, the unmount process must wait for the filesystem
1442  *  daemon to finish writing the WIM file.
1443  */
1444 static int execute_fusermount(const char *dir)
1445 {
1446         pid_t pid;
1447         int ret;
1448         int status;
1449
1450         pid = fork();
1451         if (pid == -1) {
1452                 ERROR_WITH_ERRNO("Failed to fork()");
1453                 return WIMLIB_ERR_FORK;
1454         }
1455         if (pid == 0) {
1456                 /* Child */
1457                 execlp("fusermount", "fusermount", "-u", dir, NULL);
1458                 ERROR_WITH_ERRNO("Failed to execute `fusermount'");
1459                 exit(WIMLIB_ERR_FUSERMOUNT);
1460         }
1461
1462         /* Parent */
1463         ret = waitpid(pid, &status, 0);
1464         if (ret == -1) {
1465                 ERROR_WITH_ERRNO("Failed to wait for fusermount process to "
1466                                  "terminate");
1467                 return WIMLIB_ERR_FUSERMOUNT;
1468         }
1469
1470         if (!WIFEXITED(status)) {
1471                 ERROR("'fusermount' did not terminate normally!");
1472                 return WIMLIB_ERR_FUSERMOUNT;
1473         }
1474
1475         status = WEXITSTATUS(status);
1476
1477         if (status == 0)
1478                 return 0;
1479
1480         if (status != WIMLIB_ERR_FUSERMOUNT)
1481                 return WIMLIB_ERR_FUSERMOUNT;
1482
1483         /* Try again, but with the `umount' program.  This is required on other
1484          * FUSE implementations such as FreeBSD's that do not have a
1485          * `fusermount' program. */
1486         ERROR("Falling back to 'umount'.  Note: you may need to be "
1487               "root for this to work");
1488         pid = fork();
1489         if (pid == -1) {
1490                 ERROR_WITH_ERRNO("Failed to fork()");
1491                 return WIMLIB_ERR_FORK;
1492         }
1493         if (pid == 0) {
1494                 /* Child */
1495                 execlp("umount", "umount", dir, NULL);
1496                 ERROR_WITH_ERRNO("Failed to execute `umount'");
1497                 exit(WIMLIB_ERR_FUSERMOUNT);
1498         }
1499
1500         /* Parent */
1501         ret = waitpid(pid, &status, 0);
1502         if (ret == -1) {
1503                 ERROR_WITH_ERRNO("Failed to wait for `umount' process to "
1504                                  "terminate");
1505                 return WIMLIB_ERR_FUSERMOUNT;
1506         }
1507         if (status != 0) {
1508                 ERROR("`umount' did not successfully complete");
1509                 return WIMLIB_ERR_FUSERMOUNT;
1510         }
1511         return 0;
1512 }
1513
1514 #if 0
1515 static int wimfs_access(const char *path, int mask)
1516 {
1517         return -ENOSYS;
1518 }
1519 #endif
1520
1521 static int wimfs_chmod(const char *path, mode_t mask)
1522 {
1523         struct wim_dentry *dentry;
1524         struct wimfs_context *ctx = wimfs_get_context();
1525         int ret;
1526
1527         if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
1528                 return -EPERM;
1529
1530         ret = lookup_resource(ctx->wim, path, LOOKUP_FLAG_DIRECTORY_OK,
1531                               &dentry, NULL, NULL);
1532         if (ret)
1533                 return ret;
1534
1535         ret = inode_set_unix_data(dentry->d_inode, ctx->default_uid,
1536                                   ctx->default_gid, mask,
1537                                   ctx->wim->lookup_table, UNIX_DATA_MODE);
1538         return ret ? -ENOMEM : 0;
1539 }
1540
1541 static int wimfs_chown(const char *path, uid_t uid, gid_t gid)
1542 {
1543         struct wim_dentry *dentry;
1544         struct wimfs_context *ctx = wimfs_get_context();
1545         int ret;
1546
1547         if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
1548                 return -EPERM;
1549
1550         ret = lookup_resource(ctx->wim, path, LOOKUP_FLAG_DIRECTORY_OK,
1551                               &dentry, NULL, NULL);
1552         if (ret)
1553                 return ret;
1554
1555         ret = inode_set_unix_data(dentry->d_inode, uid, gid,
1556                                   inode_default_unix_mode(dentry->d_inode),
1557                                   ctx->wim->lookup_table,
1558                                   UNIX_DATA_UID | UNIX_DATA_GID);
1559         return ret ? -ENOMEM : 0;
1560 }
1561
1562 /* Called when the filesystem is unmounted. */
1563 static void wimfs_destroy(void *p)
1564 {
1565         struct wimfs_context *wimfs_ctx = wimfs_get_context();
1566         if (open_message_queues(wimfs_ctx, true) == 0) {
1567                 struct daemon_msg_handler_context handler_ctx = {
1568                         .hdr = {
1569                                 .timeout_seconds = 5,
1570                         },
1571                         .wimfs_ctx = wimfs_ctx,
1572                 };
1573                 message_loop(wimfs_ctx->unmount_to_daemon_mq,
1574                              &daemon_msg_handler_callbacks,
1575                              &handler_ctx.hdr);
1576         }
1577 }
1578
1579 #if 0
1580 static int wimfs_fallocate(const char *path, int mode,
1581                            off_t offset, off_t len, struct fuse_file_info *fi)
1582 {
1583         struct wimfs_fd *fd = (struct wimfs_fd*)(uintptr_t)fi->fh;
1584         wimlib_assert(fd->staging_fd != -1);
1585         return fallocate(fd->staging_fd, mode, offset, len);
1586 }
1587
1588 #endif
1589
1590 static int wimfs_fgetattr(const char *path, struct stat *stbuf,
1591                           struct fuse_file_info *fi)
1592 {
1593         struct wimfs_fd *fd = (struct wimfs_fd*)(uintptr_t)fi->fh;
1594         return inode_to_stbuf(fd->f_inode, fd->f_lte, stbuf);
1595 }
1596
1597 static int wimfs_ftruncate(const char *path, off_t size,
1598                            struct fuse_file_info *fi)
1599 {
1600         struct wimfs_fd *fd = (struct wimfs_fd*)(uintptr_t)fi->fh;
1601         int ret = ftruncate(fd->staging_fd, size);
1602         if (ret != 0)
1603                 return -errno;
1604         if (fd->f_lte && size < fd->f_lte->resource_entry.original_size)
1605                 fd->f_lte->resource_entry.original_size = size;
1606         return 0;
1607 }
1608
1609 /*
1610  * Fills in a `struct stat' that corresponds to a file or directory in the WIM.
1611  */
1612 static int wimfs_getattr(const char *path, struct stat *stbuf)
1613 {
1614         struct wim_dentry *dentry;
1615         struct wim_lookup_table_entry *lte;
1616         int ret;
1617         struct wimfs_context *ctx = wimfs_get_context();
1618
1619         ret = lookup_resource(ctx->wim, path,
1620                               get_lookup_flags(ctx) | LOOKUP_FLAG_DIRECTORY_OK,
1621                               &dentry, &lte, NULL);
1622         if (ret != 0)
1623                 return ret;
1624         return inode_to_stbuf(dentry->d_inode, lte, stbuf);
1625 }
1626
1627 #ifdef ENABLE_XATTR
1628 /* Read an alternate data stream through the XATTR interface, or get its size */
1629 static int wimfs_getxattr(const char *path, const char *name, char *value,
1630                           size_t size)
1631 {
1632         int ret;
1633         struct wim_inode *inode;
1634         struct wim_ads_entry *ads_entry;
1635         size_t res_size;
1636         struct wim_lookup_table_entry *lte;
1637         struct wimfs_context *ctx = wimfs_get_context();
1638
1639         if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1640                 return -ENOTSUP;
1641
1642         if (strlen(name) < 5 || memcmp(name, "user.", 5) != 0)
1643                 return -ENOATTR;
1644         name += 5;
1645
1646         inode = wim_pathname_to_inode(ctx->wim, path);
1647         if (!inode)
1648                 return -errno;
1649
1650         ads_entry = inode_get_ads_entry(inode, name, NULL);
1651         if (!ads_entry)
1652                 return -ENOATTR;
1653
1654         lte = ads_entry->lte;
1655         res_size = wim_resource_size(lte);
1656
1657         if (size == 0)
1658                 return res_size;
1659
1660         if (res_size > size)
1661                 return -ERANGE;
1662
1663         ret = read_full_wim_resource(lte, (u8*)value,
1664                                      WIMLIB_RESOURCE_FLAG_MULTITHREADED);
1665         if (ret != 0)
1666                 return -EIO;
1667
1668         return res_size;
1669 }
1670 #endif
1671
1672 /* Create a hard link */
1673 static int wimfs_link(const char *to, const char *from)
1674 {
1675         struct wim_dentry *from_dentry, *from_dentry_parent;
1676         const char *link_name;
1677         struct wim_inode *inode;
1678         struct wim_lookup_table_entry *lte;
1679         WIMStruct *w = wimfs_get_WIMStruct();
1680         u16 i;
1681
1682         inode = wim_pathname_to_inode(w, to);
1683         if (!inode)
1684                 return -errno;
1685
1686         if (inode->i_attributes & (FILE_ATTRIBUTE_DIRECTORY |
1687                                    FILE_ATTRIBUTE_REPARSE_POINT))
1688                 return -EPERM;
1689
1690         from_dentry_parent = get_parent_dentry(w, from);
1691         if (!from_dentry_parent)
1692                 return -errno;
1693         if (!dentry_is_directory(from_dentry_parent))
1694                 return -ENOTDIR;
1695
1696         link_name = path_basename(from);
1697         if (get_dentry_child_with_name(from_dentry_parent, link_name))
1698                 return -EEXIST;
1699         from_dentry = new_dentry(link_name);
1700         if (!from_dentry)
1701                 return -errno;
1702
1703         inode_add_dentry(from_dentry, inode);
1704         from_dentry->d_inode = inode;
1705         inode->i_nlink++;
1706
1707         for (i = 0; i <= inode->i_num_ads; i++) {
1708                 lte = inode_stream_lte_resolved(inode, i);
1709                 if (lte)
1710                         lte->refcnt++;
1711         }
1712         dentry_add_child(from_dentry_parent, from_dentry);
1713         return 0;
1714 }
1715
1716 #ifdef ENABLE_XATTR
1717 static int wimfs_listxattr(const char *path, char *list, size_t size)
1718 {
1719         size_t needed_size;
1720         struct wim_inode *inode;
1721         struct wimfs_context *ctx = wimfs_get_context();
1722         u16 i;
1723         char *p;
1724
1725         if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1726                 return -ENOTSUP;
1727
1728         /* List alternate data streams, or get the list size */
1729
1730         inode = wim_pathname_to_inode(ctx->wim, path);
1731         if (!inode)
1732                 return -errno;
1733
1734         if (size == 0) {
1735                 needed_size = 0;
1736                 for (i = 0; i < inode->i_num_ads; i++)
1737                         needed_size += inode->i_ads_entries[i].stream_name_utf8_len + 6;
1738                 return needed_size;
1739         } else {
1740                 p = list;
1741                 for (i = 0; i < inode->i_num_ads; i++) {
1742                         needed_size = inode->i_ads_entries[i].stream_name_utf8_len + 6;
1743                         if (needed_size > size)
1744                                 return -ERANGE;
1745                         p += sprintf(p, "user.%s",
1746                                      inode->i_ads_entries[i].stream_name_utf8) + 1;
1747                         size -= needed_size;
1748                 }
1749                 return p - list;
1750         }
1751 }
1752 #endif
1753
1754
1755 /* Create a directory in the WIM image. */
1756 static int wimfs_mkdir(const char *path, mode_t mode)
1757 {
1758         return create_dentry(fuse_get_context(), path, mode | S_IFDIR,
1759                              FILE_ATTRIBUTE_DIRECTORY, NULL);
1760 }
1761
1762 /* Create a regular file or alternate data stream in the WIM image. */
1763 static int wimfs_mknod(const char *path, mode_t mode, dev_t rdev)
1764 {
1765         const char *stream_name;
1766         struct fuse_context *fuse_ctx = fuse_get_context();
1767         struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
1768
1769         if (!S_ISREG(mode))
1770                 return -EPERM;
1771
1772         if ((wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
1773              && (stream_name = path_stream_name(path))) {
1774                 /* Make an alternate data stream */
1775                 struct wim_ads_entry *new_entry;
1776                 struct wim_inode *inode;
1777
1778                 char *p = (char*)stream_name - 1;
1779                 wimlib_assert(*p == ':');
1780                 *p = '\0';
1781
1782                 inode = wim_pathname_to_inode(wimfs_ctx->wim, path);
1783                 if (!inode)
1784                         return -errno;
1785                 if (inode->i_attributes &
1786                     (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY))
1787                         return -ENOENT;
1788                 if (inode_get_ads_entry(inode, stream_name, NULL))
1789                         return -EEXIST;
1790                 new_entry = inode_add_ads(inode, stream_name);
1791                 if (!new_entry)
1792                         return -ENOMEM;
1793                 return 0;
1794         } else {
1795                 /* Make a normal file (not an alternate data stream) */
1796                 return create_dentry(fuse_ctx, path, mode | S_IFREG,
1797                                      FILE_ATTRIBUTE_NORMAL, NULL);
1798         }
1799 }
1800
1801
1802 /* Open a file.  */
1803 static int wimfs_open(const char *path, struct fuse_file_info *fi)
1804 {
1805         struct wim_dentry *dentry;
1806         struct wim_lookup_table_entry *lte;
1807         int ret;
1808         struct wimfs_fd *fd;
1809         struct wim_inode *inode;
1810         u16 stream_idx;
1811         u32 stream_id;
1812         struct wimfs_context *ctx = wimfs_get_context();
1813
1814         ret = lookup_resource(ctx->wim, path, get_lookup_flags(ctx),
1815                               &dentry, &lte, &stream_idx);
1816         if (ret != 0)
1817                 return ret;
1818
1819         inode = dentry->d_inode;
1820
1821         if (stream_idx == 0)
1822                 stream_id = 0;
1823         else
1824                 stream_id = inode->i_ads_entries[stream_idx - 1].stream_id;
1825
1826         /* The file resource may be in the staging directory (read-write mounts
1827          * only) or in the WIM.  If it's in the staging directory, we need to
1828          * open a native file descriptor for the corresponding file.  Otherwise,
1829          * we can read the file resource directly from the WIM file if we are
1830          * opening it read-only, but we need to extract the resource to the
1831          * staging directory if we are opening it writable. */
1832
1833         if (flags_writable(fi->flags) &&
1834             (!lte || lte->resource_location != RESOURCE_IN_STAGING_FILE)) {
1835                 u64 size = (lte) ? wim_resource_size(lte) : 0;
1836                 ret = extract_resource_to_staging_dir(inode, stream_id,
1837                                                       &lte, size, ctx);
1838                 if (ret != 0)
1839                         return ret;
1840         }
1841
1842         ret = alloc_wimfs_fd(inode, stream_id, lte, &fd,
1843                              wimfs_ctx_readonly(ctx));
1844         if (ret != 0)
1845                 return ret;
1846
1847         if (lte && lte->resource_location == RESOURCE_IN_STAGING_FILE) {
1848                 fd->staging_fd = open(lte->staging_file_name, fi->flags);
1849                 if (fd->staging_fd == -1) {
1850                         int errno_save = errno;
1851                         close_wimfs_fd(fd);
1852                         return -errno_save;
1853                 }
1854         }
1855         fi->fh = (uintptr_t)fd;
1856         return 0;
1857 }
1858
1859 /* Opens a directory. */
1860 static int wimfs_opendir(const char *path, struct fuse_file_info *fi)
1861 {
1862         struct wim_inode *inode;
1863         int ret;
1864         struct wimfs_fd *fd = NULL;
1865         struct wimfs_context *ctx = wimfs_get_context();
1866         WIMStruct *w = ctx->wim;
1867
1868         inode = wim_pathname_to_inode(w, path);
1869         if (!inode)
1870                 return -errno;
1871         if (!inode_is_directory(inode))
1872                 return -ENOTDIR;
1873         ret = alloc_wimfs_fd(inode, 0, NULL, &fd, wimfs_ctx_readonly(ctx));
1874         fi->fh = (uintptr_t)fd;
1875         return ret;
1876 }
1877
1878
1879 /*
1880  * Read data from a file in the WIM or in the staging directory.
1881  */
1882 static int wimfs_read(const char *path, char *buf, size_t size,
1883                       off_t offset, struct fuse_file_info *fi)
1884 {
1885         struct wimfs_fd *fd = (struct wimfs_fd*)(uintptr_t)fi->fh;
1886         ssize_t ret;
1887
1888         if (!fd)
1889                 return -EBADF;
1890
1891         if (!fd->f_lte) /* Empty stream with no lookup table entry */
1892                 return 0;
1893
1894         if (fd->f_lte->resource_location == RESOURCE_IN_STAGING_FILE) {
1895                 /* Read from staging file */
1896
1897                 wimlib_assert(fd->f_lte->staging_file_name);
1898                 wimlib_assert(fd->staging_fd != -1);
1899
1900                 DEBUG("Seek to offset %"PRIu64, offset);
1901
1902                 if (lseek(fd->staging_fd, offset, SEEK_SET) == -1)
1903                         return -errno;
1904                 ret = read(fd->staging_fd, buf, size);
1905                 if (ret == -1)
1906                         return -errno;
1907                 return ret;
1908         } else {
1909                 /* Read from WIM */
1910                 u64 res_size = wim_resource_size(fd->f_lte);
1911                 if (offset > res_size)
1912                         return -EOVERFLOW;
1913                 size = min(size, res_size - offset);
1914                 if (read_wim_resource(fd->f_lte, (u8*)buf,
1915                                       size, offset,
1916                                       WIMLIB_RESOURCE_FLAG_MULTITHREADED) != 0)
1917                         return -EIO;
1918                 return size;
1919         }
1920 }
1921
1922 struct fill_params {
1923         void *buf;
1924         fuse_fill_dir_t filler;
1925 };
1926
1927 static int dentry_fuse_fill(struct wim_dentry *dentry, void *arg)
1928 {
1929         struct fill_params *fill_params = arg;
1930         return fill_params->filler(fill_params->buf, dentry->file_name_utf8,
1931                                    NULL, 0);
1932 }
1933
1934 /* Fills in the entries of the directory specified by @path using the
1935  * FUSE-provided function @filler.  */
1936 static int wimfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
1937                          off_t offset, struct fuse_file_info *fi)
1938 {
1939         struct wimfs_fd *fd = (struct wimfs_fd*)(uintptr_t)fi->fh;
1940         struct wim_inode *inode;
1941
1942         if (!fd)
1943                 return -EBADF;
1944
1945         inode = fd->f_inode;
1946
1947         struct fill_params fill_params = {
1948                 .buf = buf,
1949                 .filler = filler,
1950         };
1951
1952         filler(buf, ".", NULL, 0);
1953         filler(buf, "..", NULL, 0);
1954
1955         return for_dentry_in_rbtree(inode->i_children.rb_node,
1956                                     dentry_fuse_fill, &fill_params);
1957 }
1958
1959
1960 static int wimfs_readlink(const char *path, char *buf, size_t buf_len)
1961 {
1962         struct wimfs_context *ctx = wimfs_get_context();
1963         struct wim_inode *inode = wim_pathname_to_inode(ctx->wim, path);
1964         int ret;
1965         if (!inode)
1966                 return -errno;
1967         if (!inode_is_symlink(inode))
1968                 return -EINVAL;
1969
1970         ret = inode_readlink(inode, buf, buf_len, ctx->wim,
1971                              WIMLIB_RESOURCE_FLAG_MULTITHREADED);
1972         if (ret > 0)
1973                 ret = 0;
1974         return ret;
1975 }
1976
1977 /* Close a file. */
1978 static int wimfs_release(const char *path, struct fuse_file_info *fi)
1979 {
1980         struct wimfs_fd *fd = (struct wimfs_fd*)(uintptr_t)fi->fh;
1981         return close_wimfs_fd(fd);
1982 }
1983
1984 /* Close a directory */
1985 static int wimfs_releasedir(const char *path, struct fuse_file_info *fi)
1986 {
1987         struct wimfs_fd *fd = (struct wimfs_fd*)(uintptr_t)fi->fh;
1988         return close_wimfs_fd(fd);
1989 }
1990
1991 #ifdef ENABLE_XATTR
1992 /* Remove an alternate data stream through the XATTR interface */
1993 static int wimfs_removexattr(const char *path, const char *name)
1994 {
1995         struct wim_inode *inode;
1996         struct wim_ads_entry *ads_entry;
1997         u16 ads_idx;
1998         struct wimfs_context *ctx = wimfs_get_context();
1999
2000         if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
2001                 return -ENOTSUP;
2002
2003         if (strlen(name) < 5 || memcmp(name, "user.", 5) != 0)
2004                 return -ENOATTR;
2005         name += 5;
2006
2007         inode = wim_pathname_to_inode(ctx->wim, path);
2008         if (!inode)
2009                 return -errno;
2010
2011         ads_entry = inode_get_ads_entry(inode, name, &ads_idx);
2012         if (!ads_entry)
2013                 return -ENOATTR;
2014         inode_remove_ads(inode, ads_idx, ctx->wim->lookup_table);
2015         return 0;
2016 }
2017 #endif
2018
2019 /* Renames a file or directory.  See rename (3) */
2020 static int wimfs_rename(const char *from, const char *to)
2021 {
2022         struct wim_dentry *src;
2023         struct wim_dentry *dst;
2024         struct wim_dentry *parent_of_dst;
2025         WIMStruct *w = wimfs_get_WIMStruct();
2026         int ret;
2027
2028         /* This rename() implementation currently only supports actual files
2029          * (not alternate data streams) */
2030
2031         src = get_dentry(w, from);
2032         if (!src)
2033                 return -errno;
2034
2035         dst = get_dentry(w, to);
2036
2037         if (dst) {
2038                 /* Destination file exists */
2039
2040                 if (src == dst) /* Same file */
2041                         return 0;
2042
2043                 if (!dentry_is_directory(src)) {
2044                         /* Cannot rename non-directory to directory. */
2045                         if (dentry_is_directory(dst))
2046                                 return -EISDIR;
2047                 } else {
2048                         /* Cannot rename directory to a non-directory or a non-empty
2049                          * directory */
2050                         if (!dentry_is_directory(dst))
2051                                 return -ENOTDIR;
2052                         if (inode_has_children(dst->d_inode))
2053                                 return -ENOTEMPTY;
2054                 }
2055                 parent_of_dst = dst->parent;
2056         } else {
2057                 /* Destination does not exist */
2058                 parent_of_dst = get_parent_dentry(w, to);
2059                 if (!parent_of_dst)
2060                         return -errno;
2061
2062                 if (!dentry_is_directory(parent_of_dst))
2063                         return -ENOTDIR;
2064         }
2065
2066         ret = set_dentry_name(src, path_basename(to));
2067         if (ret != 0)
2068                 return -ENOMEM;
2069         if (dst)
2070                 remove_dentry(dst, w->lookup_table);
2071         unlink_dentry(src);
2072         dentry_add_child(parent_of_dst, src);
2073         return 0;
2074 }
2075
2076 /* Remove a directory */
2077 static int wimfs_rmdir(const char *path)
2078 {
2079         struct wim_dentry *dentry;
2080         WIMStruct *w = wimfs_get_WIMStruct();
2081
2082         dentry = get_dentry(w, path);
2083         if (!dentry)
2084                 return -errno;
2085
2086         if (!dentry_is_directory(dentry))
2087                 return -ENOTDIR;
2088
2089         if (dentry_has_children(dentry))
2090                 return -ENOTEMPTY;
2091
2092         remove_dentry(dentry, w->lookup_table);
2093         return 0;
2094 }
2095
2096 #ifdef ENABLE_XATTR
2097 /* Write an alternate data stream through the XATTR interface */
2098 static int wimfs_setxattr(const char *path, const char *name,
2099                           const char *value, size_t size, int flags)
2100 {
2101         struct wim_ads_entry *existing_ads_entry;
2102         struct wim_inode *inode;
2103         u16 ads_idx;
2104         struct wimfs_context *ctx = wimfs_get_context();
2105         int ret;
2106
2107         if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
2108                 return -ENOTSUP;
2109
2110         if (strlen(name) < 5 || memcmp(name, "user.", 5) != 0)
2111                 return -ENOATTR;
2112         name += 5;
2113
2114         inode = wim_pathname_to_inode(ctx->wim, path);
2115         if (!inode)
2116                 return -errno;
2117
2118         existing_ads_entry = inode_get_ads_entry(inode, name, &ads_idx);
2119         if (existing_ads_entry) {
2120                 if (flags & XATTR_CREATE)
2121                         return -EEXIST;
2122         } else {
2123                 if (flags & XATTR_REPLACE)
2124                         return -ENOATTR;
2125         }
2126
2127         ret = inode_add_ads_with_data(inode, name, (const u8*)value,
2128                                       size, ctx->wim->lookup_table);
2129         if (ret == 0) {
2130                 if (existing_ads_entry)
2131                         inode_remove_ads(inode, ads_idx, ctx->wim->lookup_table);
2132         } else {
2133                 ret = -ENOMEM;
2134         }
2135         return ret;
2136 }
2137 #endif
2138
2139 static int wimfs_symlink(const char *to, const char *from)
2140 {
2141         struct fuse_context *fuse_ctx = fuse_get_context();
2142         struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
2143         struct wim_dentry *dentry;
2144         int ret;
2145
2146         ret = create_dentry(fuse_ctx, from, S_IFLNK | 0777,
2147                             FILE_ATTRIBUTE_REPARSE_POINT, &dentry);
2148         if (ret == 0) {
2149                 dentry->d_inode->i_reparse_tag = WIM_IO_REPARSE_TAG_SYMLINK;
2150                 if (inode_set_symlink(dentry->d_inode, to,
2151                                       wimfs_ctx->wim->lookup_table, NULL))
2152                 {
2153                         remove_dentry(dentry, wimfs_ctx->wim->lookup_table);
2154                         ret = -ENOMEM;
2155                 }
2156         }
2157         return ret;
2158 }
2159
2160
2161 /* Reduce the size of a file */
2162 static int wimfs_truncate(const char *path, off_t size)
2163 {
2164         struct wim_dentry *dentry;
2165         struct wim_lookup_table_entry *lte;
2166         int ret;
2167         u16 stream_idx;
2168         u32 stream_id;
2169         struct wim_inode *inode;
2170         struct wimfs_context *ctx = wimfs_get_context();
2171
2172         ret = lookup_resource(ctx->wim, path, get_lookup_flags(ctx),
2173                               &dentry, &lte, &stream_idx);
2174
2175         if (ret != 0)
2176                 return ret;
2177
2178         if (lte == NULL && size == 0)
2179                 return 0;
2180
2181         inode = dentry->d_inode;
2182         if (stream_idx == 0)
2183                 stream_id = 0;
2184         else
2185                 stream_id = inode->i_ads_entries[stream_idx - 1].stream_id;
2186
2187         if (lte->resource_location == RESOURCE_IN_STAGING_FILE) {
2188                 ret = truncate(lte->staging_file_name, size);
2189                 if (ret != 0)
2190                         ret = -errno;
2191         } else {
2192                 /* File in WIM.  Extract it to the staging directory, but only
2193                  * the first @size bytes of it. */
2194                 ret = extract_resource_to_staging_dir(inode, stream_id,
2195                                                       &lte, size, ctx);
2196         }
2197         return ret;
2198 }
2199
2200 /* Unlink a non-directory or alternate data stream */
2201 static int wimfs_unlink(const char *path)
2202 {
2203         struct wim_dentry *dentry;
2204         struct wim_lookup_table_entry *lte;
2205         int ret;
2206         u16 stream_idx;
2207         struct wimfs_context *ctx = wimfs_get_context();
2208
2209         ret = lookup_resource(ctx->wim, path, get_lookup_flags(ctx),
2210                               &dentry, &lte, &stream_idx);
2211
2212         if (ret != 0)
2213                 return ret;
2214
2215         if (stream_idx == 0)
2216                 remove_dentry(dentry, ctx->wim->lookup_table);
2217         else
2218                 inode_remove_ads(dentry->d_inode, stream_idx - 1,
2219                                  ctx->wim->lookup_table);
2220         return 0;
2221 }
2222
2223 #ifdef HAVE_UTIMENSAT
2224 /*
2225  * Change the timestamp on a file dentry.
2226  *
2227  * Note that alternate data streams do not have their own timestamps.
2228  */
2229 static int wimfs_utimens(const char *path, const struct timespec tv[2])
2230 {
2231         struct wim_dentry *dentry;
2232         struct wim_inode *inode;
2233         WIMStruct *w = wimfs_get_WIMStruct();
2234
2235         dentry = get_dentry(w, path);
2236         if (!dentry)
2237                 return -errno;
2238         inode = dentry->d_inode;
2239
2240         if (tv[0].tv_nsec != UTIME_OMIT) {
2241                 if (tv[0].tv_nsec == UTIME_NOW)
2242                         inode->i_last_access_time = get_wim_timestamp();
2243                 else
2244                         inode->i_last_access_time = timespec_to_wim_timestamp(&tv[0]);
2245         }
2246         if (tv[1].tv_nsec != UTIME_OMIT) {
2247                 if (tv[1].tv_nsec == UTIME_NOW)
2248                         inode->i_last_write_time = get_wim_timestamp();
2249                 else
2250                         inode->i_last_write_time = timespec_to_wim_timestamp(&tv[1]);
2251         }
2252         return 0;
2253 }
2254 #else
2255 static int wimfs_utime(const char *path, struct utimbuf *times)
2256 {
2257         struct wim_dentry *dentry;
2258         struct wim_inode *inode;
2259         WIMStruct *w = wimfs_get_WIMStruct();
2260
2261         dentry = get_dentry(w, path);
2262         if (!dentry)
2263                 return -errno;
2264         inode = dentry->d_inode;
2265
2266         inode->i_last_write_time = unix_timestamp_to_wim(times->modtime);
2267         inode->i_last_access_time = unix_timestamp_to_wim(times->actime);
2268         return 0;
2269 }
2270 #endif
2271
2272 /* Writes to a file in the WIM filesystem.
2273  * It may be an alternate data stream, but here we don't even notice because we
2274  * just get a lookup table entry. */
2275 static int wimfs_write(const char *path, const char *buf, size_t size,
2276                        off_t offset, struct fuse_file_info *fi)
2277 {
2278         struct wimfs_fd *fd = (struct wimfs_fd*)(uintptr_t)fi->fh;
2279         int ret;
2280         u64 now;
2281
2282         if (!fd)
2283                 return -EBADF;
2284
2285         wimlib_assert(fd->f_lte);
2286         wimlib_assert(fd->f_lte->staging_file_name);
2287         wimlib_assert(fd->staging_fd != -1);
2288         wimlib_assert(fd->f_inode);
2289
2290         /* Seek to the requested position */
2291         if (lseek(fd->staging_fd, offset, SEEK_SET) == -1)
2292                 return -errno;
2293
2294         /* Write the data. */
2295         ret = write(fd->staging_fd, buf, size);
2296         if (ret == -1)
2297                 return -errno;
2298
2299         now = get_wim_timestamp();
2300         fd->f_inode->i_last_write_time = now;
2301         fd->f_inode->i_last_access_time = now;
2302         return ret;
2303 }
2304
2305 static struct fuse_operations wimfs_operations = {
2306 #if 0
2307         .access      = wimfs_access,
2308 #endif
2309         .chmod       = wimfs_chmod,
2310         .chown       = wimfs_chown,
2311         .destroy     = wimfs_destroy,
2312 #if 0
2313         .fallocate   = wimfs_fallocate,
2314 #endif
2315         .fgetattr    = wimfs_fgetattr,
2316         .ftruncate   = wimfs_ftruncate,
2317         .getattr     = wimfs_getattr,
2318 #ifdef ENABLE_XATTR
2319         .getxattr    = wimfs_getxattr,
2320 #endif
2321         .link        = wimfs_link,
2322 #ifdef ENABLE_XATTR
2323         .listxattr   = wimfs_listxattr,
2324 #endif
2325         .mkdir       = wimfs_mkdir,
2326         .mknod       = wimfs_mknod,
2327         .open        = wimfs_open,
2328         .opendir     = wimfs_opendir,
2329         .read        = wimfs_read,
2330         .readdir     = wimfs_readdir,
2331         .readlink    = wimfs_readlink,
2332         .release     = wimfs_release,
2333         .releasedir  = wimfs_releasedir,
2334 #ifdef ENABLE_XATTR
2335         .removexattr = wimfs_removexattr,
2336 #endif
2337         .rename      = wimfs_rename,
2338         .rmdir       = wimfs_rmdir,
2339 #ifdef ENABLE_XATTR
2340         .setxattr    = wimfs_setxattr,
2341 #endif
2342         .symlink     = wimfs_symlink,
2343         .truncate    = wimfs_truncate,
2344         .unlink      = wimfs_unlink,
2345 #ifdef HAVE_UTIMENSAT
2346         .utimens     = wimfs_utimens,
2347 #else
2348         .utime       = wimfs_utime,
2349 #endif
2350         .write       = wimfs_write,
2351
2352         /* wimfs keeps file descriptor structures (struct wimfs_fd), so there is
2353          * no need to have the file path provided on operations such as read()
2354          * where only the file descriptor is needed. */
2355 #if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 8)
2356         .flag_nullpath_ok = 1,
2357 #endif
2358 #if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 9)
2359         .flag_nopath = 1,
2360         .flag_utime_omit_ok = 1,
2361 #endif
2362 };
2363
2364
2365 /* Mounts an image from a WIM file. */
2366 WIMLIBAPI int wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
2367                                  int mount_flags, WIMStruct **additional_swms,
2368                                  unsigned num_additional_swms,
2369                                  const char *staging_dir)
2370 {
2371         int argc;
2372         char *argv[16];
2373         int ret;
2374         char *dir_copy;
2375         struct wim_lookup_table *joined_tab, *wim_tab_save;
2376         struct wim_image_metadata *imd;
2377         struct wimfs_context ctx;
2378         struct hlist_node *cur_node;
2379         struct wim_inode *inode;
2380
2381         DEBUG("Mount: wim = %p, image = %d, dir = %s, flags = %d, ",
2382               wim, image, dir, mount_flags);
2383
2384         if (!wim || !dir)
2385                 return WIMLIB_ERR_INVALID_PARAM;
2386
2387         ret = verify_swm_set(wim, additional_swms, num_additional_swms);
2388         if (ret != 0)
2389                 return ret;
2390
2391         if ((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) && (wim->hdr.total_parts != 1)) {
2392                 ERROR("Cannot mount a split WIM read-write");
2393                 return WIMLIB_ERR_SPLIT_UNSUPPORTED;
2394         }
2395
2396         if (num_additional_swms) {
2397                 ret = new_joined_lookup_table(wim, additional_swms,
2398                                               num_additional_swms,
2399                                               &joined_tab);
2400                 if (ret != 0)
2401                         return ret;
2402                 wim_tab_save = wim->lookup_table;
2403                 wim->lookup_table = joined_tab;
2404         }
2405
2406         if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
2407                 ret = wim_run_full_verifications(wim);
2408                 if (ret != 0)
2409                         goto out;
2410         }
2411
2412         ret = select_wim_image(wim, image);
2413         if (ret != 0)
2414                 goto out;
2415
2416         DEBUG("Selected image %d", image);
2417
2418         imd = wim_get_current_image_metadata(wim);
2419
2420         if (imd->root_dentry->refcnt != 1) {
2421                 ERROR("Cannot mount image that was just exported with "
2422                       "wimlib_export_image()");
2423                 ret = WIMLIB_ERR_INVALID_PARAM;
2424                 goto out;
2425         }
2426
2427         if (imd->inode_list.first) /* May be unneeded? */
2428                 imd->inode_list.first->pprev = &imd->inode_list.first;
2429
2430         if (imd->modified) {
2431                 ERROR("Cannot mount image that was added "
2432                       "with wimlib_add_image()");
2433                 ret = WIMLIB_ERR_INVALID_PARAM;
2434                 goto out;
2435         }
2436
2437         if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
2438                 ret = lock_wim(wim, wim->fp);
2439                 if (ret != 0)
2440                         goto out;
2441         }
2442
2443         /* Use default stream interface if one was not specified */
2444         if (!(mount_flags & (WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
2445                        WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR |
2446                        WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)))
2447                 mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR;
2448
2449
2450         DEBUG("Initializing struct wimfs_context");
2451         init_wimfs_context(&ctx);
2452         ctx.wim = wim;
2453         ctx.mount_flags = mount_flags;
2454         ctx.image_inode_list = &imd->inode_list;
2455         ctx.default_uid = getuid();
2456         ctx.default_gid = getgid();
2457         if (mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
2458                 ctx.default_lookup_flags = LOOKUP_FLAG_ADS_OK;
2459
2460         DEBUG("Unlinking message queues in case they already exist");
2461         ret = set_message_queue_names(&ctx, dir);
2462         if (ret != 0)
2463                 goto out_unlock;
2464         unlink_message_queues(&ctx);
2465
2466         DEBUG("Preparing arguments to fuse_main()");
2467
2468         dir_copy = STRDUP(dir);
2469         if (!dir_copy)
2470                 goto out_free_message_queue_names;
2471
2472         argc = 0;
2473         argv[argc++] = "imagex";
2474         argv[argc++] = dir_copy;
2475
2476         /* disable multi-threaded operation for read-write mounts */
2477         if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)
2478                 argv[argc++] = "-s";
2479
2480         if (mount_flags & WIMLIB_MOUNT_FLAG_DEBUG)
2481                 argv[argc++] = "-d";
2482
2483         /*
2484          * We provide the use_ino option to the FUSE mount because we are going
2485          * to assign inode numbers ourselves. */
2486         char optstring[256] =
2487                 "use_ino"
2488                 ",subtype=wimfs"
2489                 ",attr_timeout=0"
2490 #if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 8)
2491                 ",hard_remove"
2492 #endif
2493                 ",default_permissions"
2494                 ;
2495         argv[argc++] = "-o";
2496         argv[argc++] = optstring;
2497         if ((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)) {
2498                 /* Read-write mount.  Make the staging directory */
2499                 ret = make_staging_dir(&ctx, staging_dir);
2500                 if (ret != 0)
2501                         goto out_free_dir_copy;
2502         } else {
2503                 /* Read-only mount */
2504                 strcat(optstring, ",ro");
2505         }
2506         if (mount_flags & WIMLIB_MOUNT_FLAG_ALLOW_OTHER)
2507                 strcat(optstring, ",allow_other");
2508         argv[argc] = NULL;
2509
2510 #ifdef ENABLE_DEBUG
2511         {
2512                 int i;
2513                 DEBUG("FUSE command line (argc = %d): ", argc);
2514                 for (i = 0; i < argc; i++) {
2515                         fputs(argv[i], stdout);
2516                         putchar(' ');
2517                 }
2518                 putchar('\n');
2519                 fflush(stdout);
2520         }
2521 #endif
2522
2523         /* Mark dentry tree as modified if read-write mount. */
2524         if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
2525                 imd->modified = 1;
2526                 imd->has_been_mounted_rw = 1;
2527         }
2528
2529         /* Resolve the lookup table entries for every inode in the image, and
2530          * assign inode numbers */
2531         DEBUG("Resolving lookup table entries and assigning inode numbers");
2532         ctx.next_ino = 1;
2533         hlist_for_each_entry(inode, cur_node, &imd->inode_list, i_hlist) {
2534                 inode_resolve_ltes(inode, wim->lookup_table);
2535                 inode->i_ino = ctx.next_ino++;
2536         }
2537         DEBUG("(next_ino = %"PRIu64")", ctx.next_ino);
2538
2539         DEBUG("Calling fuse_main()");
2540
2541         ret = fuse_main(argc, argv, &wimfs_operations, &ctx);
2542
2543         DEBUG("Returned from fuse_main() (ret = %d)", ret);
2544
2545         if (ret) {
2546                 ret = WIMLIB_ERR_FUSE;
2547         } else {
2548                 if (ctx.have_status)
2549                         ret = ctx.status;
2550                 else
2551                         ret = WIMLIB_ERR_TIMEOUT;
2552         }
2553         if (ctx.daemon_to_unmount_mq != (mqd_t)(-1)) {
2554                 send_unmount_finished_msg(ctx.daemon_to_unmount_mq, ret);
2555                 close_message_queues(&ctx);
2556         }
2557
2558         /* Try to delete the staging directory if a deletion wasn't yet
2559          * attempted due to an earlier error */
2560         if (ctx.staging_dir_name)
2561                 delete_staging_dir(&ctx);
2562 out_free_dir_copy:
2563         FREE(dir_copy);
2564 out_unlock:
2565         wim->wim_locked = 0;
2566 out_free_message_queue_names:
2567         free_message_queue_names(&ctx);
2568 out:
2569         if (num_additional_swms) {
2570                 free_lookup_table(wim->lookup_table);
2571                 wim->lookup_table = wim_tab_save;
2572         }
2573         return ret;
2574 }
2575
2576 /*
2577  * Unmounts the WIM file that was previously mounted on @dir by using
2578  * wimlib_mount_image().
2579  */
2580 WIMLIBAPI int wimlib_unmount_image(const char *dir, int unmount_flags,
2581                                    wimlib_progress_func_t progress_func)
2582 {
2583         int ret;
2584         struct wimfs_context wimfs_ctx;
2585
2586         init_wimfs_context(&wimfs_ctx);
2587
2588         ret = set_message_queue_names(&wimfs_ctx, dir);
2589         if (ret != 0)
2590                 goto out;
2591
2592         ret = open_message_queues(&wimfs_ctx, false);
2593         if (ret != 0)
2594                 goto out_free_message_queue_names;
2595
2596         ret = send_unmount_request_msg(wimfs_ctx.unmount_to_daemon_mq,
2597                                        unmount_flags,
2598                                        progress_func != NULL);
2599         if (ret != 0)
2600                 goto out_close_message_queues;
2601
2602         ret = execute_fusermount(dir);
2603         if (ret != 0)
2604                 goto out_close_message_queues;
2605
2606         struct unmount_msg_handler_context handler_ctx = {
2607                 .hdr = {
2608                         .timeout_seconds = 5,
2609                 },
2610                 .daemon_pid = 0,
2611                 .progress_func = progress_func,
2612         };
2613
2614         ret = message_loop(wimfs_ctx.daemon_to_unmount_mq,
2615                            &unmount_msg_handler_callbacks,
2616                            &handler_ctx.hdr);
2617         if (ret == 0)
2618                 ret = handler_ctx.status;
2619 out_close_message_queues:
2620         close_message_queues(&wimfs_ctx);
2621 out_free_message_queue_names:
2622         free_message_queue_names(&wimfs_ctx);
2623 out:
2624         return ret;
2625 }
2626
2627 #else /* WITH_FUSE */
2628
2629
2630 static inline int mount_unsupported_error()
2631 {
2632 #if defined(__WIN32__)
2633         ERROR("Sorry-- Mounting WIM images is not supported on Windows!");
2634 #else
2635         ERROR("wimlib was compiled with --without-fuse, which disables support "
2636               "for mounting WIMs.");
2637 #endif
2638         return WIMLIB_ERR_UNSUPPORTED;
2639 }
2640
2641 WIMLIBAPI int wimlib_unmount_image(const char *dir, int unmount_flags,
2642                                    wimlib_progress_func_t progress_func)
2643 {
2644         return mount_unsupported_error();
2645 }
2646
2647 WIMLIBAPI int wimlib_mount_image(WIMStruct *wim_p, int image, const char *dir,
2648                                  int mount_flags, WIMStruct **additional_swms,
2649                                  unsigned num_additional_swms,
2650                                  const char *staging_dir)
2651 {
2652         return mount_unsupported_error();
2653 }
2654
2655 #endif /* WITH_FUSE */