blob: 2dfbe8d221fb622524fca00fe995f96058bacd88 [file] [log] [blame]
//#define DEBUG
#include <vfs.h>
#include <kfs.h>
#include <slab.h>
#include <kmalloc.h>
#include <kref.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <error.h>
#include <cpio.h>
#include <pmap.h>
#include <smp.h>
#include <kmalloc.h>
enum {
Qdir = 0,
Nfilesperdirtab = 128,
Nfiles = 16384,
};
struct dirlist {
struct dirtab *me, *dot, *dotdot;
int ndir;
int mdir;
uint8_t *data;
};
static int nextdirent = 1;
static struct dirtab rootdir[Nfilesperdirtab] = {
{"#/", {Qdir, 0, QTDIR}, 0, DMDIR | 0555},
};
/* statically allocate all the dirlist structs.
* dynamically allocate dirtabs. Memory is cheap,
* let's be cache friendly when we can.
*/
static struct dirlist all[Nfiles] = {
{&rootdir[0], &rootdir[0], &rootdir[0], 1, Nfilesperdirtab, NULL},
};
static struct dirlist *rootlist = &all[0];
/*
* add a file to the list
*/
static int
addlist(struct dirlist *l, char *name, uint8_t * contents, uint32_t len,
int perm)
{
struct dirtab *dot = l->dot;
struct dirtab *me;
struct dirlist *newl;
int mydirent;
int newtype = 0;
if (nextdirent >= Nfiles)
panic("Too many files; max %d\n", Nfiles);
if (l->ndir >= l->mdir)
return -1;
mydirent = nextdirent++;
/* TODO: next dirent should be a kref_t */
newl = &all[mydirent];
newl->data = contents;
me = &dot[l->ndir];
if (perm & DMDIR) {
newl->me = kmalloc(sizeof(struct dirtab)*Nfilesperdirtab,KMALLOC_WAIT);
newl->dot = newl->me;
newl->ndir = 1; /* me */
newtype = QTDIR;
newl->dot[0].qid.type = QTDIR;
newl->dot[0].qid.vers = 0;
newl->dot[0].qid.path = mydirent;
newl->dot[0].name[0] = '.';
perm |= DMDIR;
newl->dot[0].perm = perm;
newl->mdir = Nfilesperdirtab;
} else {
newl->dot = l->dot;
newl->me = me;
newl->dotdot = l->dotdot;
}
l->ndir++;
strncpy(me->name, name, sizeof(me->name));
me->length = len;
me->perm = perm;
me->qid.type = newtype;
me->qid.vers = 0;
me->qid.path = mydirent;
printd("Added %s, path %d\n", name, me->qid.path);
return me->qid.path;
}
/*
* add a file
*/
int addfile(struct dirlist *d, char *name, uint8_t * contents, uint32_t len)
{
return addlist(d, name, contents, len, 0666);
}
/*
* add a root directory
*/
static int addrootdir(char *name)
{
return addlist(rootlist, name, NULL, 0, DMDIR | 0555);
}
static void rootreset(void)
{
addrootdir("bin");
addrootdir("lib");
addrootdir("dev");
addrootdir("env");
addrootdir("fd");
addrootdir("mnt");
addrootdir("net");
addrootdir("net.alt");
addrootdir("proc");
addrootdir("root");
addrootdir("srv");
addrootdir("tmp");
}
static struct chan *rootattach(char *spec)
{
return devattach('r', spec);
}
static int
rootgen(struct chan *c, char *name, struct dirtab *unused_d, int unused_i,
int s, struct dir *dp)
{
int t;
struct dirtab *d;
struct dirlist *l = &all[(int)c->qid.path];
printd("rootgen: l %p %d\n", l,(int)c->qid.path);
/* for directories, set c->aux to devlist, for later use in create() */
printd("rootgen: s %d, DEVDOTDOT %d\n", s, DEVDOTDOT);
if (s == DEVDOTDOT){
/* TODO: path */
devdir(c, l->dotdot->qid, l->me->name, 0, eve, 0555, dp);
return 1;
}
if (c->qid.type & QTDIR){
printd("devgen dir c %p l %p name %s ndir %d\n", c, l, name, l->ndir);
return devgen(c, name, l->me, l->ndir, s, dp);
}
t = c->qid.path;
printd("rootgen: path %d\n", t);
d = l->me;
printd("rootgen: devdir %s\n", name);
devdir(c, d->qid, d->name, d->length, eve, d->perm, dp);
return 1;
}
static struct walkqid *rootwalk(struct chan *c, struct chan *nc, char **name,
int nname)
{
struct walkqid *ret;
ret = devwalk(c, nc, name, nname, NULL, 0, rootgen);
printd("rootwalk c %p c->aux %p \n", c, c ? c->aux : NULL);
return ret;
}
static long rootstat(struct chan *c, uint8_t * dp, long n)
{
return devstat(c, dp, n, NULL, 0, rootgen);
}
static void rootcreate(struct chan *c, char *name, int omode, int perm)
{
int path;
struct dirlist *l;
if (c->qid.type != QTDIR)
error(Eperm);
if (strlen(name) > MAX_PATH_LEN)
error("name too long");
if (omode & DMDIR)
error("no dir creation yet");
l = &all[(int)c->qid.path];
omode = openmode(omode);
/* let's hope somebody checked to see if it existed yet. */
path = addfile(l, name, NULL, 0);
memset(&c->qid, 0, sizeof(c->qid));
c->qid.path = path;
c->offset = 0;
c->mode = omode;
c->flag |= COPEN;
}
static struct chan *rootopen(struct chan *c, int omode)
{
return devopen(c, omode, NULL, 0, devgen);
}
/*
* sysremove() knows this is a nop
*/
static void rootclose(struct chan *c)
{
}
static long rootread(struct chan *c, void *buf, long n, int64_t off)
{
uint32_t t;
struct dirtab *d;
struct dirlist *l;
uint8_t *data;
uint32_t offset = off;
t = c->qid.path;
l = &all[t];
if (c->qid.type & QTDIR){
return devdirread(c, buf, n, NULL, 0, rootgen);
}
d = l->me;
t--;
data = l->data;
if (offset >= d->length)
return 0;
if (offset + n > d->length)
n = d->length - offset;
memmove(buf, data + offset, n);
return n;
}
static long rootwrite(struct chan *c, void *v, long len, int64_t o)
{
uint32_t t;
struct dirtab *d;
struct dirlist *l;
uint8_t *data;
t = c->qid.path;
l = &all[t];
if (c->qid.type & QTDIR){
error(Eisdir);
return -1;
}
d = l->me;
data = l->data;
if (o < 0)
o = d->length;
if ((o + len) > d->length) {
void *newdata = kmalloc(o + len, KMALLOC_WAIT);
l->data = newdata;
memmove(newdata, data, d->length);
kfree(data);
data = newdata;
}
printd("rootwrite @ %lld, %d bytes\n", o, len);
memmove(data + o, v, len);
d->length = o + len;
return len;
}
struct dev rootdevtab = {
'r',
"root",
rootreset,
devinit,
devshutdown,
rootattach,
rootwalk,
rootstat,
rootopen,
rootcreate,
rootclose,
rootread,
devbread,
rootwrite,
devbwrite,
devremove,
devwstat,
devpower,
devconfig,
devchaninfo,
};