Example #1
0
static void
rread(Fcall* f)
{
	ulong	n, rn, nn, delta;
	Dir	d;
	Fid*	fp;

	if (!isfdir(f, &fp))
		return;
	if (f->count == 0)
		goto done;
	cleannames();
	for (n = nn = 0; n < f->count; n += rn){
		rn = convM2D((uchar*)f->data + n, f->count - n, &d, statbuf);
		if (rn <= BIT16SZ)
			break;
		d.name = importname(d.name);
		//dprint("⇒ %D\n", &d);
		nn += convD2M(&d, (uchar*)dirbuf + nn, sizeof(dirbuf) - nn);
	}
	delta = nn - n;
	setaux(fp, getaux(fp) + delta);
	f->count = nn;
	f->data = dirbuf;
done:
	closefid(fp);
}
Example #2
0
File: req.c Project: 99years/plan9
void
closereq(Req *r)
{
	int i;

	if(r == nil)
		return;

if(chatty9p > 1)
	fprint(2, "closereq %p %d\n", r, r->ref.ref);

	if(decref(&r->ref) == 0){
		if(r->fid)
			closefid(r->fid);
		if(r->newfid)
			closefid(r->newfid);
		if(r->afid)
			closefid(r->afid);
		if(r->oldreq)
			closereq(r->oldreq);
		for(i=0; i<r->nflush; i++)
			respond(r->flush[i], nil);
		free(r->flush);
		switch(r->ifcall.type){
		case Tstat:
			free(r->ofcall.stat);
			free(r->d.name);
			free(r->d.uid);
			free(r->d.gid);
			free(r->d.muid);
			break;
		}
		if(r->pool->destroy)
			r->pool->destroy(r);
		free(r->buf);
		free(r->rbuf);
		free(r);
	}
}
Example #3
0
void
closereq(Req *r)
{
    if(r == nil)
        return;

    if(chatty9p > 1)
        fprint(2, "closereq %p %ld\n", r, r->ref.ref);

    if(decref(&r->ref) == 0) {
        if(r->fid)
            closefid(r->fid);
        if(r->newfid)
            closefid(r->newfid);
        if(r->afid)
            closefid(r->afid);
        if(r->oldreq)
            closereq(r->oldreq);
        if(r->nflush)
            fprint(2, "closereq: flushes remaining\n");
        free(r->flush);
        switch(r->ifcall.type) {
        case Tstat:
            free(r->ofcall.stat);
            free(r->d.name);
            free(r->d.uid);
            free(r->d.gid);
            free(r->d.muid);
            break;
        }
        if(r->pool->destroy)
            r->pool->destroy(r);
        free(r->buf);
        free(r->rbuf);
        free(r);
    }
}
Example #4
0
static int
isfdir(Fcall* f, Fid **fpp)
{
	Fid*	fp;
	int	r;
	fp = lookupfid(fidpool, f->fid);
	if (fp == nil)
		return 0;
	r = (fp->qid.type&QTDIR);
	if (r)
		*fpp = fp;
	else
		closefid(fp);
	return r;
}
Example #5
0
// Dir read is tricky.
// We have to change the user supplied offset to match the sizes
// seen by the server. Sizes seen by client are greater than those
// seen by server since the change from ' ' to '␣' adds 2 bytes.
static void
tread(Fcall* f)
{
	Fid*	fp;

	fp = nil;
	if (!isfdir(f, &fp))
		return;
	f->count /= 3;	// sizes will grow upon return.
	if (fp == nil)
		sysfatal("can't find fid\n");
	if (f->offset == 0)
		setaux(fp, 0);
	f->offset -= getaux(fp);	// cumulative size delta
	closefid(fp);
}
Example #6
0
File: srv.c Project: 99years/plan9
static void
rwalk(Req *r, char *error)
{
	if(error || r->ofcall.nwqid < r->ifcall.nwname){
		if(r->ifcall.fid != r->ifcall.newfid && r->newfid)
			closefid(removefid(r->srv->fpool, r->newfid->fid));
		if (r->ofcall.nwqid==0){
			if(error==nil && r->ifcall.nwname!=0)
				r->error = Enotfound;
		}else
			r->error = nil;	/* No error on partial walks */
	}else{
		if(r->ofcall.nwqid == 0){
			/* Just a clone */
			r->newfid->qid = r->fid->qid;
		}else{
			/* if file trees are in use, filewalk took care of the rest */
			r->newfid->qid = r->ofcall.wqid[r->ofcall.nwqid-1];
		}
	}
}
Example #7
0
static void
service(int cfd, int sfd, int dfd)
{
	Fcall	f;
	int	r;
	Fid*	fp;

	fidpool = allocfidpool(nop);
	for(;;){
		fp = nil;
		r = getfcall(cfd, &f);
		if (r <= 0){
			fprint(dfd, "trfs: getfcall %r\n");
			break;
		}
		if(verbose)
			fprint(dfd , "c→s %F\n", &f);
		switch(f.type){
		case Tclunk:
		case Tremove:
			// BUG in lib9p? removefid leaks fid.
			// is that what it should do?
			fp = lookupfid(fidpool, f.fid);
			if (fp != nil){
				removefid(fidpool, f.fid);
				closefid(fp);
				closefid(fp);
				fp = nil;
			}
			break;
		case Tcreate:
			tcreate(&f);
			// and also...
		case Topen:
			fp = allocfid(fidpool, f.fid);
			fp->aux = 0;
			break;
		case Tread:
			tread(&f);
			break;
		case Twalk:
			twalk(&f);
			break;
		case Twstat:
			twstat(&f);
			break;
		}
		if(verbose && debug)
			fprint(dfd , "c→s %F\n", &f);
		if (putfcall(sfd, &f) < 0)
			fprint(dfd , "can't putfcall: %r\n");
		

		r = getfcall(sfd, &f);
		if (r <= 0){
			fprint(dfd, "trfs: 2nd getfcall %r\n");
			break;
		}
		if (verbose)
			fprint(dfd, "c←s %F\n", &f);
		switch(f.type){
		case Ropen:
		case Rcreate:
			fp->qid = f.qid;
			break;
		case Rread:
			rread(&f);
			break;
		case Rstat:
			rstat(&f);
			break;
		}
		if(verbose && debug)
			fprint(dfd , "c←s %F\n", &f);
		if (putfcall(cfd, &f) < 0)
			fprint(dfd , "can't 2n dputfcall: %r\n");
		if (fp != nil)
			closefid(fp);
	}
}
Example #8
0
File: srv.c Project: 99years/plan9
void
respond(Req *r, char *error)
{
	int i, m, n;
	char errbuf[ERRMAX];
	Srv *srv;

	srv = r->srv;
	assert(srv != nil);

	if(r->responded){
		assert(r->pool);
		goto free;
	}
		
	assert(r->responded == 0);
	r->error = error;

	switch(r->ifcall.type){
	default:
		assert(0);
	/*
	 * Flush is special.  If the handler says so, we return
	 * without further processing.  Respond will be called
	 * again once it is safe.
	 */
	case Tflush:
		if(rflush(r, error)<0)
			return;
		break;
	case Tversion:	rversion(r, error);	break;
	case Tauth:	rauth(r, error);	break;
	case Tattach:	rattach(r, error);	break;
	case Twalk:	rwalk(r, error);	break;
	case Topen:	ropen(r, error);	break;
	case Tcreate:	rcreate(r, error);	break;
	case Tread:	rread(r, error);	break;
	case Twrite:	rwrite(r, error);	break;
	case Tclunk:	rclunk(r, error);	break;
	case Tremove:	rremove(r, error, errbuf);	break;
	case Tstat:	rstat(r, error);	break;
	case Twstat:	rwstat(r, error);	break;
	}

	r->ofcall.tag = r->ifcall.tag;
	r->ofcall.type = r->ifcall.type+1;
	if(r->error)
		setfcallerror(&r->ofcall, r->error);

if(chatty9p)
	fprint(2, "-%d-> %F\n", srv->outfd, &r->ofcall);

	qlock(&srv->wlock);
	n = convS2M(&r->ofcall, srv->wbuf, srv->msize);
	if(n <= 0){
		fprint(2, "n = %d %F\n", n, &r->ofcall);
		abort();
	}
	assert(n > 2);
	/*
	 * There is a race here - we must remove the entry before
	 * the write, so that if the client is very fast and reuses the
	 * tag, the read loop won't think it is still in use.
	 * 
	 * By removing the entry before the write, we open up a 
	 * race with incoming Tflush messages.  Specifically, an
	 * incoming Tflush might not see r even though it has not
	 * yet been responded to.  It would then send an Rflush
	 * immediately, potentially before we do the write.  This can't
	 * happen because we already old srv->wlock, so nothing
	 * is going out on the wire before this write.
	 */
	if(r->pool)	/* not a fake */
		closereq(removereq(r->pool, r->ifcall.tag));

	qlock(&r->lk);
	r->responded = 1;
	if(r->pool)
	if(r->ref.ref == 1+r->nflush)
	if(r->fid){
		/*
		 * There are no references other than in our r->flush array,
		 * so no one else should be accessing r concurrently.
		 * Close the fid now, before responding to the message.
		 * 
		 * If the client is behaving (there are no outstanding T-messages
		 * that reference r->fid) and the message is a Tclunk or Tremove,
		 * then this closefid will call destroyfid.  
		 * 
		 * This means destroyfid can't piddle around 
		 * indefinitely (we're holding srv->wlock!), but it provides
		 * for tighter semantics as to when destroyfid is called.
		 *
		 * LANL has observed cases where waiting until after the write
		 * can delay a closefid on a Twrite for many 9P transactions,
		 * so that a handful of transactions can happen including a Tclunk
		 * and a Topen, and the original fid will still not be destroyed.
		 */
		closefid(r->fid);
		r->fid = nil;
	}
	qunlock(&r->lk);
	m = write(srv->outfd, srv->wbuf, n);
	if(m != n)
		sysfatal("lib9p srv: write %d returned %d on fd %d: %r", n, m, srv->outfd);
	qunlock(&srv->wlock);

free:
	qlock(&r->lk);	/* no one will add flushes now */

	for(i=0; i<r->nflush; i++){
		r->flush[i]->oldreq = nil;	/* so it doesn't try to lock us! */
		respond(r->flush[i], nil);
	}
	free(r->flush);
	r->flush = nil;
	r->nflush = 0;
	qunlock(&r->lk);

	if(r->pool)
		closereq(r);
	else
		free(r);
}
Example #9
0
File: srv.c Project: 99years/plan9
static void
rattach(Req *r, char *error)
{
	if(error && r->fid)
		closefid(removefid(r->srv->fpool, r->fid->fid));
}