Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include "all.h"

extern uchar buf[];

Xfid *
rpc2xfid(Rpccall *cmd, Dir *dp)
{
        char *argptr = cmd->args;
        Xfile *xp;
        Xfid *xf;
        Session *s;
        char *service;
        Authunix au;
        Qid qid;
        char client[256], *user;
        Unixidmap *m;
        int i;
        uvlong x1, x2;

        chat("rpc2xfid %.8lux %.8lux %p %p\n", *((ulong*)argptr), *((ulong*)argptr+1), buf, argptr);
        if(argptr[0] == 0 && argptr[1] == 0){   /* root */
                chat("root...");
                xp = xfroot(&argptr[2], 0);
                s = xp ? xp->s : 0;
        }else{
                ulong ul;
                chat("noroot %.8lux...", *((ulong*)argptr));
                if((ul=GLONG()) != starttime){
                        chat("bad tag %lux %lux...", ul, starttime);
                        return 0;
                }
                s = (Session *)GLONG();
                x1 = GLONG();
                x2 = GLONG();
                qid.path = x1 | (x2<<32);
                qid.vers = 0;
                qid.type = GBYTE();
                xp = xfile(&qid, s, 0);
        }
        if(xp == 0){
                chat("no xfile...");
                return 0;
        }
        if(auth2unix(&cmd->cred, &au) != 0){
                chat("auth flavor=%ld, count=%ld\n",
                        cmd->cred.flavor, cmd->cred.count);
                for(i=0; i<cmd->cred.count; i++)
                        chat(" %.2ux", ((uchar *)cmd->cred.data)[i]);
                chat("...");
                return 0;
        }else{
/*              chat("auth: %d %.*s u=%d g=%d",
 *                      au.stamp, utfnlen(au.mach.s, au.mach.n), au.mach.s, au.uid, au.gid);
 *              for(i=0; i<au.gidlen; i++)
 *                      chat(", %d", au.gids[i]);
 *              chat("...");
 */
                char *p = memchr(au.mach.s, '.', au.mach.n);
                chat("%ld@%.*s...", au.uid, utfnlen(au.mach.s, (p ? p-au.mach.s : au.mach.n)), au.mach.s);
        }
        if(au.mach.n >= sizeof client){
                chat("client name too long...");
                return 0;
        }
        memcpy(client, au.mach.s, au.mach.n);
        client[au.mach.n] = 0;
        service = xp->parent->s->service;
        cmd->up = m = pair2idmap(service, cmd->host);
        if(m == 0){
                chat("no map for pair (%s,%s)...", service, client);
                /*chat("getdom %d.%d.%d.%d", cmd->host&0xFF, (cmd->host>>8)&0xFF,
                        (cmd->host>>16)&0xFF, (cmd->host>>24)&0xFF);/**/
                /*if(getdom(cmd->host, client, sizeof(client))<0)
                        return 0;/**/
                return 0;
        }
        /*chat("map=(%s,%s)...", m->server, m->client);/**/
        cmd->user = user = id2name(&m->u.ids, au.uid);
        if(user == 0){
                chat("no user for id %ld...", au.uid);
                return 0;
        }
        chat("user=%s...", user);/**/
        xf = 0;
        if(s == xp->parent->s){
                if(!s->noauth)
                        xf = setuser(xp, user);
                if(xf == 0)
                        xf = setuser(xp, "none");
                if(xf == 0)
                        chat("can't set user none...");
        }else
                xf = xp->users;
        if(xf)
                chat("uid=%s...", xf->uid);
        if(xf && dp && xfstat(xf, dp) < 0){
                chat("can't stat %s...", xp->name);
                return 0;
        }
        return xf;
}

Xfid *
setuser(Xfile *xp, char *user)
{
        Xfid *xf, *xpf;
        Session *s;

        xf = xfid(user, xp, 1);
        if(xf->urfid)
                return xf;
        if(xp->parent==xp || !(xpf = setuser(xp->parent, user))) /* assign = */
                return xfid(user, xp, -1);
        s = xp->s;
        xf->urfid = newfid(s);
        xf->urfid->owner = &xf->urfid;
        setfid(s, xpf->urfid);
        s->f.newfid = xf->urfid - s->fids;
        s->f.nwname = 1;
        s->f.wname[0] = xp->name;
        if(xmesg(s, Twalk) || s->f.nwqid != 1)
                return xfid(user, xp, -1);
        return xf;
}

int
xfstat(Xfid *xf, Dir *dp)
{
        Xfile *xp;
        Session *s;
        char buf[128];

        xp = xf->xp;
        s = xp->s;
        if(s != xp->parent->s){
                seprint(buf, buf+sizeof buf, "#%s", xf->uid);
                dp->name = strstore(buf);
                dp->uid = xf->uid;
                dp->gid = xf->uid;
                dp->muid = xf->uid;
                dp->qid.path = (uvlong)xf->uid;
                dp->qid.type = QTFILE;
                dp->qid.vers = 0;
                dp->mode = 0666;
                dp->atime = time(0);
                dp->mtime = dp->atime;
                dp->length = NETCHLEN;
                dp->type = 0;
                dp->type = 0;
                return 0;
        }
        setfid(s, xf->urfid);
        if(xmesg(s, Tstat) == 0){
                convM2D(s->f.stat, s->f.nstat, dp, (char*)s->statbuf);
                if(xp->qid.path == dp->qid.path){
                        xp->name = strstore(dp->name);
                        return 0;
                }
                /* not reached ? */
                chat("xp->qid.path=0x%.16llux, dp->qid.path=0x%.16llux name=%s...",
                        xp->qid.path, dp->qid.path, dp->name);
        }
        if(xp != xp->parent)
                xpclear(xp);
        else
                clog("can't stat root: %s",
                        s->f.type == Rerror ? s->f.ename : "??");
        return -1;
}

int
xfwstat(Xfid *xf, Dir *dp)
{
        Xfile *xp;
        Session *s;

        xp = xf->xp;
        s = xp->s;

        /*
         * xf->urfid can be zero because some DOS NFS clients
         * try to do wstat on the #user authentication files on close.
         */
        if(s == 0 || xf->urfid == 0)
                return -1;
        setfid(s, xf->urfid);
        s->f.stat = s->statbuf;
        convD2M(dp, s->f.stat, Maxstatdata);
        if(xmesg(s, Twstat))
                return -1;
        xp->name = strstore(dp->name);
        return 0;
}

int
xfopen(Xfid *xf, int flag)
{
        static int modes[] = {
                [Oread] OREAD, [Owrite] OWRITE, [Oread|Owrite] ORDWR,
        };
        Xfile *xp;
        Session *s;
        Fid *opfid;
        int omode;

        if(xf->opfid && (xf->mode & flag & Open) == flag)
                return 0;
        omode = modes[(xf->mode|flag) & Open];
        if(flag & Trunc)
                omode |= OTRUNC;
        xp = xf->xp;
        chat("open(\"%s\", %d)...", xp->name, omode);
        s = xp->s;
        opfid = newfid(s);
        setfid(s, xf->urfid);
        s->f.newfid = opfid - s->fids;
        s->f.nwname = 0;
        if(xmesg(s, Twalk)){
                putfid(s, opfid);
                return -1;
        }
        setfid(s, opfid);
        s->f.mode = omode;
        if(xmesg(s, Topen)){
                clunkfid(s, opfid);
                return -1;
        }
        if(xf->opfid)
                clunkfid(s, xf->opfid);
        xf->mode |= flag & Open;
        xf->opfid = opfid;
        opfid->owner = &xf->opfid;
        xf->offset = 0;
        return 0;
}

void
xfclose(Xfid *xf)
{
        Xfile *xp;

        if(xf->mode & Open){
                xp = xf->xp;
                chat("close(\"%s\")...", xp->name);
                if(xf->opfid)
                        clunkfid(xp->s, xf->opfid);
                xf->mode &= ~Open;
                xf->opfid = 0;
        }
}

void
xfclear(Xfid *xf)
{
        Xfile *xp = xf->xp;

        if(xf->opfid){
                clunkfid(xp->s, xf->opfid);
                xf->opfid = 0;
        }
        if(xf->urfid){
                clunkfid(xp->s, xf->urfid);
                xf->urfid = 0;
        }
        xfid(xf->uid, xp, -1);
}

Xfid *
xfwalkcr(int type, Xfid *xf, String *elem, long perm)
{
        Session *s;
        Xfile *xp, *newxp;
        Xfid *newxf;
        Fid *nfid;

        chat("xf%s(\"%s\")...", type==Tcreate ? "create" : "walk", elem->s);
        xp = xf->xp;
        s = xp->s;
        nfid = newfid(s);
        setfid(s, xf->urfid);
        s->f.newfid = nfid - s->fids;
        if(type == Tcreate){
                s->f.nwname = 0;
                if(xmesg(s, Twalk)){
                        putfid(s, nfid);
                        return 0;
                }
                s->f.fid = nfid - s->fids;
        }
        if(type == Tcreate){
                s->f.name = elem->s;
                s->f.perm = perm;
                s->f.mode = (perm&DMDIR) ? OREAD : ORDWR;
                if(xmesg(s, type)){
                        clunkfid(s, nfid);
                        return 0;
                }
        }else{  /* Twalk */
                s->f.nwname = 1;
                s->f.wname[0] = elem->s;
                if(xmesg(s, type) || s->f.nwqid!=1){
                        putfid(s, nfid);
                        return 0;
                }
                s->f.qid = s->f.wqid[0];        /* only one element */
        }
        chat("fid=%d,qid=0x%llux,%ld,%.2ux...", s->f.fid, s->f.qid.path, s->f.qid.vers, s->f.qid.type);
        newxp = xfile(&s->f.qid, s, 1);
        if(newxp->parent == 0){
                chat("new xfile...");
                newxp->parent = xp;
                newxp->sib = xp->child;
                xp->child = newxp;
        }
        newxf = xfid(xf->uid, newxp, 1);
        if(type == Tcreate){
                newxf->mode = (perm&DMDIR) ? Oread : (Oread|Owrite);
                newxf->opfid = nfid;
                nfid->owner = &newxf->opfid;
                nfid = newfid(s);
                setfid(s, xf->urfid);
                s->f.newfid = nfid - s->fids;
                s->f.nwname = 1;
                s->f.wname[0] = elem->s;
                if(xmesg(s, Twalk) || s->f.nwqid!=1){
                        putfid(s, nfid);
                        xpclear(newxp);
                        return 0;
                }
                newxf->urfid = nfid;
                nfid->owner = &newxf->urfid;
        }else if(newxf->urfid){
                chat("old xfid %ld...", newxf->urfid-s->fids);
                clunkfid(s, nfid);
        }else{
                newxf->urfid = nfid;
                nfid->owner = &newxf->urfid;
        }
        newxp->name = strstore(elem->s);
        return newxf;
}

void
xpclear(Xfile *xp)
{
        Session *s;
        Xfid *xf;
        Xfile *xnp;

        s = xp->s;
        while(xf = xp->users)   /* assign = */
                xfclear(xf);
        while(xnp = xp->child){ /* assign = */
                xp->child = xnp->sib;
                xnp->parent = 0;
                xpclear(xnp);
                xfile(&xnp->qid, s, -1);
        }
        if(xnp = xp->parent){   /* assign = */
                if(xnp->child == xp)
                        xnp->child = xp->sib;
                else{
                        xnp = xnp->child;
                        while(xnp->sib != xp)
                                xnp = xnp->sib;
                        xnp->sib = xp->sib;
                }
                xfile(&xp->qid, s, -1);
        }
}

int
xp2fhandle(Xfile *xp, Fhandle fh)
{
        uchar *dataptr = fh;
        ulong x;
        int n;

        memset(fh, 0, FHSIZE);
        if(xp == xp->parent){   /* root */
                dataptr[0] = 0;
                dataptr[1] = 0;
                n = strlen(xp->s->service);
                if(n > FHSIZE-3)
                        n = FHSIZE-3;
                memmove(&dataptr[2], xp->s->service, n);
                dataptr[2+n] = 0;
        }else{
                PLONG(starttime);
                PLONG((u32int)(uintptr)xp->s);
                x = xp->qid.path;
                PLONG(x);
                x = xp->qid.path>>32;
                PLONG(x);
                PBYTE(xp->qid.type);
                USED(dataptr);
        }
        return FHSIZE;
}

int
dir2fattr(Unixidmap *up, Dir *dp, void *mp)
{
        uchar *dataptr = mp;
        long length;
        int r;

        r = dp->mode & 0777;
        if (dp->mode & DMDIR)
                length = 1024;
        else
                length = dp->length;
        if((dp->mode & DMDIR) && dp->type == '/' && dp->dev == 0)
                r |= 0555;
        if(dp->mode & DMDIR){
                PLONG(NFDIR);   /* type */
                r |= S_IFDIR;
                PLONG(r);       /* mode */
                PLONG(3);       /* nlink */
        }else{
                PLONG(NFREG);   /* type */
                r |= S_IFREG;
                PLONG(r);       /* mode */
                PLONG(1);       /* nlink */
        }
        r = name2id(&up->u.ids, dp->uid);
        if(r < 0){
                r = name2id(&up->u.ids, "daemon");
                if(r < 0)
                        r = 1;
        }
        PLONG(r);               /* uid */
        r = name2id(&up->g.ids, dp->gid);
        if(r < 0){
                r = name2id(&up->g.ids, "user");
                if(r < 0)
                        r = 1;
        }
        PLONG(r);               /* gid */
        PLONG(length);          /* size */
        PLONG(2048);            /* blocksize */
        PLONG(0);               /* rdev */
        r = (length+2047)/2048;
        PLONG(r);               /* blocks */
        r = (dp->type<<16) | dp->dev;
        PLONG(r);               /* fsid */
        PLONG(dp->qid.path);    /* fileid */
        PLONG(dp->atime);       /* atime */
        PLONG(0);
        PLONG(dp->mtime);       /* mtime */
        PLONG(0);
        PLONG(dp->mtime);       /* ctime */
        PLONG(0);
        return dataptr - (uchar *)mp;
}

int
convM2sattr(void *mp, Sattr *sp)
{
        uchar *argptr = mp;

        sp->mode = GLONG();
        sp->uid = GLONG();
        sp->gid = GLONG();
        sp->size = GLONG();
        sp->atime = GLONG();
        sp->ausec = GLONG();
        sp->mtime = GLONG();
        sp->musec = GLONG();
        return argptr - (uchar *)mp;
}