virtdir.c revision 1.2 1 /* $NetBSD: virtdir.c,v 1.2 2017/11/26 03:06:24 christos Exp $ */
2
3 /*
4 * Copyright 2007 Alistair Crooks. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote
15 * products derived from this software without specific prior written
16 * permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
24 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/stat.h>
34
35 #include <stdio.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <util.h>
40
41 #include "virtdir.h"
42
43 /* utility comparison routine for sorting and searching */
44 static int
45 compare(const void *vp1, const void *vp2)
46 {
47 const virt_dirent_t *tp1 = (const virt_dirent_t *) vp1;
48 const virt_dirent_t *tp2 = (const virt_dirent_t *) vp2;
49
50 return strcmp(tp1->name, tp2->name);
51 }
52
53 /* ensure intermediate directories exist */
54 static void
55 mkdirs(virtdir_t *tp, const char *path, size_t size)
56 {
57 virt_dirent_t *ep;
58 char name[MAXPATHLEN];
59 char *slash;
60
61 (void) strlcpy(name, path, sizeof(name));
62 for (slash = name + 1 ; (slash = strchr(slash + 1, '/')) != NULL ; ) {
63 *slash = 0x0;
64 if ((ep = virtdir_find(tp, name, strlen(name))) == NULL) {
65 virtdir_add(tp, name, strlen(name), 'd', NULL, 0, 0);
66 }
67 *slash = '/';
68 }
69 }
70
71 /* get rid of multiple slashes in input */
72 static size_t
73 normalise(const char *name, size_t namelen, char *path, size_t pathsize)
74 {
75 const char *np;
76 char *pp;
77 int done;
78
79 for (pp = path, np = name, done = 0 ; !done &&
80 (size_t)(pp - path) < pathsize - 1 &&
81 (size_t)(np - name) <= namelen; ) {
82 switch (*np) {
83 case '/':
84 if (pp == path || *(pp - 1) != '/') {
85 *pp++ = *np;
86 }
87 np += 1;
88 break;
89 case '\0':
90 done = 1;
91 break;
92 default:
93 *pp++ = *np++;
94 break;
95 }
96 }
97 /* XXX - trailing slash? */
98 *pp = '\0';
99 return (size_t)(pp - path);
100 }
101
102 /* initialise the tree */
103 int
104 virtdir_init(virtdir_t *tp, const char *rootdir, struct stat *d, struct stat *f, struct stat *l)
105 {
106 tp->dir = *d;
107 tp->dir.st_mode = S_IFDIR | 0755;
108 tp->dir.st_nlink = 2;
109 tp->file = *f;
110 tp->file.st_mode = S_IFREG | 0644;
111 tp->file.st_nlink = 1;
112 tp->lnk = *l;
113 tp->lnk.st_mode = S_IFLNK | 0644;
114 tp->lnk.st_nlink = 1;
115 if (rootdir != NULL) {
116 tp->rootdir = estrdup(rootdir);
117 }
118 return 1;
119 }
120
121 /* add an entry to the tree */
122 int
123 virtdir_add(virtdir_t *tp, const char *name, size_t size, uint8_t type, const char *tgt, size_t tgtlen, uint16_t select)
124 {
125 char path[MAXPATHLEN];
126 size_t pathlen;
127
128 pathlen = normalise(name, size, path, sizeof(path));
129 if (virtdir_find(tp, path, pathlen) != NULL) {
130 /* attempt to add a duplicate directory entry */
131 return 0;
132 }
133 if (tp->c == tp->size || tp->size == 0) {
134 tp->size += 10,
135 tp->v = erealloc(tp->v, tp->size * sizeof(*tp->v));
136 }
137 tp->v[tp->c].namelen = pathlen;
138 if ((tp->v[tp->c].name = estrndup(path, pathlen)) == NULL) {
139 return 0;
140 }
141 tp->v[tp->c].d_name = strrchr(tp->v[tp->c].name, '/') + 1;
142 tp->v[tp->c].type = type;
143 tp->v[tp->c].ino = (ino_t) random() & 0xfffff;
144 tp->v[tp->c].tgtlen = tgtlen;
145 if (tgt != NULL) {
146 tp->v[tp->c].tgt = estrndup(tgt, tgtlen);
147 }
148 tp->v[tp->c].select = select;
149 tp->c += 1;
150 qsort(tp->v, tp->c, sizeof(tp->v[0]), compare);
151 mkdirs(tp, path, pathlen);
152 return 1;
153 }
154
155 /* find an entry in the tree */
156 virt_dirent_t *
157 virtdir_find(virtdir_t *tp, const char *name, size_t namelen)
158 {
159 virt_dirent_t e;
160 char path[MAXPATHLEN];
161
162 (void) memset(&e, 0x0, sizeof(e));
163 e.namelen = normalise(name, namelen, path, sizeof(path));
164 e.name = path;
165 return bsearch(&e, tp->v, tp->c, sizeof(tp->v[0]), compare);
166 }
167
168 /* return the virtual offset in the tree */
169 off_t
170 virtdir_offset(virtdir_t *tp, virt_dirent_t *dp)
171 {
172 return dp - tp->v;
173 }
174
175 /* analogous to opendir(3) - open a directory, save information, and
176 * return a pointer to the dynamically allocated structure */
177 VIRTDIR *
178 openvirtdir(virtdir_t *tp, const char *d)
179 {
180 VIRTDIR *dirp;
181
182 dirp = emalloc(sizeof(*dirp));
183 dirp->dirname = estrdup(d);
184 dirp->dirnamelen = strlen(d);
185 dirp->tp = tp;
186 dirp->i = 0;
187 return dirp;
188 }
189
190 /* analogous to readdir(3) - read the next entry in the directory that
191 * was opened, and return a pointer to it */
192 virt_dirent_t *
193 readvirtdir(VIRTDIR *dirp)
194 {
195 char *from;
196
197 for ( ; dirp->i < dirp->tp->c ; dirp->i++) {
198 from = (strcmp(dirp->dirname, "/") == 0) ?
199 &dirp->tp->v[dirp->i].name[1] :
200 &dirp->tp->v[dirp->i].name[dirp->dirnamelen + 1];
201 if (strncmp(dirp->tp->v[dirp->i].name, dirp->dirname,
202 dirp->dirnamelen) == 0 &&
203 *from != '\0' && strchr(from, '/') == NULL) {
204 return &dirp->tp->v[dirp->i++];
205 }
206 }
207 return NULL;
208 }
209
210 /* free the storage associated with the virtual directory structure */
211 void
212 closevirtdir(VIRTDIR *dirp)
213 {
214 free(dirp->dirname);
215 free(dirp);
216 }
217