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