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