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