1/* $NetBSD: virtdir.c,v 1.3 2017/11/26 03:51:45 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 */ 44static int 45compare(const void *vp1, const void *vp2) 46{ 47 const virt_dirent_t *tp1 = vp1; 48 const virt_dirent_t *tp2 = vp2; 49 50 return strcmp(tp1->name, tp2->name); 51} 52 53/* ensure intermediate directories exist */ 54static void 55mkdirs(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 = '\0'; 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 */ 72static size_t 73normalise(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 */ 103int 104virtdir_init(virtdir_t *tp, const char *rootdir, const struct stat *d, 105 const struct stat *f, const struct stat *l) 106{ 107 tp->dir = *d; 108 tp->dir.st_mode = S_IFDIR | 0755; 109 tp->dir.st_nlink = 2; 110 tp->file = *f; 111 tp->file.st_mode = S_IFREG | 0644; 112 tp->file.st_nlink = 1; 113 tp->lnk = *l; 114 tp->lnk.st_mode = S_IFLNK | 0644; 115 tp->lnk.st_nlink = 1; 116 if (rootdir != NULL) { 117 tp->rootdir = estrdup(rootdir); 118 } 119 return 1; 120} 121 122/* add an entry to the tree */ 123int 124virtdir_add(virtdir_t *tp, const char *name, size_t size, uint8_t type, 125 const char *tgt, size_t tgtlen, uint16_t select) 126{ 127 char path[MAXPATHLEN]; 128 size_t pathlen; 129 130 pathlen = normalise(name, size, path, sizeof(path)); 131 if (virtdir_find(tp, path, pathlen) != NULL) { 132 /* attempt to add a duplicate directory entry */ 133 return 0; 134 } 135 if (tp->c == tp->size || tp->size == 0) { 136 tp->size += 10; 137 tp->v = erealloc(tp->v, tp->size * sizeof(*tp->v)); 138 } 139 tp->v[tp->c].namelen = pathlen; 140 tp->v[tp->c].name = estrndup(path, pathlen); 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 */ 156virt_dirent_t * 157virtdir_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, 0, 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 */ 169off_t 170virtdir_offset(const virtdir_t *tp, const 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 */ 177VIRTDIR * 178openvirtdir(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 */ 192virt_dirent_t * 193readvirtdir(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 */ 211void 212closevirtdir(VIRTDIR *dirp) 213{ 214 free(dirp->dirname); 215 free(dirp); 216} 217