1
2 /*
3 FUNIONFS: UNIONFS over FUSE Usermode filesystem
4 Copyright (C) 2005-2006 Stephane APIOU <stephane.apiou@free.fr>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 */
21
22 #include <fuse.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <dirent.h>
30 #include <sys/mman.h>
31
32 #include "funionfs.h"
33
34 extern f_opt_t f_opt;
35
36 unsigned long maxpath;
37 struct unionfs_desc *unionfs_list;
38
39 int
issubpath(char * abspath,char * basepath)40 issubpath(char *abspath, char *basepath)
41 {
42 if (*basepath != '/')
43 return 0;
44
45 if (*abspath != '/')
46 return 0;
47
48 while (*++abspath == *++basepath)
49 {
50 /* abspath and base path are equal */
51 if (*abspath == '\0')
52 return 1;
53 }
54 if (*abspath == '\0')
55 return 1;
56 return 0;
57 }
58
59 char *
abs2relpath(char * abspath,char * basepath)60 abs2relpath(char *abspath, char *basepath)
61 {
62 char *result;
63
64 if (*basepath != '/')
65 return NULL;
66
67 if (*abspath != '/')
68 return NULL;
69
70 while (*++abspath == *++basepath)
71 {
72 /* abspath and base path are equal */
73 if (*abspath == '\0')
74 return NULL;
75 }
76 /* return just after the last / */
77 while (abspath[-1] != '/')
78 abspath--;
79 while (basepath[-1] != '/')
80 basepath--;
81
82 result = (char *) malloc(strlen(basepath) * 2 + strlen(abspath) + 1);
83 if (result == NULL)
84 return NULL;
85
86 while (*basepath != '\0')
87 {
88 if (*basepath == '/')
89 strcat(result, "../");
90 }
91 if (basepath[-1] != '/')
92 strcat(result, "../");
93 strcat(result, abspath);
94
95 return result;
96 }
97
98 /* warning basepath must start with a slash */
99
100 char *
rel2abspath(char * relpath,char * basepath)101 rel2abspath(char *relpath, char *basepath)
102 {
103 char *copy_path;
104 char *copy_bpath;
105 char *orig_cpypath;
106 char *temp_path;
107 char link_path[MAX_LINKPATH];
108 char *new_path;
109 char *max_path;
110 int readlinks = 0;
111 int n;
112
113 //DEBUG_PRINTF("rel2abspath( %s , %s );\n",relpath,basepath);
114
115 /* test if basepath is an absolute path */
116
117 if (*basepath != '/')
118 return NULL;
119
120 /* Make a copy of the source path since we may need to modify it. */
121 copy_path = strdup(relpath);
122 if (copy_path == NULL)
123 return NULL;
124 orig_cpypath = copy_path;
125
126 /*
127 * Make a copy of basepath and allocate a buffer of sizeof(relpath)+sizeof(basepath) since
128 * the resulting path can't be larger
129 */
130 copy_bpath = (char *) malloc(strlen(basepath) + strlen(relpath) + 3);
131 if (copy_bpath == NULL)
132 {
133 free(orig_cpypath);
134 return NULL;
135 }
136 strcpy(copy_bpath, basepath);
137 new_path = copy_bpath;
138 max_path = copy_bpath + strlen(basepath) + strlen(relpath);
139
140 /* If it's a relative pathname use getwd for starters. */
141 if (*copy_path != '/')
142 {
143 new_path += strlen(new_path);
144 if (new_path[-1] != '/')
145 *new_path++ = '/';
146 }
147 else
148 {
149 *new_path++ = '/';
150 copy_path++;
151 }
152 /* Expand each slash-separated pathname component. */
153 while (*copy_path != '\0')
154 {
155 /* Ignore stray "/". */
156 if (*copy_path == '/')
157 {
158 copy_path++;
159 continue;
160 }
161 if (*copy_path == '.')
162 {
163 /* Ignore ".". */
164 if (copy_path[1] == '\0' || copy_path[1] == '/')
165 {
166 copy_path++;
167 continue;
168 }
169 if (copy_path[1] == '.')
170 {
171 if (copy_path[2] == '\0' || copy_path[2] == '/')
172 {
173 copy_path += 2;
174 /* Ignore ".." at root. */
175 if (new_path == copy_bpath + 1)
176 continue;
177 /* Handle ".." by backing up. */
178 while ((--new_path)[-1] != '/')
179 ;
180 continue;
181 }
182 }
183 }
184 /* Safely copy the next pathname component. */
185 while (*copy_path != '\0' && *copy_path != '/')
186 {
187 if (new_path > max_path)
188 {
189 free(copy_bpath);
190 free(orig_cpypath);
191 return NULL;
192 }
193 *new_path++ = *copy_path++;
194 }
195
196 /* Protect against infinite loops. */
197 if (readlinks++ > MAX_READLINKS)
198 {
199 free(copy_bpath);
200 free(orig_cpypath);
201 return NULL;
202 }
203 /* See if latest pathname component is a symlink. */
204 *new_path = '\0';
205 n = readlink(copy_bpath, link_path, MAX_LINKPATH - 1);
206 if (n < 0)
207 {
208 /* EINVAL means the file exists but isn't a symlink. */
209 if (errno != EINVAL)
210 {
211 free(copy_bpath);
212 free(orig_cpypath);
213 return NULL;
214 }
215 }
216 else
217 {
218 /* Note: readlink doesn't add the null byte. */
219 link_path[n] = '\0';
220 if (*link_path == '/')
221 {
222 /* Start over for an absolute symlink. */
223 *copy_bpath = '\0';
224 }
225 else
226 {
227 /* Otherwise back up over this component. */
228 while (*(--new_path) != '/')
229 ;
230 new_path[1] = '\0';
231 }
232 temp_path =
233 (char *) malloc(strlen(copy_bpath) +
234 strlen(copy_path) +
235 strlen(link_path) + 4);
236 if (temp_path == NULL)
237 {
238 free(copy_bpath);
239 free(orig_cpypath);
240 return NULL;
241 }
242 strcpy(temp_path, copy_bpath);
243 free(copy_bpath);
244 copy_bpath = temp_path;
245 new_path = copy_bpath;
246 max_path =
247 copy_bpath + strlen(copy_bpath) +
248 strlen(copy_path) + strlen(link_path) + 3;
249
250 /* Insert symlink contents into copy_path. */
251 temp_path =
252 (char *) malloc(strlen(copy_path) +
253 strlen(link_path) + 1);
254 if (temp_path == NULL)
255 {
256 free(copy_bpath);
257 free(orig_cpypath);
258 return NULL;
259 }
260 strcpy(temp_path, link_path);
261 strcat(temp_path, copy_path);
262 free(orig_cpypath);
263 orig_cpypath = temp_path;
264 copy_path = temp_path;
265 }
266 *new_path++ = '/';
267 }
268 /* Delete trailing slash but don't whomp a lone slash. */
269 if (new_path != copy_bpath + 1 && new_path[-1] == '/')
270 new_path--;
271 /* Make sure it's null terminated. */
272 *new_path = '\0';
273
274 temp_path = strdup(copy_bpath);
275 if (temp_path == NULL)
276 {
277 free(copy_bpath);
278 free(orig_cpypath);
279 return NULL;
280 }
281 free(copy_bpath);
282 free(orig_cpypath);
283
284 DEBUG_PRINTF("rel2abspath( %s , %s )= %s\n", relpath, basepath,
285 temp_path);
286
287 return temp_path;
288 }
289
290 int
funionfs_addpath(char * path,int ro)291 funionfs_addpath(char *path, int ro)
292 {
293 struct unionfs_desc *pdesc, *plast;
294 char *copy_path;
295 int res;
296 struct stat statfile;
297
298 res = lstat(path, &statfile);
299 if (res < 0)
300 return -errno;
301 if (strlen(path) > maxpath)
302 maxpath = strlen(path);
303
304 copy_path = strdup(path);
305 if (copy_path == NULL)
306 return (-ENOMEM);
307
308 pdesc = (struct unionfs_desc *) malloc(sizeof(struct unionfs_desc));
309 if (pdesc == NULL)
310 {
311 free(copy_path);
312 return (-ENOMEM);
313 }
314 if (unionfs_list != NULL)
315 {
316 plast = unionfs_list;
317 while (plast->pnext != NULL)
318 plast = plast->pnext;
319 }
320
321 pdesc->path = copy_path;
322 pdesc->ro = ro;
323 pdesc->pnext = NULL;
324 if (unionfs_list != NULL)
325 plast->pnext = pdesc;
326 else
327 unionfs_list = pdesc;
328
329 return 1;
330
331 }
332
333 /* get path for read and write
334 * return is:
335 * negative: error (-errno)
336 * bits are as follow up
337 * 01234
338 * ^^^^^
339 * |||||
340 * ||||\_ file exist in read branch, deletion is done in write branch with a deleted file
341 * |||\__ file can be created in this path
342 * ||\___ file is delete in write branch
343 * |\____ file exist in write branch
344 * \_____ file exist in read branch
345 */
346
347 int
funionfs_realpath(const char * path,char ** get_path,char ** put_path,char ** new_path,struct unionfs_desc * tab[3])348 funionfs_realpath(const char *path, char **get_path, char **put_path,
349 char **new_path, struct unionfs_desc *tab[3])
350 {
351 int len;
352 struct unionfs_desc *pdesc, *pnew;
353 int res;
354 char *cur_path, *pend;
355 struct stat statfile;
356 int deleted, to_delete;
357
358 len = strlen(path) + maxpath + f_opt.del_len + 1;
359 cur_path = (char *) malloc(len);
360 if (cur_path == NULL)
361 return -ENOMEM;
362
363 *get_path = NULL;
364 *put_path = NULL;
365 *new_path = NULL;
366 deleted = 0;
367 to_delete = 0;
368 pnew = NULL;
369
370 for (pdesc = unionfs_list; pdesc != NULL; pdesc = pdesc->pnext)
371 {
372 strncpy(cur_path, pdesc->path, len);
373 pend = cur_path + strlen(cur_path);
374 while (*--pend == '/') ;
375 pend[1] = '\0';
376 strncat(cur_path, path, len);
377 /* delete trailing slashs */
378 pend = cur_path + strlen(cur_path);
379 while (*--pend == '/') ;
380 pend[1] = '\0';
381
382 res = 0;
383 DEBUG_PRINTF("%s\n", cur_path);
384 if (lstat(cur_path, &statfile) >= 0)
385 res = 1;
386
387 strcat(cur_path, f_opt.del_string);
388 DEBUG_PRINTF("%s\n", cur_path);
389 if (lstat(cur_path, &statfile) >= 0)
390 res |= 2;
391 pend[1] = '\0';
392
393 switch (res)
394 {
395 case 3:
396 deleted = 1;
397 DEBUG_PRINTF("DELETED BUT EXISTS\n");
398 if (*get_path != NULL)
399 free(*get_path);
400 *get_path = NULL;
401 if (*put_path != NULL)
402 free(*put_path);
403 *put_path = NULL;
404 break;
405
406 case 2:
407 deleted = 1;
408 DEBUG_PRINTF("DELETED\n");
409 if (*get_path != NULL)
410 free(*get_path);
411 *get_path = NULL;
412 if (*put_path != NULL)
413 free(*put_path);
414 *put_path = NULL;
415 break;
416 case 1:
417 if (*get_path != NULL)
418 {
419 DEBUG_PRINTF("TO DELETE\n");
420 to_delete = 1;
421 }
422 deleted = 0;
423 if (pdesc->ro)
424 {
425 if (*get_path != NULL)
426 free(*get_path);
427 *get_path = cur_path;
428 tab[IDX_GET] = pdesc;
429 }
430 else
431 {
432 if (*get_path != NULL)
433 free(*get_path);
434 *get_path = cur_path;
435 tab[IDX_GET] = pdesc;
436 cur_path = (char *) malloc(len);
437 if (cur_path == NULL)
438 {
439 free(*get_path);
440 return -ENOMEM;
441 }
442 strcpy(cur_path, *get_path);
443 *put_path = cur_path;
444 tab[IDX_PUT] = pdesc;
445 }
446 cur_path = (char *) malloc(len);
447 if (cur_path == NULL)
448 {
449 if (*get_path != NULL)
450 free(*get_path);
451 if (*put_path != NULL)
452 free(*put_path);
453 return -ENOMEM;
454 }
455 break;
456 }
457 if (!pdesc->ro)
458 pnew = pdesc;
459 }
460
461 if (pnew != NULL)
462 {
463 *new_path = cur_path;
464 strncpy(cur_path, pnew->path, len);
465 pend = cur_path + strlen(cur_path);
466 while (*--pend == '/') ;
467 pend[1] = '\0';
468 strncat(cur_path, path, len);
469 /* delete trailing slashs */
470 pend = cur_path + strlen(cur_path);
471 while (*--pend == '/') ;
472 pend[1] = '\0';
473 tab[IDX_NEW] = pnew;
474 }
475 else
476 free(cur_path);
477
478 res = (*put_path != NULL) << 1 | (*get_path !=
479 NULL) | deleted << 2 | (*new_path !=
480 NULL) << 3 |
481 to_delete << 4;
482
483 if (*put_path == NULL)
484 {
485 *put_path = (char *) malloc(1);
486 **put_path = '\0';
487 }
488 if (*get_path == NULL)
489 {
490 *get_path = (char *) malloc(1);
491 **get_path = '\0';
492 }
493 if (*new_path == NULL)
494 {
495 *new_path = (char *) malloc(1);
496 **new_path = '\0';
497 }
498 return res;
499 }
500 int
old_funionfs_realpath(const char * path,char ** get_path,char ** put_path,char ** new_path,struct unionfs_desc * tab[3])501 old_funionfs_realpath(const char *path, char **get_path, char **put_path,
502 char **new_path, struct unionfs_desc *tab[3])
503 {
504 int len;
505 struct unionfs_desc *pdesc, *pnew;
506 int res;
507 char *cur_path, *pend;
508 struct stat statfile;
509 int deleted, to_delete;
510
511 len = strlen(path) + maxpath + f_opt.del_len + 1;
512 cur_path = (char *) malloc(len);
513 if (cur_path == NULL)
514 return -ENOMEM;
515
516 *get_path = NULL;
517 *put_path = NULL;
518 *new_path = NULL;
519 deleted = 0;
520 to_delete = 0;
521 pnew = NULL;
522
523 for (pdesc = unionfs_list; pdesc != NULL; pdesc = pdesc->pnext)
524 {
525 strncpy(cur_path, pdesc->path, len);
526 pend = cur_path + strlen(cur_path);
527 while (*--pend == '/') ;
528 pend[1] = '\0';
529 strncat(cur_path, path, len);
530 /* delete trailing slashs */
531 pend = cur_path + strlen(cur_path);
532 while (*--pend == '/') ;
533 pend[1] = '\0';
534
535 res = 0;
536 DEBUG_PRINTF("%s\n", cur_path);
537 if (lstat(cur_path, &statfile) >= 0)
538 res = 1;
539
540 strcat(cur_path, f_opt.del_string);
541 DEBUG_PRINTF("%s\n", cur_path);
542 if (lstat(cur_path, &statfile) >= 0)
543 res |= 2;
544 pend[1] = '\0';
545
546 switch (res)
547 {
548 case 3:
549 deleted = 1;
550 DEBUG_PRINTF("DELETED BUT EXISTS\n");
551 if (*get_path != NULL)
552 free(*get_path);
553 *get_path = NULL;
554 if (*put_path != NULL)
555 free(*put_path);
556 *put_path = NULL;
557 break;
558
559 case 2:
560 deleted = 1;
561 DEBUG_PRINTF("DELETED\n");
562 if (*get_path != NULL)
563 free(*get_path);
564 *get_path = NULL;
565 if (*put_path != NULL)
566 free(*put_path);
567 *put_path = NULL;
568 break;
569 case 1:
570 if (*get_path != NULL)
571 {
572 DEBUG_PRINTF("TO DELETE\n");
573 to_delete = 1;
574 }
575 deleted = 0;
576 if (pdesc->ro)
577 {
578 if (*get_path != NULL)
579 free(*get_path);
580 *get_path = cur_path;
581 tab[IDX_GET] = pdesc;
582 }
583 else
584 {
585 if (*get_path != NULL)
586 free(*get_path);
587 *get_path = cur_path;
588 tab[IDX_GET] = pdesc;
589 cur_path = (char *) malloc(len);
590 if (cur_path == NULL)
591 {
592 free(*get_path);
593 return -ENOMEM;
594 }
595 strcpy(cur_path, *get_path);
596 *put_path = cur_path;
597 tab[IDX_PUT] = pdesc;
598 }
599 cur_path = (char *) malloc(len);
600 if (cur_path == NULL)
601 {
602 if (*get_path != NULL)
603 free(*get_path);
604 if (*put_path != NULL)
605 free(*put_path);
606 return -ENOMEM;
607 }
608 break;
609 }
610 if (!pdesc->ro)
611 pnew = pdesc;
612 }
613
614 if (pnew != NULL)
615 {
616 *new_path = cur_path;
617 strncpy(cur_path, pnew->path, len);
618 pend = cur_path + strlen(cur_path);
619 while (*--pend == '/') ;
620 pend[1] = '\0';
621 strncat(cur_path, path, len);
622 /* delete trailing slashs */
623 pend = cur_path + strlen(cur_path);
624 while (*--pend == '/') ;
625 pend[1] = '\0';
626 tab[IDX_NEW] = pnew;
627 }
628 else
629 free(cur_path);
630
631 res = (*put_path != NULL) << 1 | (*get_path !=
632 NULL) | deleted << 2 | (*new_path !=
633 NULL) << 3 |
634 to_delete << 4;
635
636 if (*put_path == NULL)
637 {
638 *put_path = (char *) malloc(1);
639 **put_path = '\0';
640 }
641 if (*get_path == NULL)
642 {
643 *get_path = (char *) malloc(1);
644 **get_path = '\0';
645 }
646 if (*new_path == NULL)
647 {
648 *new_path = (char *) malloc(1);
649 **new_path = '\0';
650 }
651 return res;
652 }
653
654 int
funionfs_pathtowrite(const char * path)655 funionfs_pathtowrite(const char *path)
656 {
657 struct unionfs_desc *pdesc_tab[3];
658
659 char *getpath, *setpath, *newpath;
660 char *str, *pend;
661 int res;
662
663 /* create the path to file */
664 str = strdup(path);
665 if (str == NULL)
666 {
667 errno = ENOMEM;
668 return -1;
669 }
670
671 /* detect last element of pathname */
672 pend = str + strlen(str);
673 while ((*--pend != '/') && (pend >= str)) ;
674 pend[0] = '\0';
675
676 res = funionfs_realpath(str, &getpath, &setpath, &newpath, pdesc_tab);
677 if (res < 0)
678 {
679 free(str);
680 return res;
681 }
682
683
684 if (*setpath == '\0')
685 {
686 res = funionfs_copytowrite(getpath, newpath);
687 }
688 else
689 res = 0;
690
691 free(str);
692 free(getpath);
693 free(setpath);
694 free(newpath);
695
696 if (res < 0)
697 return -errno;
698
699 return 0;
700 }
701
702 int
funionfs_copytowrite(char * readpath,char * writepath)703 funionfs_copytowrite(char *readpath, char *writepath)
704 {
705 char *wstr, *rstr;
706 char *readfile, *writefile;
707 char *wpend, *rpend;
708 struct stat sb, rsb;
709 int readfd, writefd;
710 char link_path[MAX_LINKPATH];
711 struct utimbuf buf;
712 int endflag;
713
714 DEBUG_PRINTF("copytowrite %s %s\n", readpath, writepath);
715
716 /* create the path to file */
717 wstr = strdup(writepath);
718 if (wstr == NULL)
719 {
720 errno = ENOMEM;
721 return -1;
722 }
723
724 rstr = strdup(readpath);
725 if (rstr == NULL)
726 {
727 free(wstr);
728 errno = ENOMEM;
729 return -1;
730 }
731 wpend = wstr + strlen(wstr);
732 rpend = rstr + strlen(rstr);
733
734 /* find start of variable element of both pathnames */
735 while ((*wpend == *rpend) && (wpend > wstr) && (rpend > rstr))
736 {
737 wpend--;
738 rpend--;
739 }
740
741 //DEBUG_PRINTF("Identical part: %s = %s\n",rpend,wpend);
742
743 while ((*wpend != '/') && (*wpend != '\0'))
744 wpend++;
745 while ((*rpend != '/') && (*rpend != '\0'))
746 rpend++;
747 endflag = -1;
748
749 /* walk thru the path and create each element to the last element */
750 /* if the element does'nt exist, clone it from the readonly path */
751
752 //DEBUG_PRINTF("Left as constant: %s : %s\n",rpend,wpend);
753 while (endflag < 0)
754 {
755 /* suppress leading slash */
756 while (*wpend == '/')
757 wpend++;
758 while (*rpend == '/')
759 rpend++;
760 /* detect pathname element */
761 while ((*wpend != '/') && (*wpend != '\0'))
762 wpend++;
763 if (*wpend == '\0')
764 endflag = 1;
765 *wpend = '\0';
766 while ((*rpend != '/') && (*rpend != '\0'))
767 rpend++;
768 if (*rpend == '\0')
769 endflag = 1;
770 *rpend = '\0';
771
772 //DEBUG_PRINTF("Currently: %s %s\n",rstr,wstr);
773 /* get element attributes from the read path */
774 if (lstat(rstr, &rsb) < 0)
775 {
776 break;
777 }
778 /* does the file exist in the writing path ? */
779 if (lstat(wstr, &sb) < 0)
780 {
781 if (S_ISDIR(rsb.st_mode))
782 { /* a directory ? : create it */
783 if (mkdir(wstr, rsb.st_mode & 07777) < 0)
784 break;
785 }
786 if (S_ISSOCK(rsb.st_mode) || S_ISCHR(rsb.st_mode)
787 || S_ISBLK(rsb.st_mode) || S_ISFIFO(rsb.st_mode))
788 {
789 /* a device or a pipe ? : create it */
790 if (mknod(wstr, rsb.st_mode, rsb.st_rdev) < 0)
791 break;
792 }
793 if (S_ISLNK(rsb.st_mode))
794 { /* a link ?:create it */
795 if (readlink
796 (readpath, link_path, MAX_LINKPATH - 1) < 0)
797 break;
798 if (symlink(wstr, link_path) < 0)
799 break;
800 }
801 if (S_ISREG(rsb.st_mode))
802 { /* a file ?: copy it */
803 if ((readfd = open(readpath, O_RDONLY)) < 0)
804 break;
805
806 if ((writefd =
807 open(wstr, O_CREAT | O_RDWR, S_IRWXU)) < 0)
808 {
809 close(readfd);
810 break;
811 }
812
813 if (ftruncate(writefd, rsb.st_size) < 0)
814 {
815 close(readfd);
816 close(writefd);
817 break;
818 }
819
820 if ((readfile =
821 (char *) mmap(NULL, rsb.st_size, PROT_READ,
822 MAP_SHARED, readfd,
823 0)) == (char *) -1)
824 {
825 close(readfd);
826 close(writefd);
827 break;
828 }
829
830 if ((writefile =
831 (char *) mmap(NULL, rsb.st_size,
832 PROT_WRITE, MAP_SHARED,
833 writefd, 0)) == (char *) -1)
834 {
835 close(readfd);
836 close(writefd);
837 break;
838 }
839
840 memcpy(writefile, readfile, rsb.st_size);
841
842 if (munmap(readfile, rsb.st_size) < 0)
843 {
844 close(readfd);
845 close(writefd);
846 break;
847 }
848
849 if (munmap(writefile, rsb.st_size) < 0)
850 {
851 close(readfd);
852 close(writefd);
853 break;
854 }
855 close(readfd);
856 close(writefd);
857 }
858 /* set permissions, group, user and time of the readonly file */
859 if (chmod(wstr, rsb.st_mode & 07777) < 0)
860 break;
861 if (chown(wstr, rsb.st_uid, rsb.st_gid) < 0)
862 break;
863 buf.actime = rsb.st_atime;
864 buf.modtime = rsb.st_mtime;
865 if (utime(wstr, &buf) < 0)
866 break;
867 }
868 if (endflag > 0)
869 break;
870 *wpend = '/';
871 *rpend = '/';
872 }
873 free(wstr);
874 free(rstr);
875
876 return endflag;
877 }
878
879 int
parse_and_add_dirs(void)880 parse_and_add_dirs(void)
881 {
882 char *ptr, *end;
883 char *path;
884 char basepath[4096];
885 int type, ret;
886
887 ptr = getcwd(basepath, 4096);
888 if (ptr == NULL)
889 return -errno;
890
891 // first add dirlist to the hierarchy
892
893 ptr = f_opt.dirlist;
894 while (*ptr)
895 {
896 end = ptr;
897 while (*end && (*end != ':') && (*end != '='))
898 {
899 end++;
900 }
901
902 type = 0; // default type is Read/Write
903
904 if (*end == '=')
905 {
906 *end++ = '\0';
907 if ((*end != 'r') && (*end != 'R'))
908 return -1;
909 end++;
910 switch (*end++)
911 {
912 case 'o':
913 case 'O':
914 type = 1;
915 break;
916 case 'w':
917 case 'W':
918 break;
919 default:
920 return -1;
921 }
922 if (*end != ':' && *end)
923 return -1;
924 }
925 if (*end == ':')
926 *end++ = '\0';
927
928 path = rel2abspath(ptr, basepath);
929 ret = funionfs_addpath(path, type);
930 free(path);
931 if (ret < 0)
932 {
933 return -ret;
934 }
935 ptr = end;
936 }
937
938 // then add the main path to the list
939
940 if (*f_opt.firstdir != '\0')
941 {
942 if (strcmp(f_opt.firstdir, "NONE")
943 && strcmp(f_opt.firstdir, "none")
944 && strcmp(f_opt.firstdir, "None"))
945 {
946 path = rel2abspath(f_opt.firstdir, basepath);
947 ret = funionfs_addpath(path, 0);
948 free(path);
949 if (ret < 0)
950 {
951 return -ret;
952 }
953 }
954 }
955
956 return 0;
957 }
958
959 struct unionfs_walk *
funionfs_openpath(const char * path)960 funionfs_openpath(const char *path)
961 {
962 struct unionfs_walk *pwalk;
963
964 pwalk = (struct unionfs_walk *) malloc(sizeof(struct unionfs_walk));
965 if (pwalk == NULL)
966 {
967 errno = ENOMEM;
968 return NULL;
969 }
970 pwalk->path = strdup(path);
971 if (pwalk == NULL)
972 {
973 free(pwalk);
974 errno = ENOMEM;
975 return NULL;
976 }
977 pwalk->curdir = unionfs_list;
978 pwalk->str = NULL;
979
980 return pwalk;
981 }
982
983 char *
funionfs_readpath(struct unionfs_walk * pwalk,long * type)984 funionfs_readpath(struct unionfs_walk *pwalk, long *type)
985 {
986 struct unionfs_desc *pdesc;
987 char *str;
988 char *pend;
989 int res;
990 struct stat statfile;
991
992 while (1)
993 {
994 if (pwalk->str != NULL)
995 {
996 free(pwalk->str);
997 pwalk->str = NULL;
998 }
999
1000 pdesc = pwalk->curdir;
1001
1002 if (pdesc == NULL)
1003 {
1004 *type = 0;
1005 return NULL;
1006 }
1007 pwalk->curdir = pdesc->pnext;
1008
1009 str = (char *) malloc(strlen(pdesc->path) +
1010 strlen(pwalk->path) + 1);
1011 if (str == NULL)
1012 {
1013 *type = 0;
1014 errno = ENOMEM;
1015 return NULL;
1016 }
1017 pwalk->str = str;
1018
1019 strcpy(str, pdesc->path);
1020
1021 /* delete trailing slashs */
1022 pend = str + strlen(str);
1023 while (*--pend == '/') ;
1024 pend[1] = '\0';
1025
1026 strcat(str, pwalk->path);
1027
1028 /* delete trailing slashs */
1029 pend = str + strlen(str);
1030 while (*--pend == '/') ;
1031 pend[1] = '\0';
1032
1033 res = 0;
1034 DEBUG_PRINTF("%s\n", str);
1035 if (lstat(str, &statfile) >= 0)
1036 res = 1;
1037 if (res)
1038 {
1039 if (pdesc->ro)
1040 {
1041 *type = 1;
1042 }
1043 else
1044 {
1045 *type = 3;
1046 }
1047 return str;
1048 }
1049 }
1050
1051 return NULL;
1052 }
1053
1054 int
funionfs_closepath(struct unionfs_walk * pwalk)1055 funionfs_closepath(struct unionfs_walk *pwalk)
1056 {
1057 if (pwalk != NULL)
1058 {
1059 if (pwalk->str != NULL)
1060 free(pwalk->str);
1061 if (pwalk->path != NULL)
1062 free(pwalk->path);
1063 free(pwalk);
1064 }
1065 return 1;
1066 }
1067