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