Add virtual filesystem for QEMU Firmware Configuration interface.
This commit is contained in:
parent
40017b1be4
commit
c91601382a
|
@ -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>
|
|
@ -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_ */
|
|
@ -0,0 +1,259 @@
|
|||
/* $NetBSD: fwcfg.c,v 1.1 2017/11/25 23:23:39 jmcneill Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2017 Jared McNeill <jmcneill@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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue