|
|
1.1 ! root 1: /* ! 2: seekdir -- reposition a directory stream ! 3: ! 4: last edit: 25-Apr-1987 D A Gwyn ! 5: ! 6: An unsuccessful seekdir() will in general alter the current ! 7: directory position; beware. ! 8: ! 9: NOTE: 4.nBSD directory compaction makes seekdir() & telldir() ! 10: practically impossible to do right. Avoid using them! ! 11: */ ! 12: #ifdef COHERENT ! 13: #include <errno.h> ! 14: #else ! 15: #include <sys/errno.h> ! 16: #endif ! 17: ! 18: #include <sys/types.h> ! 19: #include "dirent.h" ! 20: ! 21: extern off_t lseek(); ! 22: ! 23: extern int errno; ! 24: ! 25: #ifndef NULL ! 26: #define NULL 0 ! 27: #endif ! 28: ! 29: #ifndef SEEK_SET ! 30: #define SEEK_SET 0 ! 31: #endif ! 32: ! 33: typedef int bool; /* Boolean data type */ ! 34: #define false 0 ! 35: #define true 1 ! 36: ! 37: void ! 38: seekdir( dirp, loc ) ! 39: register DIR *dirp; /* stream from opendir() */ ! 40: register off_t loc; /* position from telldir() */ ! 41: { ! 42: register bool rewind; /* "start over when stymied" flag */ ! 43: ! 44: if ( dirp == NULL || dirp->dd_buf == NULL ) ! 45: { ! 46: errno = EFAULT; ! 47: return; /* invalid pointer */ ! 48: } ! 49: ! 50: /* A (struct dirent)'s d_off is an invented quantity on 4.nBSD ! 51: NFS-supporting systems, so it is not safe to lseek() to it. */ ! 52: ! 53: /* Monotonicity of d_off is heavily exploited in the following. */ ! 54: ! 55: /* This algorithm is tuned for modest directory sizes. For ! 56: huge directories, it might be more efficient to read blocks ! 57: until the first d_off is too large, then back up one block, ! 58: or even to use binary search on the directory blocks. I ! 59: doubt that the extra code for that would be worthwhile. */ ! 60: ! 61: if ( dirp->dd_loc >= dirp->dd_size /* invalid index */ ! 62: || ((struct dirent *)&dirp->dd_buf[dirp->dd_loc])->d_off > loc ! 63: /* too far along in buffer */ ! 64: ) ! 65: dirp->dd_loc = 0; /* reset to beginning of buffer */ ! 66: /* else save time by starting at current dirp->dd_loc */ ! 67: ! 68: for ( rewind = true; ; ) ! 69: { ! 70: register struct dirent *dp; ! 71: ! 72: /* See whether the matching entry is in the current buffer. */ ! 73: ! 74: if ( (dirp->dd_loc < dirp->dd_size /* valid index */ ! 75: || readdir( dirp ) != NULL /* next buffer read */ ! 76: && (dirp->dd_loc = 0, true) /* beginning of buffer set */ ! 77: ) ! 78: && (dp = (struct dirent *)&dirp->dd_buf[dirp->dd_loc])->d_off ! 79: <= loc /* match possible in this buffer */ ! 80: ) { ! 81: for ( /* dp initialized above */ ; ! 82: (char *)dp < &dirp->dd_buf[dirp->dd_size]; ! 83: dp = (struct dirent *)((char *)dp + dp->d_reclen) ! 84: ) ! 85: if ( dp->d_off == loc ) ! 86: { /* found it! */ ! 87: dirp->dd_loc = ! 88: (char *)dp - dirp->dd_buf; ! 89: return; ! 90: } ! 91: ! 92: rewind = false; /* no point in backing up later */ ! 93: dirp->dd_loc = dirp->dd_size; /* set end of buffer */ ! 94: } ! 95: else /* whole buffer past matching entry */ ! 96: if ( !rewind ) ! 97: { /* no point in searching further */ ! 98: errno = EINVAL; ! 99: return; /* no entry at specified loc */ ! 100: } ! 101: else { /* rewind directory and start over */ ! 102: rewind = false; /* but only once! */ ! 103: ! 104: dirp->dd_loc = dirp->dd_size = 0; ! 105: ! 106: if ( lseek( dirp->dd_fd, (off_t)0, SEEK_SET ) ! 107: != 0 ! 108: ) ! 109: return; /* errno already set (EBADF) */ ! 110: ! 111: if ( loc == 0 ) ! 112: return; /* save time for rewinddir() */ ! 113: } ! 114: } ! 115: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.