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