]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/cmd/sshfs.c
disk/format: implement long name support
[plan9front.git] / sys / src / cmd / sshfs.c
index c0c14c17e291fb024613fbeb70f6ef2e2057fe0a..d0c21ec74e0c6dc2e6dae93c62172ea67e4bc7c5 100644 (file)
@@ -468,7 +468,7 @@ qidcalc(char *c)
 }
 
 void
-walkprocess(Req *r, int isdir, char *e)
+walkprocess(Req *r, char *e)
 {
        char *p;
        SFid *sf;
@@ -486,8 +486,6 @@ walkprocess(Req *r, int isdir, char *e)
                submitreq(r);
        }else{
                assert(r->ofcall.nwqid > 0);
-               if(!isdir)
-                       r->ofcall.wqid[r->ofcall.nwqid - 1].type = 0;
                wlock(sf);
                free(sf->fn);
                sf->fn = r->aux;
@@ -529,6 +527,7 @@ attrib2dir(uchar *p0, uchar *ep, Dir *d)
        d->qid.type = d->mode >> 24;
        if((flags & SSH_FILEXFER_ATTR_ACMODTIME) != 0){
                rc = unpack(p, ep - p, "uu", &d->atime, &d->mtime); if(rc < 0) return -1; p += rc;
+               d->qid.vers = d->mtime;
        }
        if((flags & SSH_FILEXFER_ATTR_EXTENDED) != 0){
                rc = unpack(p, ep - p, "u", &next); if(rc < 0) return -1; p += rc;
@@ -547,7 +546,7 @@ dir2attrib(Dir *d, uchar **rp)
        uchar *r, *p, *e;
        u32int fl;
        int uid, gid;
-       
+
        werrstr("phase error");
        r = emalloc9p(MAXATTRIB);
        e = r + MAXATTRIB;
@@ -589,21 +588,27 @@ dir2attrib(Dir *d, uchar **rp)
 }
 
 int
-attribisdir(char *fn)
+attrfixupqid(Qid *qid)
 {
-       u32int code;
+       u32int flags;
        uchar *p;
-       
-       if(unpack(rxpkt, rxlen, "_____u", &code) < 0) return -1;
-       if((code & 4) == 0){
-               fprint(2, "sshfs: can't determine if %s is a directory\n", fn);
-               return 1;
-       }
+
+       if(unpack(rxpkt, rxlen, "_____u", &flags) < 0) return -1;
        p = rxpkt + 9;
-       if(code & 1) p += 8;
-       if(code & 2) p += 8;
-       if(p + 4 > rxpkt + rxlen) return -1;
-       return (GET4(p) & 0170000) == 0040000;
+       if(flags & SSH_FILEXFER_ATTR_SIZE) p += 8;
+       if(flags & SSH_FILEXFER_ATTR_UIDGID) p += 8;
+       if(flags & SSH_FILEXFER_ATTR_PERMISSIONS){
+               if(p + 4 > rxpkt + rxlen) return -1;
+               if((GET4(p) & 0170000) != 0040000) qid->type = 0;
+               else qid->type = QTDIR;
+               p += 4;
+       }
+       if(flags & SSH_FILEXFER_ATTR_ACMODTIME){
+               if(p + 8 > rxpkt + rxlen) return -1;
+               p += 4;
+               qid->vers = GET4(p);    /* mtime for qid.vers */
+       }
+       return 0;
 }
 
 int
@@ -718,21 +723,40 @@ sshfsattach(Req *r)
 {
        SFid *sf;
 
-       if(r->ifcall.aname != nil && *r->ifcall.aname != 0 && r->aux == nil){
+       if(r->aux == nil){
+               sf = emalloc9p(sizeof(SFid));
+               if(r->ifcall.aname != nil)
+                       switch(*r->ifcall.aname){
+                       case '~':
+                               switch(r->ifcall.aname[1]){
+                               case 0: sf->fn = estrdup9p("."); break;
+                               case '/': sf->fn = estrdup9p(r->ifcall.aname + 2); break;
+                               default:
+                                       free(sf);
+                                       respond(r, "invalid attach name");
+                                       return;
+                               }
+                               break;
+                       case '/':
+                               sf->fn = estrdup9p(r->ifcall.aname);
+                               break;
+                       case 0:
+                               sf->fn = estrdup9p(root);
+                               break;
+                       default:
+                               sf->fn = pathcat(root, r->ifcall.aname);
+                       }
+               else
+                       sf->fn = estrdup9p(root);
+               r->fid->aux = sf;
                submitreq(r);
-               return;
+       }else{
+               sf = r->fid->aux;
+               sf->qid = (Qid){qidcalc(sf->fn), 0, QTDIR};
+               r->ofcall.qid = sf->qid;
+               r->fid->qid = sf->qid;
+               respond(r, nil);
        }
-       sf = emalloc9p(sizeof(SFid));
-       if(r->ifcall.aname != nil && *r->ifcall.aname != 0)
-               sf->fn = estrdup9p(r->ifcall.aname);
-       else
-               sf->fn = estrdup9p(root);
-       root = ".";
-       sf->qid = (Qid){qidcalc(sf->fn), 0, QTDIR};
-       r->ofcall.qid = sf->qid;
-       r->fid->qid = sf->qid;
-       r->fid->aux = sf;
-       respond(r, nil);
 }
 
 void
@@ -779,7 +803,7 @@ sendproc(void *)
                sf = r->req->fid != nil ? r->req->fid->aux : nil;
                switch(r->req->ifcall.type){
                case Tattach:
-                       sendpkt("bus", SSH_FXP_STAT, r->reqid, r->req->ifcall.aname, strlen(r->req->ifcall.aname));
+                       sendpkt("bus", SSH_FXP_STAT, r->reqid, sf->fn, strlen(sf->fn));
                        break;
                case Twalk:
                        sendpkt("bus", SSH_FXP_STAT, r->reqid, r->req->aux, strlen(r->req->aux));
@@ -903,6 +927,7 @@ sendproc(void *)
                        else
                                sendpkt("bus[", SSH_FXP_SETSTAT, r->reqid, sf->fn, strlen(sf->fn), s, x);
                        runlock(sf);
+                       free(s);
                        break;
                case Tremove:
                        rlock(sf);
@@ -927,9 +952,9 @@ recvproc(void *)
 
        SReq *r;
        SFid *sf;
-       int t, id, rc;
+       int t, id;
        u32int code;
-       char *msg, *lang, *hand;
+       char *msg, *lang, *hand, *s;
        int msgn, langn, handn;
        int okresp;
        char *e;
@@ -978,20 +1003,20 @@ recvproc(void *)
                switch(r->req->ifcall.type){
                case Tattach:
                        if(t != SSH_FXP_ATTRS) goto common;
-                       rc = attribisdir(r->req->ifcall.aname);
-                       r->req->aux = (void*)-1;
-                       if(rc < 0)
+                       if(attrfixupqid(&r->req->ofcall.qid) < 0)
                                goto garbage;
-                       if(rc == 0)
+                       r->req->aux = (void*)-1;
+                       if((r->req->ofcall.qid.type & QTDIR) == 0)
                                respond(r->req, "not a directory");
                        else
                                sshfsattach(r->req);
                        break;
                case Twalk:
                        if(t != SSH_FXP_ATTRS) goto common;
-                       rc = attribisdir(((SFid*)r->req->fid)->fn);
-                       if(rc < 0) goto garbage;
-                       walkprocess(r->req, rc, nil);
+                       if(r->req->ofcall.nwqid <= 0
+                       || attrfixupqid(&r->req->ofcall.wqid[r->req->ofcall.nwqid - 1]) < 0)
+                               goto garbage;
+                       walkprocess(r->req, nil);
                        break;
                case Tcreate:
                        if(okresp && r->req->aux == (void*)-1){
@@ -1006,6 +1031,14 @@ recvproc(void *)
                        sf->handn = handn;
                        sf->hand = emalloc9p(sf->handn);
                        memcpy(sf->hand, hand, sf->handn);
+                       if(r->req->ifcall.type == Tcreate){
+                               s = sf->fn;
+                               sf->fn = pathcat(s, r->req->ifcall.name);
+                               free(s);
+                               sf->qid = (Qid){qidcalc(sf->fn), 0, (r->req->ifcall.perm & DMDIR) != 0 ? QTDIR : 0};
+                               r->req->ofcall.qid = sf->qid;
+                               r->req->fid->qid = sf->qid;
+                       }
                        wunlock(sf);
                        if(r->req->ifcall.type == Tread){
                                r->req->aux = nil;
@@ -1056,6 +1089,10 @@ recvproc(void *)
                        break;
                case Twstat:
                        if(!okresp) goto common;
+                       if(!r->req->d.name[0]){
+                               respond(r->req, nil);
+                               break;
+                       }
                        if(r->req->aux == nil){
                                r->req->aux = (void *) -1;
                                submitreq(r->req);
@@ -1111,7 +1148,7 @@ recvproc(void *)
                        fprint(2, "sshfs: received unexpected packet %Σ for 9p request %F\n", t, &r->req->ifcall);
                }
                if(r->req->ifcall.type == Twalk)
-                       walkprocess(r->req, 0, e);
+                       walkprocess(r->req, e);
                else
                        respond(r->req, e);
                putsreq(r);
@@ -1303,7 +1340,7 @@ void
 usage(void)
 {
        static char *common = "[-abdRUG] [-s service] [-m mtpt] [-u uidfile] [-g gidfile]";
-       fprint(2, "usage: %s %s [-- ssh-options] host\n", argv0, common);
+       fprint(2, "usage: %s %s [-- ssh-options] [user@]host\n", argv0, common);
        fprint(2, "       %s %s -c cmdline\n", argv0, common);
        fprint(2, "       %s %s -p\n", argv0, common);
        exits("usage");
@@ -1377,4 +1414,6 @@ threadmain(int argc, char **argv)
        passwdparse(gidtab, readfile(gidfile));
        
        threadpostmountsrv(&sshfssrv, svc, mtpt, MCREATE | mflag);
+
+       exits(nil);
 }