1 /*
2  * This software is licensed under the terms of the MIT License.
3  * See COPYING for further information.
4  * ---
5  * Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
6  * Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
7  */
8 
9 #include "taisei.h"
10 
11 #include "syspath.h"
12 #include "readonly_wrapper.h"
13 
striptrailing(char * p,char ** pend)14 static void striptrailing(char *p, char **pend) {
15 	while(*pend > p && strchr(vfs_syspath_separators, *(*pend - 1))) {
16 		*--*pend = 0;
17 	}
18 }
19 
stripname(char * p,char ** pend)20 static void stripname(char *p, char **pend) {
21 	striptrailing(p, pend);
22 	while(*pend > p && !strchr(vfs_syspath_separators, *(*pend - 1))) {
23 		*--*pend = 0;
24 	}
25 	striptrailing(p, pend);
26 }
27 
mkdir_with_parents(VFSNode * n,const char * fspath)28 static bool mkdir_with_parents(VFSNode *n, const char *fspath) {
29 	if(vfs_node_mkdir(n, NULL)) {
30 		return true;
31 	}
32 
33 	char p[strlen(fspath) + 1];
34 	char *pend = p + sizeof(p) - 1;
35 
36 	memcpy(p, fspath, sizeof(p));
37 	stripname(p, &pend);
38 
39 	if(p == pend) {
40 		return false;
41 	}
42 
43 	VFSNode *pnode = vfs_alloc();
44 	if(!vfs_syspath_init(pnode, p)) {
45 		vfs_decref(pnode);
46 		return false;
47 	}
48 
49 	bool ok = mkdir_with_parents(pnode, p);
50 	vfs_decref(pnode);
51 	return ok && vfs_node_mkdir(n, NULL);
52 }
53 
vfs_mount_syspath(const char * mountpoint,const char * fspath,uint flags)54 bool vfs_mount_syspath(const char *mountpoint, const char *fspath, uint flags) {
55 	VFSNode *rdir = vfs_alloc();
56 
57 	if(!vfs_syspath_init(rdir, fspath)) {
58 		vfs_set_error("Can't initialize path: %s", vfs_get_error());
59 		vfs_decref(rdir);
60 		return false;
61 	}
62 
63 	if((flags & VFS_SYSPATH_MOUNT_MKDIR) && !mkdir_with_parents(rdir, fspath)) {
64 		vfs_set_error("Can't create directory: %s", vfs_get_error());
65 		vfs_decref(rdir);
66 		return false;
67 	}
68 
69 	if(flags & VFS_SYSPATH_MOUNT_READONLY) {
70 		VFSNode *rdir_ro = vfs_ro_wrap(rdir);
71 		vfs_decref(rdir);
72 		rdir = rdir_ro;
73 	}
74 
75 	return vfs_mount_or_decref(vfs_root, mountpoint, rdir);
76 }
77 
vfs_get_syspath_separator(void)78 char vfs_get_syspath_separator(void) {
79 	return vfs_syspath_separators[0];
80 }
81