|
@@ -84,6 +84,7 @@ struct Elemlist
|
|
|
int *off;
|
|
|
int mustbedir;
|
|
|
int nerror;
|
|
|
+ int prefix;
|
|
|
};
|
|
|
|
|
|
#define SEP(c) ((c) == 0 || (c) == '/')
|
|
@@ -742,6 +743,21 @@ undomount(Chan *c, Cname *name)
|
|
|
return c;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Walk but catch errors and return nil instead.
|
|
|
+ */
|
|
|
+static Walkqid*
|
|
|
+ewalk(Chan *c, Chan *nc, char **name, int nname)
|
|
|
+{
|
|
|
+ Walkqid *wq;
|
|
|
+
|
|
|
+ if(waserror())
|
|
|
+ return nil;
|
|
|
+ wq = devtab[c->type]->walk(c, nc, name, nname);
|
|
|
+ poperror();
|
|
|
+ return wq;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Either walks all the way or not at all. No partial results in *cp.
|
|
|
* *nerror is the number of names to display in an error message.
|
|
@@ -790,10 +806,10 @@ walk(Chan **cp, char **names, int nnames, int nomount, int *nerror)
|
|
|
dotdot = 0;
|
|
|
for(i=0; i<ntry; i++){
|
|
|
if(isdotdot(names[nhave+i])){
|
|
|
- if(i==0) {
|
|
|
+ if(i==0){
|
|
|
dotdot = 1;
|
|
|
ntry = 1;
|
|
|
- } else
|
|
|
+ }else
|
|
|
ntry = i;
|
|
|
break;
|
|
|
}
|
|
@@ -805,7 +821,7 @@ walk(Chan **cp, char **names, int nnames, int nomount, int *nerror)
|
|
|
type = c->type;
|
|
|
dev = c->dev;
|
|
|
|
|
|
- if((wq = devtab[type]->walk(c, nil, names+nhave, ntry)) == nil){
|
|
|
+ if((wq = ewalk(c, nil, names+nhave, ntry)) == nil){
|
|
|
/* try a union mount, if any */
|
|
|
if(mh && !nomount){
|
|
|
/*
|
|
@@ -813,7 +829,7 @@ walk(Chan **cp, char **names, int nnames, int nomount, int *nerror)
|
|
|
*/
|
|
|
rlock(&mh->lock);
|
|
|
for(f = mh->mount->next; f; f = f->next)
|
|
|
- if((wq = devtab[f->to->type]->walk(f->to, nil, names+nhave, ntry)) != nil)
|
|
|
+ if((wq = ewalk(f->to, nil, names+nhave, ntry)) != nil)
|
|
|
break;
|
|
|
runlock(&mh->lock);
|
|
|
if(f != nil){
|
|
@@ -973,7 +989,7 @@ growparse(Elemlist *e)
|
|
|
free(e->elems);
|
|
|
e->elems = new;
|
|
|
inew = smalloc((e->nelems+Delta+1) * sizeof(int));
|
|
|
- memmove(inew, e->off, e->nelems*sizeof(int));
|
|
|
+ memmove(inew, e->off, (e->nelems+1)*sizeof(int));
|
|
|
free(e->off);
|
|
|
e->off = inew;
|
|
|
}
|
|
@@ -989,11 +1005,11 @@ growparse(Elemlist *e)
|
|
|
* rather than a directory.
|
|
|
*/
|
|
|
static void
|
|
|
-parsename(char *name, Elemlist *e)
|
|
|
+parsename(char *aname, Elemlist *e)
|
|
|
{
|
|
|
- char *slash;
|
|
|
+ char *name, *slash;
|
|
|
|
|
|
- kstrdup(&e->name, name);
|
|
|
+ kstrdup(&e->name, aname);
|
|
|
name = e->name;
|
|
|
e->nelems = 0;
|
|
|
e->elems = nil;
|
|
@@ -1001,7 +1017,8 @@ parsename(char *name, Elemlist *e)
|
|
|
e->off[0] = skipslash(name) - name;
|
|
|
for(;;){
|
|
|
name = skipslash(name);
|
|
|
- if(*name=='\0'){
|
|
|
+ if(*name == '\0'){
|
|
|
+ e->off[e->nelems] = name+strlen(name) - e->name;
|
|
|
e->mustbedir = 1;
|
|
|
break;
|
|
|
}
|
|
@@ -1017,7 +1034,15 @@ parsename(char *name, Elemlist *e)
|
|
|
*slash++ = '\0';
|
|
|
name = slash;
|
|
|
}
|
|
|
- e->off[e->nelems] = name - e->name;
|
|
|
+
|
|
|
+ if(chandebug){
|
|
|
+ int i;
|
|
|
+
|
|
|
+ print("parsename %s:", e->name);
|
|
|
+ for(i=0; i<=e->nelems; i++)
|
|
|
+ print(" %d", e->off[i]);
|
|
|
+ print("\n");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
void*
|
|
@@ -1035,12 +1060,44 @@ memrchr(void *va, int c, long n)
|
|
|
void
|
|
|
namelenerror(char *aname, int len, char *err)
|
|
|
{
|
|
|
- char *name;
|
|
|
+ char *ename, *name, *next;
|
|
|
+ int i, errlen;
|
|
|
|
|
|
- if(len < ERRMAX/3 || (name=memrchr(aname, '/', len))==nil || name==aname)
|
|
|
- snprint(up->genbuf, sizeof up->genbuf, "%.*s", len, aname);
|
|
|
- else
|
|
|
- snprint(up->genbuf, sizeof up->genbuf, "...%.*s", (int)(len-(name-aname)), name);
|
|
|
+ /*
|
|
|
+ * If the name is short enough, just use the whole thing.
|
|
|
+ */
|
|
|
+ errlen = strlen(err);
|
|
|
+ if(len < ERRMAX/3 || len+errlen < 2*ERRMAX/3)
|
|
|
+ snprint(up->genbuf, sizeof up->genbuf, "%.*s",
|
|
|
+ utfnlen(aname, len), aname);
|
|
|
+ else{
|
|
|
+ /*
|
|
|
+ * Print a suffix of the name, but try to get a little info.
|
|
|
+ */
|
|
|
+ ename = aname+len;
|
|
|
+ next = ename;
|
|
|
+ do{
|
|
|
+ name = next;
|
|
|
+ next = memrchr(aname, '/', name-aname);
|
|
|
+ if(next == nil)
|
|
|
+ next = aname;
|
|
|
+ len = ename-next;
|
|
|
+ }while(len < ERRMAX/3 || len + errlen < 2*ERRMAX/3);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If the name is ridiculously long, chop it.
|
|
|
+ */
|
|
|
+ if(name == ename){
|
|
|
+ name = ename-ERRMAX/4;
|
|
|
+ if(name <= aname)
|
|
|
+ panic("bad math in namelenerror");
|
|
|
+ /* walk out of current UTF sequence */
|
|
|
+ for(i=0; (*name&0xC0)==0x80 && i<3; i++)
|
|
|
+ name++;
|
|
|
+ }
|
|
|
+ snprint(up->genbuf, sizeof up->genbuf, "...%.*s",
|
|
|
+ utfnlen(name, ename-name), name);
|
|
|
+ }
|
|
|
snprint(up->errstr, ERRMAX, "%#q %s", up->genbuf, err);
|
|
|
nexterror();
|
|
|
}
|
|
@@ -1070,7 +1127,7 @@ nameerror(char *name, char *err)
|
|
|
Chan*
|
|
|
namec(char *aname, int amode, int omode, ulong perm)
|
|
|
{
|
|
|
- int n, t, nomount;
|
|
|
+ int len, n, t, nomount;
|
|
|
Chan *c, *cnew;
|
|
|
Cname *cname;
|
|
|
Elemlist e;
|
|
@@ -1104,7 +1161,7 @@ namec(char *aname, int amode, int omode, ulong perm)
|
|
|
nomount = 1;
|
|
|
up->genbuf[0] = '\0';
|
|
|
n = 0;
|
|
|
- while(*name!='\0' && (*name != '/' || n < 2)){
|
|
|
+ while(*name != '\0' && (*name != '/' || n < 2)){
|
|
|
if(n >= sizeof(up->genbuf)-1)
|
|
|
error(Efilename);
|
|
|
up->genbuf[n++] = *name++;
|
|
@@ -1141,6 +1198,7 @@ namec(char *aname, int amode, int omode, ulong perm)
|
|
|
}
|
|
|
|
|
|
e.aname = aname;
|
|
|
+ e.prefix = name - aname;
|
|
|
e.name = nil;
|
|
|
e.elems = nil;
|
|
|
e.off = nil;
|
|
@@ -1150,14 +1208,20 @@ namec(char *aname, int amode, int omode, ulong perm)
|
|
|
cclose(c);
|
|
|
free(e.name);
|
|
|
free(e.elems);
|
|
|
- free(e.off);
|
|
|
/*
|
|
|
* Prepare nice error, showing first e.nerror elements of name.
|
|
|
*/
|
|
|
if(e.nerror == 0)
|
|
|
nexterror();
|
|
|
strcpy(tmperrbuf, up->errstr);
|
|
|
- namelenerror(aname, (name-aname)+e.off[e.nerror], tmperrbuf);
|
|
|
+ if(e.off[e.nerror]==0)
|
|
|
+ print("nerror=%d but off=%d\n",
|
|
|
+ e.nerror, e.off[e.nerror]);
|
|
|
+ if(chandebug)
|
|
|
+ print("showing %d+%d/%d (of %d) of %s (%d %d)\n", e.prefix, e.off[e.nerror], e.nerror, e.nelems, aname, e.off[0], e.off[1]);
|
|
|
+ len = e.prefix+e.off[e.nerror];
|
|
|
+ free(e.off);
|
|
|
+ namelenerror(aname, len, tmperrbuf);
|
|
|
}
|
|
|
|
|
|
/*
|