|
|
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.