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