Module Name: src Committed By: jmcneill Date: Sat Nov 25 23:23:39 UTC 2017
Added Files: src/sbin/mount_qemufwcfg: Makefile defs.h fwcfg.c virtdir.c virtdir.h Log Message: Add virtual filesystem for QEMU Firmware Configuration interface. To generate a diff of this commit: cvs rdiff -u -r0 -r1.1 src/sbin/mount_qemufwcfg/Makefile \ src/sbin/mount_qemufwcfg/defs.h src/sbin/mount_qemufwcfg/fwcfg.c \ src/sbin/mount_qemufwcfg/virtdir.c src/sbin/mount_qemufwcfg/virtdir.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Added files: Index: src/sbin/mount_qemufwcfg/Makefile diff -u /dev/null src/sbin/mount_qemufwcfg/Makefile:1.1 --- /dev/null Sat Nov 25 23:23:39 2017 +++ src/sbin/mount_qemufwcfg/Makefile Sat Nov 25 23:23:39 2017 @@ -0,0 +1,12 @@ +# $NetBSD: Makefile,v 1.1 2017/11/25 23:23:39 jmcneill Exp $ + +PROG= mount_qemufwcfg +SRCS= fwcfg.c virtdir.c +DPADD+= ${LIBREFUSE} +LDADD= -lrefuse +NOMAN= # defined +WARNS= 3 + +CPPFLAGS+= -D_KERNTYPES + +.include <bsd.prog.mk> Index: src/sbin/mount_qemufwcfg/defs.h diff -u /dev/null src/sbin/mount_qemufwcfg/defs.h:1.1 --- /dev/null Sat Nov 25 23:23:39 2017 +++ src/sbin/mount_qemufwcfg/defs.h Sat Nov 25 23:23:39 2017 @@ -0,0 +1,88 @@ +/* $NetBSD: defs.h,v 1.1 2017/11/25 23:23:39 jmcneill Exp $ */ + +/* + * Copyright (c) 1999-2005 Alistair Crooks. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef DEFS_H_ +#define DEFS_H_ + +#include <sys/types.h> +#include <sys/param.h> + +#ifdef HAVE_STDINT_H +#include <stdint.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define NEWARRAY(type,ptr,size,where,action) do { \ + if ((ptr = (type *) calloc(sizeof(type), (unsigned)(size))) == NULL) { \ + (void) fprintf(stderr, "%s: can't allocate %lu bytes\n", \ + where, (unsigned long)(size * sizeof(type))); \ + action; \ + } \ +} while( /* CONSTCOND */ 0) + +#define RENEW(type,ptr,size,where,action) do { \ + type *_newptr; \ + if ((_newptr = (type *) realloc(ptr, sizeof(type) * (size))) == NULL) { \ + (void) fprintf(stderr, "%s: can't realloc %lu bytes\n", \ + where, (unsigned long)(size * sizeof(type))); \ + action; \ + } else { \ + ptr = _newptr; \ + } \ +} while( /* CONSTCOND */ 0) + +#define NEW(type, ptr, where, action) NEWARRAY(type, ptr, 1, where, action) + +#define FREE(ptr) (void) free(ptr) + +#define ALLOC(type, v, size, c, init, incr, where, action) do { \ + uint32_t _newsize = size; \ + if (size == 0) { \ + _newsize = init; \ + NEWARRAY(type, v, _newsize, where ": new", action); \ + } else if (c == size) { \ + _newsize = size + incr; \ + RENEW(type, v, _newsize, where ": renew", action); \ + } \ + size = _newsize; \ +} while( /* CONSTCOND */ 0) + +/* (void) memset(&v[size], 0x0, sizeof(type) * incr); \*/ + +#define DEFINE_ARRAY(name, type) \ +typedef struct name { \ + uint32_t c; \ + uint32_t size; \ + type *v; \ +} name + +#endif /* !DEFS_H_ */ Index: src/sbin/mount_qemufwcfg/fwcfg.c diff -u /dev/null src/sbin/mount_qemufwcfg/fwcfg.c:1.1 --- /dev/null Sat Nov 25 23:23:39 2017 +++ src/sbin/mount_qemufwcfg/fwcfg.c Sat Nov 25 23:23:39 2017 @@ -0,0 +1,259 @@ +/* $NetBSD: fwcfg.c,v 1.1 2017/11/25 23:23:39 jmcneill Exp $ */ + +/*- + * Copyright (c) 2017 Jared McNeill <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: fwcfg.c,v 1.1 2017/11/25 23:23:39 jmcneill Exp $"); + +#include <sys/ioctl.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <fuse.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <dev/ic/qemufwcfgio.h> + +#include "virtdir.h" + +#define _PATH_FWCFG "/dev/qemufwcfg" + +struct fwcfg_file { + uint32_t size; + uint16_t select; + uint16_t reserved; + char name[56]; +}; + +static int fwcfg_fd; +static mode_t fwcfg_dir_mask = 0555; +static mode_t fwcfg_file_mask = 0444; +static uid_t fwcfg_uid; +static gid_t fwcfg_gid; + +static virtdir_t fwcfg_virtdir; + +static void +set_index(uint16_t index) +{ + if (ioctl(fwcfg_fd, FWCFGIO_SET_INDEX, &index) != 0) + err(EXIT_FAILURE, "failed to set index 0x%04x", index); +} + +static void +read_data(void *buf, size_t buflen) +{ + if (read(fwcfg_fd, buf, buflen) != (ssize_t)buflen) + err(EXIT_FAILURE, "failed to read data"); +} + +static int +fwcfg_getattr(const char *path, struct stat *st) +{ + virt_dirent_t *ep; + + if (strcmp(path, "/") == 0) { + memset(st, 0, sizeof(*st)); + st->st_mode = S_IFDIR | fwcfg_dir_mask; + st->st_nlink = 2; + return 0; + } + + if ((ep = virtdir_find(&fwcfg_virtdir, path, strlen(path))) == NULL) + return -ENOENT; + + switch (ep->type) { + case 'f': + memcpy(st, &fwcfg_virtdir.file, sizeof(*st)); + st->st_size = ep->tgtlen; + st->st_mode = S_IFREG | fwcfg_file_mask; + break; + case 'd': + memcpy(st, &fwcfg_virtdir.dir, sizeof(*st)); + st->st_mode = S_IFDIR | fwcfg_dir_mask; + break; + } + st->st_ino = virtdir_offset(&fwcfg_virtdir, ep) + 10; + + return 0; +} + +static int +fwcfg_readdir(const char *path, void *buf, fuse_fill_dir_t filler, + off_t offset, struct fuse_file_info *fi) +{ + static VIRTDIR *dirp; + virt_dirent_t *dp; + + if (offset == 0) { + if ((dirp = openvirtdir(&fwcfg_virtdir, path)) == NULL) + return 0; + filler(buf, ".", NULL, 0); + filler(buf, "..", NULL, 0); + } + while ((dp = readvirtdir(dirp)) != NULL) { + if (filler(buf, dp->d_name, NULL, 0) != 0) + return 0; + } + closevirtdir(dirp); + dirp = NULL; + + return 0; +} + +static int +fwcfg_open(const char *path, struct fuse_file_info *fi) +{ + return 0; +} + +static int +fwcfg_read(const char *path, char *buf, size_t size, off_t offset, + struct fuse_file_info *fi) +{ + virt_dirent_t *ep; + uint8_t tmp[64]; + + if ((ep = virtdir_find(&fwcfg_virtdir, path, strlen(path))) == NULL) + return -ENOENT; + + if (ep->select == 0) + return -ENOENT; + + set_index(ep->select); + + /* Seek to correct offset */ + while (offset > 0) { + const int len = MIN(sizeof(tmp), (size_t)offset); + read_data(tmp, len); + offset -= len; + } + + /* Read the data */ + read_data(buf, size); + + return size; +} + +static int +fwcfg_statfs(const char *path, struct statvfs *st) +{ + uint32_t count; + + set_index(FW_CFG_FILE_DIR); + read_data(&count, sizeof(count)); + + memset(st, 0, sizeof(*st)); + st->f_files = be32toh(count); + + return 0; +} + +static struct fuse_operations fwcfg_ops = { + .getattr = fwcfg_getattr, + .readdir = fwcfg_readdir, + .open = fwcfg_open, + .read = fwcfg_read, + .statfs = fwcfg_statfs, +}; + +static void +build_tree(virtdir_t *v) +{ + char path[PATH_MAX]; + struct fwcfg_file f; + uint32_t count, n; + struct stat st; + + memset(&st, 0, sizeof(st)); + st.st_uid = fwcfg_uid; + st.st_gid = fwcfg_gid; + virtdir_init(v, NULL, &st, &st, &st); + +printf("init with uid = %d, gid = %d\n", st.st_uid, st.st_gid); + + set_index(FW_CFG_FILE_DIR); + read_data(&count, sizeof(count)); + for (n = 0; n < be32toh(count); n++) { + read_data(&f, sizeof(f)); + snprintf(path, sizeof(path), "/%s", f.name); + virtdir_add(v, path, strlen(path), 'f', NULL, + be32toh(f.size), be16toh(f.select)); + } +} + +int +main(int argc, char *argv[]) +{ + const char *path = _PATH_FWCFG; + int ch, m; + char *ep; + + fwcfg_uid = geteuid(); + fwcfg_gid = getegid(); + + while ((ch = getopt(argc, argv, "F:g:m:M:u:")) != -1) { + switch (ch) { + case 'F': + path = optarg; + break; + case 'g': + fwcfg_gid = atoi(optarg); + break; + case 'm': + m = strtol(optarg, &ep, 8); + if (optarg == ep || *ep || m < 0) + errx(1, "invalid file mode: %s", optarg); + fwcfg_file_mask = m; + break; + case 'M': + m = strtol(optarg, &ep, 8); + if (optarg == ep || *ep || m < 0) + errx(1, "invalid file mode: %s", optarg); + fwcfg_dir_mask = m; + break; + case 'u': + fwcfg_uid = atoi(optarg); + break; + } + } + + fwcfg_fd = open(path, O_RDWR); + if (fwcfg_fd == -1) + err(EXIT_FAILURE, "failed to open %s", path); + + build_tree(&fwcfg_virtdir); + + for (int i = 0; i < argc; i++) + printf("argv[%d] = \"%s\"\n", i, argv[i]); + + return fuse_main(argc, argv, &fwcfg_ops, NULL); +} Index: src/sbin/mount_qemufwcfg/virtdir.c diff -u /dev/null src/sbin/mount_qemufwcfg/virtdir.c:1.1 --- /dev/null Sat Nov 25 23:23:39 2017 +++ src/sbin/mount_qemufwcfg/virtdir.c Sat Nov 25 23:23:39 2017 @@ -0,0 +1,226 @@ +/* $NetBSD: virtdir.c,v 1.1 2017/11/25 23:23:39 jmcneill Exp $ */ + +/* + * Copyright © 2007 Alistair Crooks. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/stat.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "virtdir.h" +#include "defs.h" + + /* utility comparison routine for sorting and searching */ +static int +compare(const void *vp1, const void *vp2) +{ + const virt_dirent_t *tp1 = (const virt_dirent_t *) vp1; + const virt_dirent_t *tp2 = (const virt_dirent_t *) vp2; + + return strcmp(tp1->name, tp2->name); +} + +/* save `n' chars of `s' in allocated storage */ +static char * +strnsave(const char *s, int n) +{ + char *cp; + + if (n < 0) { + n = strlen(s); + } + NEWARRAY(char, cp, n + 1, "strnsave", return NULL); + (void) memcpy(cp, s, n); + cp[n] = 0x0; + return cp; +} + +/* ensure intermediate directories exist */ +static void +mkdirs(virtdir_t *tp, const char *path, size_t size) +{ + virt_dirent_t *ep; + char name[MAXPATHLEN]; + char *slash; + + (void) strlcpy(name, path, sizeof(name)); + for (slash = name + 1 ; (slash = strchr(slash + 1, '/')) != NULL ; ) { + *slash = 0x0; + if ((ep = virtdir_find(tp, name, strlen(name))) == NULL) { + virtdir_add(tp, name, strlen(name), 'd', NULL, 0, 0); + } + *slash = '/'; + } +} + +/* get rid of multiple slashes in input */ +static int +normalise(const char *name, size_t namelen, char *path, size_t pathsize) +{ + const char *np; + char *pp; + int done; + + for (pp = path, np = name, done = 0 ; !done && (int)(pp - path) < pathsize - 1 && (int)(np - name) <= namelen ; ) { + switch(*np) { + case '/': + if (pp == path || *(pp - 1) != '/') { + *pp++ = *np; + } + np += 1; + break; + case 0x0: + done = 1; + break; + default: + *pp++ = *np++; + break; + } + } + /* XXX - trailing slash? */ + *pp = 0x0; + return (int)(pp - path); +} + +/* initialise the tree */ +int +virtdir_init(virtdir_t *tp, const char *rootdir, struct stat *d, struct stat *f, struct stat *l) +{ + (void) memcpy(&tp->dir, d, sizeof(tp->dir)); + tp->dir.st_mode = S_IFDIR | 0755; + tp->dir.st_nlink = 2; + (void) memcpy(&tp->file, f, sizeof(tp->file)); + tp->file.st_mode = S_IFREG | 0644; + tp->file.st_nlink = 1; + (void) memcpy(&tp->lnk, l, sizeof(tp->lnk)); + tp->lnk.st_mode = S_IFLNK | 0644; + tp->lnk.st_nlink = 1; + if (rootdir != NULL) { + tp->rootdir = strdup(rootdir); + } + return 1; +} + +/* add an entry to the tree */ +int +virtdir_add(virtdir_t *tp, const char *name, size_t size, uint8_t type, const char *tgt, size_t tgtlen, uint16_t select) +{ + char path[MAXPATHLEN]; + int pathlen; + + pathlen = normalise(name, size, path, sizeof(path)); + if (virtdir_find(tp, path, pathlen) != NULL) { + /* attempt to add a duplicate directory entry */ + return 0; + } + ALLOC(virt_dirent_t, tp->v, tp->size, tp->c, 10, 10, "virtdir_add", + return 0); + tp->v[tp->c].namelen = pathlen; + if ((tp->v[tp->c].name = strnsave(path, pathlen)) == NULL) { + return 0; + } + tp->v[tp->c].d_name = strrchr(tp->v[tp->c].name, '/') + 1; + tp->v[tp->c].type = type; + tp->v[tp->c].ino = (ino_t) random() & 0xfffff; + tp->v[tp->c].tgtlen = tgtlen; + if (tgt != NULL) { + tp->v[tp->c].tgt = strnsave(tgt, tgtlen); + } + tp->v[tp->c].select = select; + tp->c += 1; + qsort(tp->v, tp->c, sizeof(tp->v[0]), compare); + mkdirs(tp, path, pathlen); + return 1; +} + +/* find an entry in the tree */ +virt_dirent_t * +virtdir_find(virtdir_t *tp, const char *name, size_t namelen) +{ + virt_dirent_t e; + char path[MAXPATHLEN]; + + (void) memset(&e, 0x0, sizeof(e)); + e.namelen = normalise(name, namelen, path, sizeof(path)); + e.name = path; + return bsearch(&e, tp->v, tp->c, sizeof(tp->v[0]), compare); +} + +/* return the virtual offset in the tree */ +int +virtdir_offset(virtdir_t *tp, virt_dirent_t *dp) +{ + return (int)(dp - tp->v); +} + +/* analogous to opendir(3) - open a directory, save information, and +* return a pointer to the dynamically allocated structure */ +VIRTDIR * +openvirtdir(virtdir_t *tp, const char *d) +{ + VIRTDIR *dirp; + + NEW(VIRTDIR, dirp, "openvirtdir", exit(EXIT_FAILURE)); + dirp->dirname = strdup(d); + dirp->dirnamelen = strlen(d); + dirp->tp = tp; + dirp->i = 0; + return dirp; +} + +/* analogous to readdir(3) - read the next entry in the directory that +* was opened, and return a pointer to it */ +virt_dirent_t * +readvirtdir(VIRTDIR *dirp) +{ + char *from; + + for ( ; dirp->i < dirp->tp->c ; dirp->i++) { + from = (strcmp(dirp->dirname, "/") == 0) ? + &dirp->tp->v[dirp->i].name[1] : + &dirp->tp->v[dirp->i].name[dirp->dirnamelen + 1]; + if (strncmp(dirp->tp->v[dirp->i].name, dirp->dirname, + dirp->dirnamelen) == 0 && + *from != 0x0 && + strchr(from, '/') == NULL) { + return &dirp->tp->v[dirp->i++]; + } + } + return NULL; +} + +/* free the storage associated with the virtual directory structure */ +void +closevirtdir(VIRTDIR *dirp) +{ + free(dirp->dirname); + FREE(dirp); +} Index: src/sbin/mount_qemufwcfg/virtdir.h diff -u /dev/null src/sbin/mount_qemufwcfg/virtdir.h:1.1 --- /dev/null Sat Nov 25 23:23:39 2017 +++ src/sbin/mount_qemufwcfg/virtdir.h Sat Nov 25 23:23:39 2017 @@ -0,0 +1,81 @@ +/* $NetBSD: virtdir.h,v 1.1 2017/11/25 23:23:39 jmcneill Exp $ */ + +/* + * Copyright © 2007 Alistair Crooks. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef VIRTDIR_H_ +#define VIRTDIR_H_ 20070405 + +#include <sys/types.h> +#include <sys/stat.h> + +#include "defs.h" + +/* this struct keeps a note of all the info related to a virtual directory entry */ +typedef struct virt_dirent_t { + char *name; /* entry name - used as key */ + size_t namelen; /* length of name */ + char *d_name; /* component in this directory */ + char *tgt; /* any symlink target */ + size_t tgtlen; /* length of symlink target */ + uint8_t type; /* entry type - file, dir, lnk */ + ino_t ino; /* inode number */ + uint16_t select; /* selector */ +} virt_dirent_t; + +/* this defines the list of virtual directory entries, + sorted in name alpha order */ +typedef struct virtdir_t { + uint32_t c; /* count of entries */ + uint32_t size; /* size of allocated list */ + virt_dirent_t *v; /* list */ + char *rootdir; /* root directory of virtual fs */ + struct stat file; /* stat struct for file entries */ + struct stat dir; /* stat struct for dir entries */ + struct stat lnk; /* stat struct for symlinks */ +} virtdir_t; + +/* this struct is used to walk through directories */ +typedef struct VIRTDIR { + char *dirname; /* directory name */ + int dirnamelen; /* length of directory name */ + virtdir_t *tp; /* the directory tree */ + int i; /* current offset in dir tree */ +} VIRTDIR; + +int virtdir_init(virtdir_t *, const char *, struct stat *, struct stat *, struct stat *); +int virtdir_add(virtdir_t *, const char *, size_t, uint8_t, const char *, size_t, uint16_t); +virt_dirent_t *virtdir_find(virtdir_t *, const char *, size_t); + +VIRTDIR *openvirtdir(virtdir_t *, const char *); +virt_dirent_t *readvirtdir(VIRTDIR *); +void closevirtdir(VIRTDIR *); + +int virtdir_offset(virtdir_t *, virt_dirent_t *); + +#endif