|
|
1.1 root 1: /*
2: getdents -- get directory entries in a file system independent format
3: (SVR3 system call emulation)
4:
5: last edit: 06-Jul-1987 D A Gwyn
6:
7: This single source file supports several different methods of
8: getting directory entries from the operating system. Define
9: whichever one of the following describes your system:
10:
11: GETDENTS getdents() system call native, this library is unnecessary
12:
13: UFS original UNIX filesystem (14-character name limit)
14: BFS 4.2BSD (also 4.3BSD) native filesystem (long names)
15: NFS getdirentries() system call
16:
17: Also define any of the following that are pertinent:
18:
19: ATT_SPEC check user buffer address for longword alignment
20: BSD_SYSV BRL UNIX System V emulation environment on 4.nBSD
21: UNK have _getdents() system call, but kernel may not
22: support it
23:
24: If your C library has a getdents() system call interface, but you
25: can't count on all kernels on which your application binaries may
26: run to support it, change the system call interface name to
27: _getdents() and define "UNK" to enable the system-call validity
28: test in this "wrapper" around _getdents().
29:
30: If your system has a getdents() system call that is guaranteed
31: to always work, you shouldn't be using this source file at all.
32: */
33:
34: #ifndef lint /* for strings... */
35: static char *rcsid="$Header: /f/osi/dirent/RCS/getdents.c,v 7.0 89/11/23 21:30:58 mrose Rel $";
36: #endif
37:
38: #include "config.h"
39:
40: #if !defined(SVR3) && !defined(apollo) && !defined(GETDENTS)
41:
42: #include <sys/errno.h>
43: #include <sys/types.h>
44: #ifdef BSD_SYSV
45: #include "sys._dir.h" /* BSD flavor, not System V */
46: #else
47: #ifndef AIX
48: #include <sys/dir.h>
49: #else
50: #include "/usr/include/sys/dir.h"
51: #endif
52: #undef MAXNAMLEN /* avoid conflict with SVR3 */
53: /* Good thing we don't need to use the DIRSIZ() macro! */
54: #ifdef d_ino /* 4.3BSD/NFS using d_fileno */
55: #undef d_ino /* (not absolutely necessary) */
56: #else
57: #define d_fileno d_ino /* (struct direct) member */
58: #endif
59: #endif
60: #include "sys.dirent.h"
61: #include <sys/stat.h>
62:
63: #ifndef NFS
64: #ifdef BSD42
65: #define BFS
66: #else
67: #define UFS
68: #endif
69: #endif
70:
71: #ifdef UNK
72: #ifndef UFS
73: #include "***** ERROR ***** UNK applies only to UFS"
74: /* One could do something similar for getdirentries(), but I didn't bother. */
75: #endif
76: #include <signal.h>
77: #endif
78:
79: #if defined(UFS) + defined(BFS) + defined(NFS) != 1 /* sanity check */
80: #include "***** ERROR ***** exactly one of UFS, BFS, or NFS must be defined"
81: #endif
82:
83: #ifdef UFS
84: #define RecLen( dp ) (sizeof(struct direct)) /* fixed-length entries */
85: #else /* BFS || NFS */
86: #define RecLen( dp ) ((dp)->d_reclen) /* variable-length entries */
87: #endif
88:
89: #ifdef NFS
90: #ifdef BSD_SYSV
91: #define getdirentries _getdirentries /* package hides this system call */
92: #endif
93: extern int getdirentries();
94: static long dummy; /* getdirentries() needs basep */
95: #define GetBlock( fd, buf, n ) getdirentries( fd, buf, (int)n, &dummy )
96: #else /* UFS || BFS */
97: #ifdef BSD_SYSV
98: #define read _read /* avoid emulation overhead */
99: #endif
100: extern int read();
101: #define GetBlock( fd, buf, n ) read( fd, buf, (unsigned)n )
102: #endif
103:
104: #ifdef UNK
105: extern int _getdents(); /* actual system call */
106: #endif
107:
108: extern char *strncpy();
109: extern int fstat();
110: extern off_t lseek();
111:
112: extern int errno;
113:
114: #ifndef DIRBLKSIZ
115: #define DIRBLKSIZ 4096 /* directory file read buffer size */
116: #endif
117:
118: #ifndef NULL
119: #define NULL 0
120: #endif
121:
122: #ifndef SEEK_CUR
123: #define SEEK_CUR 1
124: #endif
125:
126: #ifndef S_ISDIR /* macro to test for directory file */
127: #define S_ISDIR( mode ) (((mode) & S_IFMT) == S_IFDIR)
128: #endif
129:
130: #ifdef UFS
131:
132: /*
133: The following routine is necessary to handle DIRSIZ-long entry names.
134: Thanks to Richard Todd for pointing this out.
135: */
136:
137: static int
138: NameLen( name ) /* return # chars in embedded name */
139: char name[]; /* -> name embedded in struct direct */
140: {
141: register char *s; /* -> name[.] */
142: register char *stop = &name[DIRSIZ]; /* -> past end of name field */
143:
144: for ( s = &name[1]; /* (empty names are impossible) */
145: *s != '\0' /* not NUL terminator */
146: && ++s < stop; /* < DIRSIZ characters scanned */
147: )
148: ;
149:
150: return s - name; /* # valid characters in name */
151: }
152:
153: #else /* BFS || NFS */
154:
155: extern int strlen();
156:
157: #define NameLen( name ) strlen( name ) /* names are always NUL-terminated */
158:
159: #endif
160:
161: #ifdef UNK
162: static enum { maybe, no, yes } state = maybe;
163: /* does _getdents() work? */
164:
165: /*ARGSUSED*/
166: static void
167: sig_catch( sig )
168: int sig; /* must be SIGSYS */
169: {
170: state = no; /* attempted _getdents() faulted */
171: }
172: #endif
173:
174: int
175: getdents( fildes, buf, nbyte ) /* returns # bytes read;
176: 0 on EOF, -1 on error */
177: int fildes; /* directory file descriptor */
178: char *buf; /* where to put the (struct dirent)s */
179: unsigned nbyte; /* size of buf[] */
180: {
181: int serrno; /* entry errno */
182: off_t offset; /* initial directory file offset */
183: struct stat statb; /* fstat() info */
184: union {
185: char dblk[DIRBLKSIZ];
186: /* directory file block buffer */
187: struct direct dummy; /* just for alignment */
188: } u; /* (avoids having to malloc()) */
189: register struct direct *dp; /* -> u.dblk[.] */
190: register struct dirent *bp; /* -> buf[.] */
191:
192: #ifdef UNK
193: switch ( state )
194: {
195: void (*shdlr)(); /* entry SIGSYS handler */
196: register int retval; /* return from _getdents() if any */
197:
198: case yes: /* _getdents() is known to work */
199: return _getdents( fildes, buf, nbyte );
200:
201: case maybe: /* first time only */
202: shdlr = signal( SIGSYS, sig_catch );
203: retval = _getdents( fildes, buf, nbyte ); /* try it */
204: (void)signal( SIGSYS, shdlr );
205:
206: if ( state == maybe ) /* SIGSYS did not occur */
207: {
208: state = yes; /* so _getdents() must have worked */
209: return retval;
210: }
211: /* else fall through into emulation */
212:
213: /* case no: /* fall through into emulation */
214: }
215: #endif
216:
217: if ( buf == NULL
218: #ifdef ATT_SPEC
219: || (unsigned long)buf % sizeof(long) != 0 /* ugh */
220: #endif
221: ) {
222: errno = EFAULT; /* invalid pointer */
223: return -1;
224: }
225:
226: if ( fstat( fildes, &statb ) != 0 )
227: return -1; /* errno set by fstat() */
228:
229: if ( !S_ISDIR( statb.st_mode ) )
230: {
231: errno = ENOTDIR; /* not a directory */
232: return -1;
233: }
234:
235: if ( (offset = lseek( fildes, (off_t)0, SEEK_CUR )) < 0 )
236: return -1; /* errno set by lseek() */
237:
238: #ifdef BFS /* no telling what remote hosts do */
239: if ( (unsigned long)offset % DIRBLKSIZ != 0 )
240: {
241: errno = ENOENT; /* file pointer probably misaligned */
242: return -1;
243: }
244: #endif
245:
246: serrno = errno; /* save entry errno */
247:
248: for ( bp = (struct dirent *)buf; bp == (struct dirent *)buf; )
249: { /* convert next directory block */
250: int size;
251:
252: do size = GetBlock( fildes, u.dblk, DIRBLKSIZ );
253: while ( size == -1 && errno == EINTR );
254:
255: if ( size <= 0 )
256: return size; /* EOF or error (EBADF) */
257:
258: for ( dp = (struct direct *)u.dblk;
259: (char *)dp < &u.dblk[size];
260: dp = (struct direct *)((char *)dp + RecLen( dp ))
261: ) {
262: #ifndef UFS
263: if ( dp->d_reclen <= 0 )
264: {
265: errno = EIO; /* corrupted directory */
266: return -1;
267: }
268: #endif
269:
270: if ( dp->d_fileno != 0 )
271: { /* non-empty; copy to user buffer */
272: register int reclen =
273: DIRENTSIZ( NameLen( dp->d_name ) );
274:
275: if ( (char *)bp + reclen > &buf[nbyte] )
276: {
277: errno = EINVAL;
278: return -1; /* buf too small */
279: }
280:
281: bp->d_ino = dp->d_fileno;
282: bp->d_off = offset + ((char *)dp - u.dblk);
283: bp->d_reclen = reclen;
284: (void)strncpy( bp->d_name, dp->d_name,
285: #ifdef UFS
286: DIRSIZ );
287: /* be sure d_name is NULL-terminated */
288: bp->d_name[DIRSIZ] = NULL;
289: #else
290: reclen - DIRENTBASESIZ );
291: /* adds NUL padding */
292: #endif
293:
294: bp = (struct dirent *)((char *)bp + reclen);
295: }
296: }
297:
298: #ifndef BFS /* 4.2BSD screwed up; fixed in 4.3BSD */
299: if ( (char *)dp > &u.dblk[size] )
300: {
301: errno = EIO; /* corrupted directory */
302: return -1;
303: }
304: #endif
305: }
306:
307: errno = serrno; /* restore entry errno */
308: return (char *)bp - buf; /* return # bytes read */
309: }
310:
311: #endif /* not SVR3 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.