ref: 0ad44955a094502fa3bf9a5cef637bc62072f91c
dir: /files.c/
#include <u.h>
#include <libc.h>
#include "dat.h"
#include "fns.h"
VFile *files = nil;
static char**
parsepath(char *path)
{
char **args;
char *s;
int numparts = 1, n;
/* root element: / */
if (path[1] == 0) {
args = mallocz(1, 1);
args[0] = nil;
return args;
}
for (s = path; *s; s++) {
if (*s == '/')
numparts++;
}
/* root dir, each directory part, ending nil */
args = mallocz(numparts+1, 1);
args[numparts] = nil;
s = strdup(path);
n = getfields(s, args, numparts, 0, "/");
assert(s == args[0]);
if (n == numparts)
return args;
free(args);
free(s);
werrstr("invalid path");
return nil;
}
static int
verifyfiles(char **parts)
{
VFile *vf;
char buf[64];
char *s;
char **a;
int i, numparts = 0;
for (a = parts; *a; a++)
numparts++;
s = buf;
*s = '/';
s++;
for (i = 1; i < numparts - 1; i++) {
strcpy(s, parts[i]);
vf = addfile(buf);
if (!vf)
return 0;
vf->isdir = 1;
s += strlen(parts[i]);
*s = '/';
s++;
}
return 1;
}
VFile*
addfile(char *path)
{
VFile *old, *new;
old = getfile(path);
if (old)
return old;
if (!files) {
files = mallocz(sizeof(VFile), 1);
files->isdir = 1;
files->path = strdup("/");
files->parts = parsepath(files->path);
}
old = files;
files = mallocz(sizeof(VFile), 1);
files->next = old;
/* verifyfiles may add new files, thus changing the global files pointer */
new = files;
new->path = strdup(path);
new->parts = parsepath(path);
if (!new->parts)
return nil;
if (!verifyfiles(new->parts))
return nil;
return new;
}
VFile*
getfile(char *path)
{
VFile *v;
for (v = files; v; v = v->next)
if (strcmp(v->path, path) == 0)
return v;
werrstr("file not found: %s", path);
return nil;
}
void
foreachfile(void (*f)(VFile*,void*), void *aux)
{
VFile *vf;
for (vf = files; vf; vf = vf->next)
f(vf, aux);
}
int
getnfiles()
{
int n = 0;
VFile *v;
for (v = files; v; v = v->next)
n++;
return n;
}
static int
Vfmt(Fmt *f)
{
VFile *v;
v = va_arg(f->args, VFile*);
return fmtprint(f, "%s (%s%s%s)", v->path,
v->isdir ? "D," : "",
v->hasread ? "R," : "",
v->haswrite ? "W" : ""
);
}
void
vfileinit()
{
fmtinstall('V', Vfmt);
}