static int32_t read(int ispread, int fd, void *p, int32_t n, int64_t off) { Proc *up = externup(); int32_t nn, nnn; Chan *c; p = validaddr(p, n, 1); c = fdtochan(fd, OREAD, 1, 1); if(waserror()){ cclose(c); nexterror(); } /* * The offset is passed through on directories, normally. * Sysseek complains, but pread is used by servers like exportfs, * that shouldn't need to worry about this issue. * * Notice that c->devoffset is the offset that c's dev is seeing. * The number of bytes read on this fd (c->offset) may be different * due to rewritings in mountfix. */ if(ispread){ if(off == ~0LL){ /* use and maintain channel's offset */ off = c->offset; ispread = 0; } } else off = c->offset; if(c->qid.type & QTDIR){ /* * Directory read: * rewind to the beginning of the file if necessary; * try to fill the buffer via mountrockread; * clear ispread to always maintain the Chan offset. */ if(off == 0LL){ if(!ispread){ c->offset = 0; c->devoffset = 0; } mountrewind(c); unionrewind(c); } if(!mountrockread(c, p, n, &nn)){ if(c->umh) nn = unionread(c, p, n); else{ if(off != c->offset) error(Edirseek); nn = c->dev->read(c, p, n, c->devoffset); } } nnn = mountfix(c, p, nn, n); ispread = 0; } else nnn = nn = c->dev->read(c, p, n, off); if(!ispread){ lock(&c->r.l); c->devoffset += nn; c->offset += nnn; unlock(&c->r.l); } poperror(); cclose(c); return nnn; }
static long read(ulong *arg, vlong *offp) { long n, nn, nnn; uchar *p; Chan *c; vlong off; n = arg[2]; validaddr(arg[1], n, 1); p = (void*)arg[1]; c = fdtochan(arg[0], OREAD, 1, 1); if(waserror()){ cclose(c); nexterror(); } /* * The offset is passed through on directories, normally. * Sysseek complains, but pread is used by servers like exportfs, * that shouldn't need to worry about this issue. * * Notice that c->devoffset is the offset that c's dev is seeing. * The number of bytes read on this fd (c->offset) may be different * due to rewritings in rockfix. */ if(offp == nil) /* use and maintain channel's offset */ off = c->offset; else off = *offp; if(off < 0) error(Enegoff); if(off == 0){ /* rewind to the beginning of the directory */ if(offp == nil){ c->offset = 0; c->devoffset = 0; } mountrewind(c); unionrewind(c); } 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 nnn = nn = devtab[c->type]->read(c, p, n, off); lock(c); c->devoffset += nn; c->offset += nnn; unlock(c); poperror(); cclose(c); return nnn; }