]> wimlib.net Git - wimlib/blob - src/mount.c
Lots of changes
[wimlib] / src / mount.c
1 /*
2  * mount.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 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 "sha1.h"
34 #include "lookup_table.h"
35 #include "xml.h"
36 #include "io.h"
37 #include "timestamp.h"
38 #include <limits.h>
39 #include <stdlib.h>
40 #include <unistd.h>
41 #include <sys/wait.h>
42 #define FUSE_USE_VERSION 26
43 #include <errno.h>
44 #include <string.h>
45 #include <sys/time.h>
46 #include <fuse.h>
47 #include <ftw.h>
48 #include <mqueue.h>
49 #include <utime.h>
50
51 #ifdef ENABLE_XATTR
52 #include <attr/xattr.h>
53 #endif
54
55 /* File descriptor to a file open on the WIM filesystem. */
56 struct wimlib_fd {
57         struct inode *f_inode;
58         struct lookup_table_entry *f_lte;
59         int staging_fd;
60         u16 idx;
61         u32 stream_id;
62 };
63
64 struct wimfs_context {
65         /* The WIMStruct for the mounted WIM. */
66         WIMStruct *wim;
67
68         /* Working directory when `imagex mount' is run. */
69         char *working_directory;
70
71         /* Name of the staging directory for a read-write mount.  Whenever a new file is
72          * created, it is done so in the staging directory.  Furthermore, whenever a
73          * file in the WIM is modified, it is extracted to the staging directory.  If
74          * changes are commited when the WIM is unmounted, the file resources are merged
75          * in from the staging directory when writing the new WIM. */
76         char *staging_dir_name;
77         size_t staging_dir_name_len;
78
79         /* Flags passed to wimlib_mount(). */
80         int mount_flags;
81
82         /* Next inode number to be assigned. */
83         u64 next_ino;
84
85         /* List of lookup table entries in the staging directory */
86         struct list_head staging_list;
87
88         /* Name and message queue descriptors for message queues between the filesystem
89          * daemon process and the unmount process.  These are used when the filesystem
90          * is unmounted and the process running wimlib_mount() (i.e. the `imagex
91          * unmount' command) needs to communicate with the filesystem daemon running
92          * fuse_main() (i.e. that spawned by the `imagex mount' or `imagex mountrw'
93          * commands */
94         char *unmount_to_daemon_mq_name;
95         char *daemon_to_unmount_mq_name;
96         mqd_t unmount_to_daemon_mq;
97         mqd_t daemon_to_unmount_mq;
98 };
99
100 static void init_wimfs_context(struct wimfs_context *ctx)
101 {
102         memset(ctx, 0, sizeof(*ctx));
103         ctx->unmount_to_daemon_mq = (mqd_t)-1;
104         ctx->daemon_to_unmount_mq = (mqd_t)-1;
105         INIT_LIST_HEAD(&ctx->staging_list);
106 }
107
108 static inline struct wimfs_context *wimfs_get_context()
109 {
110         return (struct wimfs_context*)fuse_get_context()->private_data;
111 }
112
113 static inline WIMStruct *wimfs_get_WIMStruct()
114 {
115         return wimfs_get_context()->wim;
116 }
117
118 static inline bool wimfs_ctx_readonly(const struct wimfs_context *ctx)
119 {
120         return (ctx->mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) == 0;
121 }
122
123 static inline int get_lookup_flags(const struct wimfs_context *ctx)
124 {
125         if (ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
126                 return LOOKUP_FLAG_ADS_OK;
127         else
128                 return 0;
129 }
130
131 /* Returns nonzero if write permission is requested on the file open flags */
132 static inline int flags_writable(int open_flags)
133 {
134         return open_flags & (O_RDWR | O_WRONLY);
135 }
136
137 /*
138  * Allocate a file descriptor for a stream.
139  *
140  * @inode:      inode containing the stream we're opening
141  * @stream_id:  ID of the stream we're opening
142  * @lte:        Lookup table entry for the stream (may be NULL)
143  * @fd_ret:     Return the allocated file descriptor if successful.
144  * @readonly:   True if this is a read-only mount.
145  *
146  * Return 0 iff successful or error code if unsuccessful.
147  */
148 static int alloc_wimlib_fd(struct inode *inode,
149                            u32 stream_id,
150                            struct lookup_table_entry *lte,
151                            struct wimlib_fd **fd_ret,
152                            bool readonly)
153 {
154         static const u16 fds_per_alloc = 8;
155         static const u16 max_fds = 0xffff;
156         int ret;
157
158         pthread_mutex_lock(&inode->i_mutex);
159
160         DEBUG("Allocating fd for stream ID %u from inode %lx (open = %u, allocated = %u)",
161               stream_id, inode->ino, inode->num_opened_fds,
162               inode->num_allocated_fds);
163
164         if (inode->num_opened_fds == inode->num_allocated_fds) {
165                 struct wimlib_fd **fds;
166                 u16 num_new_fds;
167
168                 if (inode->num_allocated_fds == max_fds) {
169                         ret = -EMFILE;
170                         goto out;
171                 }
172                 num_new_fds = min(fds_per_alloc,
173                                   max_fds - inode->num_allocated_fds);
174
175                 fds = REALLOC(inode->fds,
176                               (inode->num_allocated_fds + num_new_fds) *
177                                 sizeof(inode->fds[0]));
178                 if (!fds) {
179                         ret = -ENOMEM;
180                         goto out;
181                 }
182                 memset(&fds[inode->num_allocated_fds], 0,
183                        num_new_fds * sizeof(fds[0]));
184                 inode->fds = fds;
185                 inode->num_allocated_fds += num_new_fds;
186         }
187         for (u16 i = 0; ; i++) {
188                 if (!inode->fds[i]) {
189                         struct wimlib_fd *fd = CALLOC(1, sizeof(*fd));
190                         if (!fd) {
191                                 ret = -ENOMEM;
192                                 break;
193                         }
194                         fd->f_inode    = inode;
195                         fd->f_lte      = lte;
196                         fd->staging_fd = -1;
197                         fd->idx        = i;
198                         fd->stream_id  = stream_id;
199                         *fd_ret        = fd;
200                         inode->fds[i]  = fd;
201                         inode->num_opened_fds++;
202                         if (lte && !readonly)
203                                 lte->num_opened_fds++;
204                         DEBUG("Allocated fd (idx = %u)", fd->idx);
205                         ret = 0;
206                         break;
207                 }
208         }
209 out:
210         pthread_mutex_unlock(&inode->i_mutex);
211         return ret;
212 }
213
214 static void inode_put_fd(struct inode *inode, struct wimlib_fd *fd)
215 {
216         wimlib_assert(fd != NULL);
217         wimlib_assert(inode != NULL);
218
219         pthread_mutex_lock(&inode->i_mutex);
220
221         wimlib_assert(fd->f_inode == inode);
222         wimlib_assert(inode->num_opened_fds != 0);
223         wimlib_assert(fd->idx < inode->num_allocated_fds);
224         wimlib_assert(inode->fds[fd->idx] == fd);
225
226         inode->fds[fd->idx] = NULL;
227         FREE(fd);
228         if (--inode->num_opened_fds == 0 && inode->link_count == 0) {
229                 pthread_mutex_unlock(&inode->i_mutex);
230                 free_inode(inode);
231         } else {
232                 pthread_mutex_unlock(&inode->i_mutex);
233         }
234 }
235
236 static int lte_put_fd(struct lookup_table_entry *lte, struct wimlib_fd *fd)
237 {
238         wimlib_assert(fd != NULL);
239         wimlib_assert(fd->f_lte == lte);
240
241         if (!lte) /* Empty stream with no lookup table entry */
242                 return 0;
243
244         /* Close staging file descriptor if needed. */
245
246         if (lte->resource_location == RESOURCE_IN_STAGING_FILE
247              && fd->staging_fd != -1)
248         {
249                 if (close(fd->staging_fd) != 0) {
250                         ERROR_WITH_ERRNO("Failed to close staging file");
251                         return -errno;
252                 }
253         }
254         lte_decrement_num_opened_fds(lte);
255         return 0;
256 }
257
258 /* Close a file descriptor. */
259 static int close_wimlib_fd(struct wimlib_fd *fd)
260 {
261         int ret;
262         wimlib_assert(fd != NULL);
263         DEBUG("Closing fd (inode = %lu, opened = %u, allocated = %u)",
264               fd->f_inode->ino, fd->f_inode->num_opened_fds,
265               fd->f_inode->num_allocated_fds);
266         ret = lte_put_fd(fd->f_lte, fd);
267         if (ret != 0)
268                 return ret;
269
270         inode_put_fd(fd->f_inode, fd);
271         return 0;
272 }
273
274 /* Remove a dentry; i.e. remove a reference to the corresponding inode.
275  *
276  * If there are no remaining references to the inode either through dentries or
277  * open file descriptors, the inode is freed.  Otherwise, the inode is not
278  * removed, but the dentry is unlinked and freed.
279  *
280  * Either way, all lookup table entries referenced by the inode have their
281  * reference count decremented.  If a lookup table entry has no open file
282  * descriptors and no references remaining, it is freed, and the staging file is
283  * unlinked.
284  */
285 static void remove_dentry(struct dentry *dentry,
286                           struct lookup_table *lookup_table)
287 {
288         struct inode *inode = dentry->d_inode;
289         struct lookup_table_entry *lte;
290         unsigned i;
291
292         for (i = 0; i <= inode->num_ads; i++) {
293                 lte = inode_stream_lte_resolved(inode, i);
294                 if (lte)
295                         lte_decrement_refcnt(lte, lookup_table);
296         }
297         unlink_dentry(dentry);
298         put_dentry(dentry);
299 }
300
301 /* Creates a new staging file and returns its file descriptor opened for
302  * writing.
303  *
304  * @name_ret: A location into which the a pointer to the newly allocated name of
305  *                      the staging file is stored.
306  * @return:  The file descriptor for the new file.  Returns -1 and sets errno on
307  *              error, for any reason possible from the creat() function.
308  */
309 static int create_staging_file(char **name_ret, int open_flags,
310                                struct wimfs_context *ctx)
311 {
312         size_t name_len;
313         char *name;
314         struct stat stbuf;
315         int fd;
316         int errno_save;
317
318         name_len = ctx->staging_dir_name_len + 1 + SHA1_HASH_SIZE;
319         name = MALLOC(name_len + 1);
320         if (!name) {
321                 errno = ENOMEM;
322                 return -1;
323         }
324
325         do {
326
327                 memcpy(name, ctx->staging_dir_name, ctx->staging_dir_name_len);
328                 name[ctx->staging_dir_name_len] = '/';
329                 randomize_char_array_with_alnum(name + ctx->staging_dir_name_len + 1,
330                                                 SHA1_HASH_SIZE);
331                 name[name_len] = '\0';
332
333
334         /* Just in case, verify that the randomly generated name doesn't name an
335          * existing file, and try again if so  */
336         } while (stat(name, &stbuf) == 0);
337
338         if (errno != ENOENT)
339                 /* other error! */
340                 return -1;
341
342         /* doesn't exist--- ok */
343
344         DEBUG("Creating staging file `%s'", name);
345
346         fd = open(name, open_flags | O_CREAT | O_TRUNC, 0600);
347         if (fd == -1) {
348                 errno_save = errno;
349                 FREE(name);
350                 errno = errno_save;
351         } else {
352                 *name_ret = name;
353         }
354         return fd;
355 }
356
357 /*
358  * Extract a WIM resource to the staging directory.
359  *
360  * @inode:  Inode that contains the stream we are extracting
361  *
362  * @stream_id: Identifier for the stream (it stays constant even if the indices
363  * of the stream entries are changed)
364  *
365  * @lte: Pointer to pointer to the lookup table entry for the stream we need to
366  * extract, or NULL if there was no lookup table entry present for the stream
367  *
368  * @size:  Number of bytes of the stream we want to extract (this supports the
369  * wimfs_truncate() function).
370  */
371 static int extract_resource_to_staging_dir(struct inode *inode,
372                                            u32 stream_id,
373                                            struct lookup_table_entry **lte,
374                                            off_t size,
375                                            struct wimfs_context *ctx)
376 {
377         char *staging_file_name;
378         int ret;
379         int fd;
380         struct lookup_table_entry *old_lte, *new_lte;
381
382         DEBUG("Extracting resource to staging dir: inode %"PRIu64", "
383               "stream id %"PRIu32, inode->ino, stream_id);
384
385         old_lte = *lte;
386         fd = create_staging_file(&staging_file_name, O_WRONLY, ctx);
387         if (fd == -1)
388                 return -errno;
389
390         if (old_lte)
391                 ret = extract_wim_resource_to_fd(old_lte, fd, size);
392         else
393                 ret = 0;
394         if (ret != 0 || close(fd) != 0) {
395                 if (errno != 0)
396                         ret = -errno;
397                 else
398                         ret = -EIO;
399                 close(fd);
400                 goto out_delete_staging_file;
401         }
402
403         if (old_lte && inode->link_count == old_lte->refcnt) {
404                 /* The reference count of the existing lookup table
405                  * entry is the same as the link count of the inode that
406                  * contains the stream we're opening.  Therefore, ALL
407                  * the references to the lookup table entry correspond
408                  * to the stream we're trying to extract, so the lookup
409                  * table entry can be re-used.  */
410                 DEBUG("Re-using lookup table entry");
411                 lookup_table_unlink(ctx->wim->lookup_table, old_lte);
412                 new_lte = old_lte;
413         } else {
414                 if (old_lte) {
415                         /* There's an existing lookup table entry, but its
416                          * reference count is creater than the link count for
417                          * the inode containing a stream we're opening.
418                          * Therefore, we need to split the lookup table entry.
419                          * */
420                         wimlib_assert(old_lte->refcnt > inode->link_count);
421                         DEBUG("Splitting lookup table entry "
422                               "(inode->link_count = %u, old_lte->refcnt = %u)",
423                               inode->link_count, old_lte->refcnt);
424
425                 }
426
427                 new_lte = new_lookup_table_entry();
428                 if (!new_lte) {
429                         ret = -ENOMEM;
430                         goto out_delete_staging_file;
431                 }
432
433                 /* There may already be open file descriptors to this stream if
434                  * it's previously been opened read-only, but just now we're
435                  * opening it read-write.  Identify those file descriptors and
436                  * change their lookup table entry pointers to point to the new
437                  * lookup table entry, and open staging file descriptors for
438                  * them.
439                  *
440                  * At the same time, we need to count the number of these opened
441                  * file descriptors to the new lookup table entry.  If there's
442                  * an old lookup table entry, this number needs to be subtracted
443                  * from the fd's opened to the old entry. */
444                 for (u16 i = 0, j = 0; j < inode->num_opened_fds; i++) {
445                         struct wimlib_fd *fd = inode->fds[i];
446                         if (fd) {
447                                 if (fd->stream_id == stream_id) {
448                                         wimlib_assert(fd->f_lte == old_lte);
449                                         wimlib_assert(fd->staging_fd == -1);
450                                         fd->f_lte = new_lte;
451                                         new_lte->num_opened_fds++;
452                                         fd->staging_fd = open(staging_file_name, O_RDONLY);
453                                         if (fd->staging_fd == -1) {
454                                                 ret = -errno;
455                                                 goto out_revert_fd_changes;
456                                         }
457                                 }
458                                 j++;
459                         }
460                 }
461                 DEBUG("%hu fd's were already opened to the file we extracted",
462                       new_lte->num_opened_fds);
463                 if (old_lte) {
464                         old_lte->num_opened_fds -= new_lte->num_opened_fds;
465                         old_lte->refcnt -= inode->link_count;
466                 }
467         }
468
469         new_lte->resource_entry.original_size = size;
470         new_lte->refcnt                       = inode->link_count;
471         new_lte->resource_location            = RESOURCE_IN_STAGING_FILE;
472         new_lte->staging_file_name            = staging_file_name;
473         new_lte->lte_inode                    = inode;
474         random_hash(new_lte->hash);
475
476         if (stream_id == 0)
477                 inode->lte = new_lte;
478         else
479                 for (u16 i = 0; i < inode->num_ads; i++)
480                         if (inode->ads_entries[i].stream_id == stream_id)
481                                 inode->ads_entries[i].lte = new_lte;
482
483         lookup_table_insert(ctx->wim->lookup_table, new_lte);
484         list_add(&new_lte->staging_list, &ctx->staging_list);
485         *lte = new_lte;
486         return 0;
487 out_revert_fd_changes:
488         for (u16 i = 0, j = 0; j < new_lte->num_opened_fds; i++) {
489                 struct wimlib_fd *fd = inode->fds[i];
490                 if (fd && fd->stream_id == stream_id && fd->f_lte == new_lte) {
491                         fd->f_lte = old_lte;
492                         if (fd->staging_fd != -1) {
493                                 close(fd->staging_fd);
494                                 fd->staging_fd = -1;
495                         }
496                         j++;
497                 }
498         }
499         free_lookup_table_entry(new_lte);
500 out_delete_staging_file:
501         unlink(staging_file_name);
502         FREE(staging_file_name);
503         return ret;
504 }
505
506 /*
507  * Creates a randomly named staging directory and saves its name in the
508  * filesystem context structure.
509  */
510 static int make_staging_dir(struct wimfs_context *ctx)
511 {
512         /* XXX Give the user an option of where to stage files */
513
514         static const char prefix[] = "wimlib-staging-";
515         static const size_t prefix_len = sizeof(prefix) - 1;
516         static const size_t random_suffix_len = 10;
517
518         size_t pwd_len = strlen(ctx->working_directory);
519
520         ctx->staging_dir_name_len = pwd_len + 1 + prefix_len + random_suffix_len;
521
522         ctx->staging_dir_name = MALLOC(ctx->staging_dir_name_len + 1);
523         if (!ctx->staging_dir_name)
524                 return WIMLIB_ERR_NOMEM;
525
526         memcpy(ctx->staging_dir_name, ctx->working_directory, pwd_len);
527         ctx->staging_dir_name[pwd_len] = '/';
528         memcpy(ctx->staging_dir_name + pwd_len + 1, prefix, prefix_len);
529         randomize_char_array_with_alnum(ctx->staging_dir_name + pwd_len +
530                                         1 + prefix_len, random_suffix_len);
531         ctx->staging_dir_name[ctx->staging_dir_name_len] = '\0';
532
533         if (mkdir(ctx->staging_dir_name, 0700) != 0) {
534                 ERROR_WITH_ERRNO("Failed to create temporary directory `%s'",
535                                  ctx->staging_dir_name);
536                 FREE(ctx->staging_dir_name);
537                 ctx->staging_dir_name = NULL;
538                 return WIMLIB_ERR_MKDIR;
539         }
540         return 0;
541 }
542
543 static int remove_file_or_directory(const char *fpath, const struct stat *sb,
544                                     int typeflag, struct FTW *ftwbuf)
545 {
546         if (remove(fpath) == 0)
547                 return 0;
548         else {
549                 ERROR_WITH_ERRNO("Cannot remove `%s'", fpath);
550                 return WIMLIB_ERR_DELETE_STAGING_DIR;
551         }
552 }
553
554
555 /*
556  * Deletes the staging directory and all the files contained in it.
557  */
558 static int delete_staging_dir(struct wimfs_context *ctx)
559 {
560         int ret;
561         wimlib_assert(ctx->staging_dir_name != NULL);
562         ret = nftw(ctx->staging_dir_name, remove_file_or_directory,
563                    10, FTW_DEPTH);
564         FREE(ctx->staging_dir_name);
565         ctx->staging_dir_name = NULL;
566         return ret;
567 }
568
569
570 /* Simple function that returns the concatenation of 2 strings. */
571 static char *strcat_dup(const char *s1, const char *s2, size_t max_len)
572 {
573         size_t len = strlen(s1) + strlen(s2);
574         if (len > max_len)
575                 len = max_len;
576         char *p = MALLOC(len + 1);
577         if (!p)
578                 return NULL;
579         snprintf(p, len + 1, "%s%s", s1, s2);
580         return p;
581 }
582
583 static int set_message_queue_names(struct wimfs_context *ctx,
584                                    const char *mount_dir)
585 {
586         static const char *u2d_prefix = "/wimlib-unmount-to-daemon-mq";
587         static const char *d2u_prefix = "/wimlib-daemon-to-unmount-mq";
588         char *dir_path;
589         char *p;
590         int ret;
591
592         dir_path = realpath(mount_dir, NULL);
593         if (!dir_path) {
594                 ERROR_WITH_ERRNO("Failed to resolve path \"%s\"", mount_dir);
595                 return WIMLIB_ERR_NOTDIR;
596         }
597
598         DEBUG("Using absolute dir_path = `%s'", dir_path);
599
600
601         p = dir_path;
602         while (*p) {
603                 if (*p == '/')
604                         *p = 0xff;
605                 p++;
606         }
607
608         ctx->unmount_to_daemon_mq_name = strcat_dup(u2d_prefix, dir_path,
609                                                     NAME_MAX);
610         if (!ctx->unmount_to_daemon_mq_name) {
611                 ret = WIMLIB_ERR_NOMEM;
612                 goto out_free_dir_path;
613         }
614         ctx->daemon_to_unmount_mq_name = strcat_dup(d2u_prefix, dir_path,
615                                                     NAME_MAX);
616         if (!ctx->daemon_to_unmount_mq_name) {
617                 ret = WIMLIB_ERR_NOMEM;
618                 goto out_free_unmount_to_daemon_mq_name;
619         }
620
621         ret = 0;
622         goto out_free_dir_path;
623 out_free_unmount_to_daemon_mq_name:
624         FREE(ctx->unmount_to_daemon_mq_name);
625         ctx->unmount_to_daemon_mq_name = NULL;
626 out_free_dir_path:
627         FREE(dir_path);
628         return ret;
629 }
630
631 static void free_message_queue_names(struct wimfs_context *ctx)
632 {
633         FREE(ctx->unmount_to_daemon_mq_name);
634         FREE(ctx->daemon_to_unmount_mq_name);
635         ctx->unmount_to_daemon_mq_name = NULL;
636         ctx->daemon_to_unmount_mq_name = NULL;
637 }
638
639 /*
640  * Opens two POSIX message queue: one for sending messages from the unmount
641  * process to the daemon process, and one to go the other way.  The names of the
642  * message queues, which must be system-wide unique, are be based on the mount
643  * point.  (There of course is still a possibility of a collision if one were to
644  * unmount two identically named directories simultaneously...)
645  *
646  * @daemon specifies whether the calling process is the filesystem daemon or the
647  * unmount process.
648  */
649 static int open_message_queues(struct wimfs_context *ctx, bool daemon)
650 {
651         int flags;
652         int ret;
653
654         wimlib_assert(ctx->unmount_to_daemon_mq_name != NULL &&
655                       ctx->daemon_to_unmount_mq_name != NULL);
656
657         if (daemon)
658                 flags = O_RDONLY | O_CREAT;
659         else
660                 flags = O_WRONLY | O_CREAT;
661
662         DEBUG("Opening message queue \"%s\"", ctx->unmount_to_daemon_mq_name);
663         ctx->unmount_to_daemon_mq = mq_open(ctx->unmount_to_daemon_mq_name,
664                                             flags, 0700, NULL);
665
666         if (ctx->unmount_to_daemon_mq == (mqd_t)-1) {
667                 ERROR_WITH_ERRNO("mq_open()");
668                 ret = WIMLIB_ERR_MQUEUE;
669                 goto out;
670         }
671
672         if (daemon)
673                 flags = O_WRONLY | O_CREAT;
674         else
675                 flags = O_RDONLY | O_CREAT;
676
677         DEBUG("Opening message queue \"%s\"", ctx->daemon_to_unmount_mq_name);
678         ctx->daemon_to_unmount_mq = mq_open(ctx->daemon_to_unmount_mq_name,
679                                             flags, 0700, NULL);
680
681         if (ctx->daemon_to_unmount_mq == (mqd_t)-1) {
682                 ERROR_WITH_ERRNO("mq_open()");
683                 ret = WIMLIB_ERR_MQUEUE;
684                 goto out_close_unmount_to_daemon_mq;
685         }
686         ret = 0;
687         goto out;
688 out_close_unmount_to_daemon_mq:
689         mq_close(ctx->unmount_to_daemon_mq);
690         mq_unlink(ctx->unmount_to_daemon_mq_name);
691         ctx->unmount_to_daemon_mq = (mqd_t)-1;
692 out:
693         return ret;
694 }
695
696 /* Try to determine the maximum message size of a message queue.  The return
697  * value is the maximum message size, or a guess of 8192 bytes if it cannot be
698  * determined. */
699 static long mq_get_msgsize(mqd_t mq)
700 {
701         static const char *msgsize_max_file = "/proc/sys/fs/mqueue/msgsize_max";
702         FILE *fp;
703         struct mq_attr attr;
704         long msgsize;
705
706         if (mq_getattr(mq, &attr) == 0) {
707                 msgsize = attr.mq_msgsize;
708         } else {
709                 ERROR_WITH_ERRNO("mq_getattr()");
710                 ERROR("Attempting to read %s", msgsize_max_file);
711                 fp = fopen(msgsize_max_file, "rb");
712                 if (fp) {
713                         if (fscanf(fp, "%ld", &msgsize) != 1) {
714                                 ERROR("Assuming message size of 8192");
715                                 msgsize = 8192;
716                         }
717                         fclose(fp);
718                 } else {
719                         ERROR_WITH_ERRNO("Failed to open the file `%s'",
720                                          msgsize_max_file);
721                         ERROR("Assuming message size of 8192");
722                         msgsize = 8192;
723                 }
724         }
725         return msgsize;
726 }
727
728 static int get_mailbox(mqd_t mq, long needed_msgsize, long *msgsize_ret,
729                        char **mailbox_ret)
730 {
731         long msgsize;
732         char *mailbox;
733
734         msgsize = mq_get_msgsize(mq);
735
736         if (msgsize < needed_msgsize) {
737                 ERROR("Message queue max size must be at least %ld!",
738                       needed_msgsize);
739                 return WIMLIB_ERR_MQUEUE;
740         }
741
742         mailbox = MALLOC(msgsize);
743         if (!mailbox) {
744                 ERROR("Failed to allocate %ld bytes for mailbox", msgsize);
745                 return WIMLIB_ERR_NOMEM;
746         }
747         *msgsize_ret = msgsize;
748         *mailbox_ret = mailbox;
749         return 0;
750 }
751
752 static void unlink_message_queues(struct wimfs_context *ctx)
753 {
754         mq_unlink(ctx->unmount_to_daemon_mq_name);
755         mq_unlink(ctx->daemon_to_unmount_mq_name);
756 }
757
758 /* Closes the message queues, which are allocated in static variables */
759 static void close_message_queues(struct wimfs_context *ctx)
760 {
761         mq_close(ctx->unmount_to_daemon_mq);
762         ctx->unmount_to_daemon_mq = (mqd_t)(-1);
763         mq_close(ctx->daemon_to_unmount_mq);
764         ctx->daemon_to_unmount_mq = (mqd_t)(-1);
765         unlink_message_queues(ctx);
766 }
767
768 static int wimfs_access(const char *path, int mask)
769 {
770         /* Permissions not implemented */
771         return 0;
772 }
773
774 static int wimfs_chmod(const char *path, mode_t mask)
775 {
776         struct dentry *dentry;
777         struct wimfs_context *ctx = wimfs_get_context();
778         struct inode *inode;
779         struct stat stbuf;
780         int ret;
781
782         ret = lookup_resource(ctx->wim, path,
783                               get_lookup_flags(ctx) | LOOKUP_FLAG_DIRECTORY_OK,
784                               &dentry, NULL, NULL);
785         if (ret != 0)
786                 return ret;
787         inode = dentry->d_inode;
788         inode_to_stbuf(inode, NULL, &stbuf);
789         if (mask == stbuf.st_mode)
790                 return 0;
791         else
792                 return -EPERM;
793
794 }
795
796 static void inode_update_lte_ptr(struct inode *inode,
797                                  struct lookup_table_entry *old_lte,
798                                  struct lookup_table_entry *new_lte)
799 {
800         if (inode->lte == old_lte) {
801                 inode->lte = new_lte;
802         } else {
803                 for (unsigned i = 0; i < inode->num_ads; i++) {
804                         if (inode->ads_entries[i].lte == old_lte) {
805                                 inode->ads_entries[i].lte = new_lte;
806                                 break;
807                         }
808                 }
809         }
810 }
811
812 static int update_lte_of_staging_file(struct lookup_table_entry *lte,
813                                       struct lookup_table *table)
814 {
815         struct lookup_table_entry *duplicate_lte;
816         int ret;
817         u8 hash[SHA1_HASH_SIZE];
818         struct stat stbuf;
819
820         wimlib_assert(lte->resource_location == RESOURCE_IN_STAGING_FILE);
821         wimlib_assert(lte->staging_file_name);
822
823         ret = sha1sum(lte->staging_file_name, hash);
824         if (ret != 0)
825                 return ret;
826
827         lookup_table_unlink(table, lte);
828
829         duplicate_lte = __lookup_resource(table, hash);
830
831         if (duplicate_lte) {
832                 /* Merge duplicate lookup table entries */
833                 duplicate_lte->refcnt += lte->refcnt;
834                 list_del(&lte->staging_list);
835                 inode_update_lte_ptr(lte->lte_inode, lte, duplicate_lte);
836                 free_lookup_table_entry(lte);
837         } else {
838                 if (stat(lte->staging_file_name, &stbuf) != 0) {
839                         ERROR_WITH_ERRNO("Failed to stat `%s'", lte->staging_file_name);
840                         return WIMLIB_ERR_STAT;
841                 }
842                 if (stbuf.st_size == 0) {
843                         /* Zero-length stream.  No lookup table entry needed. */
844                         inode_update_lte_ptr(lte->lte_inode, lte, NULL);
845                         free_lookup_table_entry(lte);
846                 } else {
847                         wimlib_assert(&lte->file_on_disk == &lte->staging_file_name);
848                         lte->resource_entry.original_size = stbuf.st_size;
849                         lte->resource_entry.size = stbuf.st_size;
850                         lte->resource_location = RESOURCE_IN_FILE_ON_DISK;
851                         lte->lte_inode = NULL;
852                         copy_hash(lte->hash, hash);
853                         lookup_table_insert(table, lte);
854                 }
855         }
856         return 0;
857 }
858
859 static int inode_close_fds(struct inode *inode)
860 {
861         u16 num_opened_fds = inode->num_opened_fds;
862         for (u16 i = 0, j = 0; j < num_opened_fds; i++) {
863                 struct wimlib_fd *fd = inode->fds[i];
864                 if (fd) {
865                         wimlib_assert(fd->f_inode == inode);
866                         int ret = close_wimlib_fd(fd);
867                         if (ret != 0)
868                                 return ret;
869                         j++;
870                 }
871         }
872         return 0;
873 }
874
875 /* Overwrites the WIM file, with changes saved. */
876 static int rebuild_wim(struct wimfs_context *ctx, bool check_integrity)
877 {
878         int ret;
879         struct lookup_table_entry *lte, *tmp;
880         WIMStruct *w = ctx->wim;
881
882
883         DEBUG("Closing all staging file descriptors.");
884         list_for_each_entry_safe(lte, tmp, &ctx->staging_list, staging_list) {
885                 ret = inode_close_fds(lte->lte_inode);
886                 if (ret != 0)
887                         return ret;
888         }
889
890         DEBUG("Calculating SHA1 checksums for all new staging files.");
891         list_for_each_entry_safe(lte, tmp, &ctx->staging_list, staging_list) {
892                 ret = update_lte_of_staging_file(lte, ctx->wim->lookup_table);
893                 if (ret != 0)
894                         return ret;
895         }
896
897         xml_update_image_info(w, w->current_image);
898
899         ret = wimlib_overwrite(w, check_integrity, 0, NULL);
900         if (ret != 0) {
901                 ERROR("Failed to commit changes");
902                 return ret;
903         }
904         return ret;
905 }
906
907 /* Called when the filesystem is unmounted. */
908 static void wimfs_destroy(void *p)
909 {
910         /* For read-write mounts, the `imagex unmount' command, which is
911          * running in a separate process and is executing the
912          * wimlib_unmount() function, will send this process a byte
913          * through a message queue that indicates whether the --commit
914          * option was specified or not. */
915
916         long msgsize;
917         struct timespec timeout;
918         struct timeval now;
919         ssize_t bytes_received;
920         int ret;
921         char commit;
922         char check_integrity;
923         char status;
924         char *mailbox;
925         struct wimfs_context *ctx = wimfs_get_context();
926
927         if (open_message_queues(ctx, true))
928                 return;
929
930         if (get_mailbox(ctx->unmount_to_daemon_mq, 2, &msgsize, &mailbox))
931                 goto out_close_message_queues;
932
933         /* Wait at most 3 seconds before giving up and discarding changes. */
934         gettimeofday(&now, NULL);
935         timeout.tv_sec = now.tv_sec + 3;
936         timeout.tv_nsec = now.tv_usec * 1000;
937         DEBUG("Waiting for message telling us whether to commit or not, and "
938               "whether to include integrity checks.");
939
940         bytes_received = mq_timedreceive(ctx->unmount_to_daemon_mq, mailbox,
941                                          msgsize, NULL, &timeout);
942         if (bytes_received == -1) {
943                 ERROR_WITH_ERRNO("mq_timedreceive()");
944                 ERROR("Not committing.");
945                 commit = 0;
946                 check_integrity = 0;
947         } else {
948                 DEBUG("Received message: [%d %d]", mailbox[0], mailbox[1]);
949                 commit = mailbox[0];
950                 check_integrity = mailbox[1];
951         }
952
953         status = 0;
954         if (ctx->mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
955                 if (commit) {
956                         ret = chdir(ctx->working_directory);
957                         if (ret == 0) {
958                                 status = rebuild_wim(ctx, (check_integrity != 0));
959                         } else {
960                                 ERROR_WITH_ERRNO("chdir()");
961                                 status = WIMLIB_ERR_NOTDIR;
962                         }
963                 }
964                 ret = delete_staging_dir(ctx);
965                 if (ret != 0) {
966                         ERROR("Failed to delete the staging directory");
967                         if (status == 0)
968                                 status = ret;
969                 }
970         } else {
971                 DEBUG("Read-only mount");
972         }
973         DEBUG("Sending status %hhd", status);
974         ret = mq_send(ctx->daemon_to_unmount_mq, &status, 1, 1);
975         if (ret == -1)
976                 ERROR_WITH_ERRNO("Failed to send status to unmount process");
977         FREE(mailbox);
978 out_close_message_queues:
979         close_message_queues(ctx);
980 }
981
982 #if 0
983 static int wimfs_fallocate(const char *path, int mode,
984                            off_t offset, off_t len, struct fuse_file_info *fi)
985 {
986         struct wimlib_fd *fd = (struct wimlib_fd*)(uintptr_t)fi->fh;
987         wimlib_assert(fd->staging_fd != -1);
988         return fallocate(fd->staging_fd, mode, offset, len);
989 }
990
991 #endif
992
993 static int wimfs_fgetattr(const char *path, struct stat *stbuf,
994                           struct fuse_file_info *fi)
995 {
996         struct wimlib_fd *fd = (struct wimlib_fd*)(uintptr_t)fi->fh;
997         return inode_to_stbuf(fd->f_inode, fd->f_lte, stbuf);
998 }
999
1000 static int wimfs_ftruncate(const char *path, off_t size,
1001                            struct fuse_file_info *fi)
1002 {
1003         struct wimlib_fd *fd = (struct wimlib_fd*)(uintptr_t)fi->fh;
1004         int ret = ftruncate(fd->staging_fd, size);
1005         if (ret != 0)
1006                 return -errno;
1007         if (fd->f_lte && size < fd->f_lte->resource_entry.original_size)
1008                 fd->f_lte->resource_entry.original_size = size;
1009         return 0;
1010 }
1011
1012 /*
1013  * Fills in a `struct stat' that corresponds to a file or directory in the WIM.
1014  */
1015 static int wimfs_getattr(const char *path, struct stat *stbuf)
1016 {
1017         struct dentry *dentry;
1018         struct lookup_table_entry *lte;
1019         int ret;
1020         struct wimfs_context *ctx = wimfs_get_context();
1021
1022         ret = lookup_resource(ctx->wim, path,
1023                               get_lookup_flags(ctx) | LOOKUP_FLAG_DIRECTORY_OK,
1024                               &dentry, &lte, NULL);
1025         if (ret != 0)
1026                 return ret;
1027         return inode_to_stbuf(dentry->d_inode, lte, stbuf);
1028 }
1029
1030 #ifdef ENABLE_XATTR
1031 /* Read an alternate data stream through the XATTR interface, or get its size */
1032 static int wimfs_getxattr(const char *path, const char *name, char *value,
1033                           size_t size)
1034 {
1035         int ret;
1036         struct inode *inode;
1037         struct ads_entry *ads_entry;
1038         size_t res_size;
1039         struct lookup_table_entry *lte;
1040         struct wimfs_context *ctx = wimfs_get_context();
1041
1042         if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1043                 return -ENOTSUP;
1044
1045         if (strlen(name) < 5 || memcmp(name, "user.", 5) != 0)
1046                 return -ENOATTR;
1047         name += 5;
1048
1049         inode = wim_pathname_to_inode(ctx->wim, path);
1050         if (!inode)
1051                 return -ENOENT;
1052
1053         ads_entry = inode_get_ads_entry(inode, name, NULL);
1054         if (!ads_entry)
1055                 return -ENOATTR;
1056
1057         lte = ads_entry->lte;
1058         res_size = wim_resource_size(lte);
1059
1060         if (size == 0)
1061                 return res_size;
1062
1063         if (res_size > size)
1064                 return -ERANGE;
1065
1066         ret = read_full_wim_resource(lte, (u8*)value,
1067                                      WIMLIB_RESOURCE_FLAG_MULTITHREADED);
1068         if (ret != 0)
1069                 return -EIO;
1070
1071         return res_size;
1072 }
1073 #endif
1074
1075 /* Create a hard link */
1076 static int wimfs_link(const char *to, const char *from)
1077 {
1078         struct dentry *from_dentry, *from_dentry_parent;
1079         const char *link_name;
1080         struct inode *inode;
1081         struct lookup_table_entry *lte;
1082         WIMStruct *w = wimfs_get_WIMStruct();
1083
1084         inode = wim_pathname_to_inode(w, to);
1085         if (!inode)
1086                 return -ENOENT;
1087
1088         if (!inode_is_regular_file(inode))
1089                 return -EPERM;
1090
1091         from_dentry_parent = get_parent_dentry(w, from);
1092         if (!from_dentry_parent)
1093                 return -ENOENT;
1094         if (!dentry_is_directory(from_dentry_parent))
1095                 return -ENOTDIR;
1096
1097         link_name = path_basename(from);
1098         if (get_dentry_child_with_name(from_dentry_parent, link_name))
1099                 return -EEXIST;
1100         from_dentry = new_dentry(link_name);
1101         if (!from_dentry)
1102                 return -ENOMEM;
1103
1104
1105         inode_add_dentry(from_dentry, inode);
1106         from_dentry->d_inode = inode;
1107         inode->link_count++;
1108
1109         for (unsigned i = 0; i <= inode->num_ads; i++) {
1110                 lte = inode_stream_lte_resolved(inode, i);
1111                 if (lte)
1112                         lte->refcnt++;
1113         }
1114
1115         dentry_add_child(from_dentry_parent, from_dentry);
1116         return 0;
1117 }
1118
1119 #ifdef ENABLE_XATTR
1120 static int wimfs_listxattr(const char *path, char *list, size_t size)
1121 {
1122         size_t needed_size;
1123         struct inode *inode;
1124         struct wimfs_context *ctx = wimfs_get_context();
1125
1126         if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1127                 return -ENOTSUP;
1128
1129         /* List alternate data streams, or get the list size */
1130
1131         inode = wim_pathname_to_inode(ctx->wim, path);
1132         if (!inode)
1133                 return -ENOENT;
1134
1135         if (size == 0) {
1136                 needed_size = 0;
1137                 for (u16 i = 0; i < inode->num_ads; i++)
1138                         needed_size += inode->ads_entries[i].stream_name_utf8_len + 6;
1139                 return needed_size;
1140         } else {
1141                 char *p = list;
1142                 for (u16 i = 0; i < inode->num_ads; i++) {
1143                         needed_size = inode->ads_entries[i].stream_name_utf8_len + 6;
1144                         if (needed_size > size)
1145                                 return -ERANGE;
1146                         p += sprintf(p, "user.%s",
1147                                      inode->ads_entries[i].stream_name_utf8) + 1;
1148                         size -= needed_size;
1149                 }
1150                 return p - list;
1151         }
1152 }
1153 #endif
1154
1155 /*
1156  * Create a directory in the WIM.
1157  * @mode is currently ignored.
1158  */
1159 static int wimfs_mkdir(const char *path, mode_t mode)
1160 {
1161         struct dentry *parent;
1162         struct dentry *newdir;
1163         const char *basename;
1164         struct wimfs_context *ctx = wimfs_get_context();
1165
1166         parent = get_parent_dentry(ctx->wim, path);
1167         if (!parent)
1168                 return -ENOENT;
1169
1170         if (!dentry_is_directory(parent))
1171                 return -ENOTDIR;
1172
1173         basename = path_basename(path);
1174         if (get_dentry_child_with_name(parent, basename))
1175                 return -EEXIST;
1176
1177         newdir = new_dentry_with_inode(basename);
1178         newdir->d_inode->attributes |= FILE_ATTRIBUTE_DIRECTORY;
1179         newdir->d_inode->resolved = true;
1180         newdir->d_inode->ino = ctx->next_ino++;
1181         dentry_add_child(parent, newdir);
1182         return 0;
1183 }
1184
1185 /* Creates a regular file. */
1186 static int wimfs_mknod(const char *path, mode_t mode, dev_t rdev)
1187 {
1188         const char *stream_name;
1189         struct wimfs_context *ctx = wimfs_get_context();
1190         if ((ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
1191              && (stream_name = path_stream_name(path))) {
1192                 /* Make an alternate data stream */
1193                 struct ads_entry *new_entry;
1194                 struct inode *inode;
1195
1196                 char *p = (char*)stream_name - 1;
1197                 wimlib_assert(*p == ':');
1198                 *p = '\0';
1199
1200                 inode = wim_pathname_to_inode(ctx->wim, path);
1201                 if (!inode)
1202                         return -ENOENT;
1203                 if (!inode_is_regular_file(inode))
1204                         return -ENOENT;
1205                 if (inode_get_ads_entry(inode, stream_name, NULL))
1206                         return -EEXIST;
1207                 new_entry = inode_add_ads(inode, stream_name);
1208                 if (!new_entry)
1209                         return -ENOMEM;
1210         } else {
1211                 struct dentry *dentry, *parent;
1212                 const char *basename;
1213
1214                 /* Make a normal file (not an alternate data stream) */
1215
1216                 /* Make sure that the parent of @path exists and is a directory, and
1217                  * that the dentry named by @path does not already exist.  */
1218                 parent = get_parent_dentry(ctx->wim, path);
1219                 if (!parent)
1220                         return -ENOENT;
1221                 if (!dentry_is_directory(parent))
1222                         return -ENOTDIR;
1223
1224                 basename = path_basename(path);
1225                 if (get_dentry_child_with_name(parent, path))
1226                         return -EEXIST;
1227
1228                 dentry = new_dentry_with_inode(basename);
1229                 if (!dentry)
1230                         return -ENOMEM;
1231                 dentry->d_inode->resolved = true;
1232                 dentry->d_inode->ino = ctx->next_ino++;
1233                 dentry_add_child(parent, dentry);
1234         }
1235         return 0;
1236 }
1237
1238
1239 /* Open a file.  */
1240 static int wimfs_open(const char *path, struct fuse_file_info *fi)
1241 {
1242         struct dentry *dentry;
1243         struct lookup_table_entry *lte;
1244         int ret;
1245         struct wimlib_fd *fd;
1246         struct inode *inode;
1247         u16 stream_idx;
1248         u32 stream_id;
1249         struct wimfs_context *ctx = wimfs_get_context();
1250
1251         ret = lookup_resource(ctx->wim, path, get_lookup_flags(ctx),
1252                               &dentry, &lte, &stream_idx);
1253         if (ret != 0)
1254                 return ret;
1255
1256         inode = dentry->d_inode;
1257
1258         if (stream_idx == 0)
1259                 stream_id = 0;
1260         else
1261                 stream_id = inode->ads_entries[stream_idx - 1].stream_id;
1262
1263         /* The file resource may be in the staging directory (read-write mounts
1264          * only) or in the WIM.  If it's in the staging directory, we need to
1265          * open a native file descriptor for the corresponding file.  Otherwise,
1266          * we can read the file resource directly from the WIM file if we are
1267          * opening it read-only, but we need to extract the resource to the
1268          * staging directory if we are opening it writable. */
1269
1270         if (flags_writable(fi->flags) &&
1271             (!lte || lte->resource_location != RESOURCE_IN_STAGING_FILE)) {
1272                 u64 size = (lte) ? wim_resource_size(lte) : 0;
1273                 ret = extract_resource_to_staging_dir(inode, stream_id,
1274                                                       &lte, size, ctx);
1275                 if (ret != 0)
1276                         return ret;
1277         }
1278
1279         ret = alloc_wimlib_fd(inode, stream_id, lte, &fd,
1280                               wimfs_ctx_readonly(ctx));
1281         if (ret != 0)
1282                 return ret;
1283
1284         if (lte && lte->resource_location == RESOURCE_IN_STAGING_FILE) {
1285                 fd->staging_fd = open(lte->staging_file_name, fi->flags);
1286                 if (fd->staging_fd == -1) {
1287                         close_wimlib_fd(fd);
1288                         return -errno;
1289                 }
1290         }
1291         fi->fh = (uintptr_t)fd;
1292         return 0;
1293 }
1294
1295 /* Opens a directory. */
1296 static int wimfs_opendir(const char *path, struct fuse_file_info *fi)
1297 {
1298         struct inode *inode;
1299         int ret;
1300         struct wimlib_fd *fd = NULL;
1301         struct wimfs_context *ctx = wimfs_get_context();
1302         WIMStruct *w = ctx->wim;
1303
1304         inode = wim_pathname_to_inode(w, path);
1305         if (!inode)
1306                 return -ENOENT;
1307         if (!inode_is_directory(inode))
1308                 return -ENOTDIR;
1309         ret = alloc_wimlib_fd(inode, 0, NULL, &fd, wimfs_ctx_readonly(ctx));
1310         fi->fh = (uintptr_t)fd;
1311         return ret;
1312 }
1313
1314
1315 /*
1316  * Read data from a file in the WIM or in the staging directory.
1317  */
1318 static int wimfs_read(const char *path, char *buf, size_t size,
1319                       off_t offset, struct fuse_file_info *fi)
1320 {
1321         struct wimlib_fd *fd = (struct wimlib_fd*)(uintptr_t)fi->fh;
1322
1323         if (!fd)
1324                 return -EBADF;
1325
1326         if (!fd->f_lte) /* Empty stream with no lookup table entry */
1327                 return 0;
1328
1329         if (fd->f_lte->resource_location == RESOURCE_IN_STAGING_FILE) {
1330                 /* Read from staging file */
1331
1332                 wimlib_assert(fd->f_lte->staging_file_name);
1333                 wimlib_assert(fd->staging_fd != -1);
1334
1335                 ssize_t ret;
1336                 DEBUG("Seek to offset %zu", offset);
1337
1338                 if (lseek(fd->staging_fd, offset, SEEK_SET) == -1)
1339                         return -errno;
1340                 ret = read(fd->staging_fd, buf, size);
1341                 if (ret == -1)
1342                         return -errno;
1343                 return ret;
1344         } else {
1345                 /* Read from WIM */
1346
1347                 wimlib_assert(fd->f_lte->resource_location == RESOURCE_IN_WIM);
1348
1349                 u64 res_size = wim_resource_size(fd->f_lte);
1350
1351                 if (offset > res_size)
1352                         return -EOVERFLOW;
1353
1354                 size = min(size, res_size - offset);
1355
1356                 if (read_wim_resource(fd->f_lte, (u8*)buf,
1357                                       size, offset,
1358                                       WIMLIB_RESOURCE_FLAG_MULTITHREADED) != 0)
1359                         return -EIO;
1360                 return size;
1361         }
1362 }
1363
1364 struct fill_params {
1365         void *buf;
1366         fuse_fill_dir_t filler;
1367 };
1368
1369 static int dentry_fuse_fill(struct dentry *dentry, void *arg)
1370 {
1371         struct fill_params *fill_params = arg;
1372         return fill_params->filler(fill_params->buf, dentry->file_name_utf8,
1373                                    NULL, 0);
1374 }
1375
1376 /* Fills in the entries of the directory specified by @path using the
1377  * FUSE-provided function @filler.  */
1378 static int wimfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
1379                          off_t offset, struct fuse_file_info *fi)
1380 {
1381         struct wimlib_fd *fd = (struct wimlib_fd*)(uintptr_t)fi->fh;
1382         struct inode *inode;
1383
1384         if (!fd)
1385                 return -EBADF;
1386
1387         inode = fd->f_inode;
1388
1389         struct fill_params fill_params = {
1390                 .buf = buf,
1391                 .filler = filler,
1392         };
1393
1394         filler(buf, ".", NULL, 0);
1395         filler(buf, "..", NULL, 0);
1396
1397         return for_dentry_in_rbtree(inode->children.rb_node,
1398                                     dentry_fuse_fill, &fill_params);
1399 }
1400
1401
1402 static int wimfs_readlink(const char *path, char *buf, size_t buf_len)
1403 {
1404         struct wimfs_context *ctx = wimfs_get_context();
1405         struct inode *inode = wim_pathname_to_inode(ctx->wim, path);
1406         int ret;
1407         if (!inode)
1408                 return -ENOENT;
1409         if (!inode_is_symlink(inode))
1410                 return -EINVAL;
1411
1412         ret = inode_readlink(inode, buf, buf_len, ctx->wim,
1413                              WIMLIB_RESOURCE_FLAG_MULTITHREADED);
1414         if (ret > 0)
1415                 ret = 0;
1416         return ret;
1417 }
1418
1419 /* Close a file. */
1420 static int wimfs_release(const char *path, struct fuse_file_info *fi)
1421 {
1422         struct wimlib_fd *fd = (struct wimlib_fd*)(uintptr_t)fi->fh;
1423         return close_wimlib_fd(fd);
1424 }
1425
1426 /* Close a directory */
1427 static int wimfs_releasedir(const char *path, struct fuse_file_info *fi)
1428 {
1429         struct wimlib_fd *fd = (struct wimlib_fd*)(uintptr_t)fi->fh;
1430         return close_wimlib_fd(fd);
1431 }
1432
1433 #ifdef ENABLE_XATTR
1434 /* Remove an alternate data stream through the XATTR interface */
1435 static int wimfs_removexattr(const char *path, const char *name)
1436 {
1437         struct inode *inode;
1438         struct ads_entry *ads_entry;
1439         u16 ads_idx;
1440         struct wimfs_context *ctx = wimfs_get_context();
1441
1442         if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1443                 return -ENOTSUP;
1444
1445         if (strlen(name) < 5 || memcmp(name, "user.", 5) != 0)
1446                 return -ENOATTR;
1447         name += 5;
1448
1449         inode = wim_pathname_to_inode(ctx->wim, path);
1450         if (!inode)
1451                 return -ENOENT;
1452
1453         ads_entry = inode_get_ads_entry(inode, name, &ads_idx);
1454         if (!ads_entry)
1455                 return -ENOATTR;
1456         inode_remove_ads(inode, ads_idx, ctx->wim->lookup_table);
1457         return 0;
1458 }
1459 #endif
1460
1461 /* Renames a file or directory.  See rename (3) */
1462 static int wimfs_rename(const char *from, const char *to)
1463 {
1464         struct dentry *src;
1465         struct dentry *dst;
1466         struct dentry *parent_of_dst;
1467         char *file_name_utf16 = NULL, *file_name_utf8 = NULL;
1468         u16 file_name_utf16_len, file_name_utf8_len;
1469         WIMStruct *w = wimfs_get_WIMStruct();
1470         int ret;
1471
1472         /* This rename() implementation currently only supports actual files
1473          * (not alternate data streams) */
1474
1475         src = get_dentry(w, from);
1476         if (!src)
1477                 return -ENOENT;
1478
1479         dst = get_dentry(w, to);
1480
1481
1482         ret = get_names(&file_name_utf16, &file_name_utf8,
1483                         &file_name_utf16_len, &file_name_utf8_len,
1484                         path_basename(to));
1485         if (ret != 0)
1486                 return -ENOMEM;
1487
1488         if (dst) {
1489                 /* Destination file exists */
1490
1491                 if (src == dst) /* Same file */
1492                         return 0;
1493
1494                 if (!dentry_is_directory(src)) {
1495                         /* Cannot rename non-directory to directory. */
1496                         if (dentry_is_directory(dst))
1497                                 return -EISDIR;
1498                 } else {
1499                         /* Cannot rename directory to a non-directory or a non-empty
1500                          * directory */
1501                         if (!dentry_is_directory(dst))
1502                                 return -ENOTDIR;
1503                         if (inode_has_children(dst->d_inode))
1504                                 return -ENOTEMPTY;
1505                 }
1506                 parent_of_dst = dst->parent;
1507                 remove_dentry(dst, w->lookup_table);
1508         } else {
1509                 /* Destination does not exist */
1510                 parent_of_dst = get_parent_dentry(w, to);
1511                 if (!parent_of_dst)
1512                         return -ENOENT;
1513
1514                 if (!dentry_is_directory(parent_of_dst))
1515                         return -ENOTDIR;
1516         }
1517
1518         FREE(src->file_name);
1519         FREE(src->file_name_utf8);
1520         src->file_name          = file_name_utf16;
1521         src->file_name_utf8     = file_name_utf8;
1522         src->file_name_len      = file_name_utf16_len;
1523         src->file_name_utf8_len = file_name_utf8_len;
1524
1525         unlink_dentry(src);
1526         dentry_add_child(parent_of_dst, src);
1527         return 0;
1528 }
1529
1530 /* Remove a directory */
1531 static int wimfs_rmdir(const char *path)
1532 {
1533         struct dentry *dentry;
1534         WIMStruct *w = wimfs_get_WIMStruct();
1535
1536         dentry = get_dentry(w, path);
1537         if (!dentry)
1538                 return -ENOENT;
1539
1540         if (!dentry_is_empty_directory(dentry))
1541                 return -ENOTEMPTY;
1542
1543         remove_dentry(dentry, w->lookup_table);
1544         return 0;
1545 }
1546
1547 #ifdef ENABLE_XATTR
1548 /* Write an alternate data stream through the XATTR interface */
1549 static int wimfs_setxattr(const char *path, const char *name,
1550                           const char *value, size_t size, int flags)
1551 {
1552         struct ads_entry *existing_ads_entry;
1553         struct ads_entry *new_ads_entry;
1554         struct lookup_table_entry *existing_lte;
1555         struct lookup_table_entry *lte;
1556         struct inode *inode;
1557         u8 value_hash[SHA1_HASH_SIZE];
1558         u16 ads_idx;
1559         struct wimfs_context *ctx = wimfs_get_context();
1560
1561         if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
1562                 return -ENOTSUP;
1563
1564         if (strlen(name) < 5 || memcmp(name, "user.", 5) != 0)
1565                 return -ENOATTR;
1566         name += 5;
1567
1568         inode = wim_pathname_to_inode(ctx->wim, path);
1569         if (!inode)
1570                 return -ENOENT;
1571
1572         existing_ads_entry = inode_get_ads_entry(inode, name, &ads_idx);
1573         if (existing_ads_entry) {
1574                 if (flags & XATTR_CREATE)
1575                         return -EEXIST;
1576                 inode_remove_ads(inode, ads_idx, ctx->wim->lookup_table);
1577         } else {
1578                 if (flags & XATTR_REPLACE)
1579                         return -ENOATTR;
1580         }
1581         new_ads_entry = inode_add_ads(inode, name);
1582         if (!new_ads_entry)
1583                 return -ENOMEM;
1584
1585         sha1_buffer((const u8*)value, size, value_hash);
1586
1587         existing_lte = __lookup_resource(ctx->wim->lookup_table, value_hash);
1588
1589         if (existing_lte) {
1590                 lte = existing_lte;
1591                 lte->refcnt++;
1592         } else {
1593                 u8 *value_copy;
1594                 lte = new_lookup_table_entry();
1595                 if (!lte)
1596                         return -ENOMEM;
1597                 value_copy = MALLOC(size);
1598                 if (!value_copy) {
1599                         FREE(lte);
1600                         return -ENOMEM;
1601                 }
1602                 memcpy(value_copy, value, size);
1603                 lte->resource_location            = RESOURCE_IN_ATTACHED_BUFFER;
1604                 lte->attached_buffer              = value_copy;
1605                 lte->resource_entry.original_size = size;
1606                 lte->resource_entry.size          = size;
1607                 lte->resource_entry.flags         = 0;
1608                 copy_hash(lte->hash, value_hash);
1609                 lookup_table_insert(ctx->wim->lookup_table, lte);
1610         }
1611         new_ads_entry->lte = lte;
1612         return 0;
1613 }
1614 #endif
1615
1616 static int wimfs_symlink(const char *to, const char *from)
1617 {
1618         struct dentry *dentry_parent, *dentry;
1619         const char *link_name;
1620         struct inode *inode;
1621         struct wimfs_context *ctx = wimfs_get_context();
1622
1623         dentry_parent = get_parent_dentry(ctx->wim, from);
1624         if (!dentry_parent)
1625                 return -ENOENT;
1626         if (!dentry_is_directory(dentry_parent))
1627                 return -ENOTDIR;
1628
1629         link_name = path_basename(from);
1630
1631         if (get_dentry_child_with_name(dentry_parent, link_name))
1632                 return -EEXIST;
1633         dentry = new_dentry_with_inode(link_name);
1634         if (!dentry)
1635                 return -ENOMEM;
1636         inode = dentry->d_inode;
1637
1638         inode->attributes  = FILE_ATTRIBUTE_REPARSE_POINT;
1639         inode->reparse_tag = WIM_IO_REPARSE_TAG_SYMLINK;
1640         inode->ino         = ctx->next_ino++;
1641         inode->resolved    = true;
1642
1643         if (inode_set_symlink(inode, to, ctx->wim->lookup_table, NULL) != 0)
1644                 goto out_free_dentry;
1645
1646         dentry_add_child(dentry_parent, dentry);
1647         return 0;
1648 out_free_dentry:
1649         free_dentry(dentry);
1650         return -ENOMEM;
1651 }
1652
1653
1654 /* Reduce the size of a file */
1655 static int wimfs_truncate(const char *path, off_t size)
1656 {
1657         struct dentry *dentry;
1658         struct lookup_table_entry *lte;
1659         int ret;
1660         u16 stream_idx;
1661         u32 stream_id;
1662         struct inode *inode;
1663         struct wimfs_context *ctx = wimfs_get_context();
1664
1665         ret = lookup_resource(ctx->wim, path, get_lookup_flags(ctx),
1666                               &dentry, &lte, &stream_idx);
1667
1668         if (ret != 0)
1669                 return ret;
1670
1671         if (!lte) /* Already a zero-length file */
1672                 return 0;
1673
1674         inode = dentry->d_inode;
1675
1676         if (stream_idx == 0)
1677                 stream_id = 0;
1678         else
1679                 stream_id = inode->ads_entries[stream_idx - 1].stream_id;
1680
1681         if (lte->resource_location == RESOURCE_IN_STAGING_FILE) {
1682                 wimlib_assert(lte->staging_file_name);
1683                 ret = truncate(lte->staging_file_name, size);
1684                 if (ret != 0)
1685                         return -errno;
1686                 lte->resource_entry.original_size = size;
1687         } else {
1688                 wimlib_assert(lte->resource_location == RESOURCE_IN_WIM);
1689                 /* File in WIM.  Extract it to the staging directory, but only
1690                  * the first @size bytes of it. */
1691                 ret = extract_resource_to_staging_dir(inode, stream_id,
1692                                                       &lte, size, ctx);
1693         }
1694         return ret;
1695 }
1696
1697 /* Remove a regular file */
1698 static int wimfs_unlink(const char *path)
1699 {
1700         struct dentry *dentry;
1701         struct lookup_table_entry *lte;
1702         int ret;
1703         u16 stream_idx;
1704         struct wimfs_context *ctx = wimfs_get_context();
1705
1706         ret = lookup_resource(ctx->wim, path, get_lookup_flags(ctx),
1707                               &dentry, &lte, &stream_idx);
1708
1709         if (ret != 0)
1710                 return ret;
1711
1712         if (stream_idx == 0)
1713                 remove_dentry(dentry, ctx->wim->lookup_table);
1714         else
1715                 inode_remove_ads(dentry->d_inode, stream_idx - 1,
1716                                  ctx->wim->lookup_table);
1717         return 0;
1718 }
1719
1720 #ifdef HAVE_UTIMENSAT
1721 /*
1722  * Change the timestamp on a file dentry.
1723  *
1724  * Note that alternate data streams do not have their own timestamps.
1725  */
1726 static int wimfs_utimens(const char *path, const struct timespec tv[2])
1727 {
1728         struct dentry *dentry;
1729         struct inode *inode;
1730         WIMStruct *w = wimfs_get_WIMStruct();
1731
1732         dentry = get_dentry(w, path);
1733         if (!dentry)
1734                 return -ENOENT;
1735         inode = dentry->d_inode;
1736
1737         if (tv[0].tv_nsec != UTIME_OMIT) {
1738                 if (tv[0].tv_nsec == UTIME_NOW)
1739                         inode->last_access_time = get_wim_timestamp();
1740                 else
1741                         inode->last_access_time = timespec_to_wim_timestamp(&tv[0]);
1742         }
1743         if (tv[1].tv_nsec != UTIME_OMIT) {
1744                 if (tv[1].tv_nsec == UTIME_NOW)
1745                         inode->last_write_time = get_wim_timestamp();
1746                 else
1747                         inode->last_write_time = timespec_to_wim_timestamp(&tv[1]);
1748         }
1749         return 0;
1750 }
1751 #else
1752 static int wimfs_utime(const char *path, struct utimbuf *times)
1753 {
1754         struct dentry *dentry;
1755         struct inode *inode;
1756         WIMStruct *w = wimfs_get_WIMStruct();
1757
1758         dentry = get_dentry(w, path);
1759         if (!dentry)
1760                 return -ENOENT;
1761         inode = dentry->d_inode;
1762
1763         inode->last_write_time = unix_timestamp_to_wim(times->modtime);
1764         inode->last_access_time = unix_timestamp_to_wim(times->actime);
1765         return 0;
1766 }
1767 #endif
1768
1769 /* Writes to a file in the WIM filesystem.
1770  * It may be an alternate data stream, but here we don't even notice because we
1771  * just get a lookup table entry. */
1772 static int wimfs_write(const char *path, const char *buf, size_t size,
1773                        off_t offset, struct fuse_file_info *fi)
1774 {
1775         struct wimlib_fd *fd = (struct wimlib_fd*)(uintptr_t)fi->fh;
1776         int ret;
1777         u64 now;
1778
1779         if (!fd)
1780                 return -EBADF;
1781
1782         wimlib_assert(fd->f_lte);
1783         wimlib_assert(fd->f_lte->staging_file_name);
1784         wimlib_assert(fd->staging_fd != -1);
1785         wimlib_assert(fd->f_inode);
1786
1787         /* Seek to the requested position */
1788         if (lseek(fd->staging_fd, offset, SEEK_SET) == -1)
1789                 return -errno;
1790
1791         /* Write the data. */
1792         ret = write(fd->staging_fd, buf, size);
1793         if (ret == -1)
1794                 return -errno;
1795
1796         now = get_wim_timestamp();
1797         fd->f_inode->last_write_time = now;
1798         fd->f_inode->last_access_time = now;
1799         return ret;
1800 }
1801
1802 static struct fuse_operations wimfs_operations = {
1803         .access      = wimfs_access,
1804         .chmod       = wimfs_chmod,
1805         .destroy     = wimfs_destroy,
1806 #if 0
1807         .fallocate   = wimfs_fallocate,
1808 #endif
1809         .fgetattr    = wimfs_fgetattr,
1810         .ftruncate   = wimfs_ftruncate,
1811         .getattr     = wimfs_getattr,
1812 #ifdef ENABLE_XATTR
1813         .getxattr    = wimfs_getxattr,
1814 #endif
1815         .link        = wimfs_link,
1816 #ifdef ENABLE_XATTR
1817         .listxattr   = wimfs_listxattr,
1818 #endif
1819         .mkdir       = wimfs_mkdir,
1820         .mknod       = wimfs_mknod,
1821         .open        = wimfs_open,
1822         .opendir     = wimfs_opendir,
1823         .read        = wimfs_read,
1824         .readdir     = wimfs_readdir,
1825         .readlink    = wimfs_readlink,
1826         .release     = wimfs_release,
1827         .releasedir  = wimfs_releasedir,
1828 #ifdef ENABLE_XATTR
1829         .removexattr = wimfs_removexattr,
1830 #endif
1831         .rename      = wimfs_rename,
1832         .rmdir       = wimfs_rmdir,
1833 #ifdef ENABLE_XATTR
1834         .setxattr    = wimfs_setxattr,
1835 #endif
1836         .symlink     = wimfs_symlink,
1837         .truncate    = wimfs_truncate,
1838         .unlink      = wimfs_unlink,
1839 #ifdef HAVE_UTIMENSAT
1840         .utimens     = wimfs_utimens,
1841 #else
1842         .utime       = wimfs_utime,
1843 #endif
1844         .write       = wimfs_write,
1845
1846 #if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 8)
1847         .flag_nullpath_ok = 1,
1848 #endif
1849 #if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 9)
1850         .flag_nopath = 1,
1851         .flag_utime_omit_ok = 1,
1852 #endif
1853 };
1854
1855
1856 /* Mounts an image from a WIM file. */
1857 WIMLIBAPI int wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
1858                                  int mount_flags, WIMStruct **additional_swms,
1859                                  unsigned num_additional_swms)
1860 {
1861         int argc = 0;
1862         char *argv[16];
1863         int ret;
1864         char *dir_copy;
1865         struct lookup_table *joined_tab, *wim_tab_save;
1866         struct image_metadata *imd;
1867         struct wimfs_context ctx;
1868
1869         DEBUG("Mount: wim = %p, image = %d, dir = %s, flags = %d, ",
1870               wim, image, dir, mount_flags);
1871
1872         if (!wim || !dir)
1873                 return WIMLIB_ERR_INVALID_PARAM;
1874
1875         ret = verify_swm_set(wim, additional_swms, num_additional_swms);
1876         if (ret != 0)
1877                 return ret;
1878
1879         if ((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) && (wim->hdr.total_parts != 1)) {
1880                 ERROR("Cannot mount a split WIM read-write");
1881                 return WIMLIB_ERR_SPLIT_UNSUPPORTED;
1882         }
1883
1884         if (num_additional_swms) {
1885                 ret = new_joined_lookup_table(wim, additional_swms,
1886                                               num_additional_swms,
1887                                               &joined_tab);
1888                 if (ret != 0)
1889                         return ret;
1890                 wim_tab_save = wim->lookup_table;
1891                 wim->lookup_table = joined_tab;
1892         }
1893
1894         ret = select_wim_image(wim, image);
1895
1896         if (ret != 0)
1897                 goto out;
1898
1899         imd = &wim->image_metadata[image - 1];
1900
1901         DEBUG("Selected image %d", image);
1902
1903         if (imd->root_dentry->refcnt != 1) {
1904                 ERROR("Cannot mount image that was just exported with "
1905                       "wimlib_export_image()");
1906                 ret = WIMLIB_ERR_INVALID_PARAM;
1907                 goto out;
1908         }
1909
1910         if (imd->modified) {
1911                 ERROR("Cannot mount image that was added "
1912                       "with wimlib_add_image()");
1913                 ret = WIMLIB_ERR_INVALID_PARAM;
1914                 goto out;
1915         }
1916
1917         if (!(mount_flags & (WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
1918                        WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR |
1919                        WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)))
1920                 mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR;
1921
1922
1923         DEBUG("Initializing struct wimfs_context");
1924         init_wimfs_context(&ctx);
1925
1926         DEBUG("Getting current directory");
1927         ctx.working_directory = getcwd(NULL, 0);
1928         if (!ctx.working_directory) {
1929                 ERROR_WITH_ERRNO("Could not determine current directory");
1930                 ret = WIMLIB_ERR_NOTDIR;
1931                 goto out;
1932         }
1933
1934         DEBUG("Unlinking message queues in case they already exist");
1935         ret = set_message_queue_names(&ctx, dir);
1936         if (ret != 0)
1937                 goto out_free_working_directory;
1938         unlink_message_queues(&ctx);
1939
1940         DEBUG("Preparing arguments to fuse_main()");
1941
1942         dir_copy = STRDUP(dir);
1943         if (!dir_copy)
1944                 goto out_free_message_queue_names;
1945
1946         argv[argc++] = "imagex";
1947         argv[argc++] = dir_copy;
1948
1949         /* disable multi-threaded operation for read-write mounts */
1950         if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)
1951                 argv[argc++] = "-s";
1952
1953         if (mount_flags & WIMLIB_MOUNT_FLAG_DEBUG)
1954                 argv[argc++] = "-d";
1955
1956         /*
1957          * We provide the use_ino option because we are going to assign inode
1958          * numbers oursides.  The inodes will be given unique numbers in the
1959          * assign_inode_numbers() function, and the static variable @next_ino is
1960          * set to the next available inode number.
1961          */
1962         char optstring[256] = "use_ino,subtype=wimfs,attr_timeout=0";
1963         argv[argc++] = "-o";
1964         argv[argc++] = optstring;
1965         if ((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)) {
1966                 /* Read-write mount.  Make the staging directory */
1967                 ret = make_staging_dir(&ctx);
1968                 if (ret != 0)
1969                         goto out_free_dir_copy;
1970         } else {
1971                 /* Read-only mount */
1972                 strcat(optstring, ",ro");
1973         }
1974         argv[argc] = NULL;
1975
1976 #ifdef ENABLE_DEBUG
1977         {
1978                 int i;
1979                 DEBUG("FUSE command line (argc = %d): ", argc);
1980                 for (i = 0; i < argc; i++) {
1981                         fputs(argv[i], stdout);
1982                         putchar(' ');
1983                 }
1984                 putchar('\n');
1985                 fflush(stdout);
1986         }
1987 #endif
1988
1989         /* Mark dentry tree as modified if read-write mount. */
1990         if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
1991                 imd->modified = true;
1992                 imd->has_been_mounted_rw = true;
1993         }
1994
1995         /* Resolve all the lookup table entries of the dentry tree */
1996         DEBUG("Resolving lookup table entries");
1997         for_dentry_in_tree(imd->root_dentry, dentry_resolve_ltes,
1998                            wim->lookup_table);
1999
2000         ctx.next_ino = assign_inode_numbers(&imd->inode_list);
2001         DEBUG("(next_ino = %"PRIu64")", ctx.next_ino);
2002
2003         /* Finish initializing the filesystem context. */
2004         ctx.wim = wim;
2005         ctx.mount_flags = mount_flags;
2006
2007         DEBUG("Calling fuse_main()");
2008
2009         ret = fuse_main(argc, argv, &wimfs_operations, &ctx);
2010
2011         DEBUG("Returned from fuse_main() (ret = %d)", ret);
2012         if (ret)
2013                 ret = WIMLIB_ERR_FUSE;
2014 out_free_dir_copy:
2015         FREE(dir_copy);
2016 out_free_message_queue_names:
2017         free_message_queue_names(&ctx);
2018 out_free_working_directory:
2019         FREE(ctx.working_directory);
2020         ctx.working_directory = NULL;
2021 out:
2022         if (num_additional_swms) {
2023                 free_lookup_table(wim->lookup_table);
2024                 wim->lookup_table = wim_tab_save;
2025         }
2026         return ret;
2027 }
2028
2029
2030 /*
2031  * Unmounts the WIM file that was previously mounted on @dir by using
2032  * wimlib_mount_image().
2033  */
2034 WIMLIBAPI int wimlib_unmount_image(const char *dir, int unmount_flags)
2035 {
2036         pid_t pid;
2037         int status;
2038         int ret;
2039         char msg[2];
2040         struct timeval now;
2041         struct timespec timeout;
2042         long msgsize;
2043         struct wimfs_context ctx;
2044         char *mailbox;
2045
2046         init_wimfs_context(&ctx);
2047
2048         /* Open message queues between the unmount process and the
2049          * filesystem daemon. */
2050         ret = set_message_queue_names(&ctx, dir);
2051         if (ret != 0)
2052                 goto out;
2053
2054         ret = open_message_queues(&ctx, false);
2055         if (ret != 0)
2056                 goto out_free_message_queue_names;
2057
2058         /* Send a message to the filesystem daemon saying whether to commit or
2059          * not. */
2060         msg[0] = (unmount_flags & WIMLIB_UNMOUNT_FLAG_COMMIT) ? 1 : 0;
2061         msg[1] = (unmount_flags & WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY) ? 1 : 0;
2062
2063         DEBUG("Sending message: %scommit, %scheck",
2064                         (msg[0] ? "" : "don't "),
2065                         (msg[1] ? "" : "don't "));
2066         ret = mq_send(ctx.unmount_to_daemon_mq, msg, 2, 1);
2067         if (ret == -1) {
2068                 ERROR_WITH_ERRNO("Failed to notify filesystem daemon whether "
2069                                  "we want to commit changes or not");
2070                 ret = WIMLIB_ERR_MQUEUE;
2071                 goto out_close_message_queues;
2072         }
2073
2074         /* Execute `fusermount -u', which is installed setuid root, to unmount
2075          * the WIM.
2076          *
2077          * FUSE does not yet implement synchronous unmounts.  This means that
2078          * fusermount -u will return before the filesystem daemon returns from
2079          * wimfs_destroy().  This is partly what we want, because we need to
2080          * send a message from this process to the filesystem daemon telling
2081          * whether --commit was specified or not.  However, after that, the
2082          * unmount process must wait for the filesystem daemon to finish writing
2083          * the WIM file.
2084          */
2085
2086         pid = fork();
2087         if (pid == -1) {
2088                 ERROR_WITH_ERRNO("Failed to fork()");
2089                 ret = WIMLIB_ERR_FORK;
2090                 goto out_close_message_queues;
2091         }
2092         if (pid == 0) {
2093                 /* Child */
2094                 execlp("fusermount", "fusermount", "-u", dir, NULL);
2095                 ERROR_WITH_ERRNO("Failed to execute `fusermount'");
2096                 exit(WIMLIB_ERR_FUSERMOUNT);
2097         }
2098
2099         /* Parent */
2100         ret = wait(&status);
2101         if (ret == -1) {
2102                 ERROR_WITH_ERRNO("Failed to wait for fusermount process to "
2103                                  "terminate");
2104                 ret = WIMLIB_ERR_FUSERMOUNT;
2105                 goto out_close_message_queues;
2106         }
2107
2108         if (status != 0) {
2109                 ERROR("fusermount exited with status %d", status);
2110
2111                 /* Try again, but with the `umount' program.  This is required
2112                  * on other FUSE implementations such as FreeBSD's that do not
2113                  * have a `fusermount' program. */
2114
2115                 pid = fork();
2116                 if (pid == -1) {
2117                         ERROR_WITH_ERRNO("Failed to fork()");
2118                         ret = WIMLIB_ERR_FORK;
2119                         goto out_close_message_queues;
2120                 }
2121                 if (pid == 0) {
2122                         /* Child */
2123                         execlp("umount", "umount", dir, NULL);
2124                         ERROR_WITH_ERRNO("Failed to execute `umount'");
2125                         exit(WIMLIB_ERR_FUSERMOUNT);
2126                 }
2127
2128                 /* Parent */
2129                 ret = wait(&status);
2130                 if (ret == -1) {
2131                         ERROR_WITH_ERRNO("Failed to wait for `umount' process to "
2132                                          "terminate");
2133                         ret = WIMLIB_ERR_FUSERMOUNT;
2134                         goto out_close_message_queues;
2135                 }
2136                 if (status != 0) {
2137                         ERROR("`umount' exited with failure status");
2138                         ret = WIMLIB_ERR_FUSERMOUNT;
2139                         goto out_close_message_queues;
2140                 }
2141         }
2142
2143         wimlib_assert(status == 0);
2144
2145         /* Wait for a message from the filesytem daemon indicating whether  the
2146          * filesystem was unmounted successfully (0) or an error occurred (1).
2147          * This may take a long time if a big WIM file needs to be rewritten. */
2148
2149         /* Wait at most 600??? seconds before giving up and returning false.
2150          * Either it's a really big WIM file, or (more likely) the
2151          * filesystem daemon has crashed or failed for some reason.
2152          *
2153          * XXX come up with some method to determine if the filesystem
2154          * daemon has really crashed or not.
2155          *
2156          * XXX Idea: have mount daemon write its PID into the WIM file header?
2157          * No, this wouldn't work because we know the directory but not the WIM
2158          * file...
2159          * */
2160
2161         gettimeofday(&now, NULL);
2162         timeout.tv_sec = now.tv_sec + 600;
2163         timeout.tv_nsec = now.tv_usec * 1000;
2164
2165         ret = get_mailbox(ctx.daemon_to_unmount_mq, 2, &msgsize, &mailbox);
2166         if (ret != 0)
2167                 goto out_close_message_queues;
2168
2169         mailbox[0] = 0;
2170         DEBUG("Waiting for message telling us whether the unmount was "
2171                         "successful or not.");
2172         ret = mq_timedreceive(ctx.daemon_to_unmount_mq, mailbox,
2173                               msgsize, NULL, &timeout);
2174         if (ret == -1) {
2175                 if (errno == ETIMEDOUT) {
2176                         ERROR("Timed out- probably the filesystem daemon "
2177                               "crashed and the WIM was not written "
2178                               "successfully.");
2179                         ret = WIMLIB_ERR_TIMEOUT;
2180                 } else {
2181                         ERROR_WITH_ERRNO("mq_receive()");
2182                         ret = WIMLIB_ERR_MQUEUE;
2183                 }
2184                 goto out_free_mailbox;
2185
2186         }
2187         DEBUG("Received message: Unmount %s", (mailbox[0] ? "Failed" : "Ok"));
2188         ret = mailbox[0];
2189         if (ret)
2190                 ERROR("Unmount failed");
2191 out_free_mailbox:
2192         FREE(mailbox);
2193 out_close_message_queues:
2194         close_message_queues(&ctx);
2195 out_free_message_queue_names:
2196         free_message_queue_names(&ctx);
2197 out:
2198         return ret;
2199 }
2200
2201 #else /* WITH_FUSE */
2202
2203
2204 static inline int mount_unsupported_error()
2205 {
2206         ERROR("wimlib was compiled with --without-fuse, which disables support "
2207               "for mounting WIMs.");
2208         return WIMLIB_ERR_UNSUPPORTED;
2209 }
2210
2211 WIMLIBAPI int wimlib_unmount_image(const char *dir, int unmount_flags)
2212 {
2213         return mount_unsupported_error();
2214 }
2215
2216 WIMLIBAPI int wimlib_mount_image(WIMStruct *wim_p, int image, const char *dir,
2217                                  int mount_flags, WIMStruct **additional_swms,
2218                                  unsigned num_additional_swms)
2219 {
2220         return mount_unsupported_error();
2221 }
2222
2223 #endif /* WITH_FUSE */