This is a kernel bug.
sysfile.c:/^read says
dir = c->qid.type&QTDIR;
if(dir && mountrockread(c, p, n, &nn)){
/* do nothing: mountrockread filled buffer */
}else{
if(dir && c->umh)
nn = unionread(c, p, n);
else
nn = devtab[c->type]->read(c, p, n, off);
}
if(dir)
nnn = mountfix(c, p, nn, n);
else
nnn = nn;
but should say (untested)
if(c->qid.type&QTDIR) {
if(mountrockread(c, p, n, &nn)) {
/* do nothing: mountrockread filled buffer */
} else if(c->umh) {
nn = unionread(c, p, n);
} else {
if(off != c->offset)
error(Edirseek);
nn = devtab[c->type]->read(c, p, n, c->devoffset);
}
nnn = mountfix(c, p, nn, n);
} else {
nn = devtab[c->type]->read(c, p, n, off);
nnn = nn;
}
I have separated out the various if(dir) tests into
one block, but more importantly the new code passes
c->devoffset to the directory read.
No one noticed before because most 9P2000 servers
assume they are being used correctly and implement
a simpler check: if offset == 0, seek to beginning,
otherwise continue where the last read left off.
Russ