]> wimlib.net Git - wimlib/blob - src/mount.c
dentry_set_symlink_buf() fix
[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 Lesser General Public License as published by the Free
17  * Software Foundation; either version 2.1 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 Lesser General Public License for more
23  * details.
24  *
25  * You should have received a copy of the GNU Lesser 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 #include "sha1.h"
33 #include "lookup_table.h"
34 #include "xml.h"
35 #include "io.h"
36 #include "timestamp.h"
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <sys/wait.h>
40 #define FUSE_USE_VERSION 26
41 #include <errno.h>
42 #include <string.h>
43 #include <sys/time.h>
44 #include <fuse.h>
45 #include <ftw.h>
46 #include <mqueue.h>
47
48 struct wimlib_fd {
49         u16 idx;
50         int staging_fd;
51         u64 hard_link_group;
52         struct lookup_table_entry *lte;
53         struct dentry *dentry;
54 };
55
56 /* The WIMStruct for the mounted WIM. */
57 static WIMStruct *w;
58
59 /* Working directory when `imagex mount' is run. */
60 static const char *working_directory;
61
62 /* Name of the staging directory for a read-write mount.  Whenever a new file is
63  * created, it is done so in the staging directory.  Furthermore, whenever a
64  * file in the WIM is modified, it is extracted to the staging directory.  If
65  * changes are commited when the WIM is unmounted, the file resources are merged
66  * in from the staging directory when writing the new WIM. */
67 static char *staging_dir_name;
68 static size_t staging_dir_name_len;
69
70 /* Flags passed to wimlib_mount(). */
71 static int mount_flags;
72
73 /* Name of the directory on which the WIM file is mounted. */
74 static const char *mount_dir;
75
76 /* Next hard link group ID to be assigned.  These are also used as the inode
77  * numbers. */
78 static u64 next_link_group_id;
79
80 /* List of lookup table entries in the staging directory */
81 static LIST_HEAD(staging_list);
82
83 static inline int get_lookup_flags()
84 {
85         if (mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
86                 return LOOKUP_FLAG_ADS_OK;
87         else
88                 return 0;
89 }
90
91 /* Returns nonzero if write permission is requested on the file open flags */
92 static inline int flags_writable(int open_flags)
93 {
94         return open_flags & (O_RDWR | O_WRONLY);
95 }
96
97 /* 
98  * Allocate a file descriptor for a lookup table entry
99  */
100 static int alloc_wimlib_fd(struct lookup_table_entry *lte,
101                            struct wimlib_fd **fd_ret)
102 {
103         static const u16 fds_per_alloc = 8;
104         static const u16 max_fds = 0xffff;
105
106         if (lte->num_opened_fds == lte->num_allocated_fds) {
107                 struct wimlib_fd **fds;
108                 u16 num_new_fds;
109
110                 if (lte->num_allocated_fds == max_fds)
111                         return -EMFILE;
112                 num_new_fds = min(fds_per_alloc, max_fds - lte->num_allocated_fds);
113                 
114                 fds = REALLOC(lte->fds, (lte->num_allocated_fds + num_new_fds) *
115                                sizeof(lte->fds[0]));
116                 if (!fds)
117                         return -ENOMEM;
118                 memset(&fds[lte->num_allocated_fds], 0,
119                        num_new_fds * sizeof(fds[0]));
120                 lte->fds = fds;
121                 lte->num_allocated_fds += num_new_fds;
122         }
123         for (u16 i = 0; ; i++) {
124                 if (!lte->fds[i]) {
125                         struct wimlib_fd *fd = CALLOC(1, sizeof(*fd));
126                         if (!fd)
127                                 return -ENOMEM;
128                         fd->staging_fd = -1;
129                         fd->idx        = i;
130                         fd->lte        = lte;
131                         lte->fds[i]    = fd;
132                         lte->num_opened_fds++;
133                         *fd_ret        = fd;
134                         return 0;
135                 }
136         }
137 }
138
139 static int close_wimlib_fd(struct wimlib_fd *fd)
140 {
141         struct lookup_table_entry *lte = fd->lte;
142
143         wimlib_assert(lte);
144         wimlib_assert(lte->num_opened_fds);
145
146         if (lte->staging_file_name) {
147                 wimlib_assert(fd->staging_fd != -1);
148                 if (close(fd->staging_fd) != 0)
149                         return -errno;
150         }
151         if (--lte->num_opened_fds == 0 && lte->refcnt == 0) {
152                 if (lte->staging_file_name)
153                         unlink(lte->staging_file_name);
154                 free_lookup_table_entry(lte);
155         }
156         wimlib_assert(lte->fds[fd->idx] == fd);
157         lte->fds[fd->idx] = NULL;
158         FREE(fd);
159         return 0;
160 }
161
162 /* Remove a dentry and all its alternate file streams */
163 static void remove_dentry(struct dentry *dentry,
164                           struct lookup_table *lookup_table)
165 {
166         wimlib_assert(dentry);
167         wimlib_assert(dentry->resolved);
168
169         struct lookup_table_entry *lte = dentry->lte;
170         u16 i = 0;
171         while (1) {
172                 lte = lte_decrement_refcnt(lte, lookup_table);
173                 if (lte && lte->num_opened_fds)
174                         for (u16 i = 0; i < lte->num_allocated_fds; i++)
175                                 if (lte->fds[i] && lte->fds[i]->dentry == dentry)
176                                         lte->fds[i]->dentry = NULL;
177                 if (i == dentry->num_ads)
178                         break;
179                 lte = dentry->ads_entries[i].lte;
180                 i++;
181         }
182
183         unlink_dentry(dentry);
184         put_dentry(dentry);
185 }
186
187 /* Transfers file attributes from a struct dentry to a `stat' buffer. */
188 int dentry_to_stbuf(const struct dentry *dentry, struct stat *stbuf)
189 {
190         struct lookup_table_entry *lte;
191
192         if (dentry_is_symlink(dentry))
193                 stbuf->st_mode = S_IFLNK | 0777;
194         else if (dentry_is_directory(dentry))
195                 stbuf->st_mode = S_IFDIR | 0755;
196         else
197                 stbuf->st_mode = S_IFREG | 0644;
198
199         stbuf->st_ino = (ino_t)dentry->hard_link;
200
201         stbuf->st_nlink = dentry_link_group_size(dentry);
202         stbuf->st_uid   = getuid();
203         stbuf->st_gid   = getgid();
204
205         /* Use the size of the unnamed (default) file stream. */
206         if ((lte = dentry_lte(dentry))) {
207                 if (lte->staging_file_name) {
208                         struct stat native_stat;
209                         if (stat(lte->staging_file_name, &native_stat) != 0)
210                                 return -errno;
211                         stbuf->st_size = native_stat.st_size;
212                 } else {
213                         stbuf->st_size = lte->resource_entry.original_size;
214                 }
215         } else {
216                 stbuf->st_size = 0;
217         }
218
219         stbuf->st_atime   = ms_timestamp_to_unix(dentry->last_access_time);
220         stbuf->st_mtime   = ms_timestamp_to_unix(dentry->last_write_time);
221         stbuf->st_ctime   = ms_timestamp_to_unix(dentry->creation_time);
222         stbuf->st_blocks  = (stbuf->st_size + 511) / 512;
223         return 0;
224 }
225
226 /* Creates a new staging file and returns its file descriptor opened for
227  * writing.
228  *
229  * @name_ret: A location into which the a pointer to the newly allocated name of
230  *                      the staging file is stored.
231  * @return:  The file descriptor for the new file.  Returns -1 and sets errno on
232  *              error, for any reason possible from the creat() function.
233  */
234 static int create_staging_file(char **name_ret, int open_flags)
235 {
236         size_t name_len;
237         char *name;
238         struct stat stbuf;
239         int fd;
240         int errno_save;
241
242         name_len = staging_dir_name_len + 1 + WIM_HASH_SIZE;
243         name = MALLOC(name_len + 1);
244         if (!name) {
245                 errno = ENOMEM;
246                 return -1;
247         }
248
249         do {
250
251                 memcpy(name, staging_dir_name, staging_dir_name_len);
252                 name[staging_dir_name_len] = '/';
253                 randomize_char_array_with_alnum(name + staging_dir_name_len + 1,
254                                                 WIM_HASH_SIZE);
255                 name[name_len] = '\0';
256
257
258         /* Just in case, verify that the randomly generated name doesn't name an
259          * existing file, and try again if so  */
260         } while (stat(name, &stbuf) == 0);
261
262         if (errno != ENOENT)
263                 /* other error! */
264                 return -1;
265
266         /* doesn't exist--- ok */
267
268         DEBUG("Creating staging file `%s'", name);
269
270         fd = open(name, open_flags | O_CREAT | O_TRUNC, 0600); 
271         if (fd == -1) {
272                 errno_save = errno;
273                 FREE(name);
274                 errno = errno_save;
275         } else {
276                 *name_ret = name;
277         }
278         return fd;
279 }
280
281 /* 
282  * Removes open file descriptors from a lookup table entry @old_lte where the
283  * file descriptors have opened the corresponding file resource in the context
284  * of the hard link group @link_group; these file descriptors are extracted and
285  * placed in a new lookup table entry, which is returned.
286  */
287 static struct lookup_table_entry *
288 lte_extract_fds(struct lookup_table_entry *old_lte, u64 link_group)
289 {
290         int ret;
291         u16 num_transferred_fds;
292         struct lookup_table_entry *new_lte;
293
294         new_lte = new_lookup_table_entry();
295         if (!new_lte)
296                 return NULL;
297
298         num_transferred_fds = 0;
299         for (u16 i = 0; i < old_lte->num_allocated_fds; i++)
300                 if (old_lte->fds[i] && old_lte->fds[i]->dentry &&
301                     old_lte->fds[i]->dentry->hard_link == link_group)
302                         num_transferred_fds++;
303         DEBUG("Transferring %u file descriptors",
304               num_transferred_fds);
305         new_lte->fds = MALLOC(num_transferred_fds * sizeof(new_lte->fds[0]));
306         if (!new_lte->fds) {
307                 FREE(new_lte);
308                 return NULL;
309         }
310         for (u16 i = 0, j = 0; ; i++) {
311                 if (old_lte->fds[i] && old_lte->fds[i]->dentry &&
312                     old_lte->fds[i]->dentry->hard_link == link_group) {
313                         struct wimlib_fd *fd = old_lte->fds[i];
314                         old_lte->fds[i] = NULL;
315                         fd->lte = new_lte;
316                         fd->idx = j;
317                         new_lte->fds[j] = fd;
318                         if (++j == num_transferred_fds)
319                                 break;
320                 }
321         }
322         DEBUG("old_lte: %u fds open; new_lte: %u fds open",
323               old_lte->num_opened_fds, new_lte->num_opened_fds);
324         old_lte->num_opened_fds -= num_transferred_fds;
325         new_lte->num_opened_fds = num_transferred_fds;
326         new_lte->num_allocated_fds = num_transferred_fds;
327         return new_lte;
328 }
329
330 /* 
331  * Transfers an alternate data stream entry to a new lookup table entry
332  */
333 static void lte_transfer_ads_entry(struct lookup_table_entry *new_lte,
334                                    struct ads_entry *ads_entry)
335 {
336         list_del(&ads_entry->lte_group_list.list);
337         list_add(&ads_entry->lte_group_list.list, &new_lte->lte_group_list);
338         ads_entry->lte = new_lte;
339 }
340
341 /* 
342  * Transfers a dentry to a new lookup table entry
343  */
344 static void lte_transfer_dentry(struct lookup_table_entry *new_lte,
345                                 struct dentry *dentry)
346 {
347         wimlib_assert(dentry->lte_group_list.list.next);
348         wimlib_assert(new_lte->lte_group_list.next);
349         list_del(&dentry->lte_group_list.list);
350         list_add(&dentry->lte_group_list.list, &new_lte->lte_group_list);
351         dentry->lte = new_lte;
352 }
353
354 static void lte_transfer_stream_entries(struct lookup_table_entry *new_lte,
355                                         struct dentry *dentry,
356                                         unsigned stream_idx)
357 {
358         INIT_LIST_HEAD(&new_lte->lte_group_list);
359         if (stream_idx == 0) {
360                 struct list_head *pos = &dentry->link_group_list;
361                 do {
362                         struct dentry *d;
363                         d = container_of(pos, struct dentry, link_group_list);
364                         wimlib_assert(d->hard_link == dentry->hard_link);
365                         lte_transfer_dentry(new_lte, d);
366                         pos = pos->next;
367                 } while (pos != &dentry->link_group_list);
368         } else {
369                 struct ads_entry *ads_entry;
370                 wimlib_assert(stream_idx <= dentry->num_ads);
371                 ads_entry = &dentry->ads_entries[stream_idx - 1];
372                 lte_transfer_ads_entry(new_lte, ads_entry);
373         }
374 }
375
376 /* 
377  * Extract a WIM resource to the staging directory.
378  *
379  * @dentry, @stream_idx:  The stream on whose behalf we are modifying the lookup
380  * table entry (these may be more streams than this that reference the lookup
381  * table entry)
382  *
383  * @lte: Pointer to pointer to the lookup table entry for the stream we need to
384  * extract, or NULL if there was no lookup table entry present for the stream
385  *
386  * @size:  Number of bytes of the stream we want to extract (this supports the
387  * wimfs_truncate() function).
388  */
389 static int extract_resource_to_staging_dir(struct dentry *dentry,
390                                            unsigned stream_idx,
391                                            struct lookup_table_entry **lte,
392                                            off_t size)
393 {
394         char *staging_file_name;
395         int ret;
396         int fd;
397         struct lookup_table_entry *old_lte, *new_lte;
398         size_t link_group_size;
399
400         /*
401          * We need to:
402          * - Create a staging file for the WIM resource
403          * - Extract the resource to it
404          * - Create a new lte for the file resource
405          * - Transfer fds from the old lte to the new lte, but only if they share the
406          *   same hard link group as this dentry.  If there is no old lte, then this
407          *   step does not need to be done
408          * - Transfer stream entries from the old lte's list to the new lte's list.  If
409          *   there is no old lte, we instead transfer entries for the hard link group.
410          *
411          *   Note: *lte is permitted to be NULL, in which case there is no old
412          *   lookup table entry.
413          */
414
415         DEBUG("Extracting resource `%s' to staging directory", dentry->full_path_utf8);
416
417         old_lte = *lte;
418         fd = create_staging_file(&staging_file_name, O_WRONLY);
419         if (fd == -1)
420                 return -errno;
421
422         if (old_lte)
423                 ret = extract_resource_to_fd(w, &old_lte->resource_entry, fd,
424                                              size);
425         else
426                 ret = 0;
427         if (ret != 0 || close(fd) != 0) {
428                 if (errno != 0)
429                         ret = -errno;
430                 else
431                         ret = -EIO;
432                 close(fd);
433                 goto out_delete_staging_file;
434         }
435
436         link_group_size = dentry_link_group_size(dentry);
437
438         if (old_lte) {
439                 if (link_group_size == old_lte->refcnt) {
440                         /* This hard link group is the only user of the lookup
441                          * table entry, so we can re-use it. */
442                         DEBUG("Re-using lookup table entry");
443                         lookup_table_unlink(w->lookup_table, old_lte);
444                         new_lte = old_lte;
445                 } else {
446                         DEBUG("Splitting lookup table entry "
447                               "(link_group_size = %u, lte refcnt = %u)",
448                               link_group_size, old_lte->refcnt);
449                         /* Split a hard link group away from the "lookup table
450                          * entry" hard link group (i.e. we had two hard link
451                          * groups that were identical, but now we are changing
452                          * one of them) */
453
454                         /* XXX 
455                          * The ADS really complicate things here and not
456                          * everything is going to work correctly yet.  For
457                          * example it could be the same that a file contains two
458                          * file streams that are identical and therefore share
459                          * the same lookup table entry despite the fact that the
460                          * streams themselves are not hardlinked. 
461                          * XXX*/
462                         wimlib_assert(old_lte->refcnt > link_group_size);
463
464                         new_lte = lte_extract_fds(old_lte, dentry->hard_link);
465                         if (!new_lte) {
466                                 ret = -ENOMEM;
467                                 goto out_delete_staging_file;
468                         }
469
470                         lte_transfer_stream_entries(new_lte, dentry, stream_idx);
471                         old_lte->refcnt -= link_group_size;
472                 } 
473         } else {
474                 /* No old_lte was supplied, so the resource had no lookup table
475                  * entry before (it must be an empty resource) */
476                 new_lte = new_lookup_table_entry();
477                 if (!new_lte) {
478                         ret = -ENOMEM;
479                         goto out_delete_staging_file;
480                 }
481                 lte_transfer_stream_entries(new_lte, dentry, stream_idx);
482         }
483         new_lte->resource_entry.original_size = size;
484         new_lte->refcnt = link_group_size;
485         randomize_byte_array(new_lte->hash, WIM_HASH_SIZE);
486         new_lte->staging_file_name = staging_file_name;
487
488         lookup_table_insert(w->lookup_table, new_lte);
489         list_add(&new_lte->staging_list, &staging_list);
490         *lte = new_lte;
491         return 0;
492 out_delete_staging_file:
493         unlink(staging_file_name);
494         FREE(staging_file_name);
495         return ret;
496 }
497
498 /* 
499  * Creates a randomly named staging directory and returns its name into the
500  * static variable staging_dir_name.
501  *
502  * If the staging directory cannot be created, staging_dir_name is set to NULL.
503  * */
504 static void make_staging_dir()
505 {
506         /* XXX Give the user an option of where to stage files */
507
508         static char prefix[] = "wimlib-staging-";
509         static const size_t prefix_len = 15;
510         static const size_t suffix_len = 10;
511
512         size_t pwd_len = strlen(working_directory);
513
514         staging_dir_name_len = pwd_len + 1 + prefix_len + suffix_len;
515
516         staging_dir_name = MALLOC(staging_dir_name_len + 1);
517         if (!staging_dir_name) {
518                 ERROR("Out of memory");
519                 return;
520         }
521
522         memcpy(staging_dir_name, working_directory, pwd_len);
523         staging_dir_name[pwd_len] = '/';
524         memcpy(staging_dir_name + pwd_len + 1, prefix, prefix_len);
525         randomize_char_array_with_alnum(staging_dir_name + pwd_len + 1 + prefix_len,
526                                 suffix_len);
527         staging_dir_name[staging_dir_name_len] = '\0';
528
529         if (mkdir(staging_dir_name, 0700) != 0) {
530                 ERROR_WITH_ERRNO("Failed to create temporary directory `%s'",
531                                  staging_dir_name);
532                 FREE(staging_dir_name);
533                 staging_dir_name = NULL;
534         }
535 }
536
537 static int remove_file_or_directory(const char *fpath, const struct stat *sb,
538                 int typeflag, struct FTW *ftwbuf)
539 {
540         if (remove(fpath) == 0)
541                 return 0;
542         else
543                 return WIMLIB_ERR_DELETE_STAGING_DIR;
544 }
545
546
547 /* 
548  * Deletes the staging directory and all the files contained in it. 
549  */
550 static inline int delete_staging_dir()
551 {
552         int ret;
553         
554         ret = nftw(staging_dir_name, remove_file_or_directory,10, FTW_DEPTH);
555         staging_dir_name = NULL;
556         return ret;
557 }
558
559 /* Name and message queue descriptors for message queues between the filesystem
560  * daemon process and the unmount process.  These are used when the filesystem
561  * is unmounted and the process running wimlib_mount() (i.e. the `imagex
562  * unmount' command) needs to communicate with the filesystem daemon running
563  * fuse_main() (i.e. that spawned by the `imagex mount' or `imagex mountrw'
564  * commands */
565 static char *unmount_to_daemon_mq_name;
566 static char *daemon_to_unmount_mq_name;
567 static int unmount_to_daemon_mq;
568 static int daemon_to_unmount_mq;
569
570 /* Simple function that returns the concatenation of 4 strings. */
571 static char *strcat_dup(const char *s1, const char *s2, const char *s3, 
572                                                         const char *s4)
573 {
574         size_t len = strlen(s1) + strlen(s2) + strlen(s3) + strlen(s4) + 1;
575         char *p = MALLOC(len);
576         if (!p)
577                 return NULL;
578         *p = '\0';
579         strcat(p, s1);
580         strcat(p, s2);
581         strcat(p, s3);
582         strcat(p, s4);
583         return p;
584 }
585
586 /* Removes trailing forward slashes in a string. */
587 static void remove_trailing_slashes(char *s)
588 {
589         long len = strlen(s);
590         for (long i = len - 1; i >= 1; i--) {
591                 if (s[i] == '/')
592                         s[i] = '\0';
593                 else
594                         break;
595         }
596 }
597
598 /* Changes forward slashes to underscores in a string. */
599 static void s_slashes_underscores_g(char *s)
600 {
601         while (*s) {
602                 if (*s == '/')
603                         *s = '_';
604                 s++;
605         }
606 }
607
608 /* 
609  * Opens two POSIX message queue: one for sending messages from the unmount
610  * process to the daemon process, and one to go the other way.  The names of the
611  * message queues, which must be system-wide unique, are be based on the mount
612  * point.  (There of course is still a possibility of a collision if one were to
613  * unmount two identically named directories simultaneously...)
614  *
615  * @daemon specifies whether the calling process is the filesystem daemon or the
616  * unmount process.
617  */
618 static int open_message_queues(bool daemon)
619 {
620         static const char *slash = "/";
621         static const char *prefix = "wimlib-";
622         static const char *u2d_suffix = "unmount-to-daemon-mq";
623         static const char *d2u_suffix = "daemon-to-unmount-mq";
624
625         const char *mount_dir_basename = path_basename(mount_dir);
626         int flags;
627         int ret;
628
629         unmount_to_daemon_mq_name = strcat_dup(slash, mount_dir_basename,
630                                                 prefix, u2d_suffix);
631         if (!unmount_to_daemon_mq_name) {
632                 ERROR("Out of memory");
633                 return WIMLIB_ERR_NOMEM;
634         }
635         daemon_to_unmount_mq_name = strcat_dup(slash, mount_dir_basename,
636                                                 prefix, d2u_suffix);
637         if (!daemon_to_unmount_mq_name) {
638                 ERROR("Out of memory");
639                 ret = WIMLIB_ERR_NOMEM;
640                 goto err1;
641         }
642
643         remove_trailing_slashes(unmount_to_daemon_mq_name);
644         remove_trailing_slashes(daemon_to_unmount_mq_name);
645         s_slashes_underscores_g(unmount_to_daemon_mq_name + 1);
646         s_slashes_underscores_g(daemon_to_unmount_mq_name + 1);
647
648         if (daemon)
649                 flags = O_RDONLY | O_CREAT;
650         else
651                 flags = O_WRONLY | O_CREAT;
652
653         unmount_to_daemon_mq = mq_open(unmount_to_daemon_mq_name, flags, 
654                                        0700, NULL);
655
656         if (unmount_to_daemon_mq == -1) {
657                 ERROR_WITH_ERRNO("mq_open()");
658                 ret = WIMLIB_ERR_MQUEUE;
659                 goto err2;
660         }
661
662         if (daemon)
663                 flags = O_WRONLY | O_CREAT;
664         else
665                 flags = O_RDONLY | O_CREAT;
666
667         daemon_to_unmount_mq = mq_open(daemon_to_unmount_mq_name, flags, 
668                                        0700, NULL);
669
670         if (daemon_to_unmount_mq == -1) {
671                 ERROR_WITH_ERRNO("mq_open()");
672                 ret = WIMLIB_ERR_MQUEUE;
673                 goto err3;
674         }
675         return 0;
676 err3:
677         mq_close(unmount_to_daemon_mq);
678         mq_unlink(unmount_to_daemon_mq_name);
679 err2:
680         FREE(daemon_to_unmount_mq_name);
681 err1:
682         FREE(unmount_to_daemon_mq_name);
683         return ret;
684 }
685
686 static int mq_get_msgsize(mqd_t mq)
687 {
688         static const char *msgsize_max_file = "/proc/sys/fs/mqueue/msgsize_max";
689         FILE *fp;
690         struct mq_attr attr;
691         int msgsize;
692
693         if (mq_getattr(unmount_to_daemon_mq, &attr) == 0) {
694                 msgsize = attr.mq_msgsize;
695         } else {
696                 ERROR_WITH_ERRNO("mq_getattr()");
697                 ERROR("Attempting to read %s", msgsize_max_file);
698                 fp = fopen(msgsize_max_file, "rb");
699                 if (fp) {
700                         if (fscanf(fp, "%d", &msgsize) != 1) {
701                                 ERROR("Assuming message size of 8192");
702                                 msgsize = 8192;
703                         }
704                         fclose(fp);
705                 } else {
706                         ERROR_WITH_ERRNO("Failed to open the file `%s'",
707                                          msgsize_max_file);
708                         ERROR("Assuming message size of 8192");
709                         msgsize = 8192;
710                 }
711         }
712         return msgsize;
713 }
714
715 /* Closes the message queues, which are allocated in static variables */
716 static void close_message_queues()
717 {
718         mq_close(unmount_to_daemon_mq);
719         mq_close(daemon_to_unmount_mq);
720         mq_unlink(unmount_to_daemon_mq_name);
721         mq_unlink(daemon_to_unmount_mq_name);
722 }
723
724 static int wimfs_access(const char *path, int mask)
725 {
726         /* XXX Permissions not implemented */
727         return 0;
728 }
729
730 /* Closes the staging file descriptor associated with the lookup table entry, if
731  * it is opened. */
732 static int close_lte_fds(struct lookup_table_entry *lte)
733 {
734         for (u16 i = 0, j = 0; j < lte->num_opened_fds; i++) {
735                 if (lte->fds[i] && lte->fds[i]->staging_fd != -1) {
736                         if (close(lte->fds[i]->staging_fd) != 0) {
737                                 ERROR_WITH_ERRNO("Failed close file `%s'",
738                                                  lte->staging_file_name);
739                                 return WIMLIB_ERR_WRITE;
740                         }
741                         j++;
742                 }
743         }
744         return 0;
745 }
746
747 static void lte_list_change_lte_ptr(struct lookup_table_entry *lte,
748                                     struct lookup_table_entry *newptr)
749 {
750         struct list_head *pos;
751         struct stream_list_head *head;
752         list_for_each(pos, &lte->lte_group_list) {
753                 head = container_of(pos, struct stream_list_head, list);
754                 if (head->type == STREAM_TYPE_ADS) {
755                         struct ads_entry *ads_entry;
756                         ads_entry = container_of(head, struct ads_entry, lte_group_list);
757
758                         ads_entry->lte = newptr;
759                 } else {
760                         wimlib_assert(head->type == STREAM_TYPE_NORMAL);
761
762                         struct dentry *dentry;
763                         dentry = container_of(head, struct dentry, lte_group_list);
764
765                         dentry->lte = newptr;
766                 }
767         }
768 }
769
770
771 static int calculate_sha1sum_of_staging_file(struct lookup_table_entry *lte,
772                                              struct lookup_table *table)
773 {
774         struct lookup_table_entry *duplicate_lte;
775         int ret;
776         u8 hash[WIM_HASH_SIZE];
777
778         ret = sha1sum(lte->staging_file_name, hash);
779         if (ret != 0)
780                 return ret;
781
782         lookup_table_unlink(table, lte);
783         memcpy(lte->hash, hash, WIM_HASH_SIZE);
784
785         duplicate_lte = __lookup_resource(table, hash);
786
787         if (duplicate_lte) {
788                 /* Merge duplicate lookup table entries */
789
790                 lte_list_change_lte_ptr(lte, duplicate_lte);
791                 duplicate_lte->refcnt += lte->refcnt;
792                 list_splice(&duplicate_lte->lte_group_list,
793                             &lte->lte_group_list);
794
795                 free_lookup_table_entry(lte);
796         } else {
797                 lookup_table_insert(table, lte);
798         }
799
800         return 0;
801 }
802
803 /* Overwrites the WIM file, with changes saved. */
804 static int rebuild_wim(WIMStruct *w, bool check_integrity)
805 {
806         int ret;
807         struct lookup_table_entry *lte, *tmp;
808
809         /* Close all the staging file descriptors. */
810         DEBUG("Closing all staging file descriptors.");
811         list_for_each_entry(lte, &staging_list, staging_list) {
812                 ret = close_lte_fds(lte);
813                 if (ret != 0)
814                         return ret;
815         }
816
817         /* Calculate SHA1 checksums for all staging files, and merge unnecessary
818          * lookup table entries. */
819         DEBUG("Calculating SHA1 checksums for all new staging files.");
820         list_for_each_entry_safe(lte, tmp, &staging_list, staging_list) {
821                 ret = calculate_sha1sum_of_staging_file(lte, w->lookup_table);
822                 if (ret != 0)
823                         return ret;
824         }
825         if (ret != 0)
826                 return ret;
827
828         xml_update_image_info(w, w->current_image);
829
830         ret = wimlib_overwrite(w, check_integrity);
831         if (ret != 0) {
832                 ERROR("Failed to commit changes");
833                 return ret;
834         }
835         return ret;
836 }
837
838 /* Called when the filesystem is unmounted. */
839 static void wimfs_destroy(void *p)
840 {
841         /* For read-write mounts, the `imagex unmount' command, which is
842          * running in a separate process and is executing the
843          * wimlib_unmount() function, will send this process a byte
844          * through a message queue that indicates whether the --commit
845          * option was specified or not. */
846
847         int msgsize;
848         struct timespec timeout;
849         struct timeval now;
850         ssize_t bytes_received;
851         int ret;
852         char commit;
853         char check_integrity;
854         char status;
855
856         ret = open_message_queues(true);
857         if (ret != 0)
858                 exit(1);
859
860         msgsize = mq_get_msgsize(unmount_to_daemon_mq);
861         char msg[msgsize];
862         msg[0] = 0;
863         msg[1] = 0;
864
865         /* Wait at most 3 seconds before giving up and discarding changes. */
866         gettimeofday(&now, NULL);
867         timeout.tv_sec = now.tv_sec + 3;
868         timeout.tv_nsec = now.tv_usec * 1000;
869         DEBUG("Waiting for message telling us whether to commit or not, and "
870               "whether to include integrity checks.");
871
872         bytes_received = mq_timedreceive(unmount_to_daemon_mq, msg, 
873                                          msgsize, NULL, &timeout);
874         commit = msg[0];
875         check_integrity = msg[1];
876         if (bytes_received == -1) {
877                 if (errno == ETIMEDOUT) {
878                         ERROR("Timed out.");
879                 } else {
880                         ERROR_WITH_ERRNO("mq_timedreceive()");
881                 }
882                 ERROR("Not committing.");
883         } else {
884                 DEBUG("Received message: [%d %d]", msg[0], msg[1]);
885         }
886
887         status = 0;
888         if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
889                 if (commit) {
890                         status = chdir(working_directory);
891                         if (status != 0) {
892                                 ERROR_WITH_ERRNO("chdir()");
893                                 status = WIMLIB_ERR_NOTDIR;
894                                 goto done;
895                         }
896                         status = rebuild_wim(w, (check_integrity != 0));
897                 }
898                 ret = delete_staging_dir();
899                 if (ret != 0) {
900                         ERROR_WITH_ERRNO("Failed to delete the staging "
901                                          "directory");
902                         if (status == 0)
903                                 status = ret;
904                 }
905         } else {
906                 DEBUG("Read-only mount");
907         }
908 done:
909         DEBUG("Sending status %u", status);
910         ret = mq_send(daemon_to_unmount_mq, &status, 1, 1);
911         if (ret == -1)
912                 ERROR_WITH_ERRNO("Failed to send status to unmount process");
913         close_message_queues();
914 }
915
916 static int wimfs_fallocate(const char *path, int mode,
917                            off_t offset, off_t len, struct fuse_file_info *fi)
918 {
919         struct wimlib_fd *fd = (struct wimlib_fd*)fi->fh;
920         wimlib_assert(fd->staging_fd != -1);
921         return fallocate(fd->staging_fd, mode, offset, len);
922 }
923
924 static int wimfs_fgetattr(const char *path, struct stat *stbuf,
925                           struct fuse_file_info *fi)
926 {
927         struct wimlib_fd *fd = (struct wimlib_fd*)fi->fh;
928         return dentry_to_stbuf(fd->dentry, stbuf);
929 }
930
931 static int wimfs_ftruncate(const char *path, off_t size,
932                            struct fuse_file_info *fi)
933 {
934         struct wimlib_fd *fd = (struct wimlib_fd*)fi->fh;
935         int ret = ftruncate(fd->staging_fd, size);
936         if (ret != 0)
937                 return ret;
938         fd->lte->resource_entry.original_size = size;
939         return 0;
940 }
941
942 /*
943  * Fills in a `struct stat' that corresponds to a file or directory in the WIM.
944  */
945 static int wimfs_getattr(const char *path, struct stat *stbuf)
946 {
947         struct dentry *dentry = get_dentry(w, path);
948         if (!dentry)
949                 return -ENOENT;
950         return dentry_to_stbuf(dentry, stbuf);
951 }
952
953 static int wimfs_getxattr(const char *path, const char *name, char *value,
954                           size_t size)
955 {
956         /* XXX */
957         return -ENOTSUP;
958 }
959
960 /* Create a hard link */
961 static int wimfs_link(const char *to, const char *from)
962 {
963         struct dentry *to_dentry, *from_dentry, *from_dentry_parent;
964         const char *link_name;
965
966         to_dentry = get_dentry(w, to);
967         if (!to_dentry)
968                 return -ENOENT;
969         if (!dentry_is_regular_file(to_dentry))
970                 return -EPERM;
971
972         from_dentry_parent = get_parent_dentry(w, from);
973         if (!from_dentry_parent)
974                 return -ENOENT;
975         if (!dentry_is_directory(from_dentry_parent))
976                 return -ENOTDIR;
977
978         link_name = path_basename(from);
979         if (get_dentry_child_with_name(from_dentry_parent, link_name))
980                 return -EEXIST;
981         from_dentry = clone_dentry(to_dentry);
982         if (!from_dentry)
983                 return -ENOMEM;
984         if (change_dentry_name(from_dentry, link_name) != 0) {
985                 FREE(from_dentry);
986                 return -ENOMEM;
987         }
988
989         /* Add the new dentry to the dentry list for the link group */
990         list_add(&from_dentry->link_group_list, &to_dentry->link_group_list);
991
992         /* Increment reference counts for the unnamed file stream and all
993          * alternate data streams. */
994         if (from_dentry->lte) {
995                 list_add(&from_dentry->lte_group_list.list,
996                          &to_dentry->lte_group_list.list);
997                 from_dentry->lte->refcnt++;
998         }
999         for (u16 i = 0; i < from_dentry->num_ads; i++) {
1000                 struct ads_entry *ads_entry = &from_dentry->ads_entries[i];
1001                 if (ads_entry->lte)
1002                         ads_entry->lte->refcnt++;
1003         }
1004
1005         /* The ADS entries are owned by another dentry. */
1006         from_dentry->ads_entries_status = ADS_ENTRIES_USER;
1007
1008         link_dentry(from_dentry, from_dentry_parent);
1009         return 0;
1010 }
1011
1012 static int wimfs_listxattr(const char *path, char *list, size_t size)
1013 {
1014         /* XXX */
1015         return -ENOTSUP;
1016 }
1017
1018 /* 
1019  * Create a directory in the WIM.  
1020  * @mode is currently ignored.
1021  */
1022 static int wimfs_mkdir(const char *path, mode_t mode)
1023 {
1024         struct dentry *parent;
1025         struct dentry *newdir;
1026         const char *basename;
1027         
1028         parent = get_parent_dentry(w, path);
1029         if (!parent)
1030                 return -ENOENT;
1031
1032         if (!dentry_is_directory(parent))
1033                 return -ENOTDIR;
1034
1035         basename = path_basename(path);
1036         if (get_dentry_child_with_name(parent, basename))
1037                 return -EEXIST;
1038
1039         newdir = new_dentry(basename);
1040         newdir->attributes |= FILE_ATTRIBUTE_DIRECTORY;
1041         newdir->resolved = true;
1042         newdir->hard_link = next_link_group_id++;
1043         link_dentry(newdir, parent);
1044         return 0;
1045 }
1046
1047
1048 /* Creates a regular file. */
1049 static int wimfs_mknod(const char *path, mode_t mode, dev_t rdev)
1050 {
1051         const char *stream_name;
1052         if ((mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
1053              && (stream_name = path_stream_name(path))) {
1054                 /* Make an alternate data stream */
1055                 struct ads_entry *new_entry;
1056                 struct dentry *dentry;
1057
1058                 dentry = get_dentry(w, path);
1059                 if (!dentry || !dentry_is_regular_file(dentry))
1060                         return -ENOENT;
1061                 if (dentry_get_ads_entry(dentry, stream_name))
1062                         return -EEXIST;
1063                 new_entry = dentry_add_ads(dentry, stream_name);
1064                 if (!new_entry)
1065                         return -ENOENT;
1066         } else {
1067                 struct dentry *dentry, *parent;
1068                 const char *basename;
1069
1070                 /* Make a normal file (not an alternate data stream) */
1071
1072                 /* Make sure that the parent of @path exists and is a directory, and
1073                  * that the dentry named by @path does not already exist.  */
1074                 parent = get_parent_dentry(w, path);
1075                 if (!parent)
1076                         return -ENOENT;
1077                 if (!dentry_is_directory(parent))
1078                         return -ENOTDIR;
1079
1080                 basename = path_basename(path);
1081                 if (get_dentry_child_with_name(parent, path))
1082                         return -EEXIST;
1083
1084                 dentry = new_dentry(basename);
1085                 if (!dentry)
1086                         return -ENOMEM;
1087                 dentry->resolved = true;
1088                 dentry->hard_link = next_link_group_id++;
1089                 dentry->lte_group_list.type = STREAM_TYPE_NORMAL;
1090                 INIT_LIST_HEAD(&dentry->lte_group_list.list);
1091                 link_dentry(dentry, parent);
1092         }
1093         return 0;
1094 }
1095
1096
1097 /* Open a file.  */
1098 static int wimfs_open(const char *path, struct fuse_file_info *fi)
1099 {
1100         struct dentry *dentry;
1101         struct lookup_table_entry *lte;
1102         u8 *dentry_hash;
1103         int ret;
1104         struct wimlib_fd *fd;
1105         unsigned stream_idx;
1106
1107         ret = lookup_resource(w, path, get_lookup_flags(), &dentry, &lte,
1108                               &stream_idx);
1109         if (ret != 0)
1110                 return ret;
1111
1112         if (!lte) {
1113                 /* Empty file with no lookup-table entry.  This is fine if it's
1114                  * a read-only filesystem.  Otherwise we need to create a lookup
1115                  * table entry so that we can keep track of the file descriptors
1116                  * (this is important in case someone opens the file for
1117                  * writing) */
1118                 if (!(mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)) {
1119                         fi->fh = 0;
1120                         return 0;
1121                 }
1122
1123                 ret = extract_resource_to_staging_dir(dentry, stream_idx,
1124                                                       &lte, 0);
1125                 if (ret != 0)
1126                         return ret;
1127         }
1128
1129         ret = alloc_wimlib_fd(lte, &fd);
1130         if (ret != 0)
1131                 return ret;
1132
1133         fd->dentry = dentry;
1134
1135         /* The file resource may be in the staging directory (read-write
1136          * mounts only) or in the WIM.  If it's in the staging
1137          * directory, we need to open a native file descriptor for the
1138          * corresponding file.  Otherwise, we can read the file resource
1139          * directly from the WIM file if we are opening it read-only,
1140          * but we need to extract the resource to the staging directory
1141          * if we are opening it writable. */
1142         if (flags_writable(fi->flags) && !lte->staging_file_name) {
1143                 ret = extract_resource_to_staging_dir(dentry, stream_idx, &lte,
1144                                                       lte->resource_entry.original_size);
1145                 if (ret != 0)
1146                         return ret;
1147         }
1148         if (lte->staging_file_name) {
1149                 fd->staging_fd = open(lte->staging_file_name, fi->flags);
1150                 if (fd->staging_fd == -1) {
1151                         close_wimlib_fd(fd);
1152                         return -errno;
1153                 }
1154         }
1155         fi->fh = (uint64_t)fd;
1156         return 0;
1157 }
1158
1159 /* Opens a directory. */
1160 static int wimfs_opendir(const char *path, struct fuse_file_info *fi)
1161 {
1162         struct dentry *dentry;
1163         
1164         dentry = get_dentry(w, path);
1165         if (!dentry)
1166                 return -ENOENT;
1167         if (!dentry_is_directory(dentry))
1168                 return -ENOTDIR;
1169         dentry->num_times_opened++;
1170         fi->fh = (uint64_t)dentry;
1171         return 0;
1172 }
1173
1174
1175 /*
1176  * Read data from a file in the WIM or in the staging directory. 
1177  */
1178 static int wimfs_read(const char *path, char *buf, size_t size, 
1179                       off_t offset, struct fuse_file_info *fi)
1180 {
1181         struct wimlib_fd *fd = (struct wimlib_fd*)fi->fh;
1182
1183         if (!fd) {
1184                 /* Empty file with no lookup table entry on read-only mounted
1185                  * WIM */
1186                 wimlib_assert(!(mount_flags & WIMLIB_MOUNT_FLAG_READWRITE));
1187                 return 0;
1188         }
1189
1190         wimlib_assert(fd->lte);
1191
1192         if (fd->lte->staging_file_name) {
1193                 /* Read from staging file */
1194
1195                 wimlib_assert(fd->staging_fd != -1);
1196
1197                 ssize_t ret;
1198                 DEBUG("Seek to offset %zu", offset);
1199
1200                 if (lseek(fd->staging_fd, offset, SEEK_SET) == -1)
1201                         return -errno;
1202                 ret = read(fd->staging_fd, buf, size);
1203                 if (ret == -1)
1204                         return -errno;
1205                 return ret;
1206         } else {
1207                 /* Read from WIM */
1208
1209                 struct resource_entry *res_entry;
1210                 int ctype;
1211                 
1212                 res_entry = &fd->lte->resource_entry;
1213
1214                 ctype = wim_resource_compression_type(w, res_entry);
1215
1216                 if (offset > res_entry->original_size)
1217                         return -EOVERFLOW;
1218
1219                 size = min(size, res_entry->original_size - offset);
1220
1221                 if (read_resource(w->fp, res_entry->size, 
1222                                   res_entry->original_size,
1223                                   res_entry->offset, ctype, size, 
1224                                   offset, buf) != 0)
1225                         return -EIO;
1226                 return size;
1227         }
1228 }
1229
1230 /* Fills in the entries of the directory specified by @path using the
1231  * FUSE-provided function @filler.  */
1232 static int wimfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, 
1233                          off_t offset, struct fuse_file_info *fi)
1234 {
1235         struct dentry *parent, *child;
1236         
1237         parent = (struct dentry*)fi->fh;
1238         wimlib_assert(parent);
1239         child = parent->children;
1240
1241         filler(buf, ".", NULL, 0);
1242         filler(buf, "..", NULL, 0);
1243
1244         if (!child)
1245                 return 0;
1246
1247         do {
1248                 if (filler(buf, child->file_name_utf8, NULL, 0))
1249                         return 0;
1250                 child = child->next;
1251         } while (child != parent->children);
1252         return 0;
1253 }
1254
1255
1256 static int wimfs_readlink(const char *path, char *buf, size_t buf_len)
1257 {
1258         struct dentry *dentry = get_dentry(w, path);
1259         int ret;
1260         if (!dentry)
1261                 return -ENOENT;
1262         if (!dentry_is_symlink(dentry))
1263                 return -EINVAL;
1264
1265         ret = dentry_readlink(dentry, buf, buf_len, w);
1266         if (ret > 0)
1267                 ret = 0;
1268         return ret;
1269 }
1270
1271 /* Close a file. */
1272 static int wimfs_release(const char *path, struct fuse_file_info *fi)
1273 {
1274         int ret;
1275         struct wimlib_fd *fd = (struct wimlib_fd*)fi->fh;
1276
1277         if (!fd) {
1278                 /* Empty file with no lookup table entry on read-only mounted
1279                  * WIM */
1280                 wimlib_assert(!(mount_flags & WIMLIB_MOUNT_FLAG_READWRITE));
1281                 return 0;
1282         }
1283
1284         if (flags_writable(fi->flags) && fd->dentry) {
1285                 u64 now = get_timestamp();
1286                 fd->dentry->last_access_time = now;
1287                 fd->dentry->last_write_time = now;
1288         }
1289
1290         return close_wimlib_fd(fd);
1291 }
1292
1293 static int wimfs_releasedir(const char *path, struct fuse_file_info *fi)
1294 {
1295         struct dentry *dentry = (struct dentry *)fi->fh;
1296
1297         wimlib_assert(dentry);
1298         wimlib_assert(dentry->num_times_opened);
1299         if (--dentry->num_times_opened == 0)
1300                 free_dentry(dentry);
1301         return 0;
1302 }
1303
1304 static int wimfs_removexattr(const char *path, const char *name)
1305 {
1306         /* XXX */
1307         return -ENOTSUP;
1308 }
1309
1310 /* Renames a file or directory.  See rename (3) */
1311 static int wimfs_rename(const char *from, const char *to)
1312 {
1313         struct dentry *src;
1314         struct dentry *dst;
1315         struct dentry *parent_of_dst;
1316         char *file_name_utf16 = NULL, *file_name_utf8 = NULL;
1317         u16 file_name_utf16_len, file_name_utf8_len;
1318         int ret;
1319
1320         /* This rename() implementation currently only supports actual files
1321          * (not alternate data streams) */
1322         
1323         src = get_dentry(w, from);
1324         if (!src)
1325                 return -ENOENT;
1326
1327         dst = get_dentry(w, to);
1328
1329
1330         ret = get_names(&file_name_utf16, &file_name_utf8,
1331                         &file_name_utf16_len, &file_name_utf8_len,
1332                         path_basename(to));
1333         if (ret != 0)
1334                 return -ENOMEM;
1335
1336         if (dst) {
1337                 /* Destination file exists */
1338
1339                 if (src == dst) /* Same file */
1340                         return 0;
1341
1342                 if (!dentry_is_directory(src)) {
1343                         /* Cannot rename non-directory to directory. */
1344                         if (dentry_is_directory(dst))
1345                                 return -EISDIR;
1346                 } else {
1347                         /* Cannot rename directory to a non-directory or a non-empty
1348                          * directory */
1349                         if (!dentry_is_directory(dst))
1350                                 return -ENOTDIR;
1351                         if (dst->children != NULL)
1352                                 return -ENOTEMPTY;
1353                 }
1354                 parent_of_dst = dst->parent;
1355                 remove_dentry(dst, w->lookup_table);
1356         } else {
1357                 /* Destination does not exist */
1358                 parent_of_dst = get_parent_dentry(w, to);
1359                 if (!parent_of_dst)
1360                         return -ENOENT;
1361
1362                 if (!dentry_is_directory(parent_of_dst))
1363                         return -ENOTDIR;
1364         }
1365
1366         FREE(src->file_name);
1367         FREE(src->file_name_utf8);
1368         src->file_name          = file_name_utf16;
1369         src->file_name_utf8     = file_name_utf8;
1370         src->file_name_len      = file_name_utf16_len;
1371         src->file_name_utf8_len = file_name_utf8_len;
1372
1373         unlink_dentry(src);
1374         link_dentry(src, parent_of_dst);
1375         return 0;
1376 }
1377
1378 /* Remove a directory */
1379 static int wimfs_rmdir(const char *path)
1380 {
1381         struct dentry *dentry;
1382         
1383         dentry = get_dentry(w, path);
1384         if (!dentry)
1385                 return -ENOENT;
1386
1387         if (!dentry_is_empty_directory(dentry))
1388                 return -ENOTEMPTY;
1389
1390         unlink_dentry(dentry);
1391         if (dentry->num_times_opened == 0)
1392                 free_dentry(dentry);
1393         return 0;
1394 }
1395
1396 static int wimfs_setxattr(const char *path, const char *name,
1397                           const char *value, size_t size, int flags)
1398 {
1399         /* XXX */
1400         return -ENOTSUP;
1401 }
1402
1403 static int wimfs_symlink(const char *to, const char *from)
1404 {
1405         struct dentry *dentry_parent, *dentry;
1406         const char *link_name;
1407         struct lookup_table_entry *lte;
1408         
1409         dentry_parent = get_parent_dentry(w, from);
1410         if (!dentry_parent)
1411                 return -ENOENT;
1412         if (!dentry_is_directory(dentry_parent))
1413                 return -ENOTDIR;
1414
1415         link_name = path_basename(from);
1416
1417         if (get_dentry_child_with_name(dentry_parent, link_name))
1418                 return -EEXIST;
1419         dentry = new_dentry(link_name);
1420         if (!dentry)
1421                 return -ENOMEM;
1422
1423         dentry->attributes = FILE_ATTRIBUTE_REPARSE_POINT;
1424         dentry->reparse_tag = WIM_IO_REPARSE_TAG_SYMLINK;
1425
1426         if (dentry_set_symlink(dentry, to, w->lookup_table, &lte) != 0)
1427                 goto out_free_dentry;
1428
1429         wimlib_assert(lte);
1430
1431         dentry->ads_entries[1].lte_group_list.type = STREAM_TYPE_ADS;
1432         list_add(&dentry->ads_entries[1].lte_group_list.list,
1433                  &lte->lte_group_list);
1434         dentry->ads_entries[1].lte = lte;
1435         dentry->resolved = true;
1436
1437         link_dentry(dentry, dentry_parent);
1438         return 0;
1439 out_free_dentry:
1440         free_dentry(dentry);
1441         return -ENOMEM;
1442 }
1443
1444
1445 /* Reduce the size of a file */
1446 static int wimfs_truncate(const char *path, off_t size)
1447 {
1448         struct dentry *dentry;
1449         struct lookup_table_entry *lte;
1450         int ret;
1451         unsigned stream_idx;
1452         
1453         ret = lookup_resource(w, path, get_lookup_flags(), &dentry,
1454                               &lte, &stream_idx);
1455
1456         if (ret != 0)
1457                 return ret;
1458
1459         if (!lte) /* Already a zero-length file */
1460                 return 0;
1461
1462         if (lte->staging_file_name) {
1463                 ret = truncate(lte->staging_file_name, size);
1464                 if (ret != 0)
1465                         return -errno;
1466                 lte->resource_entry.original_size = size;
1467         } else {
1468                 /* File in WIM.  Extract it to the staging directory, but only
1469                  * the first @size bytes of it. */
1470                 ret = extract_resource_to_staging_dir(dentry, stream_idx,
1471                                                       &lte, size);
1472         }
1473         dentry_update_all_timestamps(dentry);
1474         return ret;
1475 }
1476
1477 /* Remove a regular file */
1478 static int wimfs_unlink(const char *path)
1479 {
1480         struct dentry *dentry;
1481         struct lookup_table_entry *lte;
1482         int ret;
1483         u8 *dentry_hash;
1484         unsigned stream_idx;
1485         
1486         ret = lookup_resource(w, path, get_lookup_flags(), &dentry,
1487                               &lte, &stream_idx);
1488
1489         if (ret != 0)
1490                 return ret;
1491
1492         if (stream_idx == 0) {
1493                 /* We are removing the full dentry including all alternate data
1494                  * streams. */
1495                 remove_dentry(dentry, w->lookup_table);
1496         } else {
1497                 /* We are removing an alternate data stream. */
1498                 struct ads_entry *ads_entry;
1499                 
1500                 ads_entry = &dentry->ads_entries[stream_idx - 1];
1501                 lte = lte_decrement_refcnt(lte, w->lookup_table);
1502                 if (lte)
1503                         list_del(&ads_entry->lte_group_list.list);
1504                 dentry_remove_ads(dentry, ads_entry);
1505         }
1506         /* Beware: The lookup table entry(s) may still be referenced by users
1507          * that have opened the corresponding streams.  They are freed later in
1508          * wimfs_release() when the last file user has closed the stream. */
1509         return 0;
1510 }
1511
1512 /* Change the timestamp on a file dentry. 
1513  *
1514  * There is no distinction between a file and its alternate data streams here.  */
1515 static int wimfs_utimens(const char *path, const struct timespec tv[2])
1516 {
1517         struct dentry *dentry = get_dentry(w, path);
1518         if (!dentry)
1519                 return -ENOENT;
1520         time_t last_access_t = (tv[0].tv_nsec == UTIME_NOW) ? 
1521                                 time(NULL) : tv[0].tv_sec;
1522         dentry->last_access_time = unix_timestamp_to_ms(last_access_t);
1523         time_t last_mod_t = (tv[1].tv_nsec == UTIME_NOW) ?  
1524                                 time(NULL) : tv[1].tv_sec;
1525         dentry->last_write_time = unix_timestamp_to_ms(last_mod_t);
1526         return 0;
1527 }
1528
1529 /* Writes to a file in the WIM filesystem. 
1530  * It may be an alternate data stream, but here we don't even notice because we
1531  * just get a lookup table entry. */
1532 static int wimfs_write(const char *path, const char *buf, size_t size, 
1533                        off_t offset, struct fuse_file_info *fi)
1534 {
1535         struct wimlib_fd *fd = (struct wimlib_fd*)fi->fh;
1536         int ret;
1537
1538         wimlib_assert(fd);
1539         wimlib_assert(fd->lte);
1540         wimlib_assert(fd->lte->staging_file_name);
1541         wimlib_assert(fd->staging_fd != -1);
1542
1543         /* Seek to the requested position */
1544         if (lseek(fd->staging_fd, offset, SEEK_SET) == -1)
1545                 return -errno;
1546
1547         /* Write the data. */
1548         ret = write(fd->staging_fd, buf, size);
1549         if (ret == -1)
1550                 return -errno;
1551
1552         return ret;
1553 }
1554
1555 static struct fuse_operations wimfs_operations = {
1556         .access      = wimfs_access,
1557         .destroy     = wimfs_destroy,
1558         .fallocate   = wimfs_fallocate,
1559         .fgetattr    = wimfs_fgetattr,
1560         .ftruncate   = wimfs_ftruncate,
1561         .getattr     = wimfs_getattr,
1562         .getxattr    = wimfs_getxattr,
1563         .link        = wimfs_link,
1564         .listxattr   = wimfs_listxattr,
1565         .mkdir       = wimfs_mkdir,
1566         .mknod       = wimfs_mknod,
1567         .open        = wimfs_open,
1568         .opendir     = wimfs_opendir,
1569         .read        = wimfs_read,
1570         .readdir     = wimfs_readdir,
1571         .readlink    = wimfs_readlink,
1572         .release     = wimfs_release,
1573         .releasedir  = wimfs_releasedir,
1574         .removexattr = wimfs_removexattr,
1575         .rename      = wimfs_rename,
1576         .rmdir       = wimfs_rmdir,
1577         .setxattr    = wimfs_setxattr,
1578         .symlink     = wimfs_symlink,
1579         .truncate    = wimfs_truncate,
1580         .unlink      = wimfs_unlink,
1581         .utimens     = wimfs_utimens,
1582         .write       = wimfs_write,
1583 };
1584
1585
1586 /* Mounts a WIM file. */
1587 WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir, 
1588                            int flags)
1589 {
1590         int argc = 0;
1591         char *argv[16];
1592         int ret;
1593         char *p;
1594
1595         DEBUG("Mount: wim = %p, image = %d, dir = %s, flags = %d, ",
1596                         wim, image, dir, flags);
1597
1598         if (!dir)
1599                 return WIMLIB_ERR_INVALID_PARAM;
1600
1601         ret = wimlib_select_image(wim, image);
1602
1603         if (ret != 0)
1604                 return ret;
1605
1606         DEBUG("Selected image %d", image);
1607
1608         next_link_group_id = assign_link_groups(wim->image_metadata[image - 1].lgt);
1609
1610         /* Resolve all the lookup table entries of the dentry tree */
1611         for_dentry_in_tree(wim_root_dentry(wim), dentry_resolve_ltes,
1612                            wim->lookup_table);
1613
1614         if (flags & WIMLIB_MOUNT_FLAG_READWRITE)
1615                 wim_get_current_image_metadata(wim)->modified = true;
1616
1617         if (!(flags & (WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
1618                        WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR |
1619                        WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)))
1620                 flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR;
1621
1622         mount_dir = dir;
1623         working_directory = getcwd(NULL, 0);
1624         if (!working_directory) {
1625                 ERROR_WITH_ERRNO("Could not determine current directory");
1626                 return WIMLIB_ERR_NOTDIR;
1627         }
1628
1629         p = STRDUP(dir);
1630         if (!p)
1631                 return WIMLIB_ERR_NOMEM;
1632
1633         argv[argc++] = "mount";
1634         argv[argc++] = p;
1635         argv[argc++] = "-s"; /* disable multi-threaded operation */
1636
1637         if (flags & WIMLIB_MOUNT_FLAG_DEBUG)
1638                 argv[argc++] = "-d";
1639
1640         /* 
1641          * We provide the use_ino option because we are going to assign inode
1642          * numbers oursides.  We've already numbered the hard link groups with
1643          * unique numbers with the assign_link_groups() function, and the static
1644          * variable next_link_group_id is set to the next available link group
1645          * ID that we will assign to new dentries.
1646          */
1647         char optstring[256] = "use_ino";
1648         argv[argc++] = "-o";
1649         argv[argc++] = optstring;
1650         if ((flags & WIMLIB_MOUNT_FLAG_READWRITE)) {
1651                 /* Read-write mount.  Make the staging directory */
1652                 make_staging_dir();
1653                 if (!staging_dir_name) {
1654                         FREE(p);
1655                         return WIMLIB_ERR_MKDIR;
1656                 }
1657         } else {
1658                 /* Read-only mount */
1659                 strcat(optstring, ",ro");
1660         }
1661         argv[argc] = NULL;
1662
1663 #ifdef ENABLE_DEBUG
1664         {
1665                 int i;
1666                 DEBUG("FUSE command line (argc = %d): ", argc);
1667                 for (i = 0; i < argc; i++) {
1668                         fputs(argv[i], stdout);
1669                         putchar(' ');
1670                 }
1671                 putchar('\n');
1672                 fflush(stdout);
1673         }
1674 #endif
1675
1676         /* Set static variables. */
1677         w = wim;
1678         mount_flags = flags;
1679
1680         ret = fuse_main(argc, argv, &wimfs_operations, NULL);
1681
1682         return (ret == 0) ? 0 : WIMLIB_ERR_FUSE;
1683 }
1684
1685
1686 /* 
1687  * Unmounts the WIM file that was previously mounted on @dir by using
1688  * wimlib_mount().
1689  */
1690 WIMLIBAPI int wimlib_unmount(const char *dir, int flags)
1691 {
1692         pid_t pid;
1693         int status;
1694         int ret;
1695         char msg[2];
1696         struct timeval now;
1697         struct timespec timeout;
1698         int msgsize;
1699         int errno_save;
1700
1701         /* Execute `fusermount -u', which is installed setuid root, to unmount
1702          * the WIM.
1703          *
1704          * FUSE does not yet implement synchronous unmounts.  This means that
1705          * fusermount -u will return before the filesystem daemon returns from
1706          * wimfs_destroy().  This is partly what we want, because we need to
1707          * send a message from this process to the filesystem daemon telling
1708          * whether --commit was specified or not.  However, after that, the
1709          * unmount process must wait for the filesystem daemon to finish writing
1710          * the WIM file. 
1711          */
1712
1713         mount_dir = dir;
1714         pid = fork();
1715         if (pid == -1) {
1716                 ERROR_WITH_ERRNO("Failed to fork()");
1717                 return WIMLIB_ERR_FORK;
1718         }
1719         if (pid == 0) {
1720                 execlp("fusermount", "fusermount", "-u", dir, NULL);
1721                 ERROR_WITH_ERRNO("Failed to execute `fusermount'");
1722                 return WIMLIB_ERR_FUSERMOUNT;
1723         }
1724
1725         ret = waitpid(pid, &status, 0);
1726         if (ret == -1) {
1727                 ERROR_WITH_ERRNO("Failed to wait for fusermount process to "
1728                                  "terminate");
1729                 return WIMLIB_ERR_FUSERMOUNT;
1730         }
1731
1732         if (status != 0) {
1733                 ERROR("fusermount exited with status %d", status);
1734                 return WIMLIB_ERR_FUSERMOUNT;
1735         }
1736
1737         /* Open message queues between the unmount process and the
1738          * filesystem daemon. */
1739         ret = open_message_queues(false);
1740         if (ret != 0)
1741                 return ret;
1742
1743         /* Send a message to the filesystem saying whether to commit or
1744          * not. */
1745         msg[0] = (flags & WIMLIB_UNMOUNT_FLAG_COMMIT) ? 1 : 0;
1746         msg[1] = (flags & WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY) ? 1 : 0;
1747
1748         DEBUG("Sending message: %s, %s", 
1749                         (msg[0] == 0) ? "don't commit" : "commit",
1750                         (msg[1] == 0) ? "don't check"  : "check");
1751         ret = mq_send(unmount_to_daemon_mq, msg, 2, 1);
1752         if (ret == -1) {
1753                 ERROR("Failed to notify filesystem daemon whether we want to "
1754                       "commit changes or not");
1755                 close_message_queues();
1756                 return WIMLIB_ERR_MQUEUE;
1757         }
1758
1759         /* Wait for a message from the filesytem daemon indicating whether  the
1760          * filesystem was unmounted successfully (0) or an error occurred (1).
1761          * This may take a long time if a big WIM file needs to be rewritten. */
1762
1763         /* Wait at most 600??? seconds before giving up and returning false.
1764          * Either it's a really big WIM file, or (more likely) the
1765          * filesystem daemon has crashed or failed for some reason.
1766          *
1767          * XXX come up with some method to determine if the filesystem
1768          * daemon has really crashed or not. */
1769
1770         gettimeofday(&now, NULL);
1771         timeout.tv_sec = now.tv_sec + 600;
1772         timeout.tv_nsec = now.tv_usec * 1000;
1773
1774         msgsize = mq_get_msgsize(daemon_to_unmount_mq);
1775         char mailbox[msgsize];
1776
1777         mailbox[0] = 0;
1778         DEBUG("Waiting for message telling us whether the unmount was "
1779                         "successful or not.");
1780         ret = mq_timedreceive(daemon_to_unmount_mq, mailbox, msgsize,
1781                               NULL, &timeout);
1782         errno_save = errno;
1783         close_message_queues();
1784         if (ret == -1) {
1785                 if (errno_save == ETIMEDOUT) {
1786                         ERROR("Timed out- probably the filesystem daemon "
1787                               "crashed and the WIM was not written "
1788                               "successfully.");
1789                         return WIMLIB_ERR_TIMEOUT;
1790                 } else {
1791                         ERROR("mq_receive(): %s", strerror(errno_save));
1792                         return WIMLIB_ERR_MQUEUE;
1793                 }
1794
1795         }
1796         DEBUG("Received message: %s",
1797               (mailbox[0] == 0) ?  "Unmount OK" : "Unmount Failed");
1798         if (mailbox[0] != 0)
1799                 ERROR("Unmount failed");
1800         return mailbox[0];
1801 }
1802
1803 #else /* WITH_FUSE */
1804
1805
1806 static inline int mount_unsupported_error()
1807 {
1808         ERROR("WIMLIB was compiled with --without-fuse, which disables support "
1809               "for mounting WIMs.");
1810         return WIMLIB_ERR_UNSUPPORTED;
1811 }
1812
1813 WIMLIBAPI int wimlib_unmount(const char *dir, int flags)
1814 {
1815         return mount_unsupported_error();
1816 }
1817
1818 WIMLIBAPI int wimlib_mount(WIMStruct *wim_p, int image, const char *dir, 
1819                            int flags)
1820 {
1821         return mount_unsupported_error();
1822 }
1823
1824 #endif /* WITH_FUSE */