/* * kernel disk file system */ #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include "devtab.h" #include "../fs/fdat.h" #include "../fs/ffns.h" enum { Kfscons = 32, /* Chan.dev for console; should probably assign separate devchar */ Qdir, Qcons, Qctl, }; extern void mntdirfix(uchar*, Chan*); static Dirtab kfsdir[] = { {"kfscons", {Qcons}, 0, 0660}, {"kfsctl", {Qctl}, 0, 0220}, }; #define NKFSDIR (sizeof(kfsdir)/sizeof(Dirtab)) void kfsreset(void) { } void kfsinit(void) { kfsmain(0, 0); } static int fcall(void (*f)(FChan*, Fcall*, Fcall*), FChan *cp, Fcall *in, Fcall *ou) { ou->ename[0] = 0; rlock(&mainlock); rlock(&cp->reflock); if(waserror()){ /* shouldn't happen */ print("fcall err: %s\n", up->env->error); strcpy(ou->ename, up->env->error); } else f(cp, in, ou); poperror(); runlock(&cp->reflock); runlock(&mainlock); return ou->ename[0] != 0; } Chan * kfsattach(char *spec) { Chan *c; Fcall in, ou; if(strcmp(spec, "cons") == 0){ c = devattach('K', spec); c->dev = Kfscons; return c; } c = devattach('K', spec); c->aux = malloc(sizeof(FChan)); if(c->aux == nil) { cclose(c); error(Enomem); } in.fid = c->fid; if(up->env) strcpy(in.uname, up->env->user); else strcpy(in.uname, eve); strncpy(in.aname, spec, sizeof(in.aname)); fcall(f_attach, c->aux, &in, &ou); if(ou.ename[0]) { cclose(c); error(ou.ename); } return c; } Chan * kfsclone(Chan *c, Chan *nc) { Fcall in, ou; if(c->dev == Kfscons) return devclone(c, nc); nc = devclone(c, nc); in.fid = c->fid; in.newfid = nc->fid; fcall(f_clone, c->aux, &in, &ou); if(ou.ename[0]) { cclose(nc); error(ou.ename); } return nc; } int kfswalk(Chan *c, char *name) { Fcall in, ou; Path *op; if(c->dev == Kfscons) return devwalk(c, name, kfsdir, NKFSDIR, devgen); in.fid = c->fid; strcpy(in.name, name); fcall(f_walk, c->aux, &in, &ou); if(ou.ename[0]){ strncpy(up->env->error, ou.ename, sizeof(up->env->error)); return 0; } c->qid = ou.qid; op = c->path; c->path = ptenter(&syspt, op, name); decref(op); return 1; } void kfsstat(Chan *c, char *db) { Fcall in, ou; if(c->dev == Kfscons){ devstat(c, db, kfsdir, NKFSDIR, devgen); return; } in.fid = c->fid; fcall(f_stat, c->aux, &in, &ou); if(ou.ename[0]) error(ou.ename); memmove(db, ou.stat, DIRLEN); mntdirfix((uchar*)db, c); } Chan * kfsopen(Chan *c, int omode) { Fcall in, ou; if(c->dev == Kfscons){ switch(c->qid.path & ~CHDIR){ case Qctl: if(!iseve()) error(Eperm); break; case Qcons: qlock(&fscons); if(waserror()){ qunlock(&fscons); nexterror(); } if(fscons.opened) error(Einuse); c = devopen(c, omode, kfsdir, NKFSDIR, devgen); if(fscons.out == nil) fscons.out = qopen(8*1024, 0, 0, 0); else qreopen(fscons.out); fscons.opened = 1; qunlock(&fscons); poperror(); return c; } return devopen(c, omode, kfsdir, NKFSDIR, devgen); } in.fid = c->fid; in.mode = omode; fcall(f_open, c->aux, &in, &ou); if(ou.ename[0]) error(ou.ename); c->offset = 0; c->qid = ou.qid; if((c->qid.path&CHDIR) && omode!=OREAD) error(Eperm); c->mode = openmode(omode); c->flag |= COPEN; return c; } void kfscreate(Chan *c, char *name, int omode, ulong perm) { Fcall in, ou; if(c->dev == Kfscons) error(Eperm); in.fid = c->fid; in.mode = omode; in.perm = perm; strcpy(in.name, name); fcall(f_create, c->aux, &in, &ou); if(ou.ename[0]) error(ou.ename); if((c->qid.path&CHDIR) && omode!=OREAD) error(Eperm); c->qid = ou.qid; c->offset = 0; c->flag |= COPEN; c->mode = openmode(omode); } void kfsremove(Chan *c) { Fcall in, ou; if(c->dev == Kfscons) error(Eperm); in.fid = c->fid; fcall(f_remove, c->aux, &in, &ou); if(ou.ename[0]) error(ou.ename); } void kfswstat(Chan *c, char *dp) { Fcall in, ou; if(c->dev == Kfscons) error(Eperm); in.fid = c->fid; memmove(in.stat, dp, DIRLEN); fcall(f_wstat, c->aux, &in, &ou); if(ou.ename[0]) error(ou.ename); } void kfsclose(Chan *c) { Fcall in, ou; if((c->flag & COPEN) == 0) return; if(c->dev == Kfscons){ if(c->qid.path == Qcons) qclose(fscons.out); return; } in.fid = c->fid; fcall(f_clunk, c->aux, &in, &ou); if(ou.ename[0]) error(ou.ename); } long kfsread(Chan *c, void *a, long n, ulong offset) { Fcall in, ou; uchar *p, *e; int isdir; if(c->dev == Kfscons){ if(n <= 0) return n; switch(c->qid.path & ~CHDIR){ default: return 0; case Qdir: return devdirread(c, a, n, kfsdir, NKFSDIR, devgen); case Qcons: return qread(fscons.out, a, n); } } if(n < 0) error(Ebadarg); in.fid = c->fid; in.data = a; /* actually uses ou.data */ in.count = n; in.offset = offset; ou.data = a; isdir = c->qid.path & CHDIR; fcall(f_read, c->aux, &in, &ou); if(ou.ename[0]) error(ou.ename); n = ou.count; if(isdir){ p = a; for(e = &p[n]; p < e; p += DIRLEN) mntdirfix(p, c); } return n; } Block* kfsbread(Chan *c, long n, ulong offset) { return devbread(c, n, offset); } long kfswrite(Chan *c, char *a, long n, ulong offset) { Fcall in, ou; if(c->dev == Kfscons){ char buf[100]; if(n <= 0) return n; switch(c->qid.path & ~CHDIR){ default: error(Egreg); case Qctl: case Qcons: if(n >= sizeof(buf)) n = sizeof(buf)-1; strncpy(buf, a, n); buf[n] = 0; if(c->qid.path == Qctl) fsctl(buf); else cmd_exec(buf); break; } return n; } if(n < 0) error(Ebadarg); in.fid = c->fid; in.data = a; in.count = n; in.offset = offset; fcall(f_write, c->aux, &in, &ou); if(ou.ename[0]) error(ou.ename); return ou.count; } long kfsbwrite(Chan *c, Block *bp, ulong offset) { return devbwrite(c, bp, offset); }