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