14366bb71SDavid du Colombier #include <u.h>
24366bb71SDavid du Colombier #include <libc.h>
34366bb71SDavid du Colombier #include <auth.h>
44366bb71SDavid du Colombier #include <fcall.h>
54366bb71SDavid du Colombier #include <thread.h>
64366bb71SDavid du Colombier
74366bb71SDavid du Colombier /*
84366bb71SDavid du Colombier * to do:
94366bb71SDavid du Colombier * - concurrency?
104366bb71SDavid du Colombier * - only worthwhile with several connections, perhaps to several file servers
114366bb71SDavid du Colombier * - cache directories
124366bb71SDavid du Colombier * - message size (dynamic buffers)
134366bb71SDavid du Colombier * - more useful stats
144366bb71SDavid du Colombier * - notes
154366bb71SDavid du Colombier * - lru for sfids in paths (also correct ref counts for paths)
164366bb71SDavid du Colombier */
174366bb71SDavid du Colombier
184366bb71SDavid du Colombier #include "dat.h"
194366bb71SDavid du Colombier #include "fns.h"
204366bb71SDavid du Colombier #include "stats.h"
214366bb71SDavid du Colombier
224366bb71SDavid du Colombier #define DPRINT if(debug)fprint
234366bb71SDavid du Colombier
244366bb71SDavid du Colombier /* maximum length of a file (used for unknown lengths) */
254366bb71SDavid du Colombier enum { MAXLEN = ((uvlong)1<<63)-1 };
264366bb71SDavid du Colombier
274366bb71SDavid du Colombier int debug, statson, noauth, openserver;
284366bb71SDavid du Colombier
294366bb71SDavid du Colombier #define MAXFDATA 8192 /* i/o size for read/write */
304366bb71SDavid du Colombier
314366bb71SDavid du Colombier struct P9fs
324366bb71SDavid du Colombier {
334366bb71SDavid du Colombier int fd[2];
344366bb71SDavid du Colombier Fcall thdr;
354366bb71SDavid du Colombier Fcall rhdr;
364366bb71SDavid du Colombier uchar sndbuf[MAXFDATA+IOHDRSZ]; /* TO DO: dynamic */
374366bb71SDavid du Colombier uchar rcvbuf[2][MAXFDATA + IOHDRSZ]; /* extra buffer to protect client data over server calls */
384366bb71SDavid du Colombier int cb; /* current buffer */
394366bb71SDavid du Colombier long len;
404366bb71SDavid du Colombier char *name;
414366bb71SDavid du Colombier };
424366bb71SDavid du Colombier
434366bb71SDavid du Colombier P9fs c; /* client conversation */
444366bb71SDavid du Colombier P9fs s; /* server conversation */
454366bb71SDavid du Colombier
464366bb71SDavid du Colombier Host host[1]; /* clients, just the one for now */
474366bb71SDavid du Colombier
484366bb71SDavid du Colombier Cfsstat cfsstat, cfsprev;
494366bb71SDavid du Colombier char statbuf[2048];
504366bb71SDavid du Colombier int statlen;
514366bb71SDavid du Colombier
524366bb71SDavid du Colombier int messagesize = MAXFDATA+IOHDRSZ; /* must be the same for all connections */
534366bb71SDavid du Colombier
544366bb71SDavid du Colombier Qid rootqid;
554366bb71SDavid du Colombier Qid ctlqid = {0x5555555555555555LL, 0, 0};
564366bb71SDavid du Colombier
574366bb71SDavid du Colombier uint cachesize = 16 * 1024 * 1024;
584366bb71SDavid du Colombier
594366bb71SDavid du Colombier /*
604366bb71SDavid du Colombier * clients directly access directories, auth files, append-only files, exclusive-use files, and mount points
614366bb71SDavid du Colombier */
624366bb71SDavid du Colombier #define isdirect(qid) (((qid).type & ~QTTMP) != QTFILE)
634366bb71SDavid du Colombier
644366bb71SDavid du Colombier static char Efidinuse[] = "fid in use";
654366bb71SDavid du Colombier static char Ebadfid[] = "invalid fid";
664366bb71SDavid du Colombier static char Enotdir[] = "not a directory";
674366bb71SDavid du Colombier static char Enonexist[] = "file does not exist";
684366bb71SDavid du Colombier static char Eexist[] = "file already exists";
694366bb71SDavid du Colombier static char Eopened[] = "opened for I/O";
704366bb71SDavid du Colombier static char Emode[] = "bad open mode";
714366bb71SDavid du Colombier static char Eremoved[] = "file has been removed";
724366bb71SDavid du Colombier
734366bb71SDavid du Colombier static SFid* freefids;
744366bb71SDavid du Colombier static u32int fidgen;
754366bb71SDavid du Colombier
764366bb71SDavid du Colombier static Data datalist;
774366bb71SDavid du Colombier
784366bb71SDavid du Colombier static Auth* authlist;
794366bb71SDavid du Colombier
804366bb71SDavid du Colombier void
usage(void)814366bb71SDavid du Colombier usage(void)
824366bb71SDavid du Colombier {
83*518acb85SDavid du Colombier fprint(2, "usage: %s [-a netaddr | -F srv] [-dknS] [mntpt] [spec]\n", argv0);
844366bb71SDavid du Colombier threadexitsall("usage");
854366bb71SDavid du Colombier }
864366bb71SDavid du Colombier
874366bb71SDavid du Colombier void
threadmain(int argc,char * argv[])884366bb71SDavid du Colombier threadmain(int argc, char *argv[])
894366bb71SDavid du Colombier {
904366bb71SDavid du Colombier int std;
91*518acb85SDavid du Colombier char *server, *mtpt, *aname;
924366bb71SDavid du Colombier
934366bb71SDavid du Colombier std = 0;
944366bb71SDavid du Colombier server = "net!$server";
954366bb71SDavid du Colombier mtpt = "/n/remote";
96*518acb85SDavid du Colombier aname = "";
974366bb71SDavid du Colombier
984366bb71SDavid du Colombier ARGBEGIN{
994366bb71SDavid du Colombier case 'a':
1004366bb71SDavid du Colombier server = EARGF(usage());
1014366bb71SDavid du Colombier break;
1024366bb71SDavid du Colombier case 'd':
1034366bb71SDavid du Colombier debug = 1;
1044366bb71SDavid du Colombier break;
1054366bb71SDavid du Colombier case 'F':
1064366bb71SDavid du Colombier server = EARGF(usage());
1074366bb71SDavid du Colombier openserver = 1;
1084366bb71SDavid du Colombier break;
1094366bb71SDavid du Colombier case 'm':
1104366bb71SDavid du Colombier cachesize = atoi(EARGF(usage())) * 1024 * 1024;
1114366bb71SDavid du Colombier if(cachesize < 8 * 1024 * 1024 ||
1124366bb71SDavid du Colombier cachesize > 3750UL * 1024 * 1024)
1134366bb71SDavid du Colombier sysfatal("implausible cache size %ud", cachesize);
1144366bb71SDavid du Colombier break;
1154366bb71SDavid du Colombier case 'n':
1164366bb71SDavid du Colombier noauth = 1;
1174366bb71SDavid du Colombier break;
1184366bb71SDavid du Colombier case 'S':
1194366bb71SDavid du Colombier statson = 1;
1204366bb71SDavid du Colombier break;
1214366bb71SDavid du Colombier case 's':
1224366bb71SDavid du Colombier std = 1;
1234366bb71SDavid du Colombier break;
1244366bb71SDavid du Colombier default:
1254366bb71SDavid du Colombier usage();
1264366bb71SDavid du Colombier }ARGEND
1274366bb71SDavid du Colombier if(argc && *argv)
1284366bb71SDavid du Colombier mtpt = *argv;
129*518acb85SDavid du Colombier if(argc > 1 && argv[1])
130*518acb85SDavid du Colombier aname = argv[1];
1314366bb71SDavid du Colombier
1324366bb71SDavid du Colombier quotefmtinstall();
1334366bb71SDavid du Colombier if(debug){
1344366bb71SDavid du Colombier fmtinstall('F', fcallfmt);
1354366bb71SDavid du Colombier fmtinstall('D', dirfmt);
1364366bb71SDavid du Colombier fmtinstall('M', dirmodefmt);
1374366bb71SDavid du Colombier }
1384366bb71SDavid du Colombier
1394366bb71SDavid du Colombier c.name = "client";
1404366bb71SDavid du Colombier s.name = "server";
1414366bb71SDavid du Colombier if(std){
1424366bb71SDavid du Colombier c.fd[0] = c.fd[1] = 1;
1434366bb71SDavid du Colombier s.fd[0] = s.fd[1] = 0;
1444366bb71SDavid du Colombier }else
145*518acb85SDavid du Colombier mountinit(server, mtpt, aname);
1464366bb71SDavid du Colombier
1474366bb71SDavid du Colombier switch(fork()){
1484366bb71SDavid du Colombier case 0:
1494366bb71SDavid du Colombier io();
1504366bb71SDavid du Colombier threadexits("");
1514366bb71SDavid du Colombier case -1:
1524366bb71SDavid du Colombier error("fork");
1534366bb71SDavid du Colombier default:
1544366bb71SDavid du Colombier _exits("");
1554366bb71SDavid du Colombier }
1564366bb71SDavid du Colombier }
1574366bb71SDavid du Colombier
1584366bb71SDavid du Colombier /*
1594366bb71SDavid du Colombier * TO DO: need to use libthread variants
1604366bb71SDavid du Colombier */
1614366bb71SDavid du Colombier void
mountinit(char * server,char * mountpoint,char * aname)162*518acb85SDavid du Colombier mountinit(char *server, char *mountpoint, char *aname)
1634366bb71SDavid du Colombier {
1644366bb71SDavid du Colombier int err;
1654366bb71SDavid du Colombier int p[2];
1664366bb71SDavid du Colombier
1674366bb71SDavid du Colombier /*
1684366bb71SDavid du Colombier * grab a channel and call up the file server
1694366bb71SDavid du Colombier */
1704366bb71SDavid du Colombier if(openserver){
1714366bb71SDavid du Colombier s.fd[0] = open(server, ORDWR);
1724366bb71SDavid du Colombier if(s.fd[0] < 0)
1734366bb71SDavid du Colombier error("opening srv file %s: %r", server);
1744366bb71SDavid du Colombier } else {
1754366bb71SDavid du Colombier s.fd[0] = dial(netmkaddr(server, 0, "9fs"), 0, 0, 0);
1764366bb71SDavid du Colombier if(s.fd[0] < 0)
1774366bb71SDavid du Colombier error("dialing %s: %r", server);
1784366bb71SDavid du Colombier }
1794366bb71SDavid du Colombier s.fd[1] = s.fd[0];
1804366bb71SDavid du Colombier
1814366bb71SDavid du Colombier /*
1824366bb71SDavid du Colombier * mount onto name space
1834366bb71SDavid du Colombier */
1844366bb71SDavid du Colombier if(pipe(p) < 0)
1854366bb71SDavid du Colombier error("pipe failed");
1864366bb71SDavid du Colombier switch(fork()){
1874366bb71SDavid du Colombier case 0:
1884366bb71SDavid du Colombier break;
1894366bb71SDavid du Colombier default:
1904366bb71SDavid du Colombier rfork(RFFDG);
1914366bb71SDavid du Colombier close(p[0]);
1924366bb71SDavid du Colombier if(noauth)
193*518acb85SDavid du Colombier err = mount(p[1], -1, mountpoint, MREPL|MCREATE|MCACHE, aname);
1944366bb71SDavid du Colombier else
195*518acb85SDavid du Colombier err = amount(p[1], mountpoint, MREPL|MCREATE|MCACHE, aname);
1964366bb71SDavid du Colombier if(err < 0)
1974366bb71SDavid du Colombier error("mount failed: %r");
1984366bb71SDavid du Colombier _exits(0);
1994366bb71SDavid du Colombier case -1:
2004366bb71SDavid du Colombier error("fork failed\n");
2014366bb71SDavid du Colombier /*BUG: no wait!*/
2024366bb71SDavid du Colombier }
2034366bb71SDavid du Colombier close(p[1]);
2044366bb71SDavid du Colombier c.fd[0] = c.fd[1] = p[0];
2054366bb71SDavid du Colombier }
2064366bb71SDavid du Colombier
2074366bb71SDavid du Colombier void
io(void)2084366bb71SDavid du Colombier io(void)
2094366bb71SDavid du Colombier {
2104366bb71SDavid du Colombier Fcall *t;
2114366bb71SDavid du Colombier
2124366bb71SDavid du Colombier datainit();
2134366bb71SDavid du Colombier t = &c.thdr;
2144366bb71SDavid du Colombier
2154366bb71SDavid du Colombier loop:
2164366bb71SDavid du Colombier rcvmsg(&c, t);
2174366bb71SDavid du Colombier
2184366bb71SDavid du Colombier if(statson){
2194366bb71SDavid du Colombier cfsstat.cm[t->type].n++;
2204366bb71SDavid du Colombier cfsstat.cm[t->type].s = nsec();
2214366bb71SDavid du Colombier }
2224366bb71SDavid du Colombier switch(t->type){
2234366bb71SDavid du Colombier default:
2244366bb71SDavid du Colombier sendreply("invalid 9p operation");
2254366bb71SDavid du Colombier break;
2264366bb71SDavid du Colombier case Tversion:
2274366bb71SDavid du Colombier rversion(t);
2284366bb71SDavid du Colombier break;
2294366bb71SDavid du Colombier case Tauth:
2304366bb71SDavid du Colombier rauth(t);
2314366bb71SDavid du Colombier break;
2324366bb71SDavid du Colombier case Tflush:
2334366bb71SDavid du Colombier rflush(t);
2344366bb71SDavid du Colombier break;
2354366bb71SDavid du Colombier case Tattach:
2364366bb71SDavid du Colombier rattach(t);
2374366bb71SDavid du Colombier break;
2384366bb71SDavid du Colombier case Twalk:
2394366bb71SDavid du Colombier rwalk(t);
2404366bb71SDavid du Colombier break;
2414366bb71SDavid du Colombier case Topen:
2424366bb71SDavid du Colombier ropen(t);
2434366bb71SDavid du Colombier break;
2444366bb71SDavid du Colombier case Tcreate:
2454366bb71SDavid du Colombier rcreate(t);
2464366bb71SDavid du Colombier break;
2474366bb71SDavid du Colombier case Tread:
2484366bb71SDavid du Colombier rread(t);
2494366bb71SDavid du Colombier break;
2504366bb71SDavid du Colombier case Twrite:
2514366bb71SDavid du Colombier rwrite(t);
2524366bb71SDavid du Colombier break;
2534366bb71SDavid du Colombier case Tclunk:
2544366bb71SDavid du Colombier rclunk(t);
2554366bb71SDavid du Colombier break;
2564366bb71SDavid du Colombier case Tremove:
2574366bb71SDavid du Colombier rremove(t);
2584366bb71SDavid du Colombier break;
2594366bb71SDavid du Colombier case Tstat:
2604366bb71SDavid du Colombier rstat(t);
2614366bb71SDavid du Colombier break;
2624366bb71SDavid du Colombier case Twstat:
2634366bb71SDavid du Colombier rwstat(t);
2644366bb71SDavid du Colombier break;
2654366bb71SDavid du Colombier }
2664366bb71SDavid du Colombier if(statson){
2674366bb71SDavid du Colombier cfsstat.cm[t->type].t += nsec() -cfsstat.cm[t->type].s;
2684366bb71SDavid du Colombier }
2694366bb71SDavid du Colombier goto loop;
2704366bb71SDavid du Colombier }
2714366bb71SDavid du Colombier
2724366bb71SDavid du Colombier void
rversion(Fcall * t)2734366bb71SDavid du Colombier rversion(Fcall *t)
2744366bb71SDavid du Colombier {
2754366bb71SDavid du Colombier if(messagesize > t->msize)
2764366bb71SDavid du Colombier messagesize = t->msize;
2774366bb71SDavid du Colombier t->msize = messagesize; /* set downstream size */
2784366bb71SDavid du Colombier delegate(t, nil, nil);
2794366bb71SDavid du Colombier }
2804366bb71SDavid du Colombier
2814366bb71SDavid du Colombier void
rauth(Fcall * t)2824366bb71SDavid du Colombier rauth(Fcall *t)
2834366bb71SDavid du Colombier {
2844366bb71SDavid du Colombier Fid *mf;
2854366bb71SDavid du Colombier
2864366bb71SDavid du Colombier mf = findfid(host, t->afid, 1);
2874366bb71SDavid du Colombier if(mf == nil)
2884366bb71SDavid du Colombier return;
2894366bb71SDavid du Colombier mf->path = newpath(nil, "#auth", (Qid){0, 0, 0}); /* path name is never used */
2904366bb71SDavid du Colombier mf->opened = allocsfid(); /* newly allocated */
2914366bb71SDavid du Colombier if(delegate(t, mf, nil) == 0){
2924366bb71SDavid du Colombier mf->qid = s.rhdr.aqid;
2934366bb71SDavid du Colombier mf->mode = ORDWR;
2944366bb71SDavid du Colombier }else{
2954366bb71SDavid du Colombier freesfid(mf->opened); /* free, don't clunk: failed to establish */
2964366bb71SDavid du Colombier mf->opened = nil;
2974366bb71SDavid du Colombier putfid(mf);
2984366bb71SDavid du Colombier }
2994366bb71SDavid du Colombier }
3004366bb71SDavid du Colombier
3014366bb71SDavid du Colombier void
rflush(Fcall *)3024366bb71SDavid du Colombier rflush(Fcall*) /* synchronous so easy */
3034366bb71SDavid du Colombier {
3044366bb71SDavid du Colombier /*TO DO: need a tag hash to find requests, once auth is asynchronous */
3054366bb71SDavid du Colombier sendreply(0);
3064366bb71SDavid du Colombier }
3074366bb71SDavid du Colombier
3084366bb71SDavid du Colombier void
rattach(Fcall * t)3094366bb71SDavid du Colombier rattach(Fcall *t)
3104366bb71SDavid du Colombier {
3114366bb71SDavid du Colombier Fid *mf, *afid;
3124366bb71SDavid du Colombier SFid *sfid;
3134366bb71SDavid du Colombier
3144366bb71SDavid du Colombier mf = findfid(host, t->fid, 1);
3154366bb71SDavid du Colombier if(mf == nil)
3164366bb71SDavid du Colombier return;
3174366bb71SDavid du Colombier sfid = nil;
3184366bb71SDavid du Colombier if(t->afid != NOFID){
3194366bb71SDavid du Colombier afid = findfid(host, t->afid, 0);
3204366bb71SDavid du Colombier if(afid == nil)
3214366bb71SDavid du Colombier return;
3224366bb71SDavid du Colombier sfid = afid->opened;
3234366bb71SDavid du Colombier if((afid->qid.type & QTAUTH) == 0 || sfid == nil){
3244366bb71SDavid du Colombier sendreply("bad auth file");
3254366bb71SDavid du Colombier return;
3264366bb71SDavid du Colombier }
3274366bb71SDavid du Colombier }
3284366bb71SDavid du Colombier mf->path = newpath(nil, "", (Qid){0, 0, 0});
3294366bb71SDavid du Colombier mf->path->sfid = allocsfid(); /* newly allocated */
3304366bb71SDavid du Colombier if(delegate(t, mf, sfid) == 0){
3314366bb71SDavid du Colombier mf->qid = s.rhdr.qid;
3324366bb71SDavid du Colombier mf->path->qid = mf->qid;
3334366bb71SDavid du Colombier if(statson == 1){
3344366bb71SDavid du Colombier statson++;
3354366bb71SDavid du Colombier rootqid = mf->qid;
3364366bb71SDavid du Colombier }
3374366bb71SDavid du Colombier }else{
3384366bb71SDavid du Colombier freesfid(mf->path->sfid); /* free, don't clunk: failed to establish */
3394366bb71SDavid du Colombier mf->path->sfid = nil;
3404366bb71SDavid du Colombier putfid(mf);
3414366bb71SDavid du Colombier }
3424366bb71SDavid du Colombier }
3434366bb71SDavid du Colombier
3444366bb71SDavid du Colombier void
rwalk(Fcall * t)3454366bb71SDavid du Colombier rwalk(Fcall *t)
3464366bb71SDavid du Colombier {
3474366bb71SDavid du Colombier Fid *mf, *nmf;
3484366bb71SDavid du Colombier SFid *sfid;
3494366bb71SDavid du Colombier Path *p;
3504366bb71SDavid du Colombier char *n;
3514366bb71SDavid du Colombier int i;
3524366bb71SDavid du Colombier
3534366bb71SDavid du Colombier mf = findfid(host, t->fid, 0);
3544366bb71SDavid du Colombier if(mf == nil)
3554366bb71SDavid du Colombier return;
3564366bb71SDavid du Colombier if(mf->path){
3574366bb71SDavid du Colombier DPRINT(2, "walk from %p %q + %d\n", mf, pathstr(mf->path), t->nwname);
3584366bb71SDavid du Colombier }
359*518acb85SDavid du Colombier if(mf->path->inval){
360*518acb85SDavid du Colombier sendreply(mf->path->inval);
361*518acb85SDavid du Colombier return;
362*518acb85SDavid du Colombier }
3634366bb71SDavid du Colombier nmf = nil;
3644366bb71SDavid du Colombier if(t->newfid != t->fid){
3654366bb71SDavid du Colombier nmf = findfid(host, t->newfid, 1);
3664366bb71SDavid du Colombier if(nmf == nil)
3674366bb71SDavid du Colombier return;
3684366bb71SDavid du Colombier nmf->qid = mf->qid;
3694366bb71SDavid du Colombier if(nmf->path != nil)
3704366bb71SDavid du Colombier freepath(nmf->path);
3714366bb71SDavid du Colombier mf->path->ref++;
3724366bb71SDavid du Colombier nmf->path = mf->path;
3734366bb71SDavid du Colombier mf = nmf; /* Walk mf */
3744366bb71SDavid du Colombier }
3754366bb71SDavid du Colombier
3764366bb71SDavid du Colombier if(statson &&
3774366bb71SDavid du Colombier mf->qid.type == rootqid.type && mf->qid.path == rootqid.path &&
3784366bb71SDavid du Colombier t->nwname == 1 && strcmp(t->wname[0], "cfsctl") == 0){
3794366bb71SDavid du Colombier /* This is the ctl file */
3804366bb71SDavid du Colombier mf->qid = ctlqid;
3814366bb71SDavid du Colombier c.rhdr.nwqid = 1;
3824366bb71SDavid du Colombier c.rhdr.wqid[0] = ctlqid;
3834366bb71SDavid du Colombier sendreply(0);
3844366bb71SDavid du Colombier return;
3854366bb71SDavid du Colombier }
3864366bb71SDavid du Colombier
3874366bb71SDavid du Colombier /*
3884366bb71SDavid du Colombier * need this as an invariant, and it should always be true, because
3894366bb71SDavid du Colombier * Twalk.fid should exist and thus have sfid. could compensate by
3904366bb71SDavid du Colombier * rewalking from nearest parent with sfid (in the limit, root from attach)
3914366bb71SDavid du Colombier */
3924366bb71SDavid du Colombier assert(mf->path->sfid != nil);
3934366bb71SDavid du Colombier
3944366bb71SDavid du Colombier if(t->nwname == 0){
3954366bb71SDavid du Colombier /* new local fid (if any) refers to existing path, shares its sfid via that path */
3964366bb71SDavid du Colombier c.rhdr.nwqid = 0;
3974366bb71SDavid du Colombier sendreply(0);
3984366bb71SDavid du Colombier return;
3994366bb71SDavid du Colombier }
4004366bb71SDavid du Colombier
4014366bb71SDavid du Colombier /* t->nwname != 0 */
4024366bb71SDavid du Colombier
4034366bb71SDavid du Colombier if(localwalk(mf, &c.thdr, &c.rhdr, &p)){
4044366bb71SDavid du Colombier /* it all worked or is known to fail (in all or in part) */
4054366bb71SDavid du Colombier if(c.rhdr.type == Rerror){
4064366bb71SDavid du Colombier DPRINT(2, "walk error: %q\n", c.rhdr.ename);
4074366bb71SDavid du Colombier sendreply(c.rhdr.ename);
4084366bb71SDavid du Colombier if(nmf != nil)
4094366bb71SDavid du Colombier putfid(nmf);
4104366bb71SDavid du Colombier return;
4114366bb71SDavid du Colombier }
4124366bb71SDavid du Colombier if(c.rhdr.nwqid != t->nwname){
4134366bb71SDavid du Colombier DPRINT(2, "partial walk, hit error\n");
4144366bb71SDavid du Colombier sendreply(0);
4154366bb71SDavid du Colombier if(nmf != nil)
4164366bb71SDavid du Colombier putfid(nmf);
4174366bb71SDavid du Colombier return;
4184366bb71SDavid du Colombier }
4194366bb71SDavid du Colombier DPRINT(2, "seen it: %q %q\n", pathstr(p), p->inval);
4204366bb71SDavid du Colombier if(p->sfid != nil){
4214366bb71SDavid du Colombier p->ref++;
4224366bb71SDavid du Colombier freepath(mf->path);
4234366bb71SDavid du Colombier mf->path = p;
4244366bb71SDavid du Colombier if(c.rhdr.nwqid > 0)
4254366bb71SDavid du Colombier mf->qid = c.rhdr.wqid[c.rhdr.nwqid-1];
4264366bb71SDavid du Colombier sendreply(0);
4274366bb71SDavid du Colombier return;
4284366bb71SDavid du Colombier }
4294366bb71SDavid du Colombier /* know the path, but need a fid on the server */
4304366bb71SDavid du Colombier }
4314366bb71SDavid du Colombier
4324366bb71SDavid du Colombier /* walk to a new server fid (ie, server always sees fid != newfid) */
4334366bb71SDavid du Colombier sfid = allocsfid(); /* must release it, if walk doesn't work */
4344366bb71SDavid du Colombier
4354366bb71SDavid du Colombier if(delegate(t, mf, sfid) < 0){ /* complete failure */
4364366bb71SDavid du Colombier if(t->nwname > 0){ /* cache first item's failure */
4374366bb71SDavid du Colombier DPRINT(2, "bad path: %q + %q -> %q\n", pathstr(mf->path), t->wname[0], s.rhdr.ename);
4384366bb71SDavid du Colombier badpath(mf->path, t->wname[0], s.rhdr.ename);
4394366bb71SDavid du Colombier }
4404366bb71SDavid du Colombier if(nmf != nil)
4414366bb71SDavid du Colombier putfid(nmf);
4424366bb71SDavid du Colombier freesfid(sfid); /* no need to clunk it, since it hasn't been assigned */
4434366bb71SDavid du Colombier return;
4444366bb71SDavid du Colombier }
4454366bb71SDavid du Colombier
4464366bb71SDavid du Colombier if(s.rhdr.nwqid == t->nwname){ /* complete success */
4474366bb71SDavid du Colombier for(i = 0; i < t->nwname; i++){
4484366bb71SDavid du Colombier n = t->wname[i];
4494366bb71SDavid du Colombier if(strcmp(n, "..") == 0){
4504366bb71SDavid du Colombier p = mf->path->parent;
4514366bb71SDavid du Colombier if(p != nil){ /* otherwise at root, no change */
4524366bb71SDavid du Colombier p->ref++;
4534366bb71SDavid du Colombier freepath(mf->path);
4544366bb71SDavid du Colombier mf->path = p;
4554366bb71SDavid du Colombier }
4564366bb71SDavid du Colombier }else
4574366bb71SDavid du Colombier mf->path = newpath(mf->path, n, s.rhdr.wqid[i]);
4584366bb71SDavid du Colombier }
4594366bb71SDavid du Colombier mf->qid = s.rhdr.wqid[s.rhdr.nwqid-1]; /* nwname != 0 (above) */
4604366bb71SDavid du Colombier if(mf->path->sfid != nil){
4614366bb71SDavid du Colombier /* shouldn't happen (otherwise we wouldn't walk, because localwalk would find it) */
4624366bb71SDavid du Colombier sysfatal("rwalk: unexpected sfid: %q -> %ud\n", pathstr(mf->path), mf->path->sfid->fid);
4634366bb71SDavid du Colombier }
4644366bb71SDavid du Colombier mf->path->sfid = sfid;
4654366bb71SDavid du Colombier return;
4664366bb71SDavid du Colombier }
4674366bb71SDavid du Colombier
4684366bb71SDavid du Colombier /* partial success; note success and failure, and release fid */
4694366bb71SDavid du Colombier p = mf->path;
4704366bb71SDavid du Colombier for(i = 0; i < s.rhdr.nwqid; i++){
4714366bb71SDavid du Colombier n = t->wname[i];
4724366bb71SDavid du Colombier if(strcmp(n, "..") == 0){
4734366bb71SDavid du Colombier if(p->parent != nil)
4744366bb71SDavid du Colombier p = p->parent;
4754366bb71SDavid du Colombier }else
4764366bb71SDavid du Colombier p = newpath(p, n, s.rhdr.wqid[i]);
4774366bb71SDavid du Colombier }
4784366bb71SDavid du Colombier n = t->wname[i];
4794366bb71SDavid du Colombier if(i == 0 || s.rhdr.wqid[i-1].type & QTDIR)
4804366bb71SDavid du Colombier badpath(p, n, Enonexist);
4814366bb71SDavid du Colombier if(nmf != nil)
4824366bb71SDavid du Colombier putfid(nmf);
4834366bb71SDavid du Colombier freesfid(sfid);
4844366bb71SDavid du Colombier }
4854366bb71SDavid du Colombier
4864366bb71SDavid du Colombier int
localwalk(Fid * mf,Fcall * t,Fcall * r,Path ** pp)4874366bb71SDavid du Colombier localwalk(Fid *mf, Fcall *t, Fcall *r, Path **pp)
4884366bb71SDavid du Colombier {
4894366bb71SDavid du Colombier Path *p, *q;
4904366bb71SDavid du Colombier char *n, *err;
4914366bb71SDavid du Colombier int i;
4924366bb71SDavid du Colombier
4934366bb71SDavid du Colombier *pp = nil;
4944366bb71SDavid du Colombier if(t->nwname == 0)
4954366bb71SDavid du Colombier return 0; /* clone */
4964366bb71SDavid du Colombier if(mf->path == nil)
4974366bb71SDavid du Colombier return 0;
4984366bb71SDavid du Colombier r->type = Rwalk;
4994366bb71SDavid du Colombier r->nwqid = 0;
5004366bb71SDavid du Colombier p = mf->path;
5014366bb71SDavid du Colombier for(i = 0; i < t->nwname; i++){
5024366bb71SDavid du Colombier n = t->wname[i];
5034366bb71SDavid du Colombier if((err = p->inval) != nil)
5044366bb71SDavid du Colombier goto Err;
5054366bb71SDavid du Colombier if((p->qid.type & QTDIR) == 0){
5064366bb71SDavid du Colombier err = Enotdir;
5074366bb71SDavid du Colombier goto Err;
5084366bb71SDavid du Colombier }
5094366bb71SDavid du Colombier if(strcmp(n, "..") == 0){
5104366bb71SDavid du Colombier if((q = p->parent) == nil)
5114366bb71SDavid du Colombier q = p;
5124366bb71SDavid du Colombier }else{
5134366bb71SDavid du Colombier for(q = p->child; q != nil; q = q->next){
5144366bb71SDavid du Colombier if(strcmp(n, q->name) == 0){
5154366bb71SDavid du Colombier if((err = q->inval) != nil)
5164366bb71SDavid du Colombier goto Err;
5174366bb71SDavid du Colombier break;
5184366bb71SDavid du Colombier }
5194366bb71SDavid du Colombier }
5204366bb71SDavid du Colombier if(q == nil)
5214366bb71SDavid du Colombier return 0; /* not found in cache, must try server */
5224366bb71SDavid du Colombier }
5234366bb71SDavid du Colombier r->wqid[r->nwqid++] = q->qid;
5244366bb71SDavid du Colombier p = q;
5254366bb71SDavid du Colombier }
5264366bb71SDavid du Colombier /* found them all: if p's not locally NOFID, link incoming fid to it as local value */
5274366bb71SDavid du Colombier *pp = p;
5284366bb71SDavid du Colombier return 1;
5294366bb71SDavid du Colombier
5304366bb71SDavid du Colombier Err:
5314366bb71SDavid du Colombier if(r->nwqid == 0){
5324366bb71SDavid du Colombier r->type = Rerror;
5334366bb71SDavid du Colombier r->ename = err;
5344366bb71SDavid du Colombier }
5354366bb71SDavid du Colombier return 1;
5364366bb71SDavid du Colombier }
5374366bb71SDavid du Colombier
5384366bb71SDavid du Colombier void
ropen(Fcall * t)5394366bb71SDavid du Colombier ropen(Fcall *t)
5404366bb71SDavid du Colombier {
5414366bb71SDavid du Colombier Fid *mf;
5424366bb71SDavid du Colombier SFid *sfid;
5434366bb71SDavid du Colombier int omode;
5444366bb71SDavid du Colombier File *file;
5454366bb71SDavid du Colombier
5464366bb71SDavid du Colombier mf = findfid(host, t->fid, 0);
5474366bb71SDavid du Colombier if(mf == nil)
5484366bb71SDavid du Colombier return;
5494366bb71SDavid du Colombier if(mf->opened != nil){
5504366bb71SDavid du Colombier sendreply(Eopened);
5514366bb71SDavid du Colombier return;
5524366bb71SDavid du Colombier }
5534366bb71SDavid du Colombier omode = openmode(t->mode);
5544366bb71SDavid du Colombier if(omode < 0){
5554366bb71SDavid du Colombier sendreply(Emode);
5564366bb71SDavid du Colombier return;
5574366bb71SDavid du Colombier }
5584366bb71SDavid du Colombier if(statson && ctltest(mf)){
5594366bb71SDavid du Colombier /* Opening ctl file */
5604366bb71SDavid du Colombier if(t->mode != OREAD){
5614366bb71SDavid du Colombier sendreply("permission denied");
5624366bb71SDavid du Colombier return;
5634366bb71SDavid du Colombier }
5644366bb71SDavid du Colombier mf->mode = OREAD;
5654366bb71SDavid du Colombier c.rhdr.qid = ctlqid;
5664366bb71SDavid du Colombier c.rhdr.iounit = 0;
5674366bb71SDavid du Colombier sendreply(0);
5684366bb71SDavid du Colombier genstats();
5694366bb71SDavid du Colombier return;
5704366bb71SDavid du Colombier }
5714366bb71SDavid du Colombier if(t->mode & (ORCLOSE|OTRUNC) || isdirect(mf->qid)){
5724366bb71SDavid du Colombier /* must have private sfid */
5734366bb71SDavid du Colombier DPRINT(2, "open dir/auth: %q\n", pathstr(mf->path));
5744366bb71SDavid du Colombier sfid = sfclone(mf->path->sfid);
5754366bb71SDavid du Colombier if(delegate(t, mf, sfid) < 0){
5764366bb71SDavid du Colombier sfclunk(sfid);
5774366bb71SDavid du Colombier return;
5784366bb71SDavid du Colombier }
5794366bb71SDavid du Colombier mf->qid = s.rhdr.qid;
5804366bb71SDavid du Colombier /* don't currently need iounit */
5814366bb71SDavid du Colombier }else if((sfid = alreadyopen(mf, omode)) == nil){
5824366bb71SDavid du Colombier sfid = sfclone(mf->path->sfid);
5834366bb71SDavid du Colombier DPRINT(2, "new open %q -> %ud\n", pathstr(mf->path), sfid->fid);
5844366bb71SDavid du Colombier if(delegate(t, mf, sfid) < 0){
5854366bb71SDavid du Colombier sfclunk(sfid);
5864366bb71SDavid du Colombier return;
5874366bb71SDavid du Colombier }
5884366bb71SDavid du Colombier if(mf->qid.type != s.rhdr.qid.type || mf->qid.path != s.rhdr.qid.path){
5894366bb71SDavid du Colombier /* file changed type or naming is volatile */
5904366bb71SDavid du Colombier print("file changed underfoot: %q %#ux %llud -> %#ux %llud\n",
5914366bb71SDavid du Colombier pathstr(mf->path), mf->qid.type, mf->qid.path, s.rhdr.qid.type, s.rhdr.qid.path);
5924366bb71SDavid du Colombier mf->path->qid = mf->qid;
5934366bb71SDavid du Colombier fileinval(mf->path);
5944366bb71SDavid du Colombier }
5954366bb71SDavid du Colombier mf->qid = s.rhdr.qid; /* picks up vers */
5964366bb71SDavid du Colombier openfile(mf, omode, s.rhdr.iounit, sfid);
5974366bb71SDavid du Colombier }else{
5984366bb71SDavid du Colombier DPRINT(2, "cached open %q -> %ud\n", pathstr(mf->path), sfid->fid);
5994366bb71SDavid du Colombier c.rhdr.qid = mf->path->file->qid;
6004366bb71SDavid du Colombier c.rhdr.iounit = mf->path->file->iounit;
6014366bb71SDavid du Colombier sendreply(0);
6024366bb71SDavid du Colombier }
6034366bb71SDavid du Colombier mf->opened = sfid;
6044366bb71SDavid du Colombier mf->mode = omode;
6054366bb71SDavid du Colombier if(t->mode & OTRUNC && !(mf->qid.type & QTAPPEND)){
6064366bb71SDavid du Colombier file = mf->path->file;
6074366bb71SDavid du Colombier if(file != nil){
6084366bb71SDavid du Colombier cacheinval(file); /* discard cached data */
6094366bb71SDavid du Colombier file->length = 0;
6104366bb71SDavid du Colombier }
6114366bb71SDavid du Colombier }
6124366bb71SDavid du Colombier }
6134366bb71SDavid du Colombier
6144366bb71SDavid du Colombier void
rcreate(Fcall * t)6154366bb71SDavid du Colombier rcreate(Fcall *t)
6164366bb71SDavid du Colombier {
6174366bb71SDavid du Colombier Fid *mf;
6184366bb71SDavid du Colombier SFid *sfid;
6194366bb71SDavid du Colombier int omode;
6204366bb71SDavid du Colombier
6214366bb71SDavid du Colombier mf = findfid(host, t->fid, 0);
6224366bb71SDavid du Colombier if(mf == nil)
6234366bb71SDavid du Colombier return;
6244366bb71SDavid du Colombier if(statson && ctltest(mf)){
6254366bb71SDavid du Colombier sendreply(Eexist);
6264366bb71SDavid du Colombier return;
6274366bb71SDavid du Colombier }
6284366bb71SDavid du Colombier omode = openmode(t->mode);
6294366bb71SDavid du Colombier if(omode < 0){
6304366bb71SDavid du Colombier sendreply(Emode);
6314366bb71SDavid du Colombier return;
6324366bb71SDavid du Colombier }
6334366bb71SDavid du Colombier /* always write-through, and by definition can't exist and be open */
6344366bb71SDavid du Colombier sfid = sfclone(mf->path->sfid);
6354366bb71SDavid du Colombier if(delegate(t, mf, sfid) == 0){
6364366bb71SDavid du Colombier mf->opened = sfid;
6374366bb71SDavid du Colombier mf->mode = omode;
6384366bb71SDavid du Colombier mf->qid = s.rhdr.qid;
6394366bb71SDavid du Colombier mf->path = newpath(mf->path, t->name, mf->qid);
6404366bb71SDavid du Colombier if(!(t->mode & ORCLOSE || isdirect(mf->qid))){
6414366bb71SDavid du Colombier /* can cache (if it's volatile, find out on subsequent open) */
6424366bb71SDavid du Colombier openfile(mf, omode, s.rhdr.iounit, sfid);
6434366bb71SDavid du Colombier }
6444366bb71SDavid du Colombier //mf->iounit = s.rhdr.iounit;
6454366bb71SDavid du Colombier }else
6464366bb71SDavid du Colombier sfclunk(sfid);
6474366bb71SDavid du Colombier }
6484366bb71SDavid du Colombier
6494366bb71SDavid du Colombier void
rclunk(Fcall * t)6504366bb71SDavid du Colombier rclunk(Fcall *t)
6514366bb71SDavid du Colombier {
6524366bb71SDavid du Colombier Fid *mf;
6534366bb71SDavid du Colombier
6544366bb71SDavid du Colombier mf = findfid(host, t->fid, 0);
6554366bb71SDavid du Colombier if(mf == nil)
6564366bb71SDavid du Colombier return;
6574366bb71SDavid du Colombier if(mf->opened != nil)
6584366bb71SDavid du Colombier closefile(mf, 1, 0);
6594366bb71SDavid du Colombier /* local clunk, not delegated */
6604366bb71SDavid du Colombier sendreply(0);
6614366bb71SDavid du Colombier putfid(mf);
6624366bb71SDavid du Colombier }
6634366bb71SDavid du Colombier
6644366bb71SDavid du Colombier void
rremove(Fcall * t)6654366bb71SDavid du Colombier rremove(Fcall *t)
6664366bb71SDavid du Colombier {
6674366bb71SDavid du Colombier Fid *mf;
6684366bb71SDavid du Colombier Path *p;
6694366bb71SDavid du Colombier SFid *sfid;
6704366bb71SDavid du Colombier File *file;
6714366bb71SDavid du Colombier
6724366bb71SDavid du Colombier mf = findfid(host, t->fid, 0);
6734366bb71SDavid du Colombier if(mf == nil)
6744366bb71SDavid du Colombier return;
6754366bb71SDavid du Colombier /* invalidate path entry; discard file; discard any local fids in use */
6764366bb71SDavid du Colombier if(statson && ctltest(mf)){
6774366bb71SDavid du Colombier sendreply("not removed");
6784366bb71SDavid du Colombier return;
6794366bb71SDavid du Colombier }
6804366bb71SDavid du Colombier file = nil;
6814366bb71SDavid du Colombier p = mf->path;
6824366bb71SDavid du Colombier if(delegate(t, mf, nil) == 0){
6834366bb71SDavid du Colombier setinval(p, Eremoved);
6844366bb71SDavid du Colombier file = p->file;
6854366bb71SDavid du Colombier p->file = nil;
6864366bb71SDavid du Colombier }
6874366bb71SDavid du Colombier /* in any case, the fid was clunked: free the sfid */
6884366bb71SDavid du Colombier if(mf->opened == nil){
6894366bb71SDavid du Colombier sfid = p->sfid;
6904366bb71SDavid du Colombier p->sfid = nil;
6914366bb71SDavid du Colombier freesfid(sfid);
6924366bb71SDavid du Colombier }else
6934366bb71SDavid du Colombier closefile(mf, 0, 1);
6944366bb71SDavid du Colombier putfid(mf);
6954366bb71SDavid du Colombier if(file != nil)
6964366bb71SDavid du Colombier putfile(file);
6974366bb71SDavid du Colombier }
6984366bb71SDavid du Colombier
6994366bb71SDavid du Colombier void
rread(Fcall * t)7004366bb71SDavid du Colombier rread(Fcall *t)
7014366bb71SDavid du Colombier {
7024366bb71SDavid du Colombier Fid *mf;
7034366bb71SDavid du Colombier int cnt, done;
7044366bb71SDavid du Colombier long n;
7054366bb71SDavid du Colombier vlong off, first;
7064366bb71SDavid du Colombier char *cp;
7074366bb71SDavid du Colombier File *file;
7084366bb71SDavid du Colombier char data[MAXFDATA];
7094366bb71SDavid du Colombier
7104366bb71SDavid du Colombier mf = findfid(host, t->fid, 0);
7114366bb71SDavid du Colombier if(mf == nil)
7124366bb71SDavid du Colombier return;
7134366bb71SDavid du Colombier
7144366bb71SDavid du Colombier off = t->offset;
7154366bb71SDavid du Colombier cnt = t->count;
7164366bb71SDavid du Colombier
7174366bb71SDavid du Colombier if(statson && ctltest(mf)){
7184366bb71SDavid du Colombier if(cnt > statlen-off)
7194366bb71SDavid du Colombier c.rhdr.count = statlen-off;
7204366bb71SDavid du Colombier else
7214366bb71SDavid du Colombier c.rhdr.count = cnt;
7224366bb71SDavid du Colombier if((int)c.rhdr.count < 0){
7234366bb71SDavid du Colombier c.rhdr.count = 0;
7244366bb71SDavid du Colombier sendreply(0);
7254366bb71SDavid du Colombier return;
7264366bb71SDavid du Colombier }
7274366bb71SDavid du Colombier c.rhdr.data = statbuf + off;
7284366bb71SDavid du Colombier sendreply(0);
7294366bb71SDavid du Colombier return;
7304366bb71SDavid du Colombier }
7314366bb71SDavid du Colombier
7324366bb71SDavid du Colombier if(mf->opened == nil || mf->mode == OWRITE){
7334366bb71SDavid du Colombier sendreply("not open for reading");
7344366bb71SDavid du Colombier return;
7354366bb71SDavid du Colombier }
7364366bb71SDavid du Colombier
7374366bb71SDavid du Colombier file = mf->path->file;
7384366bb71SDavid du Colombier if(isdirect(mf->qid) || file == nil){
7394366bb71SDavid du Colombier DPRINT(2, "delegating read\n");
7404366bb71SDavid du Colombier delegate(t, mf, nil);
7414366bb71SDavid du Colombier if(statson){
7424366bb71SDavid du Colombier if(mf->qid.type & QTDIR)
7434366bb71SDavid du Colombier cfsstat.ndirread++;
7444366bb71SDavid du Colombier else
7454366bb71SDavid du Colombier cfsstat.ndelegateread++;
7464366bb71SDavid du Colombier if(s.rhdr.count > 0){
7474366bb71SDavid du Colombier cfsstat.bytesread += s.rhdr.count;
7484366bb71SDavid du Colombier if(mf->qid.type & QTDIR)
7494366bb71SDavid du Colombier cfsstat.bytesfromdirs += s.rhdr.count;
7504366bb71SDavid du Colombier else
7514366bb71SDavid du Colombier cfsstat.bytesfromserver += s.rhdr.count;
7524366bb71SDavid du Colombier }
7534366bb71SDavid du Colombier }
7544366bb71SDavid du Colombier return;
7554366bb71SDavid du Colombier }
7564366bb71SDavid du Colombier
7574366bb71SDavid du Colombier first = off;
7584366bb71SDavid du Colombier cp = data;
7594366bb71SDavid du Colombier done = 0;
7604366bb71SDavid du Colombier while(cnt>0 && !done){
7614366bb71SDavid du Colombier if(off >= file->clength){
7624366bb71SDavid du Colombier DPRINT(2, "offset %lld >= length %lld\n", off, file->clength);
7634366bb71SDavid du Colombier break;
7644366bb71SDavid du Colombier }
7654366bb71SDavid du Colombier n = cacheread(file, cp, off, cnt);
7664366bb71SDavid du Colombier if(n <= 0){
7674366bb71SDavid du Colombier n = -n;
7684366bb71SDavid du Colombier if(n==0 || n>cnt)
7694366bb71SDavid du Colombier n = cnt;
7704366bb71SDavid du Colombier DPRINT(2, "fetch %ld bytes of data from server at offset %lld\n", n, off);
7714366bb71SDavid du Colombier s.thdr.tag = t->tag;
7724366bb71SDavid du Colombier s.thdr.type = t->type;
7734366bb71SDavid du Colombier s.thdr.fid = t->fid;
7744366bb71SDavid du Colombier s.thdr.offset = off;
7754366bb71SDavid du Colombier s.thdr.count = n;
7764366bb71SDavid du Colombier if(statson)
7774366bb71SDavid du Colombier cfsstat.ndelegateread++;
7784366bb71SDavid du Colombier if(askserver(t, mf) < 0){
7794366bb71SDavid du Colombier sendreply(s.rhdr.ename);
7804366bb71SDavid du Colombier return;
7814366bb71SDavid du Colombier }
7824366bb71SDavid du Colombier if(s.rhdr.count != n)
7834366bb71SDavid du Colombier done = 1;
7844366bb71SDavid du Colombier n = s.rhdr.count;
7854366bb71SDavid du Colombier if(n == 0){
7864366bb71SDavid du Colombier /* end of file */
7874366bb71SDavid du Colombier if(file->clength > off){
7884366bb71SDavid du Colombier DPRINT(2, "file %llud.%ld, length %lld\n",
7894366bb71SDavid du Colombier file->qid.path,
7904366bb71SDavid du Colombier file->qid.vers, off);
7914366bb71SDavid du Colombier file->clength = off;
7924366bb71SDavid du Colombier }
7934366bb71SDavid du Colombier break;
7944366bb71SDavid du Colombier }
7954366bb71SDavid du Colombier memmove(cp, s.rhdr.data, n);
7964366bb71SDavid du Colombier cachewrite(file, cp, off, n);
7974366bb71SDavid du Colombier if(statson){
7984366bb71SDavid du Colombier cfsstat.bytestocache += n;
7994366bb71SDavid du Colombier cfsstat.bytesfromserver += n;
8004366bb71SDavid du Colombier }
8014366bb71SDavid du Colombier }else{
8024366bb71SDavid du Colombier DPRINT(2, "fetched %ld bytes from cache\n", n);
8034366bb71SDavid du Colombier if(statson)
8044366bb71SDavid du Colombier cfsstat.bytesfromcache += n;
8054366bb71SDavid du Colombier }
8064366bb71SDavid du Colombier cnt -= n;
8074366bb71SDavid du Colombier off += n;
8084366bb71SDavid du Colombier cp += n;
8094366bb71SDavid du Colombier }
8104366bb71SDavid du Colombier c.rhdr.data = data;
8114366bb71SDavid du Colombier c.rhdr.count = off - first;
8124366bb71SDavid du Colombier if(statson)
8134366bb71SDavid du Colombier cfsstat.bytesread += c.rhdr.count;
8144366bb71SDavid du Colombier sendreply(0);
8154366bb71SDavid du Colombier }
8164366bb71SDavid du Colombier
8174366bb71SDavid du Colombier void
rwrite(Fcall * t)8184366bb71SDavid du Colombier rwrite(Fcall *t)
8194366bb71SDavid du Colombier {
8204366bb71SDavid du Colombier Fid *mf;
8214366bb71SDavid du Colombier File *file;
8224366bb71SDavid du Colombier u32int v1, v2, count;
8234366bb71SDavid du Colombier
8244366bb71SDavid du Colombier mf = findfid(host, t->fid, 0);
8254366bb71SDavid du Colombier if(mf == nil)
8264366bb71SDavid du Colombier return;
8274366bb71SDavid du Colombier if(statson && ctltest(mf)){
8284366bb71SDavid du Colombier sendreply("read only");
8294366bb71SDavid du Colombier return;
8304366bb71SDavid du Colombier }
8314366bb71SDavid du Colombier if(mf->opened == nil || mf->mode == OREAD){
8324366bb71SDavid du Colombier sendreply("not open for writing");
8334366bb71SDavid du Colombier return;
8344366bb71SDavid du Colombier }
8354366bb71SDavid du Colombier file = mf->path->file;
8364366bb71SDavid du Colombier if(isdirect(mf->qid) || file == nil){
8374366bb71SDavid du Colombier delegate(t, mf, nil);
8384366bb71SDavid du Colombier if(statson && s.rhdr.count > 0)
8394366bb71SDavid du Colombier cfsstat.byteswritten += s.rhdr.count;
8404366bb71SDavid du Colombier return;
8414366bb71SDavid du Colombier }
8424366bb71SDavid du Colombier
8434366bb71SDavid du Colombier /* add to local cache as write through */
8444366bb71SDavid du Colombier if(delegate(t, mf, nil) < 0)
8454366bb71SDavid du Colombier return;
8464366bb71SDavid du Colombier
8474366bb71SDavid du Colombier count = s.rhdr.count;
8484366bb71SDavid du Colombier cfsstat.byteswritten += count;
8494366bb71SDavid du Colombier
8504366bb71SDavid du Colombier v1 = mf->qid.vers + 1;
8514366bb71SDavid du Colombier v2 = mf->path->qid.vers + 1;
8524366bb71SDavid du Colombier if(v1 > v2)
8534366bb71SDavid du Colombier v1 = v2;
8544366bb71SDavid du Colombier mf->qid.vers = v1;
8554366bb71SDavid du Colombier mf->path->qid.vers = v1;
8564366bb71SDavid du Colombier file->qid.vers = v1;
8574366bb71SDavid du Colombier if(file->clength < t->offset + count)
8584366bb71SDavid du Colombier file->clength = t->offset + count;
8594366bb71SDavid du Colombier cachewrite(file, t->data, t->offset, count);
8604366bb71SDavid du Colombier }
8614366bb71SDavid du Colombier
8624366bb71SDavid du Colombier void
rstat(Fcall * t)8634366bb71SDavid du Colombier rstat(Fcall *t)
8644366bb71SDavid du Colombier {
8654366bb71SDavid du Colombier Fid *mf;
8664366bb71SDavid du Colombier Dir d;
8674366bb71SDavid du Colombier uchar statbuf[256];
8684366bb71SDavid du Colombier
8694366bb71SDavid du Colombier mf = findfid(host, t->fid, 0);
8704366bb71SDavid du Colombier if(mf == nil)
8714366bb71SDavid du Colombier return;
8724366bb71SDavid du Colombier if(statson && ctltest(mf)){
8734366bb71SDavid du Colombier genstats();
8744366bb71SDavid du Colombier d.qid = ctlqid;
8754366bb71SDavid du Colombier d.mode = 0444;
8764366bb71SDavid du Colombier d.length = statlen;
8774366bb71SDavid du Colombier d.name = "cfsctl";
8784366bb71SDavid du Colombier d.uid = "none";
8794366bb71SDavid du Colombier d.gid = "none";
8804366bb71SDavid du Colombier d.muid = "none";
8814366bb71SDavid du Colombier d.atime = time(nil);
8824366bb71SDavid du Colombier d.mtime = d.atime;
8834366bb71SDavid du Colombier c.rhdr.stat = statbuf;
8844366bb71SDavid du Colombier c.rhdr.nstat = convD2M(&d, statbuf, sizeof(statbuf));
8854366bb71SDavid du Colombier sendreply(0);
8864366bb71SDavid du Colombier return;
8874366bb71SDavid du Colombier }
8884366bb71SDavid du Colombier if(delegate(t, mf, nil) == 0){
8894366bb71SDavid du Colombier convM2D(s.rhdr.stat, s.rhdr.nstat , &d, nil);
8904366bb71SDavid du Colombier //mf->qid = d.qid;
8914366bb71SDavid du Colombier if(mf->path->file != nil)
8924366bb71SDavid du Colombier copystat(mf->path->file, &d, 0);
8934366bb71SDavid du Colombier }
8944366bb71SDavid du Colombier }
8954366bb71SDavid du Colombier
8964366bb71SDavid du Colombier void
rwstat(Fcall * t)8974366bb71SDavid du Colombier rwstat(Fcall *t)
8984366bb71SDavid du Colombier {
8994366bb71SDavid du Colombier Fid *mf;
9004366bb71SDavid du Colombier Path *p;
9014366bb71SDavid du Colombier Dir *d;
9024366bb71SDavid du Colombier int qt;
9034366bb71SDavid du Colombier
9044366bb71SDavid du Colombier mf = findfid(host, t->fid, 0);
9054366bb71SDavid du Colombier if(mf == nil)
9064366bb71SDavid du Colombier return;
9074366bb71SDavid du Colombier if(statson && ctltest(mf)){
9084366bb71SDavid du Colombier sendreply("read only");
9094366bb71SDavid du Colombier return;
9104366bb71SDavid du Colombier }
9114366bb71SDavid du Colombier if(delegate(t, mf, nil) == 0){
9124366bb71SDavid du Colombier d = malloc(sizeof(*d)+t->nstat);
9134366bb71SDavid du Colombier if(convM2D(t->stat, t->nstat, d, (char*)(d+1)) != 0){
9144366bb71SDavid du Colombier if(*d->name){ /* file renamed */
9154366bb71SDavid du Colombier p = mf->path;
9164366bb71SDavid du Colombier free(p->name);
9174366bb71SDavid du Colombier p->name = strdup(d->name);
918*518acb85SDavid du Colombier freeinval(p);
9194366bb71SDavid du Colombier }
9204366bb71SDavid du Colombier if(d->mode != ~0){
9214366bb71SDavid du Colombier qt = d->mode>>24;
9224366bb71SDavid du Colombier mf->qid.type = qt;
9234366bb71SDavid du Colombier mf->path->qid.type = qt;
9244366bb71SDavid du Colombier }
9254366bb71SDavid du Colombier if(mf->path->file != nil)
9264366bb71SDavid du Colombier copystat(mf->path->file, d, 1);
9274366bb71SDavid du Colombier }
9284366bb71SDavid du Colombier free(d);
9294366bb71SDavid du Colombier }
9304366bb71SDavid du Colombier }
9314366bb71SDavid du Colombier
9324366bb71SDavid du Colombier int
openmode(uint o)9334366bb71SDavid du Colombier openmode(uint o)
9344366bb71SDavid du Colombier {
9354366bb71SDavid du Colombier uint m;
9364366bb71SDavid du Colombier
9374366bb71SDavid du Colombier m = o & ~(OTRUNC|OCEXEC|ORCLOSE);
9384366bb71SDavid du Colombier if(m > OEXEC)
9394366bb71SDavid du Colombier return -1;
9404366bb71SDavid du Colombier if(m == OEXEC)
9414366bb71SDavid du Colombier m = OREAD;
9424366bb71SDavid du Colombier if(o&OTRUNC && m == OREAD)
9434366bb71SDavid du Colombier return -1;
9444366bb71SDavid du Colombier return m;
9454366bb71SDavid du Colombier }
9464366bb71SDavid du Colombier
9474366bb71SDavid du Colombier void
error(char * fmt,...)9484366bb71SDavid du Colombier error(char *fmt, ...)
9494366bb71SDavid du Colombier {
9504366bb71SDavid du Colombier va_list arg;
9514366bb71SDavid du Colombier static char buf[2048];
9524366bb71SDavid du Colombier
9534366bb71SDavid du Colombier va_start(arg, fmt);
9544366bb71SDavid du Colombier vseprint(buf, buf+sizeof(buf), fmt, arg);
9554366bb71SDavid du Colombier va_end(arg);
9564366bb71SDavid du Colombier fprint(2, "%s: %s\n", argv0, buf);
9574366bb71SDavid du Colombier threadexitsall("error");
9584366bb71SDavid du Colombier }
9594366bb71SDavid du Colombier
9604366bb71SDavid du Colombier void
warning(char * s)9614366bb71SDavid du Colombier warning(char *s)
9624366bb71SDavid du Colombier {
9634366bb71SDavid du Colombier fprint(2, "%s: %s: %r\n", argv0, s);
9644366bb71SDavid du Colombier }
9654366bb71SDavid du Colombier
9664366bb71SDavid du Colombier /*
9674366bb71SDavid du Colombier * send a reply to the client
9684366bb71SDavid du Colombier */
9694366bb71SDavid du Colombier void
sendreply(char * err)9704366bb71SDavid du Colombier sendreply(char *err)
9714366bb71SDavid du Colombier {
9724366bb71SDavid du Colombier if(err){
9734366bb71SDavid du Colombier c.rhdr.type = Rerror;
9744366bb71SDavid du Colombier c.rhdr.ename = err;
9754366bb71SDavid du Colombier }else{
9764366bb71SDavid du Colombier c.rhdr.type = c.thdr.type+1;
9774366bb71SDavid du Colombier c.rhdr.fid = c.thdr.fid;
9784366bb71SDavid du Colombier }
9794366bb71SDavid du Colombier c.rhdr.tag = c.thdr.tag;
9804366bb71SDavid du Colombier sendmsg(&c, &c.rhdr);
9814366bb71SDavid du Colombier }
9824366bb71SDavid du Colombier
9834366bb71SDavid du Colombier /*
9844366bb71SDavid du Colombier * local fids
9854366bb71SDavid du Colombier */
9864366bb71SDavid du Colombier Fid*
findfid(Host * host,u32int fid,int mk)9874366bb71SDavid du Colombier findfid(Host *host, u32int fid, int mk)
9884366bb71SDavid du Colombier {
9894366bb71SDavid du Colombier Fid *f, **l;
9904366bb71SDavid du Colombier
9914366bb71SDavid du Colombier if(fid == NOFID){
9924366bb71SDavid du Colombier sendreply(Ebadfid);
9934366bb71SDavid du Colombier return nil;
9944366bb71SDavid du Colombier }
9954366bb71SDavid du Colombier l = &host->fids[fid & (FidHash-1)];
9964366bb71SDavid du Colombier for(f = *l; f != nil; f = f->next){
9974366bb71SDavid du Colombier if(f->fid == fid){
9984366bb71SDavid du Colombier if(mk){
9994366bb71SDavid du Colombier sendreply(Efidinuse);
10004366bb71SDavid du Colombier return nil;
10014366bb71SDavid du Colombier }
10024366bb71SDavid du Colombier return f;
10034366bb71SDavid du Colombier }
10044366bb71SDavid du Colombier }
10054366bb71SDavid du Colombier if(!mk){
10064366bb71SDavid du Colombier sendreply(Ebadfid);
10074366bb71SDavid du Colombier return nil;
10084366bb71SDavid du Colombier }
10094366bb71SDavid du Colombier f = mallocz(sizeof(*f), 1);
10104366bb71SDavid du Colombier f->fid = fid;
10114366bb71SDavid du Colombier f->next = *l;
10124366bb71SDavid du Colombier *l = f;
10134366bb71SDavid du Colombier return f;
10144366bb71SDavid du Colombier }
10154366bb71SDavid du Colombier
10164366bb71SDavid du Colombier void
putfid(Fid * f)10174366bb71SDavid du Colombier putfid(Fid *f)
10184366bb71SDavid du Colombier {
10194366bb71SDavid du Colombier Fid **l;
10204366bb71SDavid du Colombier static Qid zeroqid;
10214366bb71SDavid du Colombier
10224366bb71SDavid du Colombier for(l = &host->fids[f->fid & (FidHash-1)]; *l != nil; l = &(*l)->next){
10234366bb71SDavid du Colombier if(*l == f){
10244366bb71SDavid du Colombier *l = f->next;
10254366bb71SDavid du Colombier break;
10264366bb71SDavid du Colombier }
10274366bb71SDavid du Colombier }
10284366bb71SDavid du Colombier if(f->opened != nil){
10294366bb71SDavid du Colombier sfclunk(f->opened);
10304366bb71SDavid du Colombier f->opened = nil;
10314366bb71SDavid du Colombier }
10324366bb71SDavid du Colombier freepath(f->path);
10334366bb71SDavid du Colombier /* poison values just in case */
10344366bb71SDavid du Colombier f->path = nil;
10354366bb71SDavid du Colombier f->fid = NOFID;
10364366bb71SDavid du Colombier f->qid = zeroqid;
10374366bb71SDavid du Colombier free(f);
10384366bb71SDavid du Colombier }
10394366bb71SDavid du Colombier
10404366bb71SDavid du Colombier /*
10414366bb71SDavid du Colombier * return server fid for local fid
10424366bb71SDavid du Colombier */
10434366bb71SDavid du Colombier u32int
mapfid(Fid * f)10444366bb71SDavid du Colombier mapfid(Fid *f)
10454366bb71SDavid du Colombier {
10464366bb71SDavid du Colombier if(f->opened != nil){
10474366bb71SDavid du Colombier DPRINT(2, "mapfid: use open fid %ud -> %ud\n", f->fid, f->opened->fid);
10484366bb71SDavid du Colombier return f->opened->fid;
10494366bb71SDavid du Colombier }
10504366bb71SDavid du Colombier if(f->path->sfid == nil)
10514366bb71SDavid du Colombier sysfatal("mapfid: missing sfid for path %q\n", pathstr(f->path));
10524366bb71SDavid du Colombier return f->path->sfid->fid;
10534366bb71SDavid du Colombier }
10544366bb71SDavid du Colombier
10554366bb71SDavid du Colombier /*
10564366bb71SDavid du Colombier * send a request to the server, get the reply,
10574366bb71SDavid du Colombier * and send that to the client
10584366bb71SDavid du Colombier */
10594366bb71SDavid du Colombier int
delegate(Fcall * t,Fid * f1,SFid * f2)10604366bb71SDavid du Colombier delegate(Fcall *t, Fid *f1, SFid *f2)
10614366bb71SDavid du Colombier {
10624366bb71SDavid du Colombier int type;
10634366bb71SDavid du Colombier
10644366bb71SDavid du Colombier type = t->type;
10654366bb71SDavid du Colombier if(statson){
10664366bb71SDavid du Colombier cfsstat.sm[type].n++;
10674366bb71SDavid du Colombier cfsstat.sm[type].s = nsec();
10684366bb71SDavid du Colombier }
10694366bb71SDavid du Colombier
10704366bb71SDavid du Colombier switch(type){
10714366bb71SDavid du Colombier case Tversion:
10724366bb71SDavid du Colombier case Tflush: /* no fid */
10734366bb71SDavid du Colombier break;
10744366bb71SDavid du Colombier case Tauth: /* afid */
10754366bb71SDavid du Colombier t->afid = mapfid(f1);
10764366bb71SDavid du Colombier break;
10774366bb71SDavid du Colombier case Tattach: /* fid, afid */
10784366bb71SDavid du Colombier t->fid = mapfid(f1);
10794366bb71SDavid du Colombier if(f2 != nil)
10804366bb71SDavid du Colombier t->afid = f2->fid;
10814366bb71SDavid du Colombier else
10824366bb71SDavid du Colombier t->afid = NOFID;
10834366bb71SDavid du Colombier break;
10844366bb71SDavid du Colombier case Twalk: /* fid, newfid */
10854366bb71SDavid du Colombier t->fid = mapfid(f1);
10864366bb71SDavid du Colombier t->newfid = f2->fid;
10874366bb71SDavid du Colombier break;
10884366bb71SDavid du Colombier default: /* fid */
10894366bb71SDavid du Colombier if(f2 != nil)
10904366bb71SDavid du Colombier t->fid = f2->fid;
10914366bb71SDavid du Colombier else
10924366bb71SDavid du Colombier t->fid = mapfid(f1);
10934366bb71SDavid du Colombier break;
10944366bb71SDavid du Colombier }
10954366bb71SDavid du Colombier
10964366bb71SDavid du Colombier sendmsg(&s, t);
10974366bb71SDavid du Colombier rcvmsg(&s, &s.rhdr);
10984366bb71SDavid du Colombier
10994366bb71SDavid du Colombier if(statson)
11004366bb71SDavid du Colombier cfsstat.sm[type].t += nsec() - cfsstat.sm[type].s;
11014366bb71SDavid du Colombier
11024366bb71SDavid du Colombier sendmsg(&c, &s.rhdr);
11034366bb71SDavid du Colombier return t->type+1 == s.rhdr.type? 0: -1;
11044366bb71SDavid du Colombier }
11054366bb71SDavid du Colombier
11064366bb71SDavid du Colombier /*
11074366bb71SDavid du Colombier * send an i/o request to the server and get a reply
11084366bb71SDavid du Colombier */
11094366bb71SDavid du Colombier int
askserver(Fcall * t,Fid * f)11104366bb71SDavid du Colombier askserver(Fcall *t, Fid *f)
11114366bb71SDavid du Colombier {
11124366bb71SDavid du Colombier int type;
11134366bb71SDavid du Colombier
11144366bb71SDavid du Colombier s.thdr.tag = t->tag;
11154366bb71SDavid du Colombier
11164366bb71SDavid du Colombier type = s.thdr.type;
11174366bb71SDavid du Colombier if(statson){
11184366bb71SDavid du Colombier cfsstat.sm[type].n++;
11194366bb71SDavid du Colombier cfsstat.sm[type].s = nsec();
11204366bb71SDavid du Colombier }
11214366bb71SDavid du Colombier
11224366bb71SDavid du Colombier s.thdr.fid = mapfid(f);
11234366bb71SDavid du Colombier sendmsg(&s, &s.thdr);
11244366bb71SDavid du Colombier rcvmsg(&s, &s.rhdr);
11254366bb71SDavid du Colombier
11264366bb71SDavid du Colombier if(statson)
11274366bb71SDavid du Colombier cfsstat.sm[type].t += nsec() - cfsstat.sm[type].s;
11284366bb71SDavid du Colombier
11294366bb71SDavid du Colombier return s.thdr.type+1 == s.rhdr.type ? 0 : -1;
11304366bb71SDavid du Colombier }
11314366bb71SDavid du Colombier
11324366bb71SDavid du Colombier /*
11334366bb71SDavid du Colombier * send/receive messages with logging
11344366bb71SDavid du Colombier */
11354366bb71SDavid du Colombier
11364366bb71SDavid du Colombier void
sendmsg(P9fs * p,Fcall * f)11374366bb71SDavid du Colombier sendmsg(P9fs *p, Fcall *f)
11384366bb71SDavid du Colombier {
11394366bb71SDavid du Colombier DPRINT(2, "->%s: %F\n", p->name, f);
11404366bb71SDavid du Colombier
11414366bb71SDavid du Colombier p->len = convS2M(f, p->sndbuf, messagesize);
11424366bb71SDavid du Colombier if(p->len <= 0)
11434366bb71SDavid du Colombier error("convS2M");
11444366bb71SDavid du Colombier if(write(p->fd[1], p->sndbuf, p->len)!=p->len)
11454366bb71SDavid du Colombier error("sendmsg");
11464366bb71SDavid du Colombier }
11474366bb71SDavid du Colombier
11484366bb71SDavid du Colombier void
rcvmsg(P9fs * p,Fcall * f)11494366bb71SDavid du Colombier rcvmsg(P9fs *p, Fcall *f)
11504366bb71SDavid du Colombier {
11514366bb71SDavid du Colombier int rlen;
11524366bb71SDavid du Colombier char buf[128];
11534366bb71SDavid du Colombier
11544366bb71SDavid du Colombier p->len = read9pmsg(p->fd[0], p->rcvbuf[p->cb], sizeof(p->rcvbuf[0]));
11554366bb71SDavid du Colombier if(p->len <= 0){
11564366bb71SDavid du Colombier snprint(buf, sizeof buf, "read9pmsg(%d)->%ld: %r",
11574366bb71SDavid du Colombier p->fd[0], p->len);
11584366bb71SDavid du Colombier error(buf);
11594366bb71SDavid du Colombier }
11604366bb71SDavid du Colombier
11614366bb71SDavid du Colombier if((rlen = convM2S(p->rcvbuf[p->cb], p->len, f)) != p->len)
11624366bb71SDavid du Colombier error("rcvmsg format error, expected length %d, got %d",
11634366bb71SDavid du Colombier rlen, p->len);
11644366bb71SDavid du Colombier DPRINT(2, "<-%s: %F\n", p->name, f);
11654366bb71SDavid du Colombier p->cb = (p->cb+1)%nelem(p->rcvbuf);
11664366bb71SDavid du Colombier }
11674366bb71SDavid du Colombier
11684366bb71SDavid du Colombier void
dump(void * a,int len)11694366bb71SDavid du Colombier dump(void *a, int len)
11704366bb71SDavid du Colombier {
11714366bb71SDavid du Colombier uchar *p;
11724366bb71SDavid du Colombier
11734366bb71SDavid du Colombier p = a;
11744366bb71SDavid du Colombier fprint(2, "%d bytes", len);
11754366bb71SDavid du Colombier while(len-- > 0)
11764366bb71SDavid du Colombier fprint(2, " %.2ux", *p++);
11774366bb71SDavid du Colombier fprint(2, "\n");
11784366bb71SDavid du Colombier }
11794366bb71SDavid du Colombier
11804366bb71SDavid du Colombier /*
11814366bb71SDavid du Colombier * requests (later, unused now)
11824366bb71SDavid du Colombier */
11834366bb71SDavid du Colombier
11844366bb71SDavid du Colombier void
readtmsgproc(void * a)11854366bb71SDavid du Colombier readtmsgproc(void *a)
11864366bb71SDavid du Colombier {
11874366bb71SDavid du Colombier //uint messagesize;
11884366bb71SDavid du Colombier int n;
11894366bb71SDavid du Colombier Req *r;
11904366bb71SDavid du Colombier Channel *reqs;
11914366bb71SDavid du Colombier
11924366bb71SDavid du Colombier reqs = a;
11934366bb71SDavid du Colombier for(;;){
11944366bb71SDavid du Colombier r = malloc(sizeof(*r)+messagesize);
11954366bb71SDavid du Colombier r->msize = messagesize;
11964366bb71SDavid du Colombier r->buf = (uchar*)(r+1);
11974366bb71SDavid du Colombier n = read9pmsg(c.fd[0], r->buf, r->msize);
11984366bb71SDavid du Colombier if(n <= 0){
11994366bb71SDavid du Colombier free(r);
12004366bb71SDavid du Colombier sendp(reqs, nil);
12014366bb71SDavid du Colombier threadexits(nil);
12024366bb71SDavid du Colombier }
12034366bb71SDavid du Colombier if(convM2S(r->buf, n, &r->t) != n){
12044366bb71SDavid du Colombier free(r);
12054366bb71SDavid du Colombier error("convM2S error in readtmsgproc");
12064366bb71SDavid du Colombier }
12074366bb71SDavid du Colombier sendp(reqs, r);
12084366bb71SDavid du Colombier }
12094366bb71SDavid du Colombier }
12104366bb71SDavid du Colombier
12114366bb71SDavid du Colombier void
readrmsgproc(void * a)12124366bb71SDavid du Colombier readrmsgproc(void *a)
12134366bb71SDavid du Colombier {
12144366bb71SDavid du Colombier //uint messagesize;
12154366bb71SDavid du Colombier int n;
12164366bb71SDavid du Colombier Fcall *r;
12174366bb71SDavid du Colombier uchar *buf;
12184366bb71SDavid du Colombier Channel *reps;
12194366bb71SDavid du Colombier
12204366bb71SDavid du Colombier reps = a;
12214366bb71SDavid du Colombier for(;;){
12224366bb71SDavid du Colombier r = malloc(sizeof(*r)+messagesize);
12234366bb71SDavid du Colombier buf = (uchar*)(r+1);
12244366bb71SDavid du Colombier n = read9pmsg(c.fd[0], buf, messagesize);
12254366bb71SDavid du Colombier if(n <= 0){
12264366bb71SDavid du Colombier free(r);
12274366bb71SDavid du Colombier sendp(reps, nil);
12284366bb71SDavid du Colombier threadexits(nil);
12294366bb71SDavid du Colombier }
12304366bb71SDavid du Colombier if(convM2S(buf, n, r) != n){
12314366bb71SDavid du Colombier free(r);
12324366bb71SDavid du Colombier error("convM2S error in readtmsgproc");
12334366bb71SDavid du Colombier }
12344366bb71SDavid du Colombier sendp(reps, r);
12354366bb71SDavid du Colombier }
12364366bb71SDavid du Colombier }
12374366bb71SDavid du Colombier
12384366bb71SDavid du Colombier void
freereq(Req * r)12394366bb71SDavid du Colombier freereq(Req *r)
12404366bb71SDavid du Colombier {
12414366bb71SDavid du Colombier free(r);
12424366bb71SDavid du Colombier }
12434366bb71SDavid du Colombier
12444366bb71SDavid du Colombier /*
12454366bb71SDavid du Colombier * server fids
12464366bb71SDavid du Colombier */
12474366bb71SDavid du Colombier
12484366bb71SDavid du Colombier SFid*
allocsfid(void)12494366bb71SDavid du Colombier allocsfid(void)
12504366bb71SDavid du Colombier {
12514366bb71SDavid du Colombier SFid *sf;
12524366bb71SDavid du Colombier
12534366bb71SDavid du Colombier sf = freefids;
12544366bb71SDavid du Colombier if(sf != nil){
12554366bb71SDavid du Colombier freefids = sf->next;
12564366bb71SDavid du Colombier sf->ref = 1;
12574366bb71SDavid du Colombier return sf;
12584366bb71SDavid du Colombier }
12594366bb71SDavid du Colombier sf = mallocz(sizeof(*sf), 1);
12604366bb71SDavid du Colombier sf->ref = 1;
12614366bb71SDavid du Colombier sf->fid = ++fidgen;
12624366bb71SDavid du Colombier return sf;
12634366bb71SDavid du Colombier }
12644366bb71SDavid du Colombier
12654366bb71SDavid du Colombier void
freesfid(SFid * sf)12664366bb71SDavid du Colombier freesfid(SFid *sf)
12674366bb71SDavid du Colombier {
12684366bb71SDavid du Colombier if(--sf->ref != 0)
12694366bb71SDavid du Colombier return;
12704366bb71SDavid du Colombier /* leave sf->fid alone */
12714366bb71SDavid du Colombier sf->next = freefids;
12724366bb71SDavid du Colombier freefids = sf;
12734366bb71SDavid du Colombier }
12744366bb71SDavid du Colombier
12754366bb71SDavid du Colombier SFid*
sfclone(SFid * sf)12764366bb71SDavid du Colombier sfclone(SFid *sf)
12774366bb71SDavid du Colombier {
12784366bb71SDavid du Colombier Fcall t, r;
12794366bb71SDavid du Colombier SFid *cf;
12804366bb71SDavid du Colombier
12814366bb71SDavid du Colombier cf = allocsfid();
12824366bb71SDavid du Colombier t.tag = c.thdr.tag;
12834366bb71SDavid du Colombier t.type = Twalk;
12844366bb71SDavid du Colombier t.fid = sf->fid;
12854366bb71SDavid du Colombier t.newfid = cf->fid;
12864366bb71SDavid du Colombier t.nwname = 0;
12874366bb71SDavid du Colombier sendmsg(&s, &t);
12884366bb71SDavid du Colombier rcvmsg(&s, &r);
12894366bb71SDavid du Colombier if(r.type == Rerror){
12904366bb71SDavid du Colombier werrstr("%s", r.ename);
12914366bb71SDavid du Colombier return nil;
12924366bb71SDavid du Colombier }
12934366bb71SDavid du Colombier assert(r.type == Rwalk); /* TO DO: out of order */
12944366bb71SDavid du Colombier return cf;
12954366bb71SDavid du Colombier }
12964366bb71SDavid du Colombier
12974366bb71SDavid du Colombier Dir*
sfstat(Path * p,u32int tag)12984366bb71SDavid du Colombier sfstat(Path *p, u32int tag)
12994366bb71SDavid du Colombier {
13004366bb71SDavid du Colombier Fcall t, r;
13014366bb71SDavid du Colombier Dir *d;
13024366bb71SDavid du Colombier
13034366bb71SDavid du Colombier assert(p->sfid != nil);
13044366bb71SDavid du Colombier t.tag = tag;
13054366bb71SDavid du Colombier t.type = Tstat;
13064366bb71SDavid du Colombier t.fid = p->sfid->fid;
13074366bb71SDavid du Colombier sendmsg(&s, &t);
13084366bb71SDavid du Colombier rcvmsg(&s, &r);
13094366bb71SDavid du Colombier if(r.type == Rerror){
13104366bb71SDavid du Colombier werrstr("%s", r.ename);
13114366bb71SDavid du Colombier return nil;
13124366bb71SDavid du Colombier }
13134366bb71SDavid du Colombier d = malloc(sizeof(*d)+r.nstat);
13144366bb71SDavid du Colombier if(convM2D(r.stat, r.nstat, d, (char*)(d+1)) == 0){
13154366bb71SDavid du Colombier free(d);
13164366bb71SDavid du Colombier werrstr("invalid stat data");
13174366bb71SDavid du Colombier return nil;
13184366bb71SDavid du Colombier }
13194366bb71SDavid du Colombier return d;
13204366bb71SDavid du Colombier }
13214366bb71SDavid du Colombier
13224366bb71SDavid du Colombier void
sfclunk(SFid * sf)13234366bb71SDavid du Colombier sfclunk(SFid *sf)
13244366bb71SDavid du Colombier {
13254366bb71SDavid du Colombier Fcall t, r;
13264366bb71SDavid du Colombier
13274366bb71SDavid du Colombier if(sf->ref > 1)
13284366bb71SDavid du Colombier return;
13294366bb71SDavid du Colombier t.tag = c.thdr.tag;
13304366bb71SDavid du Colombier t.type = Tclunk;
13314366bb71SDavid du Colombier t.fid = sf->fid;
13324366bb71SDavid du Colombier sendmsg(&s, &t);
13334366bb71SDavid du Colombier rcvmsg(&s, &r);
13344366bb71SDavid du Colombier /* don't care about result */
13354366bb71SDavid du Colombier }
13364366bb71SDavid du Colombier
13374366bb71SDavid du Colombier void
printpath(Path * p,int level)13384366bb71SDavid du Colombier printpath(Path *p, int level)
13394366bb71SDavid du Colombier {
13404366bb71SDavid du Colombier Path *q;
13414366bb71SDavid du Colombier
13424366bb71SDavid du Colombier for(int i = 0; i < level; i++)
13434366bb71SDavid du Colombier print("\t");
13444366bb71SDavid du Colombier print("%q [%lud] %q\n", p->name, p->ref, p->inval?p->inval:"");
13454366bb71SDavid du Colombier for(q = p->child; q != nil; q = q->next)
13464366bb71SDavid du Colombier printpath(q, level+1);
13474366bb71SDavid du Colombier }
13484366bb71SDavid du Colombier
13494366bb71SDavid du Colombier int
ctltest(Fid * mf)13504366bb71SDavid du Colombier ctltest(Fid *mf)
13514366bb71SDavid du Colombier {
13524366bb71SDavid du Colombier return mf->qid.type == ctlqid.type && mf->qid.path == ctlqid.path;
13534366bb71SDavid du Colombier }
13544366bb71SDavid du Colombier
13554366bb71SDavid du Colombier char *mname[]={
13564366bb71SDavid du Colombier [Tversion] "Tversion",
13574366bb71SDavid du Colombier [Tauth] "Tauth",
13584366bb71SDavid du Colombier [Tflush] "Tflush",
13594366bb71SDavid du Colombier [Tattach] "Tattach",
13604366bb71SDavid du Colombier [Twalk] "Twalk",
13614366bb71SDavid du Colombier [Topen] "Topen",
13624366bb71SDavid du Colombier [Tcreate] "Tcreate",
13634366bb71SDavid du Colombier [Tclunk] "Tclunk",
13644366bb71SDavid du Colombier [Tread] "Tread",
13654366bb71SDavid du Colombier [Twrite] "Twrite",
13664366bb71SDavid du Colombier [Tremove] "Tremove",
13674366bb71SDavid du Colombier [Tstat] "Tstat",
13684366bb71SDavid du Colombier [Twstat] "Twstat",
13694366bb71SDavid du Colombier [Rversion] "Rversion",
13704366bb71SDavid du Colombier [Rauth] "Rauth",
13714366bb71SDavid du Colombier [Rerror] "Rerror",
13724366bb71SDavid du Colombier [Rflush] "Rflush",
13734366bb71SDavid du Colombier [Rattach] "Rattach",
13744366bb71SDavid du Colombier [Rwalk] "Rwalk",
13754366bb71SDavid du Colombier [Ropen] "Ropen",
13764366bb71SDavid du Colombier [Rcreate] "Rcreate",
13774366bb71SDavid du Colombier [Rclunk] "Rclunk",
13784366bb71SDavid du Colombier [Rread] "Rread",
13794366bb71SDavid du Colombier [Rwrite] "Rwrite",
13804366bb71SDavid du Colombier [Rremove] "Rremove",
13814366bb71SDavid du Colombier [Rstat] "Rstat",
13824366bb71SDavid du Colombier [Rwstat] "Rwstat",
13834366bb71SDavid du Colombier 0,
13844366bb71SDavid du Colombier };
13854366bb71SDavid du Colombier
13864366bb71SDavid du Colombier void
genstats(void)13874366bb71SDavid du Colombier genstats(void)
13884366bb71SDavid du Colombier {
13894366bb71SDavid du Colombier int i;
13904366bb71SDavid du Colombier char *p;
13914366bb71SDavid du Colombier
13924366bb71SDavid du Colombier p = statbuf;
13934366bb71SDavid du Colombier
13944366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p,
13954366bb71SDavid du Colombier " Client Server\n");
13964366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p,
13974366bb71SDavid du Colombier " #calls Δ ms/call Δ #calls Δ ms/call Δ\n");
13984366bb71SDavid du Colombier for(i = 0; i < nelem(cfsstat.cm); i++)
13994366bb71SDavid du Colombier if(cfsstat.cm[i].n || cfsstat.sm[i].n){
14004366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p,
14014366bb71SDavid du Colombier "%7lud %7lud ", cfsstat.cm[i].n,
14024366bb71SDavid du Colombier cfsstat.cm[i].n - cfsprev.cm[i].n);
14034366bb71SDavid du Colombier if(cfsstat.cm[i].n)
14044366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p,
14054366bb71SDavid du Colombier "%7.3f ", 0.000001*cfsstat.cm[i].t/
14064366bb71SDavid du Colombier cfsstat.cm[i].n);
14074366bb71SDavid du Colombier else
14084366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p,
14094366bb71SDavid du Colombier " ");
14104366bb71SDavid du Colombier if(cfsstat.cm[i].n - cfsprev.cm[i].n)
14114366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p,
14124366bb71SDavid du Colombier "%7.3f ", 0.000001*
14134366bb71SDavid du Colombier (cfsstat.cm[i].t - cfsprev.cm[i].t)/
14144366bb71SDavid du Colombier (cfsstat.cm[i].n - cfsprev.cm[i].n));
14154366bb71SDavid du Colombier else
14164366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p,
14174366bb71SDavid du Colombier " ");
14184366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p,
14194366bb71SDavid du Colombier "%7lud %7lud ", cfsstat.sm[i].n,
14204366bb71SDavid du Colombier cfsstat.sm[i].n - cfsprev.sm[i].n);
14214366bb71SDavid du Colombier if(cfsstat.sm[i].n)
14224366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p,
14234366bb71SDavid du Colombier "%7.3f ", 0.000001*cfsstat.sm[i].t/
14244366bb71SDavid du Colombier cfsstat.sm[i].n);
14254366bb71SDavid du Colombier else
14264366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p,
14274366bb71SDavid du Colombier " ");
14284366bb71SDavid du Colombier if(cfsstat.sm[i].n - cfsprev.sm[i].n)
14294366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p,
14304366bb71SDavid du Colombier "%7.3f ", 0.000001*
14314366bb71SDavid du Colombier (cfsstat.sm[i].t - cfsprev.sm[i].t)/
14324366bb71SDavid du Colombier (cfsstat.sm[i].n - cfsprev.sm[i].n));
14334366bb71SDavid du Colombier else
14344366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p,
14354366bb71SDavid du Colombier " ");
14364366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p, "%s\n",
14374366bb71SDavid du Colombier mname[i]);
14384366bb71SDavid du Colombier }
14394366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ndirread\n",
14404366bb71SDavid du Colombier cfsstat.ndirread, cfsstat.ndirread - cfsprev.ndirread);
14414366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ndelegateread\n",
14424366bb71SDavid du Colombier cfsstat.ndelegateread, cfsstat.ndelegateread -
14434366bb71SDavid du Colombier cfsprev.ndelegateread);
14444366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ninsert\n",
14454366bb71SDavid du Colombier cfsstat.ninsert, cfsstat.ninsert - cfsprev.ninsert);
14464366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud ndelete\n",
14474366bb71SDavid du Colombier cfsstat.ndelete, cfsstat.ndelete - cfsprev.ndelete);
14484366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p, "%7lud %7lud nupdate\n",
14494366bb71SDavid du Colombier cfsstat.nupdate, cfsstat.nupdate - cfsprev.nupdate);
14504366bb71SDavid du Colombier
14514366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesread\n",
14524366bb71SDavid du Colombier cfsstat.bytesread, cfsstat.bytesread - cfsprev.bytesread);
14534366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud byteswritten\n",
14544366bb71SDavid du Colombier cfsstat.byteswritten, cfsstat.byteswritten -
14554366bb71SDavid du Colombier cfsprev.byteswritten);
14564366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesfromserver\n",
14574366bb71SDavid du Colombier cfsstat.bytesfromserver, cfsstat.bytesfromserver -
14584366bb71SDavid du Colombier cfsprev.bytesfromserver);
14594366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesfromdirs\n",
14604366bb71SDavid du Colombier cfsstat.bytesfromdirs, cfsstat.bytesfromdirs -
14614366bb71SDavid du Colombier cfsprev.bytesfromdirs);
14624366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytesfromcache\n",
14634366bb71SDavid du Colombier cfsstat.bytesfromcache, cfsstat.bytesfromcache -
14644366bb71SDavid du Colombier cfsprev.bytesfromcache);
14654366bb71SDavid du Colombier p += snprint(p, sizeof statbuf+statbuf-p, "%7llud %7llud bytestocache\n",
14664366bb71SDavid du Colombier cfsstat.bytestocache, cfsstat.bytestocache -
14674366bb71SDavid du Colombier cfsprev.bytestocache);
14684366bb71SDavid du Colombier statlen = p - statbuf;
14694366bb71SDavid du Colombier cfsprev = cfsstat;
14704366bb71SDavid du Colombier }
14714366bb71SDavid du Colombier
14724366bb71SDavid du Colombier /*
14734366bb71SDavid du Colombier * paths
14744366bb71SDavid du Colombier */
14754366bb71SDavid du Colombier
14764366bb71SDavid du Colombier Path*
newpath(Path * parent,char * name,Qid qid)14774366bb71SDavid du Colombier newpath(Path *parent, char *name, Qid qid)
14784366bb71SDavid du Colombier {
14794366bb71SDavid du Colombier Path *p;
14804366bb71SDavid du Colombier
14814366bb71SDavid du Colombier if(parent != nil){
14824366bb71SDavid du Colombier for(p = parent->child; p != nil; p = p->next){
14834366bb71SDavid du Colombier if(strcmp(p->name, name) == 0){
14844366bb71SDavid du Colombier if(p->inval != nil){
14854366bb71SDavid du Colombier free(p->inval);
14864366bb71SDavid du Colombier p->inval = nil;
14874366bb71SDavid du Colombier }
14884366bb71SDavid du Colombier p->qid = qid;
14894366bb71SDavid du Colombier p->ref++;
14904366bb71SDavid du Colombier return p;
14914366bb71SDavid du Colombier }
14924366bb71SDavid du Colombier }
14934366bb71SDavid du Colombier }
14944366bb71SDavid du Colombier p = mallocz(sizeof(*p), 1);
14954366bb71SDavid du Colombier p->ref = 2;
14964366bb71SDavid du Colombier if(name != nil)
14974366bb71SDavid du Colombier p->name = strdup(name);
14984366bb71SDavid du Colombier p->qid = qid;
14994366bb71SDavid du Colombier p->parent = parent;
15004366bb71SDavid du Colombier if(parent != nil){
15014366bb71SDavid du Colombier parent->ref++;
15024366bb71SDavid du Colombier p->next = parent->child;
15034366bb71SDavid du Colombier parent->child = p;
15044366bb71SDavid du Colombier }
15054366bb71SDavid du Colombier return p;
15064366bb71SDavid du Colombier }
15074366bb71SDavid du Colombier
15084366bb71SDavid du Colombier void
freeinval(Path * p)1509*518acb85SDavid du Colombier freeinval(Path *p)
1510*518acb85SDavid du Colombier {
1511*518acb85SDavid du Colombier Path *q, **r;
1512*518acb85SDavid du Colombier
1513*518acb85SDavid du Colombier for(r = &p->parent->child; (q = *r) != nil; r = &q->next){
1514*518acb85SDavid du Colombier if(q == p)
1515*518acb85SDavid du Colombier continue;
1516*518acb85SDavid du Colombier if(strcmp(q->name, p->name) == 0 && q->inval != nil){
1517*518acb85SDavid du Colombier if(q->ref > 1){
1518*518acb85SDavid du Colombier *r = q->next;
1519*518acb85SDavid du Colombier q->next = p->next;
1520*518acb85SDavid du Colombier p->next = q;
1521*518acb85SDavid du Colombier }
1522*518acb85SDavid du Colombier freepath(q);
1523*518acb85SDavid du Colombier break;
1524*518acb85SDavid du Colombier }
1525*518acb85SDavid du Colombier }
1526*518acb85SDavid du Colombier }
1527*518acb85SDavid du Colombier
1528*518acb85SDavid du Colombier void
setinval(Path * p,char * err)15294366bb71SDavid du Colombier setinval(Path *p, char *err)
15304366bb71SDavid du Colombier {
15314366bb71SDavid du Colombier if(p->inval != nil){
15324366bb71SDavid du Colombier free(p->inval);
15334366bb71SDavid du Colombier p->inval = nil;
15344366bb71SDavid du Colombier }
15354366bb71SDavid du Colombier if(err != nil)
15364366bb71SDavid du Colombier p->inval = strdup(err);
15374366bb71SDavid du Colombier }
15384366bb71SDavid du Colombier
15394366bb71SDavid du Colombier void
badpath(Path * parent,char * name,char * err)15404366bb71SDavid du Colombier badpath(Path *parent, char *name, char *err)
15414366bb71SDavid du Colombier {
15424366bb71SDavid du Colombier Path *p;
15434366bb71SDavid du Colombier
15444366bb71SDavid du Colombier for(p = parent->child; p != nil; p = p->next){
15454366bb71SDavid du Colombier if(strcmp(p->name, name) == 0){
15464366bb71SDavid du Colombier setinval(p, err);
15474366bb71SDavid du Colombier return;
15484366bb71SDavid du Colombier }
15494366bb71SDavid du Colombier }
15504366bb71SDavid du Colombier p = mallocz(sizeof(*p), 1);
15514366bb71SDavid du Colombier p->ref = 2;
15524366bb71SDavid du Colombier if(name != nil)
15534366bb71SDavid du Colombier p->name = strdup(name);
15544366bb71SDavid du Colombier p->inval = strdup(err);
15554366bb71SDavid du Colombier p->parent = parent;
15564366bb71SDavid du Colombier if(parent != nil){
15574366bb71SDavid du Colombier parent->ref++;
15584366bb71SDavid du Colombier p->next = parent->child;
15594366bb71SDavid du Colombier parent->child = p;
15604366bb71SDavid du Colombier }
15614366bb71SDavid du Colombier }
15624366bb71SDavid du Colombier
15634366bb71SDavid du Colombier void
fileinval(Path * p)15644366bb71SDavid du Colombier fileinval(Path *p)
15654366bb71SDavid du Colombier {
15664366bb71SDavid du Colombier if(p->file != nil){
15674366bb71SDavid du Colombier putfile(p->file);
15684366bb71SDavid du Colombier p->file = nil;
15694366bb71SDavid du Colombier }
15704366bb71SDavid du Colombier }
15714366bb71SDavid du Colombier
15724366bb71SDavid du Colombier void
freepath(Path * p)15734366bb71SDavid du Colombier freepath(Path *p)
15744366bb71SDavid du Colombier {
15754366bb71SDavid du Colombier Path *q, **r;
15764366bb71SDavid du Colombier
15774366bb71SDavid du Colombier while(p != nil && --p->ref == 0){
15784366bb71SDavid du Colombier if(p->child != nil)
15794366bb71SDavid du Colombier error("freepath child");
15804366bb71SDavid du Colombier q = p->parent;
15814366bb71SDavid du Colombier if(q != nil){
15824366bb71SDavid du Colombier for(r = &q->child; *r != nil; r = &(*r)->next){
15834366bb71SDavid du Colombier if(*r == p){
15844366bb71SDavid du Colombier *r = p->next;
15854366bb71SDavid du Colombier break;
15864366bb71SDavid du Colombier }
15874366bb71SDavid du Colombier }
15884366bb71SDavid du Colombier }
15894366bb71SDavid du Colombier if(p->sfid != nil){
15904366bb71SDavid du Colombier /* TO DO: could queue these for a great clunking proc */
15914366bb71SDavid du Colombier sfclunk(p->sfid);
15924366bb71SDavid du Colombier p->sfid = nil;
15934366bb71SDavid du Colombier }
15944366bb71SDavid du Colombier if(p->inval != nil)
15954366bb71SDavid du Colombier free(p->inval);
15964366bb71SDavid du Colombier if(p->file != nil)
15974366bb71SDavid du Colombier putfile(p->file);
15984366bb71SDavid du Colombier free(p->name);
15994366bb71SDavid du Colombier free(p);
16004366bb71SDavid du Colombier p = q;
16014366bb71SDavid du Colombier }
16024366bb71SDavid du Colombier }
16034366bb71SDavid du Colombier
16044366bb71SDavid du Colombier static char*
pathstr1(Path * p,char * ep)16054366bb71SDavid du Colombier pathstr1(Path *p, char *ep)
16064366bb71SDavid du Colombier {
16074366bb71SDavid du Colombier ep -= strlen(p->name);
16084366bb71SDavid du Colombier memmove(ep, p->name, strlen(p->name));
16094366bb71SDavid du Colombier if(p->parent != nil){
16104366bb71SDavid du Colombier *--ep = '/';
16114366bb71SDavid du Colombier ep = pathstr1(p->parent, ep);
16124366bb71SDavid du Colombier }
16134366bb71SDavid du Colombier return ep;
16144366bb71SDavid du Colombier }
16154366bb71SDavid du Colombier
16164366bb71SDavid du Colombier char*
pathstr(Path * p)16174366bb71SDavid du Colombier pathstr(Path *p)
16184366bb71SDavid du Colombier {
16194366bb71SDavid du Colombier static char buf[1000];
16204366bb71SDavid du Colombier return pathstr1(p, buf+sizeof(buf)-1);
16214366bb71SDavid du Colombier }
16224366bb71SDavid du Colombier
16234366bb71SDavid du Colombier /*
16244366bb71SDavid du Colombier * files
16254366bb71SDavid du Colombier */
16264366bb71SDavid du Colombier
16274366bb71SDavid du Colombier void
openfile(Fid * mf,int omode,u32int iounit,SFid * sfid)16284366bb71SDavid du Colombier openfile(Fid *mf, int omode, u32int iounit, SFid *sfid)
16294366bb71SDavid du Colombier {
16304366bb71SDavid du Colombier /* open mf and cache open File at p */
16314366bb71SDavid du Colombier Path *p;
16324366bb71SDavid du Colombier File *file;
16334366bb71SDavid du Colombier SFid *osfid;
16344366bb71SDavid du Colombier
16354366bb71SDavid du Colombier p = mf->path;
16364366bb71SDavid du Colombier file = p->file;
16374366bb71SDavid du Colombier if(file == nil){
16384366bb71SDavid du Colombier file = mallocz(sizeof(*file), 1);
16394366bb71SDavid du Colombier file->ref = 1;
16404366bb71SDavid du Colombier file->qid = mf->qid; /* TO DO: check for clone files */
16414366bb71SDavid du Colombier file->clength = MAXLEN;
16424366bb71SDavid du Colombier p->file = file;
16434366bb71SDavid du Colombier }
16444366bb71SDavid du Colombier osfid = file->open[omode];
16454366bb71SDavid du Colombier if(osfid != nil){
16464366bb71SDavid du Colombier DPRINT(2, "openfile: existing sfid %ud open %d\n", osfid->fid, omode);
16474366bb71SDavid du Colombier return;
16484366bb71SDavid du Colombier }
16494366bb71SDavid du Colombier DPRINT(2, "openfile: cached %ud for %q mode %d\n", sfid->fid, pathstr(p), omode);
16504366bb71SDavid du Colombier sfid->ref++;
16514366bb71SDavid du Colombier file->open[omode] = sfid;
16524366bb71SDavid du Colombier if(file->iounit == 0)
16534366bb71SDavid du Colombier file->iounit = iounit; /* BUG: might vary */
16544366bb71SDavid du Colombier }
16554366bb71SDavid du Colombier
16564366bb71SDavid du Colombier void
closefile(Fid * mf,int mustclunk,int removed)16574366bb71SDavid du Colombier closefile(Fid *mf, int mustclunk, int removed)
16584366bb71SDavid du Colombier {
16594366bb71SDavid du Colombier Path *p;
16604366bb71SDavid du Colombier File *file;
16614366bb71SDavid du Colombier SFid *sfid, *osfid;
16624366bb71SDavid du Colombier
16634366bb71SDavid du Colombier if((sfid = mf->opened) == nil)
16644366bb71SDavid du Colombier return;
16654366bb71SDavid du Colombier p = mf->path;
16664366bb71SDavid du Colombier file = p->file;
16674366bb71SDavid du Colombier if(file == nil){ /* TO DO: messy */
16684366bb71SDavid du Colombier mf->opened = nil;
16694366bb71SDavid du Colombier if(sfid->ref == 1 && mustclunk)
16704366bb71SDavid du Colombier sfclunk(sfid);
16714366bb71SDavid du Colombier freesfid(sfid);
16724366bb71SDavid du Colombier return;
16734366bb71SDavid du Colombier }
16744366bb71SDavid du Colombier osfid = file->open[mf->mode];
16754366bb71SDavid du Colombier if(osfid == sfid){
16764366bb71SDavid du Colombier if(removed || sfid->ref == 1)
16774366bb71SDavid du Colombier file->open[mf->mode] = nil;
16784366bb71SDavid du Colombier if(sfid->ref == 1){
16794366bb71SDavid du Colombier if(mustclunk)
16804366bb71SDavid du Colombier sfclunk(sfid);
16814366bb71SDavid du Colombier freesfid(sfid);
16824366bb71SDavid du Colombier }else
16834366bb71SDavid du Colombier sfid->ref--;
16844366bb71SDavid du Colombier }
16854366bb71SDavid du Colombier mf->opened = nil;
16864366bb71SDavid du Colombier }
16874366bb71SDavid du Colombier
16884366bb71SDavid du Colombier SFid*
alreadyopen(Fid * mf,uint mode)16894366bb71SDavid du Colombier alreadyopen(Fid *mf, uint mode)
16904366bb71SDavid du Colombier {
16914366bb71SDavid du Colombier File *file;
16924366bb71SDavid du Colombier SFid *sfid;
16934366bb71SDavid du Colombier
16944366bb71SDavid du Colombier file = mf->path->file;
16954366bb71SDavid du Colombier if(file == nil)
16964366bb71SDavid du Colombier return nil;
16974366bb71SDavid du Colombier sfid = file->open[mode&3];
16984366bb71SDavid du Colombier if(sfid == nil)
16994366bb71SDavid du Colombier return nil;
17004366bb71SDavid du Colombier DPRINT(2, "openfile: existing sfid %ud open %d\n", sfid->fid, mode&3);
17014366bb71SDavid du Colombier sfid->ref++;
17024366bb71SDavid du Colombier return sfid;
17034366bb71SDavid du Colombier }
17044366bb71SDavid du Colombier
17054366bb71SDavid du Colombier void
copystat(File * file,Dir * d,int iswstat)17064366bb71SDavid du Colombier copystat(File *file, Dir *d, int iswstat)
17074366bb71SDavid du Colombier {
17084366bb71SDavid du Colombier if(d->length != ~(vlong)0){
17094366bb71SDavid du Colombier /* length change: discard cached data */
17104366bb71SDavid du Colombier if(iswstat && file->length < file->clength)
17114366bb71SDavid du Colombier cacheinval(file);
17124366bb71SDavid du Colombier file->length = d->length;
17134366bb71SDavid du Colombier }
17144366bb71SDavid du Colombier if(d->mode != ~0){
17154366bb71SDavid du Colombier file->mode = d->mode;
17164366bb71SDavid du Colombier file->qid.type = d->mode>>24;
17174366bb71SDavid du Colombier }
17184366bb71SDavid du Colombier if(d->atime != ~0)
17194366bb71SDavid du Colombier file->atime = d->atime;
17204366bb71SDavid du Colombier if(d->mtime != ~0)
17214366bb71SDavid du Colombier file->mtime = d->mtime;
17224366bb71SDavid du Colombier if(*d->uid){
17234366bb71SDavid du Colombier freestr(file->uid);
17244366bb71SDavid du Colombier file->uid = newstr(d->uid);
17254366bb71SDavid du Colombier }
17264366bb71SDavid du Colombier if(*d->gid){
17274366bb71SDavid du Colombier freestr(file->gid);
17284366bb71SDavid du Colombier file->gid = newstr(d->gid);
17294366bb71SDavid du Colombier }
17304366bb71SDavid du Colombier if(*d->muid){
17314366bb71SDavid du Colombier freestr(file->muid);
17324366bb71SDavid du Colombier file->muid = newstr(d->muid);
17334366bb71SDavid du Colombier }
17344366bb71SDavid du Colombier }
17354366bb71SDavid du Colombier
17364366bb71SDavid du Colombier void
putfile(File * f)17374366bb71SDavid du Colombier putfile(File *f)
17384366bb71SDavid du Colombier {
17394366bb71SDavid du Colombier int i;
17404366bb71SDavid du Colombier SFid *sfid;
17414366bb71SDavid du Colombier
17424366bb71SDavid du Colombier if(--f->ref != 0)
17434366bb71SDavid du Colombier return;
17444366bb71SDavid du Colombier for(i = 0; i < nelem(f->open); i++){
17454366bb71SDavid du Colombier sfid = f->open[i];
17464366bb71SDavid du Colombier if(sfid != nil){
17474366bb71SDavid du Colombier f->open[i] = nil;
17484366bb71SDavid du Colombier sfclunk(sfid);
17494366bb71SDavid du Colombier freesfid(sfid);
17504366bb71SDavid du Colombier }
17514366bb71SDavid du Colombier }
17524366bb71SDavid du Colombier freestr(f->uid);
17534366bb71SDavid du Colombier freestr(f->gid);
17544366bb71SDavid du Colombier freestr(f->muid);
17554366bb71SDavid du Colombier cacheinval(f);
17564366bb71SDavid du Colombier free(f->cached);
17574366bb71SDavid du Colombier free(f);
17584366bb71SDavid du Colombier }
17594366bb71SDavid du Colombier
17604366bb71SDavid du Colombier /*
17614366bb71SDavid du Colombier * data
17624366bb71SDavid du Colombier */
17634366bb71SDavid du Colombier
17644366bb71SDavid du Colombier static int radix[] = {10, 12, 14};
17654366bb71SDavid du Colombier static uint range[] = {8, 32, 0};
17664366bb71SDavid du Colombier static uint cacheused;
17674366bb71SDavid du Colombier
17684366bb71SDavid du Colombier void
datainit(void)17694366bb71SDavid du Colombier datainit(void)
17704366bb71SDavid du Colombier {
17714366bb71SDavid du Colombier datalist.forw = datalist.back = &datalist;
17724366bb71SDavid du Colombier }
17734366bb71SDavid du Colombier
17744366bb71SDavid du Colombier Data*
allocdata(File * file,uint n,uint nbytes)17754366bb71SDavid du Colombier allocdata(File *file, uint n, uint nbytes)
17764366bb71SDavid du Colombier {
17774366bb71SDavid du Colombier Data *d;
17784366bb71SDavid du Colombier
17794366bb71SDavid du Colombier while(cacheused+nbytes > cachesize && datalist.forw != datalist.back)
17804366bb71SDavid du Colombier freedata(datalist.forw);
17814366bb71SDavid du Colombier cacheused += nbytes;
17824366bb71SDavid du Colombier d = mallocz(sizeof(*d), 0);
17834366bb71SDavid du Colombier d->owner = file;
17844366bb71SDavid du Colombier d->n = n;
17854366bb71SDavid du Colombier d->base = malloc(nbytes);
17864366bb71SDavid du Colombier d->size = nbytes;
17874366bb71SDavid du Colombier d->min = 0;
17884366bb71SDavid du Colombier d->max = 0;
17894366bb71SDavid du Colombier d->forw = &datalist;
17904366bb71SDavid du Colombier d->back = datalist.back;
17914366bb71SDavid du Colombier d->back->forw = d;
17924366bb71SDavid du Colombier datalist.back = d;
17934366bb71SDavid du Colombier return d;
17944366bb71SDavid du Colombier }
17954366bb71SDavid du Colombier
17964366bb71SDavid du Colombier void
freedata(Data * d)17974366bb71SDavid du Colombier freedata(Data *d)
17984366bb71SDavid du Colombier {
17994366bb71SDavid du Colombier d->forw->back = d->back;
18004366bb71SDavid du Colombier d->back->forw = d->forw;
18014366bb71SDavid du Colombier cacheused -= d->size;
18024366bb71SDavid du Colombier if(d->owner != nil)
18034366bb71SDavid du Colombier d->owner->cached[d->n] = nil;
18044366bb71SDavid du Colombier free(d->base);
18054366bb71SDavid du Colombier free(d);
18064366bb71SDavid du Colombier }
18074366bb71SDavid du Colombier
18084366bb71SDavid du Colombier /*
18094366bb71SDavid du Colombier * move recently-used data to end
18104366bb71SDavid du Colombier */
18114366bb71SDavid du Colombier void
usedata(Data * d)18124366bb71SDavid du Colombier usedata(Data *d)
18134366bb71SDavid du Colombier {
18144366bb71SDavid du Colombier if(datalist.back == d)
18154366bb71SDavid du Colombier return; /* already at end */
18164366bb71SDavid du Colombier
18174366bb71SDavid du Colombier d->forw->back = d->back;
18184366bb71SDavid du Colombier d->back->forw = d->forw;
18194366bb71SDavid du Colombier
18204366bb71SDavid du Colombier d->forw = &datalist;
18214366bb71SDavid du Colombier d->back = datalist.back;
18224366bb71SDavid du Colombier d->back->forw = d;
18234366bb71SDavid du Colombier datalist.back = d;
18244366bb71SDavid du Colombier }
18254366bb71SDavid du Colombier
18264366bb71SDavid du Colombier /*
18274366bb71SDavid du Colombier * data cache
18284366bb71SDavid du Colombier */
18294366bb71SDavid du Colombier
18304366bb71SDavid du Colombier int
cacheread(File * file,void * buf,vlong offset,int nbytes)18314366bb71SDavid du Colombier cacheread(File *file, void *buf, vlong offset, int nbytes)
18324366bb71SDavid du Colombier {
18334366bb71SDavid du Colombier char *p;
18344366bb71SDavid du Colombier Data *d;
18354366bb71SDavid du Colombier int n, o;
18364366bb71SDavid du Colombier
18374366bb71SDavid du Colombier DPRINT(2, "file %lld length %lld\n", file->qid.path, file->clength);
18384366bb71SDavid du Colombier p = buf;
18394366bb71SDavid du Colombier while(nbytes > 0){
18404366bb71SDavid du Colombier d = finddata(file, offset, &o);
18414366bb71SDavid du Colombier if(d == nil)
18424366bb71SDavid du Colombier break;
18434366bb71SDavid du Colombier if(o < d->min){
18444366bb71SDavid du Colombier if(p == (char*)buf)
18454366bb71SDavid du Colombier return -(d->min-o); /* fill the gap */
18464366bb71SDavid du Colombier break;
18474366bb71SDavid du Colombier }else if(o >= d->max)
18484366bb71SDavid du Colombier break;
18494366bb71SDavid du Colombier usedata(d);
18504366bb71SDavid du Colombier /* o >= d->min && o < d->max */
18514366bb71SDavid du Colombier n = nbytes;
18524366bb71SDavid du Colombier if(n > d->max-o)
18534366bb71SDavid du Colombier n = d->max-o;
18544366bb71SDavid du Colombier memmove(p, d->base+o, n);
18554366bb71SDavid du Colombier p += n;
18564366bb71SDavid du Colombier nbytes -= n;
18574366bb71SDavid du Colombier offset += n;
18584366bb71SDavid du Colombier }
18594366bb71SDavid du Colombier return p-(char*)buf;
18604366bb71SDavid du Colombier }
18614366bb71SDavid du Colombier
18624366bb71SDavid du Colombier void
cachewrite(File * file,void * buf,vlong offset,int nbytes)18634366bb71SDavid du Colombier cachewrite(File *file, void *buf, vlong offset, int nbytes)
18644366bb71SDavid du Colombier {
18654366bb71SDavid du Colombier char *p;
18664366bb71SDavid du Colombier Data *d;
18674366bb71SDavid du Colombier int n, o;
18684366bb71SDavid du Colombier
18694366bb71SDavid du Colombier p = buf;
18704366bb71SDavid du Colombier while(nbytes > 0){
18714366bb71SDavid du Colombier d = storedata(file, offset, &o);
18724366bb71SDavid du Colombier if(d == nil)
18734366bb71SDavid du Colombier break;
18744366bb71SDavid du Colombier n = nbytes;
18754366bb71SDavid du Colombier if(n > d->size-o)
18764366bb71SDavid du Colombier n = d->size-o;
18774366bb71SDavid du Colombier cachemerge(d, p, o, n);
18784366bb71SDavid du Colombier p += n;
18794366bb71SDavid du Colombier offset += n;
18804366bb71SDavid du Colombier nbytes -= n;
18814366bb71SDavid du Colombier }
18824366bb71SDavid du Colombier if(offset > file->clength)
18834366bb71SDavid du Colombier file->clength = offset;
18844366bb71SDavid du Colombier }
18854366bb71SDavid du Colombier
18864366bb71SDavid du Colombier /*
18874366bb71SDavid du Colombier * merge data in if it overlaps existing contents,
18884366bb71SDavid du Colombier * or simply replace existing contents otherwise
18894366bb71SDavid du Colombier */
18904366bb71SDavid du Colombier void
cachemerge(Data * p,char * from,int start,int len)18914366bb71SDavid du Colombier cachemerge(Data *p, char *from, int start, int len)
18924366bb71SDavid du Colombier {
18934366bb71SDavid du Colombier int end;
18944366bb71SDavid du Colombier
18954366bb71SDavid du Colombier end = start + len;
18964366bb71SDavid du Colombier memmove(p->base+start, from, len);
18974366bb71SDavid du Colombier
18984366bb71SDavid du Colombier if(start > p->max || p->min > end){
18994366bb71SDavid du Colombier p->min = start;
19004366bb71SDavid du Colombier p->max = end;
19014366bb71SDavid du Colombier }else{
19024366bb71SDavid du Colombier if(start < p->min)
19034366bb71SDavid du Colombier p->min = start;
19044366bb71SDavid du Colombier if(end > p->max)
19054366bb71SDavid du Colombier p->max = end;
19064366bb71SDavid du Colombier }
19074366bb71SDavid du Colombier }
19084366bb71SDavid du Colombier
19094366bb71SDavid du Colombier void
cacheinval(File * file)19104366bb71SDavid du Colombier cacheinval(File *file)
19114366bb71SDavid du Colombier {
19124366bb71SDavid du Colombier Data *d;
19134366bb71SDavid du Colombier int i;
19144366bb71SDavid du Colombier
19154366bb71SDavid du Colombier if(file->cached != nil){
19164366bb71SDavid du Colombier for(i = 0; i < file->ndata; i++){
19174366bb71SDavid du Colombier d = file->cached[i];
19184366bb71SDavid du Colombier if(d != nil){
19194366bb71SDavid du Colombier file->cached[i] = nil;
19204366bb71SDavid du Colombier d->owner = nil;
19214366bb71SDavid du Colombier freedata(d);
19224366bb71SDavid du Colombier }
19234366bb71SDavid du Colombier }
19244366bb71SDavid du Colombier /* leave the array */
19254366bb71SDavid du Colombier }
19264366bb71SDavid du Colombier file->clength = 0;
19274366bb71SDavid du Colombier }
19284366bb71SDavid du Colombier
19294366bb71SDavid du Colombier Data*
finddata(File * file,uvlong offset,int * blkoff)19304366bb71SDavid du Colombier finddata(File *file, uvlong offset, int *blkoff)
19314366bb71SDavid du Colombier {
19324366bb71SDavid du Colombier int r, x;
19334366bb71SDavid du Colombier uvlong base, o;
19344366bb71SDavid du Colombier
19354366bb71SDavid du Colombier x = 0;
19364366bb71SDavid du Colombier base = 0;
19374366bb71SDavid du Colombier for(r = 0; r < nelem(radix); r++){
19384366bb71SDavid du Colombier o = (offset - base) >> radix[r];
19394366bb71SDavid du Colombier DPRINT(2, "file %llud offset %llud x %d base %llud o %llud\n", file->qid.path, offset, x, base, o);
19404366bb71SDavid du Colombier if(range[r] == 0 || o < range[r]){
19414366bb71SDavid du Colombier o += x;
19424366bb71SDavid du Colombier if(o >= file->ndata)
19434366bb71SDavid du Colombier break;
19444366bb71SDavid du Colombier *blkoff = (offset-base) & ((1<<radix[r])-1);
19454366bb71SDavid du Colombier return file->cached[(int)o];
19464366bb71SDavid du Colombier }
19474366bb71SDavid du Colombier base += range[r]<<radix[r];
19484366bb71SDavid du Colombier x += range[r];
19494366bb71SDavid du Colombier }
19504366bb71SDavid du Colombier return nil;
19514366bb71SDavid du Colombier }
19524366bb71SDavid du Colombier
19534366bb71SDavid du Colombier Data*
storedata(File * file,uvlong offset,int * blkoff)19544366bb71SDavid du Colombier storedata(File *file, uvlong offset, int *blkoff)
19554366bb71SDavid du Colombier {
19564366bb71SDavid du Colombier int r, x, v, size;
19574366bb71SDavid du Colombier uvlong base, o;
19584366bb71SDavid du Colombier Data **p;
19594366bb71SDavid du Colombier
19604366bb71SDavid du Colombier if(file->cached == nil){
19614366bb71SDavid du Colombier file->cached = mallocz(16*sizeof(*file->cached), 1);
19624366bb71SDavid du Colombier file->ndata = 16;
19634366bb71SDavid du Colombier }
19644366bb71SDavid du Colombier x = 0;
19654366bb71SDavid du Colombier base = 0;
19664366bb71SDavid du Colombier for(r = 0; r < nelem(radix); r++){
19674366bb71SDavid du Colombier o = (offset - base) >> radix[r];
19684366bb71SDavid du Colombier DPRINT(2, "store file %llud offset %llud x %d base %llud o %llud\n", file->qid.path, offset, x, base, o);
19694366bb71SDavid du Colombier if(range[r] == 0 || o < range[r]){
19704366bb71SDavid du Colombier o += x;
19714366bb71SDavid du Colombier if(o >= file->ndata){
19724366bb71SDavid du Colombier if(o >= 512)
19734366bb71SDavid du Colombier return nil; /* won't fit */
19744366bb71SDavid du Colombier v = (o+32+31)&~31;
19754366bb71SDavid du Colombier file->cached = realloc(file->cached, v*sizeof(*file->cached));
19764366bb71SDavid du Colombier memset(file->cached+file->ndata, 0, (v-file->ndata)*sizeof(*file->cached));
19774366bb71SDavid du Colombier file->ndata = v;
19784366bb71SDavid du Colombier }
19794366bb71SDavid du Colombier size = 1 << radix[r];
19804366bb71SDavid du Colombier DPRINT(2, " -> %d %d\n", (int)o, size);
19814366bb71SDavid du Colombier *blkoff = (offset-base) & (size-1);
19824366bb71SDavid du Colombier p = &file->cached[(int)o];
19834366bb71SDavid du Colombier if(*p == nil)
19844366bb71SDavid du Colombier *p = allocdata(file, (int)o, size);
19854366bb71SDavid du Colombier else
19864366bb71SDavid du Colombier usedata(*p);
19874366bb71SDavid du Colombier return *p;
19884366bb71SDavid du Colombier }
19894366bb71SDavid du Colombier base += range[r]<<radix[r];
19904366bb71SDavid du Colombier x += range[r];
19914366bb71SDavid du Colombier }
19924366bb71SDavid du Colombier return nil;
19934366bb71SDavid du Colombier }
19944366bb71SDavid du Colombier
19954366bb71SDavid du Colombier /*
19964366bb71SDavid du Colombier * Strings
19974366bb71SDavid du Colombier */
19984366bb71SDavid du Colombier
19994366bb71SDavid du Colombier enum{
20004366bb71SDavid du Colombier Strhashmask= (1<<8)-1,
20014366bb71SDavid du Colombier };
20024366bb71SDavid du Colombier
20034366bb71SDavid du Colombier static struct{
20044366bb71SDavid du Colombier QLock;
20054366bb71SDavid du Colombier String* htab[Strhashmask+1];
20064366bb71SDavid du Colombier } stralloc;
20074366bb71SDavid du Colombier
20084366bb71SDavid du Colombier String**
hashslot(char * s)20094366bb71SDavid du Colombier hashslot(char *s)
20104366bb71SDavid du Colombier {
20114366bb71SDavid du Colombier uint h, g;
20124366bb71SDavid du Colombier uchar *p;
20134366bb71SDavid du Colombier
20144366bb71SDavid du Colombier h = 0;
20154366bb71SDavid du Colombier for(p = (uchar*)s; *p != 0; p++){
20164366bb71SDavid du Colombier h = (h<<4) + *p;
20174366bb71SDavid du Colombier g = h & (0xF<<28);
20184366bb71SDavid du Colombier if(g != 0)
20194366bb71SDavid du Colombier h ^= ((g>>24) & 0xFF) | g;
20204366bb71SDavid du Colombier }
20214366bb71SDavid du Colombier return &stralloc.htab[h & Strhashmask];
20224366bb71SDavid du Colombier }
20234366bb71SDavid du Colombier
20244366bb71SDavid du Colombier String*
newstr(char * val)20254366bb71SDavid du Colombier newstr(char *val)
20264366bb71SDavid du Colombier {
20274366bb71SDavid du Colombier String *s, **l;
20284366bb71SDavid du Colombier
20294366bb71SDavid du Colombier //qlock(&stralloc);
20304366bb71SDavid du Colombier for(l = hashslot(val); (s = *l) != nil; l = &s->next){
20314366bb71SDavid du Colombier if(strcmp(s->s, val) == 0){
20324366bb71SDavid du Colombier s->ref++;
20334366bb71SDavid du Colombier //qunlock(&stralloc);
20344366bb71SDavid du Colombier return s;
20354366bb71SDavid du Colombier }
20364366bb71SDavid du Colombier }
20374366bb71SDavid du Colombier s = malloc(sizeof(*s));
20384366bb71SDavid du Colombier s->s = strdup(val);
20394366bb71SDavid du Colombier s->len = strlen(s->s);
20404366bb71SDavid du Colombier s->ref = 1;
20414366bb71SDavid du Colombier s->next = *l;
20424366bb71SDavid du Colombier *l = s;
20434366bb71SDavid du Colombier //qunlock(&stralloc);
20444366bb71SDavid du Colombier return s;
20454366bb71SDavid du Colombier }
20464366bb71SDavid du Colombier
20474366bb71SDavid du Colombier String*
dupstr(String * s)20484366bb71SDavid du Colombier dupstr(String *s)
20494366bb71SDavid du Colombier {
20504366bb71SDavid du Colombier s->ref++;
20514366bb71SDavid du Colombier return s;
20524366bb71SDavid du Colombier }
20534366bb71SDavid du Colombier
20544366bb71SDavid du Colombier void
freestr(String * s)20554366bb71SDavid du Colombier freestr(String *s)
20564366bb71SDavid du Colombier {
20574366bb71SDavid du Colombier String **l;
20584366bb71SDavid du Colombier
20594366bb71SDavid du Colombier if(s != nil && --s->ref == 0){
20604366bb71SDavid du Colombier //qlock(&stralloc);
20614366bb71SDavid du Colombier for(l = hashslot(s->s); *l != nil; l = &(*l)->next){
20624366bb71SDavid du Colombier if(*l == s){
20634366bb71SDavid du Colombier *l = s->next;
20644366bb71SDavid du Colombier break;
20654366bb71SDavid du Colombier }
20664366bb71SDavid du Colombier }
20674366bb71SDavid du Colombier //qunlock(&stralloc);
20684366bb71SDavid du Colombier free(s->s);
20694366bb71SDavid du Colombier free(s);
20704366bb71SDavid du Colombier }
20714366bb71SDavid du Colombier }
2072