1*9a747e4fSDavid du Colombier /*
2*9a747e4fSDavid du Colombier opendir -- open a directory stream
3*9a747e4fSDavid du Colombier
4*9a747e4fSDavid du Colombier last edit: 16-Jun-1987 D A Gwyn
5*9a747e4fSDavid du Colombier */
6*9a747e4fSDavid du Colombier
7*9a747e4fSDavid du Colombier #include <sys/errno.h>
8*9a747e4fSDavid du Colombier #include <sys/types.h>
9*9a747e4fSDavid du Colombier #include <sys/stat.h>
10*9a747e4fSDavid du Colombier #include "paxdir.h"
11*9a747e4fSDavid du Colombier
12*9a747e4fSDavid du Colombier #ifdef BSD_SYSV
13*9a747e4fSDavid du Colombier /*
14*9a747e4fSDavid du Colombier <sys/_dir.h> -- definitions for 4.2,4.3BSD directories
15*9a747e4fSDavid du Colombier
16*9a747e4fSDavid du Colombier last edit: 25-Apr-1987 D A Gwyn
17*9a747e4fSDavid du Colombier
18*9a747e4fSDavid du Colombier A directory consists of some number of blocks of DIRBLKSIZ bytes each,
19*9a747e4fSDavid du Colombier where DIRBLKSIZ is chosen such that it can be transferred to disk in a
20*9a747e4fSDavid du Colombier single atomic operation (e.g., 512 bytes on most machines).
21*9a747e4fSDavid du Colombier
22*9a747e4fSDavid du Colombier Each DIRBLKSIZ-byte block contains some number of directory entry
23*9a747e4fSDavid du Colombier structures, which are of variable length. Each directory entry has the
24*9a747e4fSDavid du Colombier beginning of a (struct direct) at the front of it, containing its
25*9a747e4fSDavid du Colombier filesystem-unique ident number, the length of the entry, and the length
26*9a747e4fSDavid du Colombier of the name contained in the entry. These are followed by the NUL-
27*9a747e4fSDavid du Colombier terminated name padded to a (long) boundary with 0 bytes. The maximum
28*9a747e4fSDavid du Colombier length of a name in a directory is MAXNAMELEN.
29*9a747e4fSDavid du Colombier
30*9a747e4fSDavid du Colombier The macro DIRSIZ(dp) gives the amount of space required to represent a
31*9a747e4fSDavid du Colombier directory entry. Free space in a directory is represented by entries
32*9a747e4fSDavid du Colombier that have dp->d_reclen > DIRSIZ(dp). All DIRBLKSIZ bytes in a
33*9a747e4fSDavid du Colombier directory block are claimed by the directory entries; this usually
34*9a747e4fSDavid du Colombier results in the last entry in a directory having a large dp->d_reclen.
35*9a747e4fSDavid du Colombier When entries are deleted from a directory, the space is returned to the
36*9a747e4fSDavid du Colombier previous entry in the same directory block by increasing its
37*9a747e4fSDavid du Colombier dp->d_reclen. If the first entry of a directory block is free, then
38*9a747e4fSDavid du Colombier its dp->d_fileno is set to 0; entries other than the first in a
39*9a747e4fSDavid du Colombier directory do not normally have dp->d_fileno set to 0.
40*9a747e4fSDavid du Colombier
41*9a747e4fSDavid du Colombier prerequisite: <sys/types.h>
42*9a747e4fSDavid du Colombier */
43*9a747e4fSDavid du Colombier
44*9a747e4fSDavid du Colombier #if defined(accel) || defined(sun) || defined(vax)
45*9a747e4fSDavid du Colombier #define DIRBLKSIZ 512 /* size of directory block */
46*9a747e4fSDavid du Colombier #else
47*9a747e4fSDavid du Colombier #ifdef alliant
48*9a747e4fSDavid du Colombier #define DIRBLKSIZ 4096 /* size of directory block */
49*9a747e4fSDavid du Colombier #else
50*9a747e4fSDavid du Colombier #ifdef gould
51*9a747e4fSDavid du Colombier #define DIRBLKSIZ 1024 /* size of directory block */
52*9a747e4fSDavid du Colombier #else
53*9a747e4fSDavid du Colombier #ifdef ns32000 /* Dynix System V */
54*9a747e4fSDavid du Colombier #define DIRBLKSIZ 2600 /* size of directory block */
55*9a747e4fSDavid du Colombier #else /* be conservative; multiple blocks are okay
56*9a747e4fSDavid du Colombier * but fractions are not */
57*9a747e4fSDavid du Colombier #define DIRBLKSIZ 4096 /* size of directory block */
58*9a747e4fSDavid du Colombier #endif
59*9a747e4fSDavid du Colombier #endif
60*9a747e4fSDavid du Colombier #endif
61*9a747e4fSDavid du Colombier #endif
62*9a747e4fSDavid du Colombier
63*9a747e4fSDavid du Colombier #define MAXNAMELEN 255 /* maximum filename length */
64*9a747e4fSDavid du Colombier /* NOTE: not MAXNAMLEN, which has been preempted by SVR3 <dirent.h> */
65*9a747e4fSDavid du Colombier
66*9a747e4fSDavid du Colombier struct direct { /* data from read()/_getdirentries() */
67*9a747e4fSDavid du Colombier unsigned long d_fileno; /* unique ident of entry */
68*9a747e4fSDavid du Colombier unsigned short d_reclen; /* length of this record */
69*9a747e4fSDavid du Colombier unsigned short d_namlen; /* length of string in d_name */
70*9a747e4fSDavid du Colombier char d_name[MAXNAMELEN + 1]; /* NUL-terminated filename */
71*9a747e4fSDavid du Colombier };
72*9a747e4fSDavid du Colombier
73*9a747e4fSDavid du Colombier /*
74*9a747e4fSDavid du Colombier The DIRSIZ macro gives the minimum record length which will hold the
75*9a747e4fSDavid du Colombier directory entry. This requires the amount of space in a (struct
76*9a747e4fSDavid du Colombier direct) without the d_name field, plus enough space for the name with a
77*9a747e4fSDavid du Colombier terminating NUL character, rounded up to a (long) boundary.
78*9a747e4fSDavid du Colombier
79*9a747e4fSDavid du Colombier (Note that Berkeley didn't properly compensate for struct padding,
80*9a747e4fSDavid du Colombier but we nevertheless have to use the same size as the actual system.)
81*9a747e4fSDavid du Colombier */
82*9a747e4fSDavid du Colombier
83*9a747e4fSDavid du Colombier #define DIRSIZ( dp ) ((sizeof(struct direct) - (MAXNAMELEN+1) \
84*9a747e4fSDavid du Colombier + sizeof(long) + (dp)->d_namlen) \
85*9a747e4fSDavid du Colombier / sizeof(long) * sizeof(long))
86*9a747e4fSDavid du Colombier
87*9a747e4fSDavid du Colombier #else
88*9a747e4fSDavid du Colombier #include <sys/dir.h>
89*9a747e4fSDavid du Colombier #ifdef SYSV3
90*9a747e4fSDavid du Colombier #undef MAXNAMLEN /* avoid conflict with SVR3 */
91*9a747e4fSDavid du Colombier #endif
92*9a747e4fSDavid du Colombier /* Good thing we don't need to use the DIRSIZ() macro! */
93*9a747e4fSDavid du Colombier #ifdef d_ino /* 4.3BSD/NFS using d_fileno */
94*9a747e4fSDavid du Colombier #undef d_ino /* (not absolutely necessary) */
95*9a747e4fSDavid du Colombier #else
96*9a747e4fSDavid du Colombier #define d_fileno d_ino /* (struct direct) member */
97*9a747e4fSDavid du Colombier #endif
98*9a747e4fSDavid du Colombier #endif
99*9a747e4fSDavid du Colombier #ifdef UNK
100*9a747e4fSDavid du Colombier #ifndef UFS
101*9a747e4fSDavid du Colombier #include "***** ERROR ***** UNK applies only to UFS"
102*9a747e4fSDavid du Colombier /* One could do something similar for getdirentries(), but I didn't bother. */
103*9a747e4fSDavid du Colombier #endif
104*9a747e4fSDavid du Colombier #include <signal.h>
105*9a747e4fSDavid du Colombier #endif
106*9a747e4fSDavid du Colombier
107*9a747e4fSDavid du Colombier #if defined(UFS) + defined(BFS) + defined(NFS) != 1 /* sanity check */
108*9a747e4fSDavid du Colombier #include "***** ERROR ***** exactly one of UFS, BFS, or NFS must be defined"
109*9a747e4fSDavid du Colombier #endif
110*9a747e4fSDavid du Colombier
111*9a747e4fSDavid du Colombier #ifdef UFS
112*9a747e4fSDavid du Colombier #define RecLen( dp ) (sizeof(struct direct)) /* fixed-length entries */
113*9a747e4fSDavid du Colombier #else /* BFS || NFS */
114*9a747e4fSDavid du Colombier #define RecLen( dp ) ((dp)->d_reclen) /* variable-length entries */
115*9a747e4fSDavid du Colombier #endif
116*9a747e4fSDavid du Colombier
117*9a747e4fSDavid du Colombier #ifdef NFS
118*9a747e4fSDavid du Colombier #ifdef BSD_SYSV
119*9a747e4fSDavid du Colombier #define getdirentries _getdirentries /* package hides this system call */
120*9a747e4fSDavid du Colombier #endif
121*9a747e4fSDavid du Colombier extern int getdirentries();
122*9a747e4fSDavid du Colombier static long dummy; /* getdirentries() needs basep */
123*9a747e4fSDavid du Colombier #define GetBlock( fd, buf, n ) getdirentries( fd, buf, (unsigned)n, &dummy )
124*9a747e4fSDavid du Colombier #else /* UFS || BFS */
125*9a747e4fSDavid du Colombier #ifdef BSD_SYSV
126*9a747e4fSDavid du Colombier #define read _read /* avoid emulation overhead */
127*9a747e4fSDavid du Colombier #endif
128*9a747e4fSDavid du Colombier extern int read();
129*9a747e4fSDavid du Colombier #define GetBlock( fd, buf, n ) read( fd, buf, (unsigned)n )
130*9a747e4fSDavid du Colombier #endif
131*9a747e4fSDavid du Colombier
132*9a747e4fSDavid du Colombier #ifdef UNK
133*9a747e4fSDavid du Colombier extern int _getdents(); /* actual system call */
134*9a747e4fSDavid du Colombier #endif
135*9a747e4fSDavid du Colombier
136*9a747e4fSDavid du Colombier extern char *strncpy();
137*9a747e4fSDavid du Colombier extern int fstat();
138*9a747e4fSDavid du Colombier extern OFFSET lseek();
139*9a747e4fSDavid du Colombier
140*9a747e4fSDavid du Colombier extern int errno;
141*9a747e4fSDavid du Colombier
142*9a747e4fSDavid du Colombier #ifndef DIRBLKSIZ
143*9a747e4fSDavid du Colombier #define DIRBLKSIZ 4096 /* directory file read buffer size */
144*9a747e4fSDavid du Colombier #endif
145*9a747e4fSDavid du Colombier
146*9a747e4fSDavid du Colombier #ifndef NULL
147*9a747e4fSDavid du Colombier #define NULL 0
148*9a747e4fSDavid du Colombier #endif
149*9a747e4fSDavid du Colombier
150*9a747e4fSDavid du Colombier #ifndef SEEK_CUR
151*9a747e4fSDavid du Colombier #define SEEK_CUR 1
152*9a747e4fSDavid du Colombier #endif
153*9a747e4fSDavid du Colombier
154*9a747e4fSDavid du Colombier #ifndef S_ISDIR /* macro to test for directory file */
155*9a747e4fSDavid du Colombier #define S_ISDIR( mode ) (((mode) & S_IFMT) == S_IFDIR)
156*9a747e4fSDavid du Colombier #endif
157*9a747e4fSDavid du Colombier
158*9a747e4fSDavid du Colombier
159*9a747e4fSDavid du Colombier #ifndef SEEK_CUR
160*9a747e4fSDavid du Colombier #define SEEK_CUR 1
161*9a747e4fSDavid du Colombier #endif
162*9a747e4fSDavid du Colombier
163*9a747e4fSDavid du Colombier #ifdef BSD_SYSV
164*9a747e4fSDavid du Colombier #define open _open /* avoid emulation overhead */
165*9a747e4fSDavid du Colombier #endif
166*9a747e4fSDavid du Colombier
167*9a747e4fSDavid du Colombier extern int getdents(); /* SVR3 system call, or emulation */
168*9a747e4fSDavid du Colombier
169*9a747e4fSDavid du Colombier typedef char *pointer; /* (void *) if you have it */
170*9a747e4fSDavid du Colombier
171*9a747e4fSDavid du Colombier extern void free();
172*9a747e4fSDavid du Colombier extern pointer malloc();
173*9a747e4fSDavid du Colombier extern int
174*9a747e4fSDavid du Colombier open(), close(), fstat();
175*9a747e4fSDavid du Colombier
176*9a747e4fSDavid du Colombier extern int errno;
177*9a747e4fSDavid du Colombier extern OFFSET lseek();
178*9a747e4fSDavid du Colombier
179*9a747e4fSDavid du Colombier #ifndef SEEK_SET
180*9a747e4fSDavid du Colombier #define SEEK_SET 0
181*9a747e4fSDavid du Colombier #endif
182*9a747e4fSDavid du Colombier
183*9a747e4fSDavid du Colombier typedef int bool; /* Boolean data type */
184*9a747e4fSDavid du Colombier #define false 0
185*9a747e4fSDavid du Colombier #define true 1
186*9a747e4fSDavid du Colombier
187*9a747e4fSDavid du Colombier
188*9a747e4fSDavid du Colombier #ifndef NULL
189*9a747e4fSDavid du Colombier #define NULL 0
190*9a747e4fSDavid du Colombier #endif
191*9a747e4fSDavid du Colombier
192*9a747e4fSDavid du Colombier #ifndef O_RDONLY
193*9a747e4fSDavid du Colombier #define O_RDONLY 0
194*9a747e4fSDavid du Colombier #endif
195*9a747e4fSDavid du Colombier
196*9a747e4fSDavid du Colombier #ifndef S_ISDIR /* macro to test for directory file */
197*9a747e4fSDavid du Colombier #define S_ISDIR( mode ) (((mode) & S_IFMT) == S_IFDIR)
198*9a747e4fSDavid du Colombier #endif
199*9a747e4fSDavid du Colombier
200*9a747e4fSDavid du Colombier #ifdef __STDC__
201*9a747e4fSDavid du Colombier
opendir(char * dirname)202*9a747e4fSDavid du Colombier DIR *opendir(char *dirname)
203*9a747e4fSDavid du Colombier
204*9a747e4fSDavid du Colombier #else
205*9a747e4fSDavid du Colombier
206*9a747e4fSDavid du Colombier DIR *opendir(dirname)
207*9a747e4fSDavid du Colombier char *dirname; /* name of directory */
208*9a747e4fSDavid du Colombier
209*9a747e4fSDavid du Colombier #endif
210*9a747e4fSDavid du Colombier {
211*9a747e4fSDavid du Colombier register DIR *dirp; /* -> malloc'ed storage */
212*9a747e4fSDavid du Colombier register int fd; /* file descriptor for read */
213*9a747e4fSDavid du Colombier struct stat sbuf; /* result of fstat() */
214*9a747e4fSDavid du Colombier
215*9a747e4fSDavid du Colombier if ((fd = open(dirname, O_RDONLY)) < 0)
216*9a747e4fSDavid du Colombier return ((DIR *)NULL); /* errno set by open() */
217*9a747e4fSDavid du Colombier
218*9a747e4fSDavid du Colombier if (fstat(fd, &sbuf) != 0 || !S_ISDIR(sbuf.st_mode)) {
219*9a747e4fSDavid du Colombier close(fd);
220*9a747e4fSDavid du Colombier errno = ENOTDIR;
221*9a747e4fSDavid du Colombier return ((DIR *)NULL); /* not a directory */
222*9a747e4fSDavid du Colombier }
223*9a747e4fSDavid du Colombier if ((dirp = (DIR *) malloc(sizeof(DIR))) == (DIR *)NULL
224*9a747e4fSDavid du Colombier || (dirp->dd_buf = (char *) malloc((unsigned) DIRBUF)) == (char *)NULL
225*9a747e4fSDavid du Colombier ) {
226*9a747e4fSDavid du Colombier register int serrno = errno;
227*9a747e4fSDavid du Colombier /* errno set to ENOMEM by sbrk() */
228*9a747e4fSDavid du Colombier
229*9a747e4fSDavid du Colombier if (dirp != (DIR *)NULL)
230*9a747e4fSDavid du Colombier free((pointer) dirp);
231*9a747e4fSDavid du Colombier
232*9a747e4fSDavid du Colombier close(fd);
233*9a747e4fSDavid du Colombier errno = serrno;
234*9a747e4fSDavid du Colombier return ((DIR *)NULL); /* not enough memory */
235*9a747e4fSDavid du Colombier }
236*9a747e4fSDavid du Colombier dirp->dd_fd = fd;
237*9a747e4fSDavid du Colombier dirp->dd_loc = dirp->dd_size = 0; /* refill needed */
238*9a747e4fSDavid du Colombier
239*9a747e4fSDavid du Colombier return dirp;
240*9a747e4fSDavid du Colombier }
241*9a747e4fSDavid du Colombier
242*9a747e4fSDavid du Colombier
243*9a747e4fSDavid du Colombier /*
244*9a747e4fSDavid du Colombier * closedir -- close a directory stream
245*9a747e4fSDavid du Colombier *
246*9a747e4fSDavid du Colombier * last edit: 11-Nov-1988 D A Gwyn
247*9a747e4fSDavid du Colombier */
248*9a747e4fSDavid du Colombier
249*9a747e4fSDavid du Colombier #ifdef __STDC__
250*9a747e4fSDavid du Colombier
closedir(register DIR * dirp)251*9a747e4fSDavid du Colombier int closedir(register DIR *dirp)
252*9a747e4fSDavid du Colombier
253*9a747e4fSDavid du Colombier #else
254*9a747e4fSDavid du Colombier
255*9a747e4fSDavid du Colombier int closedir(dirp)
256*9a747e4fSDavid du Colombier register DIR *dirp; /* stream from opendir() */
257*9a747e4fSDavid du Colombier
258*9a747e4fSDavid du Colombier #endif
259*9a747e4fSDavid du Colombier {
260*9a747e4fSDavid du Colombier register int fd;
261*9a747e4fSDavid du Colombier
262*9a747e4fSDavid du Colombier if ( dirp == (DIR *)NULL || dirp->dd_buf == (char *)NULL ) {
263*9a747e4fSDavid du Colombier errno = EFAULT;
264*9a747e4fSDavid du Colombier return -1; /* invalid pointer */
265*9a747e4fSDavid du Colombier }
266*9a747e4fSDavid du Colombier
267*9a747e4fSDavid du Colombier fd = dirp->dd_fd; /* bug fix thanks to R. Salz */
268*9a747e4fSDavid du Colombier free( (pointer)dirp->dd_buf );
269*9a747e4fSDavid du Colombier free( (pointer)dirp );
270*9a747e4fSDavid du Colombier return close( fd );
271*9a747e4fSDavid du Colombier }
272*9a747e4fSDavid du Colombier
273*9a747e4fSDavid du Colombier
274*9a747e4fSDavid du Colombier /*
275*9a747e4fSDavid du Colombier readdir -- read next entry from a directory stream
276*9a747e4fSDavid du Colombier
277*9a747e4fSDavid du Colombier last edit: 25-Apr-1987 D A Gwyn
278*9a747e4fSDavid du Colombier */
279*9a747e4fSDavid du Colombier
280*9a747e4fSDavid du Colombier #ifdef __STDC__
281*9a747e4fSDavid du Colombier
readdir(register DIR * dirp)282*9a747e4fSDavid du Colombier struct dirent *readdir(register DIR *dirp)
283*9a747e4fSDavid du Colombier
284*9a747e4fSDavid du Colombier #else
285*9a747e4fSDavid du Colombier
286*9a747e4fSDavid du Colombier struct dirent *readdir(dirp)
287*9a747e4fSDavid du Colombier register DIR *dirp; /* stream from opendir() */
288*9a747e4fSDavid du Colombier
289*9a747e4fSDavid du Colombier #endif
290*9a747e4fSDavid du Colombier {
291*9a747e4fSDavid du Colombier register struct dirent *dp; /* -> directory data */
292*9a747e4fSDavid du Colombier
293*9a747e4fSDavid du Colombier if (dirp == (DIR *)NULL || dirp->dd_buf == (char *)NULL) {
294*9a747e4fSDavid du Colombier errno = EFAULT;
295*9a747e4fSDavid du Colombier return (struct dirent *)NULL; /* invalid pointer */
296*9a747e4fSDavid du Colombier }
297*9a747e4fSDavid du Colombier do {
298*9a747e4fSDavid du Colombier if (dirp->dd_loc >= dirp->dd_size) /* empty or obsolete */
299*9a747e4fSDavid du Colombier dirp->dd_loc = dirp->dd_size = 0;
300*9a747e4fSDavid du Colombier
301*9a747e4fSDavid du Colombier if (dirp->dd_size == 0 /* need to refill buffer */
302*9a747e4fSDavid du Colombier && (dirp->dd_size =
303*9a747e4fSDavid du Colombier getdents(dirp->dd_fd, dirp->dd_buf, (unsigned) DIRBUF)
304*9a747e4fSDavid du Colombier ) <= 0
305*9a747e4fSDavid du Colombier )
306*9a747e4fSDavid du Colombier return ((struct dirent *)NULL); /* EOF or error */
307*9a747e4fSDavid du Colombier
308*9a747e4fSDavid du Colombier dp = (struct dirent *) & dirp->dd_buf[dirp->dd_loc];
309*9a747e4fSDavid du Colombier dirp->dd_loc += dp->d_reclen;
310*9a747e4fSDavid du Colombier }
311*9a747e4fSDavid du Colombier while (dp->d_ino == 0L); /* don't rely on getdents() */
312*9a747e4fSDavid du Colombier
313*9a747e4fSDavid du Colombier return dp;
314*9a747e4fSDavid du Colombier }
315*9a747e4fSDavid du Colombier
316*9a747e4fSDavid du Colombier
317*9a747e4fSDavid du Colombier /*
318*9a747e4fSDavid du Colombier seekdir -- reposition a directory stream
319*9a747e4fSDavid du Colombier
320*9a747e4fSDavid du Colombier last edit: 24-May-1987 D A Gwyn
321*9a747e4fSDavid du Colombier
322*9a747e4fSDavid du Colombier An unsuccessful seekdir() will in general alter the current
323*9a747e4fSDavid du Colombier directory position; beware.
324*9a747e4fSDavid du Colombier
325*9a747e4fSDavid du Colombier NOTE: 4.nBSD directory compaction makes seekdir() & telldir()
326*9a747e4fSDavid du Colombier practically impossible to do right. Avoid using them!
327*9a747e4fSDavid du Colombier */
328*9a747e4fSDavid du Colombier
329*9a747e4fSDavid du Colombier #ifdef __STDC__
330*9a747e4fSDavid du Colombier
seekdir(register DIR * dirp,register OFFSET loc)331*9a747e4fSDavid du Colombier void seekdir(register DIR *dirp, register OFFSET loc)
332*9a747e4fSDavid du Colombier
333*9a747e4fSDavid du Colombier #else
334*9a747e4fSDavid du Colombier
335*9a747e4fSDavid du Colombier void seekdir(dirp, loc)
336*9a747e4fSDavid du Colombier register DIR *dirp; /* stream from opendir() */
337*9a747e4fSDavid du Colombier register OFFSET loc; /* position from telldir() */
338*9a747e4fSDavid du Colombier
339*9a747e4fSDavid du Colombier #endif
340*9a747e4fSDavid du Colombier {
341*9a747e4fSDavid du Colombier register bool rewind; /* "start over when stymied" flag */
342*9a747e4fSDavid du Colombier
343*9a747e4fSDavid du Colombier if (dirp == (DIR *)NULL || dirp->dd_buf == (char *)NULL) {
344*9a747e4fSDavid du Colombier errno = EFAULT;
345*9a747e4fSDavid du Colombier return; /* invalid pointer */
346*9a747e4fSDavid du Colombier }
347*9a747e4fSDavid du Colombier /*
348*9a747e4fSDavid du Colombier * A (struct dirent)'s d_off is an invented quantity on 4.nBSD
349*9a747e4fSDavid du Colombier * NFS-supporting systems, so it is not safe to lseek() to it.
350*9a747e4fSDavid du Colombier */
351*9a747e4fSDavid du Colombier
352*9a747e4fSDavid du Colombier /* Monotonicity of d_off is heavily exploited in the following. */
353*9a747e4fSDavid du Colombier
354*9a747e4fSDavid du Colombier /*
355*9a747e4fSDavid du Colombier * This algorithm is tuned for modest directory sizes. For huge
356*9a747e4fSDavid du Colombier * directories, it might be more efficient to read blocks until the first
357*9a747e4fSDavid du Colombier * d_off is too large, then back up one block, or even to use binary
358*9a747e4fSDavid du Colombier * search on the directory blocks. I doubt that the extra code for that
359*9a747e4fSDavid du Colombier * would be worthwhile.
360*9a747e4fSDavid du Colombier */
361*9a747e4fSDavid du Colombier
362*9a747e4fSDavid du Colombier if (dirp->dd_loc >= dirp->dd_size /* invalid index */
363*9a747e4fSDavid du Colombier || ((struct dirent *) & dirp->dd_buf[dirp->dd_loc])->d_off > loc
364*9a747e4fSDavid du Colombier /* too far along in buffer */
365*9a747e4fSDavid du Colombier )
366*9a747e4fSDavid du Colombier dirp->dd_loc = 0; /* reset to beginning of buffer */
367*9a747e4fSDavid du Colombier /* else save time by starting at current dirp->dd_loc */
368*9a747e4fSDavid du Colombier
369*9a747e4fSDavid du Colombier for (rewind = true;;) {
370*9a747e4fSDavid du Colombier register struct dirent *dp;
371*9a747e4fSDavid du Colombier
372*9a747e4fSDavid du Colombier /* See whether the matching entry is in the current buffer. */
373*9a747e4fSDavid du Colombier
374*9a747e4fSDavid du Colombier if ((dirp->dd_loc < dirp->dd_size /* valid index */
375*9a747e4fSDavid du Colombier || readdir(dirp) != (struct dirent *)NULL /* next buffer read */
376*9a747e4fSDavid du Colombier && (dirp->dd_loc = 0, true) /* beginning of buffer set */
377*9a747e4fSDavid du Colombier )
378*9a747e4fSDavid du Colombier && (dp = (struct dirent *) & dirp->dd_buf[dirp->dd_loc])->d_off
379*9a747e4fSDavid du Colombier <= loc /* match possible in this buffer */
380*9a747e4fSDavid du Colombier ) {
381*9a747e4fSDavid du Colombier for ( /* dp initialized above */ ;
382*9a747e4fSDavid du Colombier (char *) dp < &dirp->dd_buf[dirp->dd_size];
383*9a747e4fSDavid du Colombier dp = (struct dirent *) ((char *) dp + dp->d_reclen)
384*9a747e4fSDavid du Colombier )
385*9a747e4fSDavid du Colombier if (dp->d_off == loc) { /* found it! */
386*9a747e4fSDavid du Colombier dirp->dd_loc =
387*9a747e4fSDavid du Colombier (char *) dp - dirp->dd_buf;
388*9a747e4fSDavid du Colombier return;
389*9a747e4fSDavid du Colombier }
390*9a747e4fSDavid du Colombier rewind = false; /* no point in backing up later */
391*9a747e4fSDavid du Colombier dirp->dd_loc = dirp->dd_size; /* set end of buffer */
392*9a747e4fSDavid du Colombier } else
393*9a747e4fSDavid du Colombier /* whole buffer past matching entry */ if (!rewind) { /* no point in searching
394*9a747e4fSDavid du Colombier * further */
395*9a747e4fSDavid du Colombier errno = EINVAL;
396*9a747e4fSDavid du Colombier return; /* no entry at specified loc */
397*9a747e4fSDavid du Colombier } else { /* rewind directory and start over */
398*9a747e4fSDavid du Colombier rewind = false; /* but only once! */
399*9a747e4fSDavid du Colombier
400*9a747e4fSDavid du Colombier dirp->dd_loc = dirp->dd_size = 0;
401*9a747e4fSDavid du Colombier
402*9a747e4fSDavid du Colombier if (lseek(dirp->dd_fd, (OFFSET) 0, SEEK_SET)
403*9a747e4fSDavid du Colombier != 0
404*9a747e4fSDavid du Colombier )
405*9a747e4fSDavid du Colombier return; /* errno already set (EBADF) */
406*9a747e4fSDavid du Colombier
407*9a747e4fSDavid du Colombier if (loc == 0)
408*9a747e4fSDavid du Colombier return; /* save time */
409*9a747e4fSDavid du Colombier }
410*9a747e4fSDavid du Colombier }
411*9a747e4fSDavid du Colombier }
412*9a747e4fSDavid du Colombier
413*9a747e4fSDavid du Colombier
414*9a747e4fSDavid du Colombier /* telldir - report directory stream position
415*9a747e4fSDavid du Colombier *
416*9a747e4fSDavid du Colombier * DESCRIPTION
417*9a747e4fSDavid du Colombier *
418*9a747e4fSDavid du Colombier * Returns the offset of the next directory entry in the
419*9a747e4fSDavid du Colombier * directory associated with dirp.
420*9a747e4fSDavid du Colombier *
421*9a747e4fSDavid du Colombier * NOTE: 4.nBSD directory compaction makes seekdir() & telldir()
422*9a747e4fSDavid du Colombier * practically impossible to do right. Avoid using them!
423*9a747e4fSDavid du Colombier *
424*9a747e4fSDavid du Colombier * PARAMETERS
425*9a747e4fSDavid du Colombier *
426*9a747e4fSDavid du Colombier * DIR *dirp - stream from opendir()
427*9a747e4fSDavid du Colombier *
428*9a747e4fSDavid du Colombier * RETURNS
429*9a747e4fSDavid du Colombier *
430*9a747e4fSDavid du Colombier * Return offset of next entry
431*9a747e4fSDavid du Colombier */
432*9a747e4fSDavid du Colombier
433*9a747e4fSDavid du Colombier
434*9a747e4fSDavid du Colombier #ifdef __STDC__
435*9a747e4fSDavid du Colombier
telldir(DIR * dirp)436*9a747e4fSDavid du Colombier OFFSET telldir(DIR *dirp)
437*9a747e4fSDavid du Colombier
438*9a747e4fSDavid du Colombier #else
439*9a747e4fSDavid du Colombier
440*9a747e4fSDavid du Colombier OFFSET telldir(dirp)
441*9a747e4fSDavid du Colombier DIR *dirp; /* stream from opendir() */
442*9a747e4fSDavid du Colombier
443*9a747e4fSDavid du Colombier #endif
444*9a747e4fSDavid du Colombier {
445*9a747e4fSDavid du Colombier if (dirp == (DIR *)NULL || dirp->dd_buf == (char *)NULL) {
446*9a747e4fSDavid du Colombier errno = EFAULT;
447*9a747e4fSDavid du Colombier return -1; /* invalid pointer */
448*9a747e4fSDavid du Colombier }
449*9a747e4fSDavid du Colombier if (dirp->dd_loc < dirp->dd_size) /* valid index */
450*9a747e4fSDavid du Colombier return ((struct dirent *) & dirp->dd_buf[dirp->dd_loc])->d_off;
451*9a747e4fSDavid du Colombier else /* beginning of next directory block */
452*9a747e4fSDavid du Colombier return lseek(dirp->dd_fd, (OFFSET) 0, SEEK_CUR);
453*9a747e4fSDavid du Colombier }
454*9a747e4fSDavid du Colombier
455*9a747e4fSDavid du Colombier
456*9a747e4fSDavid du Colombier #ifdef UFS
457*9a747e4fSDavid du Colombier
458*9a747e4fSDavid du Colombier /*
459*9a747e4fSDavid du Colombier The following routine is necessary to handle DIRSIZ-long entry names.
460*9a747e4fSDavid du Colombier Thanks to Richard Todd for pointing this out.
461*9a747e4fSDavid du Colombier */
462*9a747e4fSDavid du Colombier
463*9a747e4fSDavid du Colombier
464*9a747e4fSDavid du Colombier /* return # chars in embedded name */
465*9a747e4fSDavid du Colombier
466*9a747e4fSDavid du Colombier #ifdef __STDC__
467*9a747e4fSDavid du Colombier
NameLen(char * name)468*9a747e4fSDavid du Colombier static int NameLen(char *name)
469*9a747e4fSDavid du Colombier
470*9a747e4fSDavid du Colombier #else
471*9a747e4fSDavid du Colombier
472*9a747e4fSDavid du Colombier static int NameLen(name)
473*9a747e4fSDavid du Colombier char *name; /* -> name embedded in struct direct */
474*9a747e4fSDavid du Colombier
475*9a747e4fSDavid du Colombier #endif
476*9a747e4fSDavid du Colombier {
477*9a747e4fSDavid du Colombier register char *s; /* -> name[.] */
478*9a747e4fSDavid du Colombier register char *stop = &name[DIRSIZ]; /* -> past end of name field */
479*9a747e4fSDavid du Colombier
480*9a747e4fSDavid du Colombier for (s = &name[1]; /* (empty names are impossible) */
481*9a747e4fSDavid du Colombier *s != '\0' /* not NUL terminator */
482*9a747e4fSDavid du Colombier && ++s < stop; /* < DIRSIZ characters scanned */
483*9a747e4fSDavid du Colombier );
484*9a747e4fSDavid du Colombier
485*9a747e4fSDavid du Colombier return s - name; /* # valid characters in name */
486*9a747e4fSDavid du Colombier }
487*9a747e4fSDavid du Colombier
488*9a747e4fSDavid du Colombier #else /* BFS || NFS */
489*9a747e4fSDavid du Colombier
490*9a747e4fSDavid du Colombier extern int strlen();
491*9a747e4fSDavid du Colombier
492*9a747e4fSDavid du Colombier #define NameLen( name ) strlen( name ) /* names are always NUL-terminated */
493*9a747e4fSDavid du Colombier
494*9a747e4fSDavid du Colombier #endif
495*9a747e4fSDavid du Colombier
496*9a747e4fSDavid du Colombier #ifdef UNK
497*9a747e4fSDavid du Colombier static enum {
498*9a747e4fSDavid du Colombier maybe, no, yes
499*9a747e4fSDavid du Colombier } state = maybe;
500*9a747e4fSDavid du Colombier
501*9a747e4fSDavid du Colombier
502*9a747e4fSDavid du Colombier /* sig_catch - used to catch signals
503*9a747e4fSDavid du Colombier *
504*9a747e4fSDavid du Colombier * DESCRIPTION
505*9a747e4fSDavid du Colombier *
506*9a747e4fSDavid du Colombier * Used to catch signals.
507*9a747e4fSDavid du Colombier */
508*9a747e4fSDavid du Colombier
509*9a747e4fSDavid du Colombier /*ARGSUSED*/
510*9a747e4fSDavid du Colombier
511*9a747e4fSDavid du Colombier #ifdef __STDC__
512*9a747e4fSDavid du Colombier
sig_catch(int sig)513*9a747e4fSDavid du Colombier static void sig_catch(int sig)
514*9a747e4fSDavid du Colombier
515*9a747e4fSDavid du Colombier #else
516*9a747e4fSDavid du Colombier
517*9a747e4fSDavid du Colombier static void sig_catch(sig)
518*9a747e4fSDavid du Colombier int sig; /* must be SIGSYS */
519*9a747e4fSDavid du Colombier
520*9a747e4fSDavid du Colombier #endif
521*9a747e4fSDavid du Colombier {
522*9a747e4fSDavid du Colombier state = no; /* attempted _getdents() faulted */
523*9a747e4fSDavid du Colombier }
524*9a747e4fSDavid du Colombier #endif
525*9a747e4fSDavid du Colombier
526*9a747e4fSDavid du Colombier
527*9a747e4fSDavid du Colombier /* getdents - get directory entries
528*9a747e4fSDavid du Colombier *
529*9a747e4fSDavid du Colombier * DESCRIPTION
530*9a747e4fSDavid du Colombier *
531*9a747e4fSDavid du Colombier * Gets directory entries from the filesystem in an implemenation
532*9a747e4fSDavid du Colombier * defined way.
533*9a747e4fSDavid du Colombier *
534*9a747e4fSDavid du Colombier * PARAMETERS
535*9a747e4fSDavid du Colombier *
536*9a747e4fSDavid du Colombier * int fildes - directory file descriptor
537*9a747e4fSDavid du Colombier * char *buf - where to put the (struct dirent)s
538*9a747e4fSDavid du Colombier * unsigned nbyte - size of buf[]
539*9a747e4fSDavid du Colombier *
540*9a747e4fSDavid du Colombier * RETURNS
541*9a747e4fSDavid du Colombier *
542*9a747e4fSDavid du Colombier * Returns number of bytes read; 0 on EOF, -1 on error
543*9a747e4fSDavid du Colombier */
544*9a747e4fSDavid du Colombier
545*9a747e4fSDavid du Colombier #ifdef __STDC__
546*9a747e4fSDavid du Colombier
getdents(int fildes,char * buf,unsigned nbyte)547*9a747e4fSDavid du Colombier int getdents(int fildes, char *buf, unsigned nbyte)
548*9a747e4fSDavid du Colombier
549*9a747e4fSDavid du Colombier #else
550*9a747e4fSDavid du Colombier
551*9a747e4fSDavid du Colombier int getdents(fildes, buf, nbyte)
552*9a747e4fSDavid du Colombier int fildes; /* directory file descriptor */
553*9a747e4fSDavid du Colombier char *buf; /* where to put the (struct dirent)s */
554*9a747e4fSDavid du Colombier unsigned nbyte; /* size of buf[] */
555*9a747e4fSDavid du Colombier
556*9a747e4fSDavid du Colombier #endif
557*9a747e4fSDavid du Colombier {
558*9a747e4fSDavid du Colombier int serrno; /* entry errno */
559*9a747e4fSDavid du Colombier OFFSET offset; /* initial directory file offset */
560*9a747e4fSDavid du Colombier struct stat statb; /* fstat() info */
561*9a747e4fSDavid du Colombier union {
562*9a747e4fSDavid du Colombier /* directory file block buffer */
563*9a747e4fSDavid du Colombier #ifdef UFS
564*9a747e4fSDavid du Colombier char dblk[DIRBLKSIZ + 1];
565*9a747e4fSDavid du Colombier #else
566*9a747e4fSDavid du Colombier char dblk[DIRBLKSIZ];
567*9a747e4fSDavid du Colombier #endif
568*9a747e4fSDavid du Colombier struct direct dummy; /* just for alignment */
569*9a747e4fSDavid du Colombier } u; /* (avoids having to malloc()) */
570*9a747e4fSDavid du Colombier register struct direct *dp; /* -> u.dblk[.] */
571*9a747e4fSDavid du Colombier register struct dirent *bp; /* -> buf[.] */
572*9a747e4fSDavid du Colombier
573*9a747e4fSDavid du Colombier #ifdef UNK
574*9a747e4fSDavid du Colombier switch (state) {
575*9a747e4fSDavid du Colombier SIG_T (*shdlr)(); /* entry SIGSYS handler */
576*9a747e4fSDavid du Colombier register int retval; /* return from _getdents() if any */
577*9a747e4fSDavid du Colombier
578*9a747e4fSDavid du Colombier case yes: /* _getdents() is known to work */
579*9a747e4fSDavid du Colombier return _getdents(fildes, buf, nbyte);
580*9a747e4fSDavid du Colombier
581*9a747e4fSDavid du Colombier case maybe: /* first time only */
582*9a747e4fSDavid du Colombier shdlr = signal(SIGSYS, sig_catch);
583*9a747e4fSDavid du Colombier retval = _getdents(fildes, buf, nbyte); /* try it */
584*9a747e4fSDavid du Colombier signal(SIGSYS, shdlr);
585*9a747e4fSDavid du Colombier
586*9a747e4fSDavid du Colombier if (state == maybe) { /* SIGSYS did not occur */
587*9a747e4fSDavid du Colombier state = yes; /* so _getdents() must have worked */
588*9a747e4fSDavid du Colombier return retval;
589*9a747e4fSDavid du Colombier }
590*9a747e4fSDavid du Colombier /* else fall through into emulation */
591*9a747e4fSDavid du Colombier
592*9a747e4fSDavid du Colombier /* case no: /* fall through into emulation */
593*9a747e4fSDavid du Colombier }
594*9a747e4fSDavid du Colombier #endif
595*9a747e4fSDavid du Colombier
596*9a747e4fSDavid du Colombier if (buf == (char *)NULL
597*9a747e4fSDavid du Colombier #ifdef ATT_SPEC
598*9a747e4fSDavid du Colombier || (unsigned long) buf % sizeof(long) != 0 /* ugh */
599*9a747e4fSDavid du Colombier #endif
600*9a747e4fSDavid du Colombier ) {
601*9a747e4fSDavid du Colombier errno = EFAULT; /* invalid pointer */
602*9a747e4fSDavid du Colombier return -1;
603*9a747e4fSDavid du Colombier }
604*9a747e4fSDavid du Colombier if (fstat(fildes, &statb) != 0) {
605*9a747e4fSDavid du Colombier return -1; /* errno set by fstat() */
606*9a747e4fSDavid du Colombier }
607*9a747e4fSDavid du Colombier
608*9a747e4fSDavid du Colombier if (!S_ISDIR(statb.st_mode)) {
609*9a747e4fSDavid du Colombier errno = ENOTDIR; /* not a directory */
610*9a747e4fSDavid du Colombier return -1;
611*9a747e4fSDavid du Colombier }
612*9a747e4fSDavid du Colombier if ((offset = lseek(fildes, (OFFSET) 0, SEEK_CUR)) < 0) {
613*9a747e4fSDavid du Colombier return -1; /* errno set by lseek() */
614*9a747e4fSDavid du Colombier }
615*9a747e4fSDavid du Colombier
616*9a747e4fSDavid du Colombier #ifdef BFS /* no telling what remote hosts do */
617*9a747e4fSDavid du Colombier if ((unsigned long) offset % DIRBLKSIZ != 0) {
618*9a747e4fSDavid du Colombier errno = ENOENT; /* file pointer probably misaligned */
619*9a747e4fSDavid du Colombier return -1;
620*9a747e4fSDavid du Colombier }
621*9a747e4fSDavid du Colombier #endif
622*9a747e4fSDavid du Colombier
623*9a747e4fSDavid du Colombier serrno = errno; /* save entry errno */
624*9a747e4fSDavid du Colombier
625*9a747e4fSDavid du Colombier for (bp = (struct dirent *) buf; bp == (struct dirent *) buf;) {
626*9a747e4fSDavid du Colombier
627*9a747e4fSDavid du Colombier /* convert next directory block */
628*9a747e4fSDavid du Colombier int size;
629*9a747e4fSDavid du Colombier
630*9a747e4fSDavid du Colombier do {
631*9a747e4fSDavid du Colombier size = GetBlock(fildes, u.dblk, DIRBLKSIZ);
632*9a747e4fSDavid du Colombier } while (size == -1 && errno == EINTR);
633*9a747e4fSDavid du Colombier
634*9a747e4fSDavid du Colombier if (size <= 0) {
635*9a747e4fSDavid du Colombier return size; /* EOF or error (EBADF) */
636*9a747e4fSDavid du Colombier }
637*9a747e4fSDavid du Colombier
638*9a747e4fSDavid du Colombier for (dp = (struct direct *) u.dblk;
639*9a747e4fSDavid du Colombier (char *) dp < &u.dblk[size];
640*9a747e4fSDavid du Colombier dp = (struct direct *) ((char *) dp + RecLen(dp))
641*9a747e4fSDavid du Colombier ) {
642*9a747e4fSDavid du Colombier #ifndef UFS
643*9a747e4fSDavid du Colombier if (dp->d_reclen <= 0) {
644*9a747e4fSDavid du Colombier errno = EIO; /* corrupted directory */
645*9a747e4fSDavid du Colombier return -1;
646*9a747e4fSDavid du Colombier }
647*9a747e4fSDavid du Colombier #endif
648*9a747e4fSDavid du Colombier
649*9a747e4fSDavid du Colombier if (dp->d_fileno != 0) { /* non-empty; copy to user buffer */
650*9a747e4fSDavid du Colombier register int reclen =
651*9a747e4fSDavid du Colombier DIRENTSIZ(NameLen(dp->d_name));
652*9a747e4fSDavid du Colombier
653*9a747e4fSDavid du Colombier if ((char *) bp + reclen > &buf[nbyte]) {
654*9a747e4fSDavid du Colombier errno = EINVAL;
655*9a747e4fSDavid du Colombier return -1; /* buf too small */
656*9a747e4fSDavid du Colombier }
657*9a747e4fSDavid du Colombier bp->d_ino = dp->d_fileno;
658*9a747e4fSDavid du Colombier bp->d_off = offset + ((char *) dp - u.dblk);
659*9a747e4fSDavid du Colombier bp->d_reclen = reclen;
660*9a747e4fSDavid du Colombier
661*9a747e4fSDavid du Colombier {
662*9a747e4fSDavid du Colombier #ifdef UFS
663*9a747e4fSDavid du Colombier /* Is the following kludge ugly? You bet. */
664*9a747e4fSDavid du Colombier
665*9a747e4fSDavid du Colombier register char save = dp->d_name[DIRSIZ];
666*9a747e4fSDavid du Colombier /* save original data */
667*9a747e4fSDavid du Colombier
668*9a747e4fSDavid du Colombier dp->d_name[DIRSIZ] = '\0';
669*9a747e4fSDavid du Colombier /* ensure NUL termination */
670*9a747e4fSDavid du Colombier #endif
671*9a747e4fSDavid du Colombier /* adds NUL padding */
672*9a747e4fSDavid du Colombier strncpy(bp->d_name, dp->d_name, reclen - DIRENTBASESIZ);
673*9a747e4fSDavid du Colombier #ifdef UFS
674*9a747e4fSDavid du Colombier dp->d_name[DIRSIZ] = save;
675*9a747e4fSDavid du Colombier /* restore original data */
676*9a747e4fSDavid du Colombier #endif
677*9a747e4fSDavid du Colombier }
678*9a747e4fSDavid du Colombier
679*9a747e4fSDavid du Colombier bp = (struct dirent *) ((char *) bp + reclen);
680*9a747e4fSDavid du Colombier }
681*9a747e4fSDavid du Colombier }
682*9a747e4fSDavid du Colombier
683*9a747e4fSDavid du Colombier #ifndef BFS /* 4.2BSD screwed up; fixed in 4.3BSD */
684*9a747e4fSDavid du Colombier if ((char *) dp > &u.dblk[size]) {
685*9a747e4fSDavid du Colombier errno = EIO; /* corrupted directory */
686*9a747e4fSDavid du Colombier return -1;
687*9a747e4fSDavid du Colombier }
688*9a747e4fSDavid du Colombier #endif
689*9a747e4fSDavid du Colombier }
690*9a747e4fSDavid du Colombier
691*9a747e4fSDavid du Colombier errno = serrno; /* restore entry errno */
692*9a747e4fSDavid du Colombier return (char *) bp - buf; /* return # bytes read */
693*9a747e4fSDavid du Colombier }
694