child-delete: Reply as usual when concurrently rekeying the IKE_SA
[strongswan.git] / src / dumm / cowfs.c
1 /*
2 * Copyright (C) 2009 Tobias Brunner
3 * Copyright (C) 2007 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 * Copyright (C) 2001-2007 Miklos Szeredi
6 *
7 * Based on example shipped with FUSE.
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 * for more details.
18 */
19
20
21 #define FUSE_USE_VERSION 26
22 #define _GNU_SOURCE
23
24 #include <fuse.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <dirent.h>
31 #include <errno.h>
32 #include <sys/time.h>
33
34 #include "cowfs.h"
35
36 #include <library.h>
37 #include <utils/debug.h>
38 #include <threading/thread.h>
39 #include <threading/rwlock.h>
40 #include <collections/linked_list.h>
41
42 /** define _XOPEN_SOURCE 500 fails when using libstrongswan, define popen */
43 extern ssize_t pread(int fd, void *buf, size_t count, off_t offset);
44 extern ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
45
46 typedef struct private_cowfs_t private_cowfs_t;
47
48 struct private_cowfs_t {
49 /** public cowfs interface */
50 cowfs_t public;
51 /** fuse channel to mountpoint */
52 struct fuse_chan *chan;
53 /** fuse handle */
54 struct fuse *fuse;
55 /** mountpoint of cowfs FUSE */
56 char *mount;
57 /** master filesystem path */
58 char *master;
59 /** host filesystem path */
60 char *host;
61 /** overlay filesystems */
62 linked_list_t *overlays;
63 /** lock for overlays */
64 rwlock_t *lock;
65 /** fd of read only master filesystem */
66 int master_fd;
67 /** copy on write overlay to master */
68 int host_fd;
69 /** thread processing FUSE */
70 thread_t *thread;
71 };
72
73 typedef struct overlay_t overlay_t;
74
75 /**
76 * data for overlay filesystems
77 */
78 struct overlay_t {
79 /** path to overlay */
80 char *path;
81 /** overlay fd */
82 int fd;
83 };
84
85 /**
86 * destroy an overlay
87 */
88 static void overlay_destroy(overlay_t *this)
89 {
90 close(this->fd);
91 free(this->path);
92 free(this);
93 }
94
95 /**
96 * compare two overlays by path
97 */
98 static bool overlay_equals(overlay_t *this, overlay_t *other)
99 {
100 return streq(this->path, other->path);
101 }
102
103 /**
104 * remove and destroy the overlay with the given absolute path.
105 * returns FALSE, if not found.
106 */
107 static bool overlay_remove(private_cowfs_t *this, char *path)
108 {
109 overlay_t over, *current;
110 over.path = path;
111 if (this->overlays->find_first(this->overlays,
112 (linked_list_match_t)overlay_equals, (void**)&current, &over) != SUCCESS)
113 {
114 return FALSE;
115 }
116 this->overlays->remove(this->overlays, current, NULL);
117 overlay_destroy(current);
118 return TRUE;
119 }
120
121 /**
122 * get this pointer stored in fuse context
123 */
124 static private_cowfs_t *get_this()
125 {
126 return (fuse_get_context())->private_data;
127 }
128
129 /**
130 * make a path relative
131 */
132 static void rel(const char **path)
133 {
134 if (**path == '/')
135 {
136 (*path)++;
137 }
138 if (**path == '\0')
139 {
140 *path = ".";
141 }
142 }
143
144 /**
145 * get the highest overlay in which path exists
146 */
147 static int get_rd(const char *path)
148 {
149 overlay_t *over;
150 enumerator_t *enumerator;
151 private_cowfs_t *this = get_this();
152
153 this->lock->read_lock(this->lock);
154 enumerator = this->overlays->create_enumerator(this->overlays);
155 while (enumerator->enumerate(enumerator, (void**)&over))
156 {
157 if (faccessat(over->fd, path, F_OK, 0) == 0)
158 {
159 int fd = over->fd;
160 enumerator->destroy(enumerator);
161 this->lock->unlock(this->lock);
162 return fd;
163 }
164 }
165 enumerator->destroy(enumerator);
166 this->lock->unlock(this->lock);
167
168 if (faccessat(this->host_fd, path, F_OK, 0) == 0)
169 {
170 return this->host_fd;
171 }
172 return this->master_fd;
173 }
174
175 /**
176 * get the highest overlay available, to write something
177 */
178 static int get_wr(const char *path)
179 {
180 overlay_t *over;
181 private_cowfs_t *this = get_this();
182 int fd = this->host_fd;
183 this->lock->read_lock(this->lock);
184 if (this->overlays->get_first(this->overlays, (void**)&over) == SUCCESS)
185 {
186 fd = over->fd;
187 }
188 this->lock->unlock(this->lock);
189 return fd;
190 }
191
192 /**
193 * create full "path" at "wr" the same way they exist at "rd"
194 */
195 static bool clone_path(int rd, int wr, const char *path)
196 {
197 char *pos, *full;
198 struct stat st;
199 full = strdupa(path);
200 pos = full;
201
202 while ((pos = strchr(pos, '/')))
203 {
204 *pos = '\0';
205 if (fstatat(wr, full, &st, 0) < 0)
206 {
207 /* TODO: handle symlinks!? */
208 if (fstatat(rd, full, &st, 0) < 0)
209 {
210 return FALSE;
211 }
212 if (mkdirat(wr, full, st.st_mode) < 0)
213 {
214 return FALSE;
215 }
216 }
217 *pos = '/';
218 pos++;
219 }
220 return TRUE;
221 }
222
223 /**
224 * copy a (special) file from a readonly to a read-write overlay
225 */
226 static int copy(const char *path)
227 {
228 char *buf[4096];
229 int len;
230 int rd, wr;
231 int from, to;
232 struct stat st;
233
234 rd = get_rd(path);
235 wr = get_wr(path);
236
237 if (rd == wr)
238 {
239 /* already writeable */
240 return wr;
241 }
242 if (fstatat(rd, path, &st, 0) < 0)
243 {
244 return -1;
245 }
246 if (!clone_path(rd, wr, path))
247 {
248 return -1;
249 }
250 if (mknodat(wr, path, st.st_mode, st.st_rdev) < 0)
251 {
252 return -1;
253 }
254 /* copy if no special file */
255 if (st.st_size)
256 {
257 from = openat(rd, path, O_RDONLY, st.st_mode);
258 if (from < 0)
259 {
260 return -1;
261 }
262 to = openat(wr, path, O_WRONLY , st.st_mode);
263 if (to < 0)
264 {
265 close(from);
266 return -1;
267 }
268 while ((len = read(from, buf, sizeof(buf))) > 0)
269 {
270 if (write(to, buf, len) < len)
271 {
272 /* TODO: only on len < 0 ? */
273 close(from);
274 close(to);
275 return -1;
276 }
277 }
278 close(from);
279 close(to);
280 if (len < 0)
281 {
282 return -1;
283 }
284 }
285 return wr;
286 }
287
288 /**
289 * FUSE getattr method
290 */
291 static int cowfs_getattr(const char *path, struct stat *stbuf)
292 {
293 rel(&path);
294
295 if (fstatat(get_rd(path), path, stbuf, AT_SYMLINK_NOFOLLOW) < 0)
296 {
297 return -errno;
298 }
299 return 0;
300 }
301
302 /**
303 * FUSE access method
304 */
305 static int cowfs_access(const char *path, int mask)
306 {
307 rel(&path);
308
309 if (faccessat(get_rd(path), path, mask, 0) < 0)
310 {
311 return -errno;
312 }
313 return 0;
314 }
315
316 /**
317 * FUSE readlink method
318 */
319 static int cowfs_readlink(const char *path, char *buf, size_t size)
320 {
321 int res;
322
323 rel(&path);
324
325 res = readlinkat(get_rd(path), path, buf, size - 1);
326 if (res < 0)
327 {
328 return -errno;
329 }
330 buf[res] = '\0';
331 return 0;
332 }
333
334 /**
335 * get a directory stream of two concatenated paths
336 */
337 static DIR* get_dir(char *dir, const char *subdir)
338 {
339 char *full;
340
341 if (dir == NULL)
342 {
343 return NULL;
344 }
345
346 full = alloca(strlen(dir) + strlen(subdir) + 1);
347 strcpy(full, dir);
348 strcat(full, subdir);
349
350 return opendir(full);
351 }
352
353 /**
354 * check if a directory stream contains a directory
355 */
356 static bool contains_dir(DIR *d, char *dirname)
357 {
358 struct dirent *ent;
359
360 rewinddir(d);
361 while ((ent = readdir(d)))
362 {
363 if (streq(ent->d_name, dirname))
364 {
365 return TRUE;
366 }
367 }
368 return FALSE;
369 }
370
371 /**
372 * check if one of the higher overlays contains a directory
373 */
374 static bool overlays_contain_dir(DIR **d, char *dirname)
375 {
376 for (; *d; ++d)
377 {
378 if (contains_dir(*d, dirname))
379 {
380 return TRUE;
381 }
382 }
383 return FALSE;
384 }
385
386 /**
387 * FUSE readdir method
388 */
389 static int cowfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
390 off_t offset, struct fuse_file_info *fi)
391 {
392 #define ADD_DIR(overlay, base, path) ({\
393 DIR *dir = get_dir(base, path);\
394 if (dir) { *(--overlay) = dir; }\
395 })
396 private_cowfs_t *this = get_this();
397 int count;
398 DIR **d, **overlays;
399 struct stat st;
400 struct dirent *ent;
401 overlay_t *over;
402 enumerator_t *enumerator;
403
404 memset(&st, 0, sizeof(st));
405
406 this->lock->read_lock(this->lock);
407 /* create a null-terminated array of DIR objects for all overlays (including
408 * the master and host layer). the order is from bottom to top */
409 count = this->overlays->get_count(this->overlays) + 2;
410 overlays = calloc(count + 1, sizeof(DIR*));
411 d = &overlays[count];
412
413 enumerator = this->overlays->create_enumerator(this->overlays);
414 while (enumerator->enumerate(enumerator, (void**)&over))
415 {
416 ADD_DIR(d, over->path, path);
417 }
418 enumerator->destroy(enumerator);
419 this->lock->unlock(this->lock);
420
421 ADD_DIR(d, this->host, path);
422 ADD_DIR(d, this->master, path);
423
424 for (; *d; ++d)
425 {
426 rewinddir(*d);
427 while((ent = readdir(*d)))
428 {
429 if (!overlays_contain_dir(d + 1, ent->d_name))
430 {
431 st.st_ino = ent->d_ino;
432 st.st_mode = ent->d_type << 12;
433 filler(buf, ent->d_name, &st, 0);
434 }
435 }
436 closedir(*d);
437 }
438
439 free(overlays);
440 return 0;
441 }
442
443 /**
444 * FUSE mknod method
445 */
446 static int cowfs_mknod(const char *path, mode_t mode, dev_t rdev)
447 {
448 int fd;
449 rel(&path);
450
451 fd = get_wr(path);
452 if (!clone_path(get_rd(path), fd, path))
453 {
454 return -errno;
455 }
456
457 if (mknodat(fd, path, mode, rdev) < 0)
458 {
459 return -errno;
460 }
461 return 0;
462 }
463
464 /**
465 * FUSE mkdir method
466 */
467 static int cowfs_mkdir(const char *path, mode_t mode)
468 {
469 int fd;
470 rel(&path);
471
472 fd = get_wr(path);
473 if (!clone_path(get_rd(path), fd, path))
474 {
475 return -errno;
476 }
477 if (mkdirat(fd, path, mode) < 0)
478 {
479 return -errno;
480 }
481 return 0;
482 }
483
484 /**
485 * FUSE unlink method
486 */
487 static int cowfs_unlink(const char *path)
488 {
489 rel(&path);
490
491 /* TODO: whiteout master */
492 if (unlinkat(get_wr(path), path, 0) < 0)
493 {
494 return -errno;
495 }
496 return 0;
497 }
498
499 /**
500 * FUSE rmdir method
501 */
502 static int cowfs_rmdir(const char *path)
503 {
504 rel(&path);
505
506 /* TODO: whiteout master */
507 if (unlinkat(get_wr(path), path, AT_REMOVEDIR) < 0)
508 {
509 return -errno;
510 }
511 return 0;
512 }
513
514 /**
515 * FUSE symlink method
516 */
517 static int cowfs_symlink(const char *from, const char *to)
518 {
519 int fd;
520 const char *fromrel = from;
521
522 rel(&to);
523 rel(&fromrel);
524
525 fd = get_wr(to);
526 if (!clone_path(get_rd(fromrel), fd, fromrel))
527 {
528 return -errno;
529 }
530 if (symlinkat(from, fd, to) < 0)
531 {
532 return -errno;
533 }
534 return 0;
535 }
536
537 /**
538 * FUSE rename method
539 */
540 static int cowfs_rename(const char *from, const char *to)
541 {
542 int fd;
543
544 rel(&from);
545 rel(&to);
546
547 fd = copy(from);
548 if (fd < 0)
549 {
550 return -errno;
551 }
552 if (renameat(fd, from, get_wr(to), to) < 0)
553 {
554 return -errno;
555 }
556 return 0;
557 }
558
559 /**
560 * FUSE link method
561 */
562 static int cowfs_link(const char *from, const char *to)
563 {
564 int rd, wr;
565
566 rel(&from);
567 rel(&to);
568
569 rd = get_rd(from);
570 wr = get_wr(to);
571
572 if (!clone_path(rd, wr, to))
573 {
574 DBG1(DBG_LIB, "cloning path '%s' failed", to);
575 return -errno;
576 }
577 if (linkat(rd, from, wr, to, 0) < 0)
578 {
579 DBG1(DBG_LIB, "linking '%s' to '%s' failed", from, to);
580 return -errno;
581 }
582 return 0;
583 }
584
585 /**
586 * FUSE chmod method
587 */
588 static int cowfs_chmod(const char *path, mode_t mode)
589 {
590 int fd;
591 struct stat st;
592
593 rel(&path);
594 fd = get_rd(path);
595 if (fstatat(fd, path, &st, 0) < 0)
596 {
597 return -errno;
598 }
599 if (st.st_mode == mode)
600 {
601 return 0;
602 }
603 fd = copy(path);
604 if (fd < 0)
605 {
606 return -errno;
607 }
608 if (fchmodat(fd, path, mode, 0) < 0)
609 {
610 return -errno;
611 }
612 return 0;
613 }
614
615 /**
616 * FUSE chown method
617 */
618 static int cowfs_chown(const char *path, uid_t uid, gid_t gid)
619 {
620 int fd;
621 struct stat st;
622
623 rel(&path);
624 fd = get_rd(path);
625 if (fstatat(fd, path, &st, 0) < 0)
626 {
627 return -errno;
628 }
629 if (st.st_uid == uid && st.st_gid == gid)
630 {
631 return 0;
632 }
633 fd = copy(path);
634 if (fd < 0)
635 {
636 return -errno;
637 }
638 if (fchownat(fd, path, uid, gid, AT_SYMLINK_NOFOLLOW) < 0)
639 {
640 return -errno;
641 }
642 return 0;
643 }
644
645 /**
646 * FUSE truncate method
647 */
648 static int cowfs_truncate(const char *path, off_t size)
649 {
650 int fd;
651 struct stat st;
652
653 rel(&path);
654 fd = get_rd(path);
655 if (fstatat(fd, path, &st, 0) < 0)
656 {
657 return -errno;
658 }
659 if (st.st_size == size)
660 {
661 return 0;
662 }
663 fd = copy(path);
664 if (fd < 0)
665 {
666 return -errno;
667 }
668 fd = openat(fd, path, O_WRONLY);
669 if (fd < 0)
670 {
671 return -errno;
672 }
673 if (ftruncate(fd, size) < 0)
674 {
675 close(fd);
676 return -errno;
677 }
678 close(fd);
679 return 0;
680 }
681
682 /**
683 * FUSE utimens method
684 */
685 static int cowfs_utimens(const char *path, const struct timespec ts[2])
686 {
687 struct timeval tv[2];
688 int fd;
689
690 rel(&path);
691 fd = copy(path);
692 if (fd < 0)
693 {
694 return -errno;
695 }
696
697 tv[0].tv_sec = ts[0].tv_sec;
698 tv[0].tv_usec = ts[0].tv_nsec / 1000;
699 tv[1].tv_sec = ts[1].tv_sec;
700 tv[1].tv_usec = ts[1].tv_nsec / 1000;
701
702 if (futimesat(fd, path, tv) < 0)
703 {
704 return -errno;
705 }
706 return 0;
707 }
708
709 /**
710 * FUSE open method
711 */
712 static int cowfs_open(const char *path, struct fuse_file_info *fi)
713 {
714 int fd;
715
716 rel(&path);
717 fd = get_rd(path);
718
719 fd = openat(fd, path, fi->flags);
720 if (fd < 0)
721 {
722 return -errno;
723 }
724 close(fd);
725 return 0;
726 }
727
728 /**
729 * FUSE read method
730 */
731 static int cowfs_read(const char *path, char *buf, size_t size, off_t offset,
732 struct fuse_file_info *fi)
733 {
734 int file, fd, res;
735
736 rel(&path);
737
738 fd = get_rd(path);
739
740 file = openat(fd, path, O_RDONLY);
741 if (file < 0)
742 {
743 return -errno;
744 }
745
746 res = pread(file, buf, size, offset);
747 if (res < 0)
748 {
749 res = -errno;
750 }
751 close(file);
752 return res;
753 }
754
755 /**
756 * FUSE write method
757 */
758 static int cowfs_write(const char *path, const char *buf, size_t size,
759 off_t offset, struct fuse_file_info *fi)
760 {
761 int file, fd, res;
762
763 rel(&path);
764
765 fd = copy(path);
766 if (fd < 0)
767 {
768 return -errno;
769 }
770 file = openat(fd, path, O_WRONLY);
771 if (file < 0)
772 {
773 return -errno;
774 }
775 res = pwrite(file, buf, size, offset);
776 if (res < 0)
777 {
778 res = -errno;
779 }
780 close(file);
781 return res;
782 }
783
784 /**
785 * FUSE statfs method
786 */
787 static int cowfs_statfs(const char *path, struct statvfs *stbuf)
788 {
789 int fd;
790
791 fd = get_rd(path);
792 if (fstatvfs(fd, stbuf) < 0)
793 {
794 return -errno;
795 }
796
797 return 0;
798 }
799
800 /**
801 * FUSE init method
802 */
803 static void *cowfs_init(struct fuse_conn_info *conn)
804 {
805 struct fuse_context *ctx;
806
807 ctx = fuse_get_context();
808
809 return ctx->private_data;
810 }
811
812 /**
813 * FUSE method vectors
814 */
815 static struct fuse_operations cowfs_operations = {
816 .getattr = cowfs_getattr,
817 .access = cowfs_access,
818 .readlink = cowfs_readlink,
819 .readdir = cowfs_readdir,
820 .mknod = cowfs_mknod,
821 .mkdir = cowfs_mkdir,
822 .symlink = cowfs_symlink,
823 .unlink = cowfs_unlink,
824 .rmdir = cowfs_rmdir,
825 .rename = cowfs_rename,
826 .link = cowfs_link,
827 .chmod = cowfs_chmod,
828 .chown = cowfs_chown,
829 .truncate = cowfs_truncate,
830 .utimens = cowfs_utimens,
831 .open = cowfs_open,
832 .read = cowfs_read,
833 .write = cowfs_write,
834 .statfs = cowfs_statfs,
835 .init = cowfs_init,
836 };
837
838 METHOD(cowfs_t, add_overlay, bool,
839 private_cowfs_t *this, char *path)
840 {
841 overlay_t *over = malloc_thing(overlay_t);
842 over->fd = open(path, O_RDONLY | O_DIRECTORY);
843 if (over->fd < 0)
844 {
845 DBG1(DBG_LIB, "failed to open overlay directory '%s': %m", path);
846 free(over);
847 return FALSE;
848 }
849 over->path = realpath(path, NULL);
850 this->lock->write_lock(this->lock);
851 overlay_remove(this, over->path);
852 this->overlays->insert_first(this->overlays, over);
853 this->lock->unlock(this->lock);
854 return TRUE;
855 }
856
857 METHOD(cowfs_t, del_overlay, bool,
858 private_cowfs_t *this, char *path)
859 {
860 bool removed;
861 char real[PATH_MAX];
862 this->lock->write_lock(this->lock);
863 removed = overlay_remove(this, realpath(path, real));
864 this->lock->unlock(this->lock);
865 return removed;
866 }
867
868 METHOD(cowfs_t, pop_overlay, bool,
869 private_cowfs_t *this)
870 {
871 overlay_t *over;
872 this->lock->write_lock(this->lock);
873 if (this->overlays->remove_first(this->overlays, (void**)&over) != SUCCESS)
874 {
875 this->lock->unlock(this->lock);
876 return FALSE;
877 }
878 this->lock->unlock(this->lock);
879 overlay_destroy(over);
880 return TRUE;
881 }
882
883 METHOD(cowfs_t, destroy, void,
884 private_cowfs_t *this)
885 {
886 fuse_exit(this->fuse);
887 fuse_unmount(this->mount, this->chan);
888 this->thread->join(this->thread);
889 fuse_destroy(this->fuse);
890 this->lock->destroy(this->lock);
891 this->overlays->destroy_function(this->overlays, (void*)overlay_destroy);
892 free(this->mount);
893 free(this->master);
894 free(this->host);
895 close(this->master_fd);
896 close(this->host_fd);
897 free(this);
898 }
899
900 /**
901 * creates a new cowfs fuse instance
902 */
903 cowfs_t *cowfs_create(char *master, char *host, char *mount)
904 {
905 struct fuse_args args = {0, NULL, 0};
906 private_cowfs_t *this;
907
908 INIT(this,
909 .public = {
910 .add_overlay = _add_overlay,
911 .del_overlay = _del_overlay,
912 .pop_overlay = _pop_overlay,
913 .destroy = _destroy,
914 }
915 );
916
917 this->master_fd = open(master, O_RDONLY | O_DIRECTORY);
918 if (this->master_fd < 0)
919 {
920 DBG1(DBG_LIB, "failed to open master filesystem '%s'", master);
921 free(this);
922 return NULL;
923 }
924 this->host_fd = open(host, O_RDONLY | O_DIRECTORY);
925 if (this->host_fd < 0)
926 {
927 DBG1(DBG_LIB, "failed to open host filesystem '%s'", host);
928 close(this->master_fd);
929 free(this);
930 return NULL;
931 }
932
933 this->chan = fuse_mount(mount, &args);
934 if (this->chan == NULL)
935 {
936 DBG1(DBG_LIB, "mounting cowfs FUSE on '%s' failed", mount);
937 close(this->master_fd);
938 close(this->host_fd);
939 free(this);
940 return NULL;
941 }
942
943 this->fuse = fuse_new(this->chan, &args, &cowfs_operations,
944 sizeof(cowfs_operations), this);
945 if (this->fuse == NULL)
946 {
947 DBG1(DBG_LIB, "creating cowfs FUSE handle failed");
948 close(this->master_fd);
949 close(this->host_fd);
950 fuse_unmount(mount, this->chan);
951 free(this);
952 return NULL;
953 }
954
955 this->mount = strdup(mount);
956 this->master = strdup(master);
957 this->host = strdup(host);
958 this->overlays = linked_list_create();
959 this->lock = rwlock_create(RWLOCK_TYPE_DEFAULT);
960
961 this->thread = thread_create((thread_main_t)fuse_loop, this->fuse);
962 if (!this->thread)
963 {
964 DBG1(DBG_LIB, "creating thread to handle FUSE failed");
965 fuse_unmount(mount, this->chan);
966 this->lock->destroy(this->lock);
967 this->overlays->destroy(this->overlays);
968 free(this->mount);
969 free(this->master);
970 free(this->host);
971 close(this->master_fd);
972 close(this->host_fd);
973 free(this);
974 return NULL;
975 }
976
977 return &this->public;
978 }
979