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 <[email protected]>
+ * 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