URI:
       tfs.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tfs.c (6137B)
       ---
            1 /* Copyright (C) 2003 Russ Cox, Massachusetts Institute of Technology */
            2 /* See COPYRIGHT */
            3 
            4 #include <u.h>
            5 #include <libc.h>
            6 #include <fcall.h>
            7 #include <9pclient.h>
            8 #include <thread.h>
            9 #include "fsimpl.h"
           10 
           11 static int _fssend(Mux*, void*);
           12 static void *_fsrecv(Mux*);
           13 static int _fsgettag(Mux*, void*);
           14 static int _fssettag(Mux*, void*, uint);
           15 
           16 int chatty9pclient;
           17 int eofkill9pclient;
           18 
           19 enum
           20 {
           21         CFidchunk = 32
           22 };
           23 
           24 CFsys*
           25 fsinit(int fd)
           26 {
           27         CFsys *fs;
           28         int n;
           29 
           30         fmtinstall('F', fcallfmt);
           31         fmtinstall('D', dirfmt);
           32         fmtinstall('M', dirmodefmt);
           33 
           34         fs = mallocz(sizeof(CFsys), 1);
           35         if(fs == nil){
           36                 werrstr("mallocz: %r");
           37                 return nil;
           38         }
           39         fs->fd = fd;
           40         fs->ref = 1;
           41         fs->mux.aux = fs;
           42         fs->mux.mintag = 0;
           43         fs->mux.maxtag = 256;
           44         fs->mux.send = _fssend;
           45         fs->mux.recv = _fsrecv;
           46         fs->mux.gettag = _fsgettag;
           47         fs->mux.settag = _fssettag;
           48         fs->iorecv = ioproc();
           49         fs->iosend = ioproc();
           50         muxinit(&fs->mux);
           51 
           52         strcpy(fs->version, "9P2000");
           53         if((n = fsversion(fs, 8192, fs->version, sizeof fs->version)) < 0){
           54                 werrstr("fsversion: %r");
           55                 _fsunmount(fs);
           56                 return nil;
           57         }
           58         fs->msize = n;
           59         return fs;
           60 }
           61 
           62 CFid*
           63 fsroot(CFsys *fs)
           64 {
           65         /* N.B. no incref */
           66         return fs->root;
           67 }
           68 
           69 CFsys*
           70 fsmount(int fd, char *aname)
           71 {
           72         CFsys *fs;
           73         CFid *fid;
           74 
           75         fs = fsinit(fd);
           76         if(fs == nil)
           77                 return nil;
           78 
           79         if((fid = fsattach(fs, nil, getuser(), aname)) == nil){
           80                 _fsunmount(fs);
           81                 return nil;
           82         }
           83         fssetroot(fs, fid);
           84         return fs;
           85 }
           86 
           87 void
           88 _fsunmount(CFsys *fs)
           89 {
           90         fs->fd = -1;
           91         fsunmount(fs);
           92 }
           93 
           94 void
           95 fsunmount(CFsys *fs)
           96 {
           97         fsclose(fs->root);
           98         fs->root = nil;
           99         _fsdecref(fs);
          100 }
          101 
          102 void
          103 _fsdecref(CFsys *fs)
          104 {
          105         CFid *f, **l, *next;
          106 
          107         qlock(&fs->lk);
          108         --fs->ref;
          109         /*fprint(2, "fsdecref %p to %d\n", fs, fs->ref); */
          110         if(fs->ref == 0){
          111                 if(fs->fd >= 0)
          112                         close(fs->fd);
          113                 /* trim the list down to just the first in each chunk */
          114                 for(l=&fs->freefid; *l; ){
          115                         if((*l)->fid%CFidchunk == 0)
          116                                 l = &(*l)->next;
          117                         else
          118                                 *l = (*l)->next;
          119                 }
          120                 /* now free the list */
          121                 for(f=fs->freefid; f; f=next){
          122                         next = f->next;
          123                         free(f);
          124                 }
          125                 closeioproc(fs->iorecv);
          126                 closeioproc(fs->iosend);
          127                 free(fs);
          128                 return;
          129         }
          130         qunlock(&fs->lk);
          131 }
          132 
          133 int
          134 fsversion(CFsys *fs, int msize, char *version, int nversion)
          135 {
          136         void *freep;
          137         int r, oldmintag, oldmaxtag;
          138         Fcall tx, rx;
          139 
          140         tx.tag = 0;
          141         tx.type = Tversion;
          142         tx.version = version;
          143         tx.msize = msize;
          144 
          145         /*
          146          * bit of a clumsy hack -- force libmux to use NOTAG as tag.
          147          * version can only be sent when there are no other messages
          148          * outstanding on the wire, so this is more reasonable than it looks.
          149          */
          150         oldmintag = fs->mux.mintag;
          151         oldmaxtag = fs->mux.maxtag;
          152         fs->mux.mintag = NOTAG;
          153         fs->mux.maxtag = NOTAG+1;
          154         r = _fsrpc(fs, &tx, &rx, &freep);
          155         fs->mux.mintag = oldmintag;
          156         fs->mux.maxtag = oldmaxtag;
          157         if(r < 0){
          158                 werrstr("fsrpc: %r");
          159                 return -1;
          160         }
          161 
          162         strecpy(version, version+nversion, rx.version);
          163         free(freep);
          164         fs->msize = rx.msize;
          165         return rx.msize;
          166 }
          167 
          168 CFid*
          169 fsattach(CFsys *fs, CFid *afid, char *user, char *aname)
          170 {
          171         Fcall tx, rx;
          172         CFid *fid;
          173 
          174         if(aname == nil)
          175                 aname = "";
          176 
          177         if((fid = _fsgetfid(fs)) == nil)
          178                 return nil;
          179 
          180         tx.tag = 0;
          181         tx.type = Tattach;
          182         tx.afid = afid ? afid->fid : NOFID;
          183         tx.fid = fid->fid;
          184         tx.uname = user;
          185         tx.aname = aname;
          186 
          187         if(_fsrpc(fs, &tx, &rx, 0) < 0){
          188                 _fsputfid(fid);
          189                 return nil;
          190         }
          191         fid->qid = rx.qid;
          192         return fid;
          193 }
          194 
          195 void
          196 fssetroot(CFsys *fs, CFid *fid)
          197 {
          198         if(fs->root)
          199                 _fsputfid(fs->root);
          200         fs->root = fid;
          201 }
          202 
          203 int
          204 _fsrpc(CFsys *fs, Fcall *tx, Fcall *rx, void **freep)
          205 {
          206         int n, nn;
          207         void *tpkt, *rpkt;
          208 
          209         n = sizeS2M(tx);
          210         tpkt = malloc(n);
          211         if(freep)
          212                 *freep = nil;
          213         if(tpkt == nil)
          214                 return -1;
          215         tx->tag = 0;
          216         if(chatty9pclient)
          217                 fprint(2, "<- %F\n", tx);
          218         nn = convS2M(tx, tpkt, n);
          219         if(nn != n){
          220                 free(tpkt);
          221                 werrstr("lib9pclient: sizeS2M convS2M mismatch");
          222                 fprint(2, "%r\n");
          223                 return -1;
          224         }
          225         rpkt = muxrpc(&fs->mux, tpkt);
          226         free(tpkt);
          227         if(rpkt == nil){
          228                 werrstr("muxrpc: %r");
          229                 return -1;
          230         }
          231         n = GBIT32((uchar*)rpkt);
          232         nn = convM2S(rpkt, n, rx);
          233         if(nn != n){
          234                 free(rpkt);
          235                 werrstr("lib9pclient: convM2S packet size mismatch %d %d", n, nn);
          236                 fprint(2, "%r\n");
          237                 return -1;
          238         }
          239         if(chatty9pclient)
          240                 fprint(2, "-> %F\n", rx);
          241         if(rx->type == Rerror){
          242                 werrstr("%s", rx->ename);
          243                 free(rpkt);
          244                 return -1;
          245         }
          246         if(rx->type != tx->type+1){
          247                 werrstr("packet type mismatch -- tx %d rx %d",
          248                         tx->type, rx->type);
          249                 free(rpkt);
          250                 return -1;
          251         }
          252         if(freep)
          253                 *freep = rpkt;
          254         else
          255                 free(rpkt);
          256         return 0;
          257 }
          258 
          259 CFid*
          260 _fsgetfid(CFsys *fs)
          261 {
          262         int i;
          263         CFid *f;
          264 
          265         qlock(&fs->lk);
          266         if(fs->freefid == nil){
          267                 f = mallocz(sizeof(CFid)*CFidchunk, 1);
          268                 if(f == nil){
          269                         qunlock(&fs->lk);
          270                         return nil;
          271                 }
          272                 for(i=0; i<CFidchunk; i++){
          273                         f[i].fid = fs->nextfid++;
          274                         f[i].next = &f[i+1];
          275                         f[i].fs = fs;
          276                 }
          277                 f[i-1].next = nil;
          278                 fs->freefid = f;
          279         }
          280         f = fs->freefid;
          281         fs->freefid = f->next;
          282         fs->ref++;
          283         qunlock(&fs->lk);
          284         f->offset = 0;
          285         f->mode = -1;
          286         f->qid.path = 0;
          287         f->qid.vers = 0;
          288         f->qid.type = 0;
          289         return f;
          290 }
          291 
          292 void
          293 _fsputfid(CFid *f)
          294 {
          295         CFsys *fs;
          296 
          297         fs = f->fs;
          298         qlock(&fs->lk);
          299         f->next = fs->freefid;
          300         fs->freefid = f;
          301         qunlock(&fs->lk);
          302         _fsdecref(fs);
          303 }
          304 
          305 static int
          306 _fsgettag(Mux *mux, void *pkt)
          307 {
          308         return GBIT16((uchar*)pkt+5);
          309 }
          310 
          311 static int
          312 _fssettag(Mux *mux, void *pkt, uint tag)
          313 {
          314         PBIT16((uchar*)pkt+5, tag);
          315         return 0;
          316 }
          317 
          318 static int
          319 _fssend(Mux *mux, void *pkt)
          320 {
          321         CFsys *fs;
          322         int n;
          323 
          324         fs = mux->aux;
          325         n = iowrite(fs->iosend, fs->fd, pkt, GBIT32((uchar*)pkt));
          326         if(n < 0 && eofkill9pclient)
          327                 threadexitsall(nil);
          328         return n;
          329 }
          330 
          331 static void*
          332 _fsrecv(Mux *mux)
          333 {
          334         uchar *pkt;
          335         uchar buf[4];
          336         int n, nfd;
          337         CFsys *fs;
          338 
          339         fs = mux->aux;
          340         n = ioreadn(fs->iorecv, fs->fd, buf, 4);
          341         if(n != 4){
          342                 if(eofkill9pclient)
          343                         threadexitsall(nil);
          344                 return nil;
          345         }
          346         n = GBIT32(buf);
          347         pkt = malloc(n+4);
          348         if(pkt == nil){
          349                 fprint(2, "lib9pclient out of memory reading 9p packet; here comes trouble\n");
          350                 return nil;
          351         }
          352         PBIT32(pkt, n);
          353         if(ioreadn(fs->iorecv, fs->fd, pkt+4, n-4) != n-4){
          354                 free(pkt);
          355                 return nil;
          356         }
          357         if(pkt[4] == Ropenfd){
          358                 if((nfd=iorecvfd(fs->iorecv, fs->fd)) < 0){
          359                         fprint(2, "recv fd error: %r\n");
          360                         free(pkt);
          361                         return nil;
          362                 }
          363                 PBIT32(pkt+n-4, nfd);
          364         }
          365         return pkt;
          366 }
          367 
          368 Qid
          369 fsqid(CFid *fid)
          370 {
          371         return fid->qid;
          372 }