Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

/* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
/* See COPYRIGHT */

#include <u.h>
#include <libc.h>
#include <fcall.h>
#include <9pclient.h>
#include <thread.h>
#include "fsimpl.h"


static int _fssend(CFsys*, void*);
static void *_fsrecv(CFsys*);
static int _fsgettag(void*);
static int _fssettag(void*, uint);

int chatty9pclient;
int eofkill9pclient;

enum
{
        CFidchunk = 32
};


pthread_mutex_t fs_lock;

CFsys*
fsinit(int fd)
{

        pthread_mutex_init(&fs_lock, NULL);


        print ("fsinit \n");
        CFsys *fs;
        int n;
        
        fmtinstall('F', fcallfmt);
        fmtinstall('D', dirfmt);
        fmtinstall('M', dirmodefmt);

        fs = mallocz(sizeof(CFsys), 1);
        if(fs == nil){
                werrstr("mallocz: %r");
                return nil;
        }
        fs->fd = fd;
        fs->ref = 1;
//      fs->mux.aux = fs;
//      fs->mux.mintag = 0;
//      fs->mux.maxtag = 256;
//      fs->mux.send = _fssend;
//      fs->mux.recv = _fsrecv;
//      fs->mux.gettag = _fsgettag;
//      fs->mux.settag = _fssettag;
        //fs->iorecv = ioproc();
        //fs->iosend = ioproc();


//      muxinit(&fs->mux);
        
        strcpy(fs->version, "9P2000");
        if((n = fsversion(fs, 8192, fs->version, sizeof fs->version)) < 0){
                werrstr("fsversion: %r");
                _fsunmount(fs);
                return nil;
        }
        print ("fsinit done\n");
        fs->msize = n;
        return fs;
}

CFid*
fsroot(CFsys *fs)
{
        /* N.B. no incref */
        return fs->root;
}

CFsys*
fsmount(int fd, char *aname)
{
        CFsys *fs;
        CFid *fid;

        fs = fsinit(fd);
        if(fs == nil)
                return nil;

        if((fid = fsattach(fs, nil, getuser(), aname)) == nil){
                _fsunmount(fs);
                return nil;
        }
        fssetroot(fs, fid);
        return fs;
}

void
_fsunmount(CFsys *fs)
{
        fs->fd = -1;
        fsunmount(fs);
}

void
fsunmount(CFsys *fs)
{
        fsclose(fs->root);
        fs->root = nil;
        _fsdecref(fs);
}

void
_fsdecref(CFsys *fs)
{
        CFid *f, **l, *next;

//      qlock(&fs->lk);
        --fs->ref;
        /*fprint(2, "fsdecref %p to %d\n", fs, fs->ref); */
        if(fs->ref == 0){
                if(fs->fd >= 0)
                        close(fs->fd);
                /* trim the list down to just the first in each chunk */
                for(l=&fs->freefid; *l; ){
                        if((*l)->fid%CFidchunk == 0)
                                l = &(*l)->next;
                        else
                                *l = (*l)->next;
                }
                /* now free the list */
                for(f=fs->freefid; f; f=next){
                        next = f->next;
                        free(f);
                }
//              closeioproc(fs->iorecv);
//              closeioproc(fs->iosend);
                free(fs);
                return;
        }
//      qunlock(&fs->lk);
}

int
fsversion(CFsys *fs, int msize, char *version, int nversion)
{
        void *freep;
        int r, oldmintag, oldmaxtag;
        Fcall tx, rx;

        tx.tag = 0;
        tx.type = Tversion;
        tx.version = version;
        tx.msize = msize;

        print ("fsversion \n");
        /*
         * bit of a clumsy hack -- force libmux to use NOTAG as tag.
         * version can only be sent when there are no other messages
         * outstanding on the wire, so this is more reasonable than it looks.
         */
//      oldmintag = fs->mux.mintag;
//      oldmaxtag = fs->mux.maxtag;
//      fs->mux.mintag = NOTAG;
//      fs->mux.maxtag = NOTAG+1;
        r = _fsrpc(fs, &tx, &rx, &freep);
//      fs->mux.mintag = oldmintag;
//      fs->mux.maxtag = oldmaxtag;
        if(r < 0){
                werrstr("fsrpc: %r");
                return -1;
        }
        print ("fsversion done\n");

        strecpy(version, version+nversion, rx.version);
        free(freep);
        fs->msize = rx.msize;
        return rx.msize;
}

CFid*
fsattach(CFsys *fs, CFid *afid, char *user, char *aname)
{
        Fcall tx, rx;
        CFid *fid;

        if(aname == nil)
                aname = "";

        if((fid = _fsgetfid(fs)) == nil)
                return nil;

        tx.tag = 0;
        tx.type = Tattach;
        tx.afid = afid ? afid->fid : NOFID;
        tx.fid = fid->fid;
        tx.uname = user;
        tx.aname = aname;

        if(_fsrpc(fs, &tx, &rx, 0) < 0){
                _fsputfid(fid);
                return nil;
        }
//      fid->qid = rx.qid;
        return fid;
}

void
fssetroot(CFsys *fs, CFid *fid)
{
        if(fs->root)
                _fsputfid(fs->root);
        fs->root = fid;
}





void*
mixrpc(CFsys *fs, void *tx, int n)
{
        fs_sock_send(fs->fd,tx,n);
        return _fsrecv(fs);
}


int
_fsrpc(CFsys *fs, Fcall *tx, Fcall *rx, void **freep)
{
        int n, nn;
        void *tpkt, *rpkt;

        print ("_fsrpc >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> \n");

        n = sizeS2M(tx);
        tpkt = malloc(n);
        if(freep)
                *freep = nil;
        if(tpkt == nil)
                return -1;
        tx->tag = 0;
        if(chatty9pclient)
                fprint(2, "<- %F\n", tx);
        nn = convS2M(tx, tpkt, n);
        if(nn != n){
                free(tpkt);
                werrstr("lib9pclient: sizeS2M convS2M mismatch");
                fprint(2, "%r\n");
                return -1;
        }
        print ("_fsrpc muxrpc \n");

        rpkt = mixrpc(fs, tpkt, nn);


        print ("_fsrpc muxrpc done\n");
        free(tpkt);
        if(rpkt == nil){
                werrstr("muxrpc: %r");
                return -1;
        }
        n = GBIT32((uchar*)rpkt);
        nn = convM2S(rpkt, n, rx);
        if(nn != n){
                free(rpkt);
                werrstr("lib9pclient: convM2S packet size mismatch %d %d", n, nn);
                fprint(2, "%r\n");
                return -1;
        }
        if(chatty9pclient)
                fprint(2, "-> %F\n", rx);
        print ("_fsrpc done\n");
        if(rx->type == Rerror){
                werrstr("%s", rx->ename);
                free(rpkt);
                return -1;
        }
        if(rx->type != tx->type+1){
                werrstr("packet type mismatch -- tx %d rx %d",
                        tx->type, rx->type);
                free(rpkt);
                return -1;
        }
        if(freep)
                *freep = rpkt;
        else
                free(rpkt);
        return 0;
}

CFid*
_fsgetfid(CFsys *fs)
{
        int i;
        CFid *f;

//      print("getlock find  %p\n",&fs->lk);
//      qlock(&fs->lk);
//      print("getlock find done \n");


        if(fs->freefid == nil){
                f = mallocz(sizeof(CFid)*CFidchunk, 1);
                if(f == nil){
//                      qunlock(&fs->lk);
                        return nil;
                }
                for(i=0; i<CFidchunk; i++){
                        f[i].fid = fs->nextfid++;
                        f[i].next = &f[i+1];
                        f[i].fs = fs;
                }
                f[i-1].next = nil;
                fs->freefid = f;
        }
        f = fs->freefid;
        fs->freefid = f->next;
        fs->ref++;
//      qunlock(&fs->lk);
        f->offset = 0;
        f->mode = -1;
//      f->qid.path = 0;
//      f->qid.vers = 0;
//      f->qid.type = 0;
        return f;
}

void
_fsputfid(CFid *f)
{
        CFsys *fs;

        fs = f->fs;
//qlock/        qlock(&fs->lk);
        f->next = fs->freefid;
        fs->freefid = f;
//      qunlock(&fs->lk);
        _fsdecref(fs);
}

static int
_fsgettag(void *pkt)
{
        print ("_fsgettag entered\n");
        return GBIT16((uchar*)pkt+5);
}

static int
_fssettag(void *pkt, uint tag)
{
        print ("_fssettag entered\n");
        PBIT16((uchar*)pkt+5, tag);
        return 0;
}

static void*
_fsrecv(CFsys *fs)
{
        uchar *pkt;
        uchar buf[4];
        int n, nfd;
//      CFsys *fs;


        print ("_fsrecv entered\n");

//      fs = mux->aux;
//      n = ioreadn(fs->iorecv, fs->fd, buf, 4);
        n = fs_sock_recv(fs->fd,buf,4); 
        if(n != 4){
                if(eofkill9pclient)
                        threadexitsall(nil);
                return nil;
        }
        n = GBIT32(buf);
        pkt = malloc(n+4);
        if(pkt == nil){
                fprint(2, "lib9pclient out of memory reading 9p packet; here comes trouble\n");
                return nil;
        }
        PBIT32(pkt, n);
// tabbe
        if(fs_sock_recv( fs->fd, pkt+4, n-4) != n-4){
                free(pkt);
                return nil;
        }

/*      if(pkt[4] == Ropenfd){
                if((nfd=iorecvfd(fs->iorecv, fs->fd)) < 0){
                        fprint(2, "recv fd error: %r\n");
                        free(pkt);
                        return nil;
                }
                PBIT32(pkt+n-4, nfd);
        }*/
        return pkt;
}

/*
Qid
fsqid(CFid *fid)
{
        print ("_fsquid entered\n");
        return fid->qid;
}
*/