a
This commit is contained in:
821
kern/exportfs.c
Normal file
821
kern/exportfs.c
Normal file
@ -0,0 +1,821 @@
|
||||
#include "u.h"
|
||||
#include "lib.h"
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
#include "error.h"
|
||||
|
||||
typedef struct Fid Fid;
|
||||
typedef struct Export Export;
|
||||
typedef struct Exq Exq;
|
||||
|
||||
#define nil ((void*)0)
|
||||
|
||||
enum
|
||||
{
|
||||
Nfidhash = 1,
|
||||
MAXRPC = MAXMSG+MAXFDATA,
|
||||
MAXDIRREAD = (MAXFDATA/DIRLEN)*DIRLEN
|
||||
};
|
||||
|
||||
struct Export
|
||||
{
|
||||
Ref r;
|
||||
Exq* work;
|
||||
Lock fidlock;
|
||||
Fid* fid[Nfidhash];
|
||||
Chan* root;
|
||||
Chan* io;
|
||||
Pgrp* pgrp;
|
||||
int npart;
|
||||
char part[MAXRPC];
|
||||
};
|
||||
|
||||
struct Fid
|
||||
{
|
||||
Fid* next;
|
||||
Fid** last;
|
||||
Chan* chan;
|
||||
long offset;
|
||||
int fid;
|
||||
int ref; /* fcalls using the fid; locked by Export.Lock */
|
||||
int attached; /* fid attached or cloned but not clunked */
|
||||
};
|
||||
|
||||
struct Exq
|
||||
{
|
||||
Lock lk;
|
||||
int nointr;
|
||||
int noresponse; /* don't respond to this one */
|
||||
Exq* next;
|
||||
int shut; /* has been noted for shutdown */
|
||||
Export* export;
|
||||
void* slave;
|
||||
Fcall rpc;
|
||||
char buf[MAXRPC];
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
Lock l;
|
||||
Qlock qwait;
|
||||
Rendez rwait;
|
||||
Exq *head; /* work waiting for a slave */
|
||||
Exq *tail;
|
||||
}exq;
|
||||
|
||||
static void exshutdown(Export*);
|
||||
static void exflush(Export*, int, int);
|
||||
static void exslave(void*);
|
||||
static void exfree(Export*);
|
||||
static void exportproc(Export*);
|
||||
|
||||
static char* Exauth(Export*, Fcall*);
|
||||
static char* Exattach(Export*, Fcall*);
|
||||
static char* Exclunk(Export*, Fcall*);
|
||||
static char* Excreate(Export*, Fcall*);
|
||||
static char* Exopen(Export*, Fcall*);
|
||||
static char* Exread(Export*, Fcall*);
|
||||
static char* Exremove(Export*, Fcall*);
|
||||
static char* Exstat(Export*, Fcall*);
|
||||
static char* Exwalk(Export*, Fcall*);
|
||||
static char* Exwrite(Export*, Fcall*);
|
||||
static char* Exwstat(Export*, Fcall*);
|
||||
static char* Exversion(Export*, Fcall*);
|
||||
|
||||
static char *(*fcalls[Tmax])(Export*, Fcall*);
|
||||
|
||||
static char Enofid[] = "no such fid";
|
||||
static char Eseekdir[] = "can't seek on a directory";
|
||||
static char Ereaddir[] = "unaligned read of a directory";
|
||||
static int exdebug = 0;
|
||||
|
||||
int
|
||||
sysexport(int fd)
|
||||
{
|
||||
Chan *c;
|
||||
Export *fs;
|
||||
|
||||
if(waserror())
|
||||
return -1;
|
||||
|
||||
c = fdtochan(fd, ORDWR, 1, 1);
|
||||
poperror();
|
||||
c->flag |= CMSG;
|
||||
|
||||
fs = mallocz(sizeof(Export));
|
||||
fs->r.ref = 1;
|
||||
fs->pgrp = up->pgrp;
|
||||
refinc(&fs->pgrp->r);
|
||||
refinc(&up->slash->r);
|
||||
fs->root = up->slash;
|
||||
refinc(&fs->root->r);
|
||||
fs->root = domount(fs->root);
|
||||
fs->io = c;
|
||||
|
||||
exportproc(fs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
exportinit(void)
|
||||
{
|
||||
lock(&exq.l);
|
||||
if(fcalls[Tversion] != nil) {
|
||||
unlock(&exq.l);
|
||||
return;
|
||||
}
|
||||
|
||||
fmtinstall('F', fcallfmt);
|
||||
fmtinstall('D', dirfmt);
|
||||
fmtinstall('M', dirmodefmt);
|
||||
fcalls[Tversion] = Exversion;
|
||||
fcalls[Tauth] = Exauth;
|
||||
fcalls[Tattach] = Exattach;
|
||||
fcalls[Twalk] = Exwalk;
|
||||
fcalls[Topen] = Exopen;
|
||||
fcalls[Tcreate] = Excreate;
|
||||
fcalls[Tread] = Exread;
|
||||
fcalls[Twrite] = Exwrite;
|
||||
fcalls[Tclunk] = Exclunk;
|
||||
fcalls[Tremove] = Exremove;
|
||||
fcalls[Tstat] = Exstat;
|
||||
fcalls[Twstat] = Exwstat;
|
||||
unlock(&exq.l);
|
||||
}
|
||||
|
||||
void
|
||||
exportproc(Export *fs)
|
||||
{
|
||||
Exq *q;
|
||||
char *buf;
|
||||
int n, cn, len;
|
||||
|
||||
exportinit();
|
||||
|
||||
for(;;){
|
||||
q = mallocz(sizeof(Exq));
|
||||
if(q == 0)
|
||||
panic("no memory");
|
||||
|
||||
q->rpc.data = q->buf + MAXMSG;
|
||||
|
||||
buf = q->buf;
|
||||
len = MAXRPC;
|
||||
if(fs->npart) {
|
||||
memmove(buf, fs->part, fs->npart);
|
||||
buf += fs->npart;
|
||||
len -= fs->npart;
|
||||
goto chk;
|
||||
}
|
||||
for(;;) {
|
||||
if(waserror())
|
||||
goto bad;
|
||||
|
||||
n = (*devtab[fs->io->type].read)(fs->io, buf, len, 0);
|
||||
poperror();
|
||||
|
||||
if(n <= 0)
|
||||
goto bad;
|
||||
|
||||
buf += n;
|
||||
len -= n;
|
||||
chk:
|
||||
n = buf - q->buf;
|
||||
|
||||
/* convM2S returns size of correctly decoded message */
|
||||
cn = convM2S(q->buf, &q->rpc, n);
|
||||
if(cn < 0){
|
||||
iprint("bad message type in devmnt\n");
|
||||
goto bad;
|
||||
}
|
||||
if(cn > 0) {
|
||||
n -= cn;
|
||||
if(n < 0){
|
||||
iprint("negative size in devmnt");
|
||||
goto bad;
|
||||
}
|
||||
fs->npart = n;
|
||||
if(n != 0)
|
||||
memmove(fs->part, q->buf+cn, n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(exdebug)
|
||||
iprint("export %d <- %F\n", getpid(), &q->rpc);
|
||||
|
||||
if(q->rpc.type == Tflush){
|
||||
exflush(fs, q->rpc.tag, q->rpc.oldtag);
|
||||
free(q);
|
||||
continue;
|
||||
}
|
||||
|
||||
q->export = fs;
|
||||
refinc(&fs->r);
|
||||
|
||||
lock(&exq.l);
|
||||
if(exq.head == nil)
|
||||
exq.head = q;
|
||||
else
|
||||
exq.tail->next = q;
|
||||
q->next = nil;
|
||||
exq.tail = q;
|
||||
unlock(&exq.l);
|
||||
if(exq.qwait.first == nil) {
|
||||
n = thread("exportfs", exslave, nil);
|
||||
/* iprint("launch export (pid=%ux)\n", n); */
|
||||
}
|
||||
rendwakeup(&exq.rwait);
|
||||
}
|
||||
bad:
|
||||
free(q);
|
||||
exshutdown(fs);
|
||||
exfree(fs);
|
||||
}
|
||||
|
||||
void
|
||||
exflush(Export *fs, int flushtag, int tag)
|
||||
{
|
||||
Exq *q, **last;
|
||||
int n;
|
||||
Fcall fc;
|
||||
char buf[MAXMSG];
|
||||
|
||||
/* hasn't been started? */
|
||||
lock(&exq.l);
|
||||
last = &exq.head;
|
||||
for(q = exq.head; q != nil; q = q->next){
|
||||
if(q->export == fs && q->rpc.tag == tag){
|
||||
*last = q->next;
|
||||
unlock(&exq.l);
|
||||
exfree(fs);
|
||||
free(q);
|
||||
goto Respond;
|
||||
}
|
||||
last = &q->next;
|
||||
}
|
||||
unlock(&exq.l);
|
||||
|
||||
/* in progress? */
|
||||
lock(&fs->r.l);
|
||||
for(q = fs->work; q != nil; q = q->next){
|
||||
if(q->rpc.tag == tag && !q->noresponse){
|
||||
lock(&q->lk);
|
||||
q->noresponse = 1;
|
||||
if(!q->nointr)
|
||||
intr(q->slave);
|
||||
unlock(&q->lk);
|
||||
unlock(&fs->r.l);
|
||||
goto Respond;
|
||||
return;
|
||||
}
|
||||
}
|
||||
unlock(&fs->r.l);
|
||||
|
||||
if(exdebug) iprint("exflush: did not find rpc: %d\n", tag);
|
||||
|
||||
Respond:
|
||||
fc.type = Rflush;
|
||||
fc.tag = flushtag;
|
||||
n = convS2M(&fc, buf);
|
||||
if(exdebug) iprint("exflush -> %F\n", &fc);
|
||||
if(!waserror()){
|
||||
(*devtab[fs->io->type].write)(fs->io, buf, n, 0);
|
||||
poperror();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
exshutdown(Export *fs)
|
||||
{
|
||||
Exq *q, **last;
|
||||
|
||||
lock(&exq.l);
|
||||
last = &exq.head;
|
||||
for(q = exq.head; q != nil; q = *last){
|
||||
if(q->export == fs){
|
||||
*last = q->next;
|
||||
exfree(fs);
|
||||
free(q);
|
||||
continue;
|
||||
}
|
||||
last = &q->next;
|
||||
}
|
||||
unlock(&exq.l);
|
||||
|
||||
lock(&fs->r.l);
|
||||
q = fs->work;
|
||||
while(q != nil){
|
||||
if(q->shut){
|
||||
q = q->next;
|
||||
continue;
|
||||
}
|
||||
q->shut = 1;
|
||||
unlock(&fs->r.l);
|
||||
/* postnote(q->slave, 1, "interrupted", NUser); */
|
||||
iprint("postnote 2!\n");
|
||||
lock(&fs->r.l);
|
||||
q = fs->work;
|
||||
}
|
||||
unlock(&fs->r.l);
|
||||
}
|
||||
|
||||
void
|
||||
exfree(Export *fs)
|
||||
{
|
||||
Fid *f, *n;
|
||||
int i;
|
||||
|
||||
if(refdec(&fs->r) != 0)
|
||||
return;
|
||||
closepgrp(fs->pgrp);
|
||||
cclose(fs->root);
|
||||
cclose(fs->io);
|
||||
for(i = 0; i < Nfidhash; i++){
|
||||
for(f = fs->fid[i]; f != nil; f = n){
|
||||
if(f->chan != nil)
|
||||
cclose(f->chan);
|
||||
n = f->next;
|
||||
free(f);
|
||||
}
|
||||
}
|
||||
free(fs);
|
||||
}
|
||||
|
||||
int
|
||||
exwork(void *a)
|
||||
{
|
||||
return exq.head != nil;
|
||||
}
|
||||
|
||||
void
|
||||
exslave(void *a)
|
||||
{
|
||||
Export *fs;
|
||||
Exq *q, *t, **last;
|
||||
char *err;
|
||||
int n;
|
||||
/*
|
||||
closepgrp(up->pgrp);
|
||||
up->pgrp = nil;
|
||||
*/
|
||||
for(;;){
|
||||
qlock(&exq.qwait);
|
||||
rendsleep(&exq.rwait, exwork, nil);
|
||||
|
||||
lock(&exq.l);
|
||||
q = exq.head;
|
||||
if(q == nil) {
|
||||
unlock(&exq.l);
|
||||
qunlock(&exq.qwait);
|
||||
continue;
|
||||
}
|
||||
exq.head = q->next;
|
||||
q->slave = curthread();
|
||||
unlock(&exq.l);
|
||||
|
||||
qunlock(&exq.qwait);
|
||||
|
||||
q->noresponse = 0;
|
||||
q->nointr = 0;
|
||||
fs = q->export;
|
||||
lock(&fs->r.l);
|
||||
q->next = fs->work;
|
||||
fs->work = q;
|
||||
unlock(&fs->r.l);
|
||||
|
||||
up->pgrp = q->export->pgrp;
|
||||
|
||||
if(exdebug > 1)
|
||||
iprint("exslave dispatch %d %F\n", getpid(), &q->rpc);
|
||||
|
||||
if(waserror()){
|
||||
iprint("exslave err %r\n");
|
||||
err = up->errstr;
|
||||
goto Err;
|
||||
}
|
||||
if(q->rpc.type >= Tmax || !fcalls[q->rpc.type])
|
||||
err = "bad fcall type";
|
||||
else
|
||||
err = (*fcalls[q->rpc.type])(fs, &q->rpc);
|
||||
|
||||
poperror();
|
||||
Err:;
|
||||
q->rpc.type++;
|
||||
if(err){
|
||||
q->rpc.type = Rerror;
|
||||
strncpy(q->rpc.ename, err, ERRLEN);
|
||||
}
|
||||
n = convS2M(&q->rpc, q->buf);
|
||||
|
||||
if(exdebug)
|
||||
iprint("exslve %d -> %F\n", getpid(), &q->rpc);
|
||||
|
||||
lock(&q->lk);
|
||||
if(q->noresponse == 0){
|
||||
q->nointr = 1;
|
||||
clearintr();
|
||||
if(!waserror()){
|
||||
(*devtab[fs->io->type].write)(fs->io, q->buf, n, 0);
|
||||
poperror();
|
||||
}
|
||||
}
|
||||
unlock(&q->lk);
|
||||
|
||||
/*
|
||||
* exflush might set noresponse at this point, but
|
||||
* setting noresponse means don't send a response now;
|
||||
* it's okay that we sent a response already.
|
||||
*/
|
||||
if(exdebug > 1)
|
||||
iprint("exslave %d written %d\n", getpid(), q->rpc.tag);
|
||||
|
||||
lock(&fs->r.l);
|
||||
last = &fs->work;
|
||||
for(t = fs->work; t != nil; t = t->next){
|
||||
if(t == q){
|
||||
*last = q->next;
|
||||
break;
|
||||
}
|
||||
last = &t->next;
|
||||
}
|
||||
unlock(&fs->r.l);
|
||||
|
||||
exfree(q->export);
|
||||
free(q);
|
||||
}
|
||||
iprint("exslave shut down");
|
||||
threadexit();
|
||||
}
|
||||
|
||||
Fid*
|
||||
Exmkfid(Export *fs, int fid)
|
||||
{
|
||||
ulong h;
|
||||
Fid *f, *nf;
|
||||
|
||||
nf = mallocz(sizeof(Fid));
|
||||
if(nf == nil)
|
||||
return nil;
|
||||
lock(&fs->fidlock);
|
||||
h = fid % Nfidhash;
|
||||
for(f = fs->fid[h]; f != nil; f = f->next){
|
||||
if(f->fid == fid){
|
||||
unlock(&fs->fidlock);
|
||||
free(nf);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
nf->next = fs->fid[h];
|
||||
if(nf->next != nil)
|
||||
nf->next->last = &nf->next;
|
||||
nf->last = &fs->fid[h];
|
||||
fs->fid[h] = nf;
|
||||
|
||||
nf->fid = fid;
|
||||
nf->ref = 1;
|
||||
nf->attached = 1;
|
||||
nf->offset = 0;
|
||||
nf->chan = nil;
|
||||
unlock(&fs->fidlock);
|
||||
return nf;
|
||||
}
|
||||
|
||||
Fid*
|
||||
Exgetfid(Export *fs, int fid)
|
||||
{
|
||||
Fid *f;
|
||||
ulong h;
|
||||
|
||||
lock(&fs->fidlock);
|
||||
h = fid % Nfidhash;
|
||||
for(f = fs->fid[h]; f; f = f->next) {
|
||||
if(f->fid == fid){
|
||||
if(f->attached == 0)
|
||||
break;
|
||||
f->ref++;
|
||||
unlock(&fs->fidlock);
|
||||
return f;
|
||||
}
|
||||
}
|
||||
unlock(&fs->fidlock);
|
||||
return nil;
|
||||
}
|
||||
|
||||
void
|
||||
Exputfid(Export *fs, Fid *f)
|
||||
{
|
||||
lock(&fs->fidlock);
|
||||
f->ref--;
|
||||
if(f->ref == 0 && f->attached == 0){
|
||||
if(f->chan != nil)
|
||||
cclose(f->chan);
|
||||
f->chan = nil;
|
||||
*f->last = f->next;
|
||||
if(f->next != nil)
|
||||
f->next->last = f->last;
|
||||
unlock(&fs->fidlock);
|
||||
free(f);
|
||||
return;
|
||||
}
|
||||
unlock(&fs->fidlock);
|
||||
}
|
||||
|
||||
char*
|
||||
Exsession(Export *e, Fcall *rpc)
|
||||
{
|
||||
memset(rpc->authid, 0, sizeof(rpc->authid));
|
||||
memset(rpc->authdom, 0, sizeof(rpc->authdom));
|
||||
memset(rpc->chal, 0, sizeof(rpc->chal));
|
||||
return nil;
|
||||
}
|
||||
|
||||
char*
|
||||
Exauth(Export *e, Fcall *f)
|
||||
{
|
||||
return "authentication not required";
|
||||
}
|
||||
|
||||
char*
|
||||
Exattach(Export *fs, Fcall *rpc)
|
||||
{
|
||||
Fid *f;
|
||||
|
||||
f = Exmkfid(fs, rpc->fid);
|
||||
if(f == nil)
|
||||
return Einuse;
|
||||
if(waserror()){
|
||||
f->attached = 0;
|
||||
Exputfid(fs, f);
|
||||
return up->errstr;
|
||||
}
|
||||
f->chan = clone(fs->root, nil);
|
||||
poperror();
|
||||
rpc->qid = f->chan->qid;
|
||||
Exputfid(fs, f);
|
||||
return nil;
|
||||
}
|
||||
|
||||
char*
|
||||
Exclone(Export *fs, Fcall *rpc)
|
||||
{
|
||||
Fid *f, *nf;
|
||||
|
||||
if(rpc->fid == rpc->newfid)
|
||||
return Einuse;
|
||||
f = Exgetfid(fs, rpc->fid);
|
||||
if(f == nil)
|
||||
return Enofid;
|
||||
nf = Exmkfid(fs, rpc->newfid);
|
||||
if(nf == nil){
|
||||
Exputfid(fs, f);
|
||||
return Einuse;
|
||||
}
|
||||
if(waserror()){
|
||||
Exputfid(fs, f);
|
||||
Exputfid(fs, nf);
|
||||
return up->errstr;
|
||||
}
|
||||
nf->chan = clone(f->chan, nil);
|
||||
poperror();
|
||||
Exputfid(fs, f);
|
||||
Exputfid(fs, nf);
|
||||
return nil;
|
||||
}
|
||||
|
||||
char*
|
||||
Exclunk(Export *fs, Fcall *rpc)
|
||||
{
|
||||
Fid *f;
|
||||
|
||||
f = Exgetfid(fs, rpc->fid);
|
||||
if(f != nil){
|
||||
f->attached = 0;
|
||||
Exputfid(fs, f);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
char*
|
||||
Exwalk(Export *fs, Fcall *rpc)
|
||||
{
|
||||
Fid *f;
|
||||
Chan *c;
|
||||
|
||||
f = Exgetfid(fs, rpc->fid);
|
||||
if(f == nil)
|
||||
return Enofid;
|
||||
if(waserror()){
|
||||
Exputfid(fs, f);
|
||||
return up->errstr;
|
||||
}
|
||||
c = walk(f->chan, rpc->name, 1);
|
||||
if(c == nil)
|
||||
error(Enonexist);
|
||||
poperror();
|
||||
|
||||
f->chan = c;
|
||||
rpc->qid = c->qid;
|
||||
Exputfid(fs, f);
|
||||
return nil;
|
||||
}
|
||||
|
||||
char*
|
||||
Exopen(Export *fs, Fcall *rpc)
|
||||
{
|
||||
Fid *f;
|
||||
Chan *c;
|
||||
|
||||
f = Exgetfid(fs, rpc->fid);
|
||||
if(f == nil)
|
||||
return Enofid;
|
||||
if(waserror()){
|
||||
Exputfid(fs, f);
|
||||
return up->errstr;
|
||||
}
|
||||
c = f->chan;
|
||||
c = (*devtab[c->type].open)(c, rpc->mode);
|
||||
poperror();
|
||||
|
||||
f->chan = c;
|
||||
f->offset = 0;
|
||||
rpc->qid = f->chan->qid;
|
||||
Exputfid(fs, f);
|
||||
return nil;
|
||||
}
|
||||
|
||||
char*
|
||||
Excreate(Export *fs, Fcall *rpc)
|
||||
{
|
||||
Fid *f;
|
||||
Chan *c;
|
||||
|
||||
f = Exgetfid(fs, rpc->fid);
|
||||
if(f == nil)
|
||||
return Enofid;
|
||||
if(waserror()){
|
||||
Exputfid(fs, f);
|
||||
return up->errstr;
|
||||
}
|
||||
c = f->chan;
|
||||
if(c->mnt && !(c->flag&CCREATE))
|
||||
c = createdir(c);
|
||||
(*devtab[c->type].create)(c, rpc->name, rpc->mode, rpc->perm);
|
||||
poperror();
|
||||
|
||||
f->chan = c;
|
||||
rpc->qid = f->chan->qid;
|
||||
Exputfid(fs, f);
|
||||
return nil;
|
||||
}
|
||||
|
||||
char*
|
||||
Exread(Export *fs, Fcall *rpc)
|
||||
{
|
||||
Fid *f;
|
||||
Chan *c;
|
||||
long off;
|
||||
int dir, n, seek;
|
||||
|
||||
f = Exgetfid(fs, rpc->fid);
|
||||
if(f == nil)
|
||||
return Enofid;
|
||||
|
||||
c = f->chan;
|
||||
dir = c->qid.path & CHDIR;
|
||||
if(dir){
|
||||
rpc->count -= rpc->count%DIRLEN;
|
||||
if(rpc->offset%DIRLEN || rpc->count==0){
|
||||
Exputfid(fs, f);
|
||||
return Ereaddir;
|
||||
}
|
||||
if(f->offset > rpc->offset){
|
||||
Exputfid(fs, f);
|
||||
return Eseekdir;
|
||||
}
|
||||
}
|
||||
|
||||
if(waserror()) {
|
||||
Exputfid(fs, f);
|
||||
return up->errstr;
|
||||
}
|
||||
|
||||
for(;;){
|
||||
n = rpc->count;
|
||||
seek = 0;
|
||||
off = rpc->offset;
|
||||
if(dir && f->offset != off){
|
||||
off = f->offset;
|
||||
n = rpc->offset - off;
|
||||
if(n > MAXDIRREAD)
|
||||
n = MAXDIRREAD;
|
||||
seek = 1;
|
||||
}
|
||||
if(dir && c->mnt != nil)
|
||||
n = unionread(c, rpc->data, n);
|
||||
else{
|
||||
c->offset = off;
|
||||
n = (*devtab[c->type].read)(c, rpc->data, n, off);
|
||||
}
|
||||
if(n == 0 || !seek)
|
||||
break;
|
||||
f->offset = off + n;
|
||||
c->offset += n;
|
||||
}
|
||||
rpc->count = n;
|
||||
poperror();
|
||||
Exputfid(fs, f);
|
||||
return nil;
|
||||
}
|
||||
|
||||
char*
|
||||
Exwrite(Export *fs, Fcall *rpc)
|
||||
{
|
||||
Fid *f;
|
||||
Chan *c;
|
||||
|
||||
f = Exgetfid(fs, rpc->fid);
|
||||
if(f == nil)
|
||||
return Enofid;
|
||||
if(waserror()){
|
||||
Exputfid(fs, f);
|
||||
return up->errstr;
|
||||
}
|
||||
c = f->chan;
|
||||
if(c->qid.path & CHDIR)
|
||||
error(Eisdir);
|
||||
rpc->count = (*devtab[c->type].write)(c, rpc->data, rpc->count, rpc->offset);
|
||||
poperror();
|
||||
Exputfid(fs, f);
|
||||
return nil;
|
||||
}
|
||||
|
||||
char*
|
||||
Exstat(Export *fs, Fcall *rpc)
|
||||
{
|
||||
Fid *f;
|
||||
Chan *c;
|
||||
|
||||
f = Exgetfid(fs, rpc->fid);
|
||||
if(f == nil)
|
||||
return Enofid;
|
||||
if(waserror()){
|
||||
Exputfid(fs, f);
|
||||
return up->errstr;
|
||||
}
|
||||
c = f->chan;
|
||||
(*devtab[c->type].stat)(c, rpc->stat);
|
||||
poperror();
|
||||
Exputfid(fs, f);
|
||||
return nil;
|
||||
}
|
||||
|
||||
char*
|
||||
Exwstat(Export *fs, Fcall *rpc)
|
||||
{
|
||||
Fid *f;
|
||||
Chan *c;
|
||||
|
||||
f = Exgetfid(fs, rpc->fid);
|
||||
if(f == nil)
|
||||
return Enofid;
|
||||
if(waserror()){
|
||||
Exputfid(fs, f);
|
||||
return up->errstr;
|
||||
}
|
||||
c = f->chan;
|
||||
(*devtab[c->type].wstat)(c, rpc->stat);
|
||||
poperror();
|
||||
Exputfid(fs, f);
|
||||
return nil;
|
||||
}
|
||||
|
||||
char*
|
||||
Exremove(Export *fs, Fcall *rpc)
|
||||
{
|
||||
Fid *f;
|
||||
Chan *c;
|
||||
|
||||
f = Exgetfid(fs, rpc->fid);
|
||||
if(f == nil)
|
||||
return Enofid;
|
||||
if(waserror()){
|
||||
Exputfid(fs, f);
|
||||
return up->errstr;
|
||||
}
|
||||
c = f->chan;
|
||||
(*devtab[c->type].remove)(c);
|
||||
poperror();
|
||||
|
||||
/*
|
||||
* chan is already clunked by remove.
|
||||
* however, we need to recover the chan,
|
||||
* and follow sysremove's lead in making to point to root.
|
||||
*/
|
||||
c->type = 0;
|
||||
|
||||
f->attached = 0;
|
||||
Exputfid(fs, f);
|
||||
return nil;
|
||||
}
|
Reference in New Issue
Block a user