int readonly;
int debug;
+char *root = ".";
#define dprint(...) if(debug) fprint(2, __VA_ARGS__)
#pragma varargck type "Σ" int
for(p = tab[(ulong)id % HASH]; p != nil; p = p->next)
if(p->id == id)
- return strdup(p->name);
+ return estrdup9p(p->name);
return smprint("%d", id);
}
return rxpkt[0];
}
+void
+freedir1(Dir *d)
+{
+ free(d->name);
+ free(d->uid);
+ free(d->gid);
+ free(d->muid);
+}
+
void
freedir(SFid *s)
{
int i;
- Dir *d;
- for(i = 0; i < s->ndirent; i++){
- d = &s->dirent[i];
- free(d->name);
- free(d->uid);
- free(d->gid);
- free(d->muid);
- }
+ for(i = 0; i < s->ndirent; i++)
+ freedir1(&s->dirent[i]);
free(s->dirent);
s->dirent = nil;
s->ndirent = 0;
char *
pathcat(char *p, char *c)
{
- if(strcmp(p, ".") == 0)
- return strdup(c);
- return smprint("%s/%s", p, c);
+ return cleanname(smprint("%s/%s", p, c));
}
char *
parentdir(char *p)
{
- char *q, *r;
-
- if(strcmp(p, ".") == 0) return strdup(".");
- if(strcmp(p, "/") == 0) return strdup("/");
- q = strdup(p);
- r = strrchr(q, '/');
- if(r != nil) *r = 0;
- return q;
+ return pathcat(p, "..");
}
char *
char *q;
q = strrchr(p, '/');
- if(q == nil) return strdup(p);
- return strdup(q+1);
+ if(q == nil) return estrdup9p(p);
+ return estrdup9p(q+1);
}
u64int
}
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->uid = idlookup(uidtab, uid);
d->gid = idlookup(gidtab, gid);
}else{
- d->uid = strdup("sshfs");
- d->gid = strdup("sshfs");
+ d->uid = estrdup9p("sshfs");
+ d->gid = estrdup9p("sshfs");
}
- d->muid = strdup(d->uid);
+ d->muid = estrdup9p(d->uid);
if((flags & SSH_FILEXFER_ATTR_PERMISSIONS) != 0){
rc = unpack(p, ep - p, "u", &perm); if(rc < 0) return -1; p += rc;
d->mode = perm & 0777;
- if((perm & 0040000) != 0) d->mode |= DMDIR;
+ if((perm & 0170000) == 0040000) d->mode |= DMDIR;
}
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);
e = r + MAXATTRIB;
return p - r;
}
+int
+attrfixupqid(Qid *qid)
+{
+ u32int flags;
+ uchar *p;
+
+ if(unpack(rxpkt, rxlen, "_____u", &flags) < 0) return -1;
+ p = rxpkt + 9;
+ 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;
+ 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
parsedir(SFid *sf)
{
p = rxpkt + 9;
ep = rxpkt + rxlen;
for(i = 0; i < c; i++){
- rc = unpack(p, ep - p, "ss", &fn, &fns, &ln, &lns); if(rc < 0) goto err; p += rc;
memset(d, 0, sizeof(Dir));
+ rc = unpack(p, ep - p, "ss", &fn, &fns, &ln, &lns); if(rc < 0) goto err; p += rc;
rc = attrib2dir(p, ep, d); if(rc < 0) goto err; p += rc;
if(fn[0] == '.' && (fns == 1 || fns == 2 && fn[1] == '.')){
- free(d->uid);
- free(d->gid);
- free(d->muid);
+ freedir1(d);
continue;
}
d->name = emalloc9p(fns + 1);
memcpy(d->name, fn, fns);
+ d->name[fns] = 0;
s = pathcat(sf->fn, d->name);
d->qid.path = qidcalc(s);
free(s);
wunlock(sf);
return 0;
err:
+ freedir1(d);
wunlock(sf);
return -1;
}
}
sf = emalloc9p(sizeof(SFid));
if(r->ifcall.aname != nil && *r->ifcall.aname != 0)
- sf->fn = strdup(r->ifcall.aname);
+ sf->fn = estrdup9p(r->ifcall.aname);
else
- sf->fn = strdup(".");
+ sf->fn = estrdup9p(root);
+ root = ".";
sf->qid = (Qid){qidcalc(sf->fn), 0, QTDIR};
r->ofcall.qid = sf->qid;
r->fid->qid = sf->qid;
}else if(r->req->aux == (void*)-2){
sendpkt("bus", SSH_FXP_OPENDIR, r->reqid, sf->fn, strlen(sf->fn));
}else{
- sendpkt("bus", SSH_FXP_READDIR, r->reqid, sf->hand, sf->handn);
sf->dirreads++;
+ sendpkt("bus", SSH_FXP_READDIR, r->reqid, sf->hand, sf->handn);
}
wunlock(sf);
}else{
rlock(sf);
r->req->d.name = finalelem(sf->fn);
r->req->d.qid = sf->qid;
- if(sf->handn > 0)
+ if(sf->handn > 0 && (sf->qid.type & QTDIR) == 0)
sendpkt("bus", SSH_FXP_FSTAT, r->reqid, sf->hand, sf->handn);
else
sendpkt("bus", SSH_FXP_STAT, r->reqid, sf->fn, strlen(sf->fn));
rlock(sf);
s = parentdir(sf->fn);
t = pathcat(s, r->req->d.name);
- sendpkt("buss", SSH_FXP_RENAME, r->reqid, sf->fn, strlen(sf->fn), t, strlen(t));
free(s);
r->req->aux = t;
+ sendpkt("buss", SSH_FXP_RENAME, r->reqid, sf->fn, strlen(sf->fn), t, strlen(t));
runlock(sf);
break;
}
else
sendpkt("bus[", SSH_FXP_SETSTAT, r->reqid, sf->fn, strlen(sf->fn), s, x);
runlock(sf);
+ free(s);
break;
case Tremove:
rlock(sf);
SFid *sf;
int t, id;
u32int code;
- char *msg, *lang, *hand;
+ char *msg, *lang, *hand, *s;
int msgn, langn, handn;
int okresp;
- uchar *p;
char *e;
threadsetname("recv");
}
id = GET4(rxpkt + 1);
if(id >= MAXREQID){
- fprint(2, "sshfs: received response with id out of range, %d > %d\n", id, MAXREQID);
+ fprint(2, "sshfs: received %Σ response with id out of range, %d > %d\n", t, id, MAXREQID);
continue;
}
qlock(&sreqidlock);
r = sreqrd[id];
if(r != nil){
sreqrd[id] = nil;
+ r->reqid = -1;
rwakeup(&sreqidrend);
}
qunlock(&sreqidlock);
if(r == nil){
- fprint(2, "sshfs: received response to non-existent request (req id = %d)\n", id);
+ fprint(2, "sshfs: received %Σ response to non-existent request (req id = %d)\n", t, id);
continue;
}
if(r->closefid != nil){
switch(r->req->ifcall.type){
case Tattach:
if(t != SSH_FXP_ATTRS) goto common;
- if(unpack(rxpkt, rxlen, "_____u", &code) < 0) goto garbage;
+ if(attrfixupqid(&r->req->ofcall.qid) < 0)
+ goto garbage;
r->req->aux = (void*)-1;
- if((code & 4) == 0){
- fprint(2, "sshfs: can't determine if %s is a directory\n", r->req->ifcall.aname);
- sshfsattach(r->req);
- break;
- }
- p = rxpkt + 9;
- if(code & 1) p += 8;
- if(code & 2) p += 8;
- if(p + 4 > rxpkt + rxlen) goto garbage;
- if((GET4(p) & 0040000) == 0)
+ 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;
- if(unpack(rxpkt, rxlen, "_____u", &code) < 0) goto garbage;
- if((code & 4) == 0){
- fprint(2, "sshfs: can't determine if %s is a directory\n", ((SFid*)r->req->fid)->fn);
- walkprocess(r->req, 0, nil);
- break;
- }
- p = rxpkt + 9;
- if(code & 1) p += 8;
- if(code & 2) p += 8;
- if(p + 4 > rxpkt + rxlen) goto garbage;
- walkprocess(r->req, GET4(p) & 0040000, 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;
submitreq(r->req);
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);
r->newfid->qid = r->fid->qid;
s = r->fid->aux;
t = emalloc9p(sizeof(SFid));
- t->fn = strdup(s->fn);
+ t->fn = estrdup9p(s->fn);
t->qid = s->qid;
r->newfid->aux = t;
}else
respond(r, nil);
return;
}
- p = strdup(t->fn);
+ p = estrdup9p(t->fn);
for(i = 0; i < r->ifcall.nwname; i++){
- if(strcmp(r->ifcall.wname[i], "..") == 0)
- q = parentdir(p);
- else
- q = pathcat(p, r->ifcall.wname[i]);
+ q = pathcat(p, r->ifcall.wname[i]);
free(p);
p = q;
r->ofcall.wqid[i] = (Qid){qidcalc(p), 0, QTDIR};
free(r->aux);
}
+void
+sshfsstart(Srv *)
+{
+ proccreate(sendproc, nil, mainstacksize);
+ proccreate(recvproc, nil, mainstacksize);
+}
+
void
sshfsend(Srv *)
{
}
Srv sshfssrv = {
+ .start sshfsstart,
.attach sshfsattach,
.walk sshfswalk,
.open submitreq,
.remove submitreq,
.destroyfid sshfsdestroyfid,
.destroyreq sshfsdestroyreq,
- .end sshfsend
+ .end sshfsend,
};
char *
void
passwdparse(IDEnt **tab, char *s)
{
- char *p;
- char *n;
- int id;
IDEnt *e, **b;
+ char *p, *n;
+ int id;
- p = s;
- for(;;){
+ if(s == nil)
+ return;
+ for(p = s;;){
n = p;
p = strpbrk(p, ":\n"); if(p == nil) break; if(*p != ':'){ p++; continue; }
*p = 0;
if(p == nil) break;
p++;
e = emalloc9p(sizeof(IDEnt));
- e->name = strdup(n);
+ e->name = estrdup9p(n);
e->id = id;
b = &tab[((ulong)e->id) % HASH];
e->next = *b;
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");
case 'a': mflag |= MAFTER; break;
case 'b': mflag |= MBEFORE; break;
case 'm': mtpt = EARGF(usage()); break;
+ case 'M': mtpt = nil; break;
case 'u': uidfile = EARGF(usage()); break;
case 'U': uidfile = nil; break;
case 'g': gidfile = EARGF(usage()); break;
case 'G': gidfile = nil; break;
+ case 'r': root = EARGF(usage()); break;
default: usage();
}ARGEND;
}
pipe(pfd);
rdfd = wrfd = pfd[0];
- procrfork(startssh, nil, mainstacksize, RFFDG|RFNOTEG);
+ procrfork(startssh, nil, mainstacksize, RFFDG|RFNOTEG|RFNAMEG);
close(pfd[1]);
}
passwdparse(uidtab, readfile(uidfile));
passwdparse(gidtab, readfile(gidfile));
- procrfork(sendproc, 0, mainstacksize, RFNOTEG);
- procrfork(recvproc, 0, mainstacksize, RFNOTEG);
threadpostmountsrv(&sshfssrv, svc, mtpt, MCREATE | mflag);
}