struct SReq {
Req *req;
SFid *closefid;
- int reqid;
SReq *next;
};
return -1;
}
+int
+allocsreqid(SReq *r)
+{
+ int i;
+
+ qlock(&sreqidlock);
+ for(;;){
+ for(i = 0; i < MAXREQID; i++)
+ if(sreqrd[i] == nil){
+ sreqrd[i] = r;
+ goto out;
+ }
+ rsleep(&sreqidrend);
+ }
+out:
+ qunlock(&sreqidlock);
+ return i;
+}
+
int
vpack(uchar *p, int n, char *fmt, va_list a)
{
uchar *p0 = p, *e = p+n;
+ SReq *sr = nil;
u32int u;
u64int v;
void *s;
for(;;){
switch(c = *fmt++){
case '\0':
+ if(sr != nil){
+ u = allocsreqid(sr);
+ PUT4(p0+1, u);
+ }
return p - p0;
case '_':
if(++p > e) goto err;
memmove(p, s, u);
p += u;
break;
+ case 'q':
+ p += 4;
+ if(p != p0+5 || p > e) goto err;
+ sr = va_arg(a, SReq*);
+ break;
case 'u':
u = va_arg(a, int);
if(p+4 > e) goto err;
s->dirpos = 0;
}
-
void
putsfid(SFid *s)
{
if(s == nil) return;
+
+ wlock(s);
+ wunlock(s);
+
free(s->fn);
free(s->hand);
freedir(s);
void
putsreq(SReq *s)
{
- if(s == nil) return;
- if(s->reqid != -1){
- qlock(&sreqidlock);
- sreqrd[s->reqid] = nil;
- rwakeup(&sreqidrend);
- qunlock(&sreqidlock);
- }
- putsfid(s->closefid);
free(s);
}
qunlock(&sreqwrlock);
}
-
void
submitreq(Req *r)
{
SReq *s;
s = emalloc9p(sizeof(SReq));
- s->reqid = -1;
s->req = r;
submitsreq(s);
}
}
void
-walkprocess(Req *r, int isdir, char *e)
+walkprocess(Req *r, char *e)
{
char *p;
SFid *sf;
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;
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;
uchar *r, *p, *e;
u32int fl;
int uid, gid;
-
+
werrstr("phase error");
- r = emalloc9p(MAXATTRIB);
+ *rp = r = emalloc9p(MAXATTRIB);
e = r + MAXATTRIB;
fl = 0;
p = r + 4;
rc = pack(p, e - p, "uu", d->atime, d->mtime); if(rc < 0) return -1; p += rc;
}
PUT4(r, fl);
- *rp = r;
return p - r;
}
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
void
sshfsread(Req *r)
{
- SFid *sf;
-
if((r->fid->qid.type & QTDIR) == 0){
submitreq(r);
return;
}
- sf = r->fid->aux;
if(r->ifcall.offset == 0){
+ SFid *sf = r->fid->aux;
wlock(sf);
freedir(sf);
if(sf->dirreads > 0){
+ wunlock(sf);
r->aux = (void*)-1;
submitreq(r);
- wunlock(sf);
return;
}
wunlock(sf);
{
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
{
SReq *r;
SFid *sf;
- int i;
int x, y;
char *s, *t;
sreqwr = r->next;
if(sreqwr == nil) sreqlast = &sreqwr;
qunlock(&sreqwrlock);
-
- qlock(&sreqidlock);
- idagain:
- for(i = 0; i < MAXREQID; i++)
- if(sreqrd[i] == nil){
- sreqrd[i] = r;
- r->reqid = i;
- break;
- }
- if(i == MAXREQID){
- rsleep(&sreqidrend);
- goto idagain;
- }
- qunlock(&sreqidlock);
- if(r->closefid != nil){
- sendpkt("bus", SSH_FXP_CLOSE, r->reqid, r->closefid->hand, r->closefid->handn);
+ sf = r->closefid;
+ if(sf != nil){
+ rlock(sf);
+ sendpkt("bqs", SSH_FXP_CLOSE, r, sf->hand, sf->handn);
+ runlock(sf);
continue;
}
if(r->req == nil)
sysfatal("nil request in queue");
- sf = r->req->fid != nil ? r->req->fid->aux : nil;
+ sf = r->req->fid->aux;
switch(r->req->ifcall.type){
case Tattach:
- sendpkt("bus", SSH_FXP_STAT, r->reqid, r->req->ifcall.aname, strlen(r->req->ifcall.aname));
+ rlock(sf);
+ sendpkt("bqs", SSH_FXP_STAT, r, sf->fn, strlen(sf->fn));
+ runlock(sf);
break;
case Twalk:
- sendpkt("bus", SSH_FXP_STAT, r->reqid, r->req->aux, strlen(r->req->aux));
+ sendpkt("bqs", SSH_FXP_STAT, r, r->req->aux, strlen(r->req->aux));
break;
case Topen:
- rlock(sf);
- if((r->req->ofcall.qid.type & QTDIR) != 0)
- sendpkt("bus", SSH_FXP_OPENDIR, r->reqid, sf->fn, strlen(sf->fn));
- else{
+ if((r->req->ofcall.qid.type & QTDIR) != 0){
+ rlock(sf);
+ sendpkt("bqs", SSH_FXP_OPENDIR, r, sf->fn, strlen(sf->fn));
+ runlock(sf);
+ }else{
x = r->req->ifcall.mode;
y = 0;
switch(x & 3){
}
if(readonly && (y & SSH_FXF_WRITE) != 0){
respond(r->req, "mounted read-only");
- runlock(sf);
putsreq(r);
break;
}
if((x & OTRUNC) != 0)
y |= SSH_FXF_TRUNC;
- sendpkt("busuu", SSH_FXP_OPEN, r->reqid, sf->fn, strlen(sf->fn), y, 0);
+ rlock(sf);
+ sendpkt("bqsuu", SSH_FXP_OPEN, r, sf->fn, strlen(sf->fn), y, 0);
+ runlock(sf);
}
- runlock(sf);
break;
case Tcreate:
rlock(sf);
runlock(sf);
if((r->req->ifcall.perm & DMDIR) != 0){
if(r->req->aux == nil){
- sendpkt("busuu", SSH_FXP_MKDIR, r->reqid, s, strlen(s),
- SSH_FILEXFER_ATTR_PERMISSIONS, r->req->ifcall.perm & 0777);
r->req->aux = (void*)-1;
+ sendpkt("bqsuu", SSH_FXP_MKDIR, r, s, strlen(s),
+ SSH_FILEXFER_ATTR_PERMISSIONS, r->req->ifcall.perm & 0777);
}else{
- sendpkt("bus", SSH_FXP_OPENDIR, r->reqid, s, strlen(s));
r->req->aux = (void*)-2;
+ sendpkt("bqs", SSH_FXP_OPENDIR, r, s, strlen(s));
}
free(s);
break;
case OWRITE: y |= SSH_FXF_WRITE; break;
case ORDWR: y |= SSH_FXF_READ | SSH_FXF_WRITE; break;
}
- sendpkt("busuuu", SSH_FXP_OPEN, r->reqid, s, strlen(s), y,
+ sendpkt("bqsuuu", SSH_FXP_OPEN, r, s, strlen(s), y,
SSH_FILEXFER_ATTR_PERMISSIONS, r->req->ifcall.perm & 0777);
free(s);
break;
if((r->req->fid->qid.type & QTDIR) != 0){
wlock(sf);
if(r->req->aux == (void*)-1){
- sendpkt("bus", SSH_FXP_CLOSE, r->reqid, sf->hand, sf->handn);
+ sendpkt("bqs", SSH_FXP_CLOSE, r, sf->hand, sf->handn);
free(sf->hand);
sf->hand = nil;
sf->handn = 0;
sf->direof = 0;
sf->dirreads = 0;
}else if(r->req->aux == (void*)-2){
- sendpkt("bus", SSH_FXP_OPENDIR, r->reqid, sf->fn, strlen(sf->fn));
+ sendpkt("bqs", SSH_FXP_OPENDIR, r, sf->fn, strlen(sf->fn));
}else{
sf->dirreads++;
- sendpkt("bus", SSH_FXP_READDIR, r->reqid, sf->hand, sf->handn);
+ sendpkt("bqs", SSH_FXP_READDIR, r, sf->hand, sf->handn);
}
wunlock(sf);
}else{
rlock(sf);
- sendpkt("busvuu", SSH_FXP_READ, r->reqid, sf->hand, sf->handn,
+ sendpkt("bqsvuu", SSH_FXP_READ, r, sf->hand, sf->handn,
r->req->ifcall.offset, r->req->ifcall.count);
runlock(sf);
}
case Twrite:
x = r->req->ifcall.count - r->req->ofcall.count;
if(x >= MAXWRITE) x = MAXWRITE;
+ r->req->ofcall.offset = x;
rlock(sf);
- sendpkt("busvs", SSH_FXP_WRITE, r->reqid, sf->hand, sf->handn,
+ sendpkt("bqsvs", SSH_FXP_WRITE, r, sf->hand, sf->handn,
r->req->ifcall.offset + r->req->ofcall.count,
r->req->ifcall.data + r->req->ofcall.count,
x);
runlock(sf);
- r->req->ofcall.offset = x;
break;
case Tstat:
rlock(sf);
r->req->d.name = finalelem(sf->fn);
r->req->d.qid = sf->qid;
if(sf->handn > 0 && (sf->qid.type & QTDIR) == 0)
- sendpkt("bus", SSH_FXP_FSTAT, r->reqid, sf->hand, sf->handn);
+ sendpkt("bqs", SSH_FXP_FSTAT, r, sf->hand, sf->handn);
else
- sendpkt("bus", SSH_FXP_STAT, r->reqid, sf->fn, strlen(sf->fn));
+ sendpkt("bqs", SSH_FXP_STAT, r, sf->fn, strlen(sf->fn));
runlock(sf);
break;
case Twstat:
- if(r->req->aux == (void *) -1){
+ if(r->req->aux == (void*)-1){
rlock(sf);
s = parentdir(sf->fn);
t = pathcat(s, r->req->d.name);
- free(s);
r->req->aux = t;
- sendpkt("buss", SSH_FXP_RENAME, r->reqid, sf->fn, strlen(sf->fn), t, strlen(t));
+ sendpkt("bqss", SSH_FXP_RENAME, r, sf->fn, strlen(sf->fn), t, strlen(t));
runlock(sf);
+ free(s);
break;
}
x = dir2attrib(&r->req->d, (uchar **) &s);
if(x < 0){
responderror(r->req);
putsreq(r);
+ free(s);
break;
}
rlock(sf);
if(sf->handn > 0)
- sendpkt("bus[", SSH_FXP_FSETSTAT, r->reqid, sf->hand, sf->handn, s, x);
+ sendpkt("bqs[", SSH_FXP_FSETSTAT, r, sf->hand, sf->handn, s, x);
else
- sendpkt("bus[", SSH_FXP_SETSTAT, r->reqid, sf->fn, strlen(sf->fn), s, x);
+ sendpkt("bqs[", SSH_FXP_SETSTAT, r, sf->fn, strlen(sf->fn), s, x);
runlock(sf);
+ free(s);
break;
case Tremove:
rlock(sf);
if((sf->qid.type & QTDIR) != 0)
- sendpkt("bus", SSH_FXP_RMDIR, r->reqid, sf->fn, strlen(sf->fn));
+ sendpkt("bqs", SSH_FXP_RMDIR, r, sf->fn, strlen(sf->fn));
else
- sendpkt("bus", SSH_FXP_REMOVE, r->reqid, sf->fn, strlen(sf->fn));
+ sendpkt("bqs", SSH_FXP_REMOVE, r, sf->fn, strlen(sf->fn));
runlock(sf);
break;
default:
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;
r = sreqrd[id];
if(r != nil){
sreqrd[id] = nil;
- r->reqid = -1;
rwakeup(&sreqidrend);
}
qunlock(&sreqidlock);
continue;
}
if(r->closefid != nil){
+ putsfid(r->closefid);
putsreq(r);
continue;
}
if(r->req == nil)
sysfatal("recvproc: r->req == nil");
- sf = r->req->fid != nil ? r->req->fid->aux : nil;
+ sf = r->req->fid->aux;
okresp = rxlen >= 9 && t == SSH_FXP_STATUS && GET4(rxpkt+5) == SSH_FX_OK;
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){
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;
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;
+ r->req->aux = (void*)-1;
submitreq(r->req);
}else{
wlock(sf);
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);
return;
if(sf->hand != nil){
sr = emalloc9p(sizeof(SReq));
- sr->reqid = -1;
sr->closefid = sf;
submitsreq(sr);
}else
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");
+ threadexits("usage");
}
void
}
pipe(pfd);
rdfd = wrfd = pfd[0];
- procrfork(startssh, nil, mainstacksize, RFFDG|RFNOTEG);
+ procrfork(startssh, nil, mainstacksize, RFFDG|RFNOTEG|RFNAMEG);
close(pfd[1]);
}
passwdparse(gidtab, readfile(gidfile));
threadpostmountsrv(&sshfssrv, svc, mtpt, MCREATE | mflag);
+
+ threadexits(nil);
}