Add routines to manipulate virtual directory entries, for use with

librefuse-based file systems.

These are especially useful for file systems which present virtual
directory hierarchies to the caller.

The routines build up and manage an array of virtual directory
entries, indexed upon full pathname within the file system.  This is
analogous to the way refuse indexes its own entries.  Routines are
available to add, delete, and find entries.  Each entry can be one of
3 types - file ('f'), directory ('d') or symbolic link ('l').  Each
entry can also be associated with a target, which is a character
string allocated upon addition.  This can be useful for virtual
directory entries of the symbolic link type.

The virtual directory entries can be traversed as an ordered list
(the entries are ordered alphabetically), or can be accessed by
directory component, using routines analogous to opendir(3), readdir(3),
and closedir(3).
This commit is contained in:
agc 2007-04-15 15:10:56 +00:00
parent 6997fa5f35
commit 777436c8cf
5 changed files with 550 additions and 0 deletions

View File

@ -0,0 +1,7 @@
PROG=v
SRCS=virtdir.c
CPPFLAGS+= -DVIRTDIR_DEBUG
WARNS=4
MAN=virtdir.3
.include <bsd.prog.mk>

View File

@ -0,0 +1,88 @@
/* $NetBSD: defs.h,v 1.1 2007/04/15 15:10:57 agc 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_ */

View File

@ -0,0 +1,126 @@
.\" $NetBSD: virtdir.3,v 1.1 2007/04/15 15:10:57 agc 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.
.\"
.Dd January 23, 2007
.Dt VIRTDIR 3
.Os
.Sh NAME
.Nm virtdir
.Nd Utility routines for virtual directories for refuse operations
.Sh SYNOPSIS
.In virtdir.h
.Ft int
.Fo virtdir_init
.Fa "virtdir_t *tree" "struct stat *dir" "struct stat *file" "struct stat *symlink"
.Fc
.Ft int
.Fo virtdir_add
.Fa "virtdir_t *tree" "const char *name" "size_t namesize" "uint8_t type" "char *target"
.Fc
.Ft int
.Fo virtdir_del
.Fa "virtdir_t *tree" "const char *name" "size_t namesize"
.Fc
.Ft int
.Fo virtdir_find
.Fa "virtdir_t *tree" "const char *name" "size_t namesize"
.Fc
.Ft int
.Fo virtdir_find_tgt
.Fa "virtdir_t *tree" "const char *name" "size_t namesize"
.Fc
.Ft void
.Fo virtdir_drop
.Fa "virtdir_t *tree"
.Fc
.Ft VIRTDIR *
.Fo openvirtdir
.Fa "virtdir_t *tree" "const char *directory"
.Fc
.Ft virt_dirent_t *
.Fo readvirtdir
.Fa "VIRTDIR *dirp"
.Fc
.Ft void
.Fo closevirtdir
.Fa "VIRTDIR *dirp"
.Fc
.Sh DESCRIPTION
.Nm
provides virtual directory functionality for the benefit of
.Xr librefuse 3
file systems (and also for FUSE-based file systems).
.Pp
It uses the framework provided by the
.Xr puffs 3
subsystem, and, through that, the kernel interface provided by
.Xr puffs 4 .
.Pp
The
.Nm
routines build up and manage a list of virtual directory entries.
Each virtual directory entry is indexed by its full pathname within
the file system.
This is consistent with the way that
.Xr librefuse 3
locates directory entries - by full pathname.
.Pp
The list of paths is sorted alphabetically.
Each of these virtual directory entries has a distinct type -
file ('f'), directory ('d') or symbolic link ('l').
Additionally, an entry can point to a target - this
is useful when modelling virtual directory entries which are
symbolic links.
The list contains three basic
.Xr stat 2
structures, which contain basic information for file, directory
and symbolic link entries. This information can be specified at
initialisation time, and customised within the individual
getattr operation routines as specified by the
individual file systems.
The
.Nm
functionality can also make virtual directory entries available
on a per-directory basis
to the caller by means of routines analogous to
.Xr opendir 3 ,
.Xr readdir 3 and
.Xr closedir 3 .
These are
openvirtdir, readvirtdir and closevirtdir, respectively.
.Sh SEE ALSO
.Xr librefuse 3 ,
.Xr puffs 3 ,
.Xr puffs 4
.Sh HISTORY
An unsupported experimental version of
.Nm
first appeared in
.Nx 5.0 .
.Sh AUTHOR
.An Alistair Crooks Aq agc@NetBSD.org

View File

@ -0,0 +1,251 @@
/*
* 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 <fuse.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;
}
/* initialise the tree */
int
virtdir_init(virtdir_t *tp, 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;
return 1;
}
/* add an entry to the tree */
int
virtdir_add(virtdir_t *tp, const char *name, size_t size, uint8_t type, char *tgt)
{
struct stat st;
if (tp->v == NULL) {
(void) stat(".", &st);
virtdir_init(tp, &st, &st, &st);
}
ALLOC(virt_dirent_t, tp->v, tp->size, tp->c, 10, 10, "virtdir_add",
return 0);
tp->v[tp->c].namelen = size;
if ((tp->v[tp->c].name = strnsave(name, size)) == NULL) {
return 0;
}
tp->v[tp->c].d_name = strrchr(tp->v[tp->c].name, '/') + 1;
tp->v[tp->c].type = type;
if (tgt != NULL) {
tp->v[tp->c].tgt = strdup(tgt);
tp->v[tp->c].tgtlen = strlen(tgt);
}
tp->c += 1;
qsort(tp->v, tp->c, sizeof(tp->v[0]), compare);
return 1;
}
/* add an entry to the tree */
int
virtdir_del(virtdir_t *tp, const char *name, size_t size)
{
virt_dirent_t *ep;
int i;
if ((ep = virtdir_find(tp, name, size)) == NULL) {
return 0;
}
i = (int)(ep - tp->v) / sizeof(tp->v[0]);
for (tp->c -= 1 ; i < tp->c ; i++) {
tp->v[i] = tp->v[i + 1];
}
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;
(void) memset(&e, 0x0, sizeof(e));
e.name = __UNCONST(name);
e.namelen = namelen;
return bsearch(&e, tp->v, tp->c, sizeof(tp->v[0]), compare);
}
/* 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 &&
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);
}
/* find a target in the tree -- not quick! */
virt_dirent_t *
virtdir_find_tgt(virtdir_t *tp, const char *tgt, size_t tgtlen)
{
/* we don't need no stinking binary searches */
int i;
for (i = 0 ; i < tp->c ; i++) {
if (tp->v[i].tgt && strcmp(tp->v[i].tgt, tgt) == 0) {
return &tp->v[i];
}
}
return NULL;
}
/* kill all of the space allocated to the tree */
void
virtdir_drop(virtdir_t *tp)
{
int i;
for (i = 0 ; i < tp->c ; i++) {
FREE(tp->v[i].name);
if (tp->v[i].tgt) {
FREE(tp->v[i].tgt);
}
}
FREE(tp->v);
}
#ifdef VIRTDIR_DEBUG
static void
ptree(virtdir_t * tp)
{
int i;
for (i = 0 ; i < tp->c ; i++) {
printf("%s, tgt %s\n", tp->v[i].name, tp->v[i].tgt);
}
}
#endif
#ifdef VIRTDIR_DEBUG
int
main(int argc, char **argv)
{
virt_dirent_t *tp;
virtdir_t t;
struct stat st;
(void) memset(&t, 0x0, sizeof(t));
stat(".", &st);
virtdir_add(&t, ".", 1, 'd', NULL);
stat("..", &st);
virtdir_add(&t, "..", 2, 'd', NULL);
st.st_mode = S_IFREG | 0644;
virtdir_add(&t, "file1", 5, 'f', NULL);
ptree(&t);
virtdir_add(&t, "file2", 5, 'f', NULL);
virtdir_add(&t, "file0", 5, 'f', NULL);
virtdir_add(&t, "abcde", 5, 'f', NULL);
virtdir_add(&t, "bcdef", 5, 'f', NULL);
virtdir_add(&t, "a", 1, 'f', NULL);
ptree(&t);
if ((tp = virtdir_find(&t, "a", 1)) == NULL) {
printf("borked2\n");
} else {
printf("a found\n");
}
virtdir_drop(&t);
exit(EXIT_SUCCESS);
}
#endif

View File

@ -0,0 +1,78 @@
/*
* 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 FUSE_TREE_H_
#define FUSE_TREE_H_ 20070405
#include <sys/types.h>
#include <sys/stat.h>
#include <fuse.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 */
} 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 */
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 *, struct stat *, struct stat *, struct stat *);
int virtdir_add(virtdir_t *, const char *, size_t, uint8_t, char *);
int virtdir_del(virtdir_t *, const char *, size_t);
virt_dirent_t *virtdir_find(virtdir_t *, const char *, size_t);
virt_dirent_t *virtdir_find_tgt(virtdir_t *, const char *, size_t);
void virtdir_drop(virtdir_t *);
VIRTDIR *openvirtdir(virtdir_t *, const char *);
virt_dirent_t *readvirtdir(VIRTDIR *);
void closevirtdir(VIRTDIR *);
#endif