2003-12-11 17:50:28 +00:00
|
|
|
#include <u.h>
|
|
|
|
#include <libc.h>
|
|
|
|
#include <draw.h>
|
|
|
|
#include <thread.h>
|
|
|
|
#include <cursor.h>
|
|
|
|
#include <mouse.h>
|
|
|
|
#include <keyboard.h>
|
|
|
|
#include <frame.h>
|
|
|
|
#include <fcall.h>
|
|
|
|
#include <plumb.h>
|
|
|
|
#include "dat.h"
|
|
|
|
#include "fns.h"
|
|
|
|
|
|
|
|
static int sfd;
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
Nhash = 16,
|
|
|
|
DEBUG = 0
|
|
|
|
};
|
|
|
|
|
|
|
|
static Fid *fids[Nhash];
|
|
|
|
|
|
|
|
Fid *newfid(int);
|
|
|
|
|
|
|
|
static Xfid* fsysflush(Xfid*, Fid*);
|
|
|
|
static Xfid* fsysauth(Xfid*, Fid*);
|
|
|
|
static Xfid* fsysversion(Xfid*, Fid*);
|
|
|
|
static Xfid* fsysattach(Xfid*, Fid*);
|
|
|
|
static Xfid* fsyswalk(Xfid*, Fid*);
|
|
|
|
static Xfid* fsysopen(Xfid*, Fid*);
|
|
|
|
static Xfid* fsyscreate(Xfid*, Fid*);
|
|
|
|
static Xfid* fsysread(Xfid*, Fid*);
|
|
|
|
static Xfid* fsyswrite(Xfid*, Fid*);
|
|
|
|
static Xfid* fsysclunk(Xfid*, Fid*);
|
|
|
|
static Xfid* fsysremove(Xfid*, Fid*);
|
|
|
|
static Xfid* fsysstat(Xfid*, Fid*);
|
|
|
|
static Xfid* fsyswstat(Xfid*, Fid*);
|
|
|
|
|
|
|
|
Xfid* (*fcall[Tmax])(Xfid*, Fid*) =
|
|
|
|
{
|
|
|
|
[Tflush] = fsysflush,
|
|
|
|
[Tversion] = fsysversion,
|
|
|
|
[Tauth] = fsysauth,
|
|
|
|
[Tattach] = fsysattach,
|
|
|
|
[Twalk] = fsyswalk,
|
|
|
|
[Topen] = fsysopen,
|
|
|
|
[Tcreate] = fsyscreate,
|
|
|
|
[Tread] = fsysread,
|
|
|
|
[Twrite] = fsyswrite,
|
|
|
|
[Tclunk] = fsysclunk,
|
|
|
|
[Tremove]= fsysremove,
|
|
|
|
[Tstat] = fsysstat,
|
|
|
|
[Twstat] = fsyswstat,
|
|
|
|
};
|
|
|
|
|
|
|
|
char Eperm[] = "permission denied";
|
|
|
|
char Eexist[] = "file does not exist";
|
|
|
|
char Enotdir[] = "not a directory";
|
|
|
|
|
|
|
|
Dirtab dirtab[]=
|
|
|
|
{
|
|
|
|
{ ".", QTDIR, Qdir, 0500|DMDIR },
|
|
|
|
{ "acme", QTDIR, Qacme, 0500|DMDIR },
|
|
|
|
{ "cons", QTFILE, Qcons, 0600 },
|
|
|
|
{ "consctl", QTFILE, Qconsctl, 0000 },
|
|
|
|
{ "draw", QTDIR, Qdraw, 0000|DMDIR }, /* to suppress graphics progs started in acme */
|
|
|
|
{ "editout", QTFILE, Qeditout, 0200 },
|
|
|
|
{ "index", QTFILE, Qindex, 0400 },
|
|
|
|
{ "label", QTFILE, Qlabel, 0600 },
|
|
|
|
{ "new", QTDIR, Qnew, 0500|DMDIR },
|
|
|
|
{ nil, }
|
|
|
|
};
|
|
|
|
|
|
|
|
Dirtab dirtabw[]=
|
|
|
|
{
|
|
|
|
{ ".", QTDIR, Qdir, 0500|DMDIR },
|
|
|
|
{ "addr", QTFILE, QWaddr, 0600 },
|
|
|
|
{ "body", QTAPPEND, QWbody, 0600|DMAPPEND },
|
|
|
|
{ "ctl", QTFILE, QWctl, 0600 },
|
|
|
|
{ "data", QTFILE, QWdata, 0600 },
|
|
|
|
{ "editout", QTFILE, QWeditout, 0200 },
|
|
|
|
{ "event", QTFILE, QWevent, 0600 },
|
|
|
|
{ "rdsel", QTFILE, QWrdsel, 0400 },
|
|
|
|
{ "wrsel", QTFILE, QWwrsel, 0200 },
|
|
|
|
{ "tag", QTAPPEND, QWtag, 0600|DMAPPEND },
|
|
|
|
{ nil, }
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct Mnt Mnt;
|
|
|
|
struct Mnt
|
|
|
|
{
|
|
|
|
QLock lk;
|
|
|
|
int id;
|
|
|
|
Mntdir *md;
|
|
|
|
};
|
|
|
|
|
|
|
|
Mnt mnt;
|
|
|
|
|
|
|
|
Xfid* respond(Xfid*, Fcall*, char*);
|
|
|
|
int dostat(int, Dirtab*, uchar*, int, uint);
|
|
|
|
uint getclock(void);
|
|
|
|
|
|
|
|
char *user = "Wile E. Coyote";
|
|
|
|
static int closing = 0;
|
|
|
|
int messagesize = Maxblock+IOHDRSZ; /* good start */
|
|
|
|
|
|
|
|
void fsysproc(void *);
|
|
|
|
|
|
|
|
void
|
|
|
|
fsysinit(void)
|
|
|
|
{
|
|
|
|
int p[2];
|
2004-02-29 22:10:26 +00:00
|
|
|
char *u;
|
2003-12-11 17:50:28 +00:00
|
|
|
|
|
|
|
if(pipe(p) < 0)
|
|
|
|
error("can't create pipe");
|
|
|
|
if(post9pservice(p[0], "acme") < 0)
|
|
|
|
error("can't post service");
|
|
|
|
sfd = p[1];
|
|
|
|
fmtinstall('F', fcallfmt);
|
|
|
|
if((u = getuser()) != nil)
|
|
|
|
user = estrdup(u);
|
2004-02-29 22:10:26 +00:00
|
|
|
threadcreate(fsysproc, nil, STACK);
|
2003-12-11 17:50:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fsysproc(void *v)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
Xfid *x;
|
|
|
|
Fid *f;
|
|
|
|
Fcall t;
|
|
|
|
uchar *buf;
|
|
|
|
|
|
|
|
USED(v);
|
|
|
|
x = nil;
|
|
|
|
for(;;){
|
|
|
|
buf = emalloc(messagesize+UTFmax); /* overflow for appending partial rune in xfidwrite */
|
2004-02-29 22:10:26 +00:00
|
|
|
n = threadread9pmsg(sfd, buf, messagesize);
|
2003-12-11 17:50:28 +00:00
|
|
|
if(n <= 0){
|
|
|
|
if(closing)
|
|
|
|
break;
|
|
|
|
error("i/o error on server channel");
|
|
|
|
}
|
|
|
|
if(x == nil){
|
|
|
|
sendp(cxfidalloc, nil);
|
|
|
|
x = recvp(cxfidalloc);
|
|
|
|
}
|
|
|
|
x->buf = buf;
|
|
|
|
if(convM2S(buf, n, &x->fcall) != n)
|
|
|
|
error("convert error in convM2S");
|
|
|
|
if(DEBUG)
|
|
|
|
fprint(2, "%F\n", &x->fcall);
|
|
|
|
if(fcall[x->fcall.type] == nil)
|
|
|
|
x = respond(x, &t, "bad fcall type");
|
|
|
|
else{
|
|
|
|
if(x->fcall.type==Tversion || x->fcall.type==Tauth)
|
|
|
|
f = nil;
|
|
|
|
else
|
|
|
|
f = newfid(x->fcall.fid);
|
|
|
|
x->f = f;
|
|
|
|
x = (*fcall[x->fcall.type])(x, f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Mntdir*
|
|
|
|
fsysaddid(Rune *dir, int ndir, Rune **incl, int nincl)
|
|
|
|
{
|
|
|
|
Mntdir *m;
|
|
|
|
int id;
|
|
|
|
|
|
|
|
qlock(&mnt.lk);
|
|
|
|
id = ++mnt.id;
|
|
|
|
m = emalloc(sizeof *m);
|
|
|
|
m->id = id;
|
|
|
|
m->dir = dir;
|
|
|
|
m->ref = 1; /* one for Command, one will be incremented in attach */
|
|
|
|
m->ndir = ndir;
|
|
|
|
m->next = mnt.md;
|
|
|
|
m->incl = incl;
|
|
|
|
m->nincl = nincl;
|
|
|
|
mnt.md = m;
|
|
|
|
qunlock(&mnt.lk);
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fsysdelid(Mntdir *idm)
|
|
|
|
{
|
|
|
|
Mntdir *m, *prev;
|
|
|
|
int i;
|
|
|
|
char buf[64];
|
|
|
|
|
|
|
|
if(idm == nil)
|
|
|
|
return;
|
|
|
|
qlock(&mnt.lk);
|
|
|
|
if(--idm->ref > 0){
|
|
|
|
qunlock(&mnt.lk);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
prev = nil;
|
|
|
|
for(m=mnt.md; m; m=m->next){
|
|
|
|
if(m == idm){
|
|
|
|
if(prev)
|
|
|
|
prev->next = m->next;
|
|
|
|
else
|
|
|
|
mnt.md = m->next;
|
|
|
|
for(i=0; i<m->nincl; i++)
|
|
|
|
free(m->incl[i]);
|
|
|
|
free(m->incl);
|
|
|
|
free(m->dir);
|
|
|
|
free(m);
|
|
|
|
qunlock(&mnt.lk);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
prev = m;
|
|
|
|
}
|
|
|
|
qunlock(&mnt.lk);
|
|
|
|
sprint(buf, "fsysdelid: can't find id %d\n", idm->id);
|
|
|
|
sendp(cerr, estrdup(buf));
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Called only in exec.c:/^run(), from a different FD group
|
|
|
|
*/
|
|
|
|
Mntdir*
|
|
|
|
fsysmount(Rune *dir, int ndir, Rune **incl, int nincl)
|
|
|
|
{
|
|
|
|
return fsysaddid(dir, ndir, incl, nincl);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
fsysclose(void)
|
|
|
|
{
|
|
|
|
closing = 1;
|
|
|
|
close(sfd);
|
|
|
|
}
|
|
|
|
|
|
|
|
Xfid*
|
|
|
|
respond(Xfid *x, Fcall *t, char *err)
|
|
|
|
{
|
|
|
|
int n;
|
|
|
|
|
|
|
|
if(err){
|
|
|
|
t->type = Rerror;
|
|
|
|
t->ename = err;
|
|
|
|
}else
|
|
|
|
t->type = x->fcall.type+1;
|
|
|
|
t->fid = x->fcall.fid;
|
|
|
|
t->tag = x->fcall.tag;
|
|
|
|
if(x->buf == nil)
|
|
|
|
x->buf = emalloc(messagesize);
|
|
|
|
n = convS2M(t, x->buf, messagesize);
|
|
|
|
if(n <= 0)
|
2004-02-29 22:10:26 +00:00
|
|
|
{
|
|
|
|
fprint(2, "convert error (n=%d, msgsize %d): have %F\n", n, messagesize, &x->fcall);
|
|
|
|
fprint(2, "\tresponse: %F\n", t);
|
2003-12-11 17:50:28 +00:00
|
|
|
error("convert error in convS2M");
|
2004-02-29 22:10:26 +00:00
|
|
|
}
|
2003-12-11 17:50:28 +00:00
|
|
|
if(write(sfd, x->buf, n) != n)
|
|
|
|
error("write error in respond");
|
|
|
|
free(x->buf);
|
|
|
|
x->buf = nil;
|
|
|
|
if(DEBUG)
|
|
|
|
fprint(2, "r: %F\n", t);
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
Xfid*
|
|
|
|
fsysversion(Xfid *x, Fid *f)
|
|
|
|
{
|
|
|
|
Fcall t;
|
|
|
|
|
|
|
|
USED(f);
|
|
|
|
if(x->fcall.msize < 256)
|
|
|
|
return respond(x, &t, "version: message size too small");
|
|
|
|
messagesize = x->fcall.msize;
|
|
|
|
t.msize = messagesize;
|
|
|
|
if(strncmp(x->fcall.version, "9P2000", 6) != 0)
|
|
|
|
return respond(x, &t, "unrecognized 9P version");
|
|
|
|
t.version = "9P2000";
|
|
|
|
return respond(x, &t, nil);
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
Xfid*
|
|
|
|
fsysauth(Xfid *x, Fid *f)
|
|
|
|
{
|
|
|
|
USED(f);
|
|
|
|
return respond(x, nil, "acme: authentication not required");
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
Xfid*
|
|
|
|
fsysflush(Xfid *x, Fid *f)
|
|
|
|
{
|
|
|
|
USED(f);
|
|
|
|
sendp(x->c, xfidflush);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
Xfid*
|
|
|
|
fsysattach(Xfid *x, Fid *f)
|
|
|
|
{
|
|
|
|
Fcall t;
|
|
|
|
int id;
|
|
|
|
Mntdir *m;
|
2003-12-17 04:34:52 +00:00
|
|
|
char buf[128];
|
2003-12-11 17:50:28 +00:00
|
|
|
|
|
|
|
if(strcmp(x->fcall.uname, user) != 0)
|
|
|
|
return respond(x, &t, Eperm);
|
|
|
|
f->busy = TRUE;
|
|
|
|
f->open = FALSE;
|
|
|
|
f->qid.path = Qdir;
|
|
|
|
f->qid.type = QTDIR;
|
|
|
|
f->qid.vers = 0;
|
|
|
|
f->dir = dirtab;
|
|
|
|
f->nrpart = 0;
|
|
|
|
f->w = nil;
|
|
|
|
t.qid = f->qid;
|
|
|
|
f->mntdir = nil;
|
|
|
|
id = atoi(x->fcall.aname);
|
|
|
|
qlock(&mnt.lk);
|
|
|
|
for(m=mnt.md; m; m=m->next)
|
|
|
|
if(m->id == id){
|
|
|
|
f->mntdir = m;
|
|
|
|
m->ref++;
|
|
|
|
break;
|
|
|
|
}
|
2003-12-17 04:34:52 +00:00
|
|
|
if(m == nil){
|
|
|
|
snprint(buf, sizeof buf, "unknown id '%s' in attach", x->fcall.aname);
|
|
|
|
sendp(cerr, estrdup(buf));
|
|
|
|
}
|
2003-12-11 17:50:28 +00:00
|
|
|
qunlock(&mnt.lk);
|
|
|
|
return respond(x, &t, nil);
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
Xfid*
|
|
|
|
fsyswalk(Xfid *x, Fid *f)
|
|
|
|
{
|
|
|
|
Fcall t;
|
|
|
|
int c, i, j, id;
|
|
|
|
Qid q;
|
|
|
|
uchar type;
|
|
|
|
ulong path;
|
|
|
|
Fid *nf;
|
|
|
|
Dirtab *d, *dir;
|
|
|
|
Window *w;
|
|
|
|
char *err;
|
|
|
|
|
|
|
|
nf = nil;
|
|
|
|
w = nil;
|
|
|
|
if(f->open)
|
|
|
|
return respond(x, &t, "walk of open file");
|
|
|
|
if(x->fcall.fid != x->fcall.newfid){
|
|
|
|
nf = newfid(x->fcall.newfid);
|
|
|
|
if(nf->busy)
|
|
|
|
return respond(x, &t, "newfid already in use");
|
|
|
|
nf->busy = TRUE;
|
|
|
|
nf->open = FALSE;
|
|
|
|
nf->mntdir = f->mntdir;
|
|
|
|
if(f->mntdir)
|
|
|
|
f->mntdir->ref++;
|
|
|
|
nf->dir = f->dir;
|
|
|
|
nf->qid = f->qid;
|
|
|
|
nf->w = f->w;
|
|
|
|
nf->nrpart = 0; /* not open, so must be zero */
|
|
|
|
if(nf->w)
|
|
|
|
incref(&nf->w->ref);
|
|
|
|
f = nf; /* walk f */
|
|
|
|
}
|
|
|
|
|
|
|
|
t.nwqid = 0;
|
|
|
|
err = nil;
|
|
|
|
dir = nil;
|
|
|
|
id = WIN(f->qid);
|
|
|
|
q = f->qid;
|
|
|
|
|
|
|
|
if(x->fcall.nwname > 0){
|
|
|
|
for(i=0; i<x->fcall.nwname; i++){
|
|
|
|
if((q.type & QTDIR) == 0){
|
|
|
|
err = Enotdir;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(strcmp(x->fcall.wname[i], "..") == 0){
|
|
|
|
type = QTDIR;
|
|
|
|
path = Qdir;
|
|
|
|
id = 0;
|
|
|
|
if(w){
|
|
|
|
winclose(w);
|
|
|
|
w = nil;
|
|
|
|
}
|
|
|
|
Accept:
|
|
|
|
if(i == MAXWELEM){
|
|
|
|
err = "name too long";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
q.type = type;
|
|
|
|
q.vers = 0;
|
|
|
|
q.path = QID(id, path);
|
|
|
|
t.wqid[t.nwqid++] = q;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* is it a numeric name? */
|
|
|
|
for(j=0; (c=x->fcall.wname[i][j]); j++)
|
|
|
|
if(c<'0' || '9'<c)
|
|
|
|
goto Regular;
|
|
|
|
/* yes: it's a directory */
|
|
|
|
if(w) /* name has form 27/23; get out before losing w */
|
|
|
|
break;
|
|
|
|
id = atoi(x->fcall.wname[i]);
|
|
|
|
qlock(&row.lk);
|
|
|
|
w = lookid(id, FALSE);
|
|
|
|
if(w == nil){
|
|
|
|
qunlock(&row.lk);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
incref(&w->ref); /* we'll drop reference at end if there's an error */
|
|
|
|
path = Qdir;
|
|
|
|
type = QTDIR;
|
|
|
|
qunlock(&row.lk);
|
|
|
|
dir = dirtabw;
|
|
|
|
goto Accept;
|
|
|
|
|
|
|
|
Regular:
|
|
|
|
// if(FILE(f->qid) == Qacme) /* empty directory */
|
|
|
|
// break;
|
|
|
|
if(strcmp(x->fcall.wname[i], "new") == 0){
|
|
|
|
if(w)
|
|
|
|
error("w set in walk to new");
|
|
|
|
sendp(cnewwindow, nil); /* signal newwindowthread */
|
|
|
|
w = recvp(cnewwindow); /* receive new window */
|
|
|
|
incref(&w->ref);
|
|
|
|
type = QTDIR;
|
|
|
|
path = QID(w->id, Qdir);
|
|
|
|
id = w->id;
|
|
|
|
dir = dirtabw;
|
|
|
|
goto Accept;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(id == 0)
|
|
|
|
d = dirtab;
|
|
|
|
else
|
|
|
|
d = dirtabw;
|
|
|
|
d++; /* skip '.' */
|
|
|
|
for(; d->name; d++)
|
|
|
|
if(strcmp(x->fcall.wname[i], d->name) == 0){
|
|
|
|
path = d->qid;
|
|
|
|
type = d->type;
|
|
|
|
dir = d;
|
|
|
|
goto Accept;
|
|
|
|
}
|
|
|
|
|
|
|
|
break; /* file not found */
|
|
|
|
}
|
|
|
|
|
|
|
|
if(i==0 && err == nil)
|
|
|
|
err = Eexist;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(err!=nil || t.nwqid<x->fcall.nwname){
|
|
|
|
if(nf){
|
|
|
|
nf->busy = FALSE;
|
|
|
|
fsysdelid(nf->mntdir);
|
|
|
|
}
|
|
|
|
}else if(t.nwqid == x->fcall.nwname){
|
|
|
|
if(w){
|
|
|
|
f->w = w;
|
|
|
|
w = nil; /* don't drop the reference */
|
|
|
|
}
|
|
|
|
if(dir)
|
|
|
|
f->dir = dir;
|
|
|
|
f->qid = q;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(w != nil)
|
|
|
|
winclose(w);
|
|
|
|
|
|
|
|
return respond(x, &t, err);
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
Xfid*
|
|
|
|
fsysopen(Xfid *x, Fid *f)
|
|
|
|
{
|
|
|
|
Fcall t;
|
|
|
|
int m;
|
|
|
|
|
|
|
|
/* can't truncate anything, so just disregard */
|
|
|
|
x->fcall.mode &= ~(OTRUNC|OCEXEC);
|
|
|
|
/* can't execute or remove anything */
|
|
|
|
if(x->fcall.mode==OEXEC || (x->fcall.mode&ORCLOSE))
|
|
|
|
goto Deny;
|
|
|
|
switch(x->fcall.mode){
|
|
|
|
default:
|
|
|
|
goto Deny;
|
|
|
|
case OREAD:
|
|
|
|
m = 0400;
|
|
|
|
break;
|
|
|
|
case OWRITE:
|
|
|
|
m = 0200;
|
|
|
|
break;
|
|
|
|
case ORDWR:
|
|
|
|
m = 0600;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if(((f->dir->perm&~(DMDIR|DMAPPEND))&m) != m)
|
|
|
|
goto Deny;
|
|
|
|
|
|
|
|
sendp(x->c, xfidopen);
|
|
|
|
return nil;
|
|
|
|
|
|
|
|
Deny:
|
|
|
|
return respond(x, &t, Eperm);
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
Xfid*
|
|
|
|
fsyscreate(Xfid *x, Fid *f)
|
|
|
|
{
|
|
|
|
Fcall t;
|
|
|
|
|
|
|
|
USED(f);
|
|
|
|
return respond(x, &t, Eperm);
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
int
|
|
|
|
idcmp(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
return *(int*)a - *(int*)b;
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
Xfid*
|
|
|
|
fsysread(Xfid *x, Fid *f)
|
|
|
|
{
|
|
|
|
Fcall t;
|
|
|
|
uchar *b;
|
|
|
|
int i, id, n, o, e, j, k, *ids, nids;
|
|
|
|
Dirtab *d, dt;
|
|
|
|
Column *c;
|
|
|
|
uint clock, len;
|
|
|
|
char buf[16];
|
|
|
|
|
|
|
|
if(f->qid.type & QTDIR){
|
|
|
|
if(FILE(f->qid) == Qacme){ /* empty dir */
|
|
|
|
t.data = nil;
|
|
|
|
t.count = 0;
|
|
|
|
respond(x, &t, nil);
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
o = x->fcall.offset;
|
|
|
|
e = x->fcall.offset+x->fcall.count;
|
|
|
|
clock = getclock();
|
|
|
|
b = emalloc(messagesize);
|
|
|
|
id = WIN(f->qid);
|
|
|
|
n = 0;
|
|
|
|
if(id > 0)
|
|
|
|
d = dirtabw;
|
|
|
|
else
|
|
|
|
d = dirtab;
|
|
|
|
d++; /* first entry is '.' */
|
|
|
|
for(i=0; d->name!=nil && i<e; i+=len){
|
|
|
|
len = dostat(WIN(x->f->qid), d, b+n, x->fcall.count-n, clock);
|
|
|
|
if(len <= BIT16SZ)
|
|
|
|
break;
|
|
|
|
if(i >= o)
|
|
|
|
n += len;
|
|
|
|
d++;
|
|
|
|
}
|
|
|
|
if(id == 0){
|
|
|
|
qlock(&row.lk);
|
|
|
|
nids = 0;
|
|
|
|
ids = nil;
|
|
|
|
for(j=0; j<row.ncol; j++){
|
|
|
|
c = row.col[j];
|
|
|
|
for(k=0; k<c->nw; k++){
|
|
|
|
ids = realloc(ids, (nids+1)*sizeof(int));
|
|
|
|
ids[nids++] = c->w[k]->id;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
qunlock(&row.lk);
|
|
|
|
qsort(ids, nids, sizeof ids[0], idcmp);
|
|
|
|
j = 0;
|
|
|
|
dt.name = buf;
|
|
|
|
for(; j<nids && i<e; i+=len){
|
|
|
|
k = ids[j];
|
|
|
|
sprint(dt.name, "%d", k);
|
|
|
|
dt.qid = QID(k, Qdir);
|
|
|
|
dt.type = QTDIR;
|
|
|
|
dt.perm = DMDIR|0700;
|
|
|
|
len = dostat(k, &dt, b+n, x->fcall.count-n, clock);
|
|
|
|
if(len == 0)
|
|
|
|
break;
|
|
|
|
if(i >= o)
|
|
|
|
n += len;
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
free(ids);
|
|
|
|
}
|
|
|
|
t.data = (char*)b;
|
|
|
|
t.count = n;
|
|
|
|
respond(x, &t, nil);
|
|
|
|
free(b);
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
sendp(x->c, xfidread);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
Xfid*
|
|
|
|
fsyswrite(Xfid *x, Fid *f)
|
|
|
|
{
|
|
|
|
USED(f);
|
|
|
|
sendp(x->c, xfidwrite);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
Xfid*
|
|
|
|
fsysclunk(Xfid *x, Fid *f)
|
|
|
|
{
|
|
|
|
fsysdelid(f->mntdir);
|
|
|
|
sendp(x->c, xfidclose);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
Xfid*
|
|
|
|
fsysremove(Xfid *x, Fid *f)
|
|
|
|
{
|
|
|
|
Fcall t;
|
|
|
|
|
|
|
|
USED(f);
|
|
|
|
return respond(x, &t, Eperm);
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
Xfid*
|
|
|
|
fsysstat(Xfid *x, Fid *f)
|
|
|
|
{
|
|
|
|
Fcall t;
|
|
|
|
|
|
|
|
t.stat = emalloc(messagesize-IOHDRSZ);
|
|
|
|
t.nstat = dostat(WIN(x->f->qid), f->dir, t.stat, messagesize-IOHDRSZ, getclock());
|
|
|
|
x = respond(x, &t, nil);
|
|
|
|
free(t.stat);
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
|
|
|
|
static
|
|
|
|
Xfid*
|
|
|
|
fsyswstat(Xfid *x, Fid *f)
|
|
|
|
{
|
|
|
|
Fcall t;
|
|
|
|
|
|
|
|
USED(f);
|
|
|
|
return respond(x, &t, Eperm);
|
|
|
|
}
|
|
|
|
|
|
|
|
Fid*
|
|
|
|
newfid(int fid)
|
|
|
|
{
|
|
|
|
Fid *f, *ff, **fh;
|
|
|
|
|
|
|
|
ff = nil;
|
|
|
|
fh = &fids[fid&(Nhash-1)];
|
|
|
|
for(f=*fh; f; f=f->next)
|
|
|
|
if(f->fid == fid)
|
|
|
|
return f;
|
|
|
|
else if(ff==nil && f->busy==FALSE)
|
|
|
|
ff = f;
|
|
|
|
if(ff){
|
|
|
|
ff->fid = fid;
|
|
|
|
return ff;
|
|
|
|
}
|
|
|
|
f = emalloc(sizeof *f);
|
|
|
|
f->fid = fid;
|
|
|
|
f->next = *fh;
|
|
|
|
*fh = f;
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint
|
|
|
|
getclock(void)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
char buf[32];
|
|
|
|
|
|
|
|
buf[0] = '\0';
|
|
|
|
pread(clockfd, buf, sizeof buf, 0);
|
|
|
|
return atoi(buf);
|
|
|
|
*/
|
|
|
|
return time(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
dostat(int id, Dirtab *dir, uchar *buf, int nbuf, uint clock)
|
|
|
|
{
|
|
|
|
Dir d;
|
|
|
|
|
|
|
|
d.qid.path = QID(id, dir->qid);
|
|
|
|
d.qid.vers = 0;
|
|
|
|
d.qid.type = dir->type;
|
|
|
|
d.mode = dir->perm;
|
|
|
|
d.length = 0; /* would be nice to do better */
|
|
|
|
d.name = dir->name;
|
|
|
|
d.uid = user;
|
|
|
|
d.gid = user;
|
|
|
|
d.muid = user;
|
|
|
|
d.atime = clock;
|
|
|
|
d.mtime = clock;
|
|
|
|
return convD2M(&d, buf, nbuf);
|
|
|
|
}
|