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