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