smk@axiom.UUCP (Steven M. Kramer) (03/08/84)
When a readdir() is done, if the read fails, dd_size becomes -1 and readdir() returns NULL. If a telldir() is then done, the location is off by one. That's because readdir() should reset dd_size to 0 (which is what it was BEFORE it entered the if test in readdir() ). The fix is to reset dd_size to 0, which is what it was before the read() was done. There may be other similar problems along this vein, but offhand I can't think of any. As for my past bug fix (for those of you that still have that version of the 4.2 compatibility library), I fixed one bug but put another back in. Mark Plotnick found the problem and fixed if by reading the test for dd_loc!=0 in seekdir(). The problem, according to Mark, was: In your original code, if offset is 0, then the lseek is done, but readdir isn't called at all. (the test at the top of the while loop fails). Therefore, dd_size and dd_buf still contain info pertaining to the old block. As soon as a readdir is done everything will be OK, since the new block will be read in; the problem only occurs if a seekdir is done without an intervening readdir. If the seekdir is to a spot within the current block (not at the beginning), then your test succeeds (since you're only checking offset), dd_loc is set to the (non-zero) offset, and bingo we've clobbered the only signal we have that the new block needed to be read in. Admittedly this will probably never happen; I can't even think of a use for telldir() and seekdir() other than to rewind the directory to the beginning. The fix is to change: if (offset != 0 && (curloc & ~(DIRBLKSIZ-1)) == base) { --to-- if (dirp->dd_loc != 0 && offset != 0 && (curloc & ~(DIRBLKSIZ-1)) == base) { Both the offset and dd_loc check are needed. Mark also correctly states that dirp->dd_size = 0; should be added after the dirp->dd_loc = 0; line in seekdir(). -- --steve kramer {allegra,genrad,ihnp4,utzoo,philabs,uw-beaver}!linus!axiom!smk (UUCP) linus!axiom!smk@mitre-bedford (MIL)