1echo 'directory.3': 2sed 's/^X//' >'directory.3' <<'!' 3X.TH DIRECTORY 3 imported 4X.DA 9 Oct 1985 5X.SH NAME 6Xopendir, readdir, telldir, seekdir, rewinddir, closedir \- high-level directory operations 7X.SH SYNOPSIS 8X.B #include <sys/types.h> 9X.br 10X.B #include <ndir.h> 11X.PP 12X.SM 13X.B DIR 14X.B *opendir(filename) 15X.br 16X.B char *filename; 17X.PP 18X.SM 19X.B struct direct 20X.B *readdir(dirp) 21X.br 22X.B DIR *dirp; 23X.PP 24X.SM 25X.B long 26X.B telldir(dirp) 27X.br 28X.B DIR *dirp; 29X.PP 30X.SM 31X.B seekdir(dirp, loc) 32X.br 33X.B DIR *dirp; 34X.br 35X.B long loc; 36X.PP 37X.SM 38X.B rewinddir(dirp) 39X.br 40X.B DIR *dirp; 41X.PP 42X.SM 43X.B closedir(dirp) 44X.br 45X.B DIR *dirp; 46X.SH DESCRIPTION 47XThis library provides high-level primitives for directory scanning, 48Xsimilar to those available for 4.2BSD's (very different) directory system. 49X.\"The purpose of this library is to simulate 50X.\"the new flexible length directory names of 4.2bsd UNIX 51X.\"on top of the old directory structure of v7. 52XIt incidentally provides easy portability to and from 4.2BSD (insofar 53Xas such portability is not compromised by other 4.2/VAX dependencies). 54X.\"It allows programs to be converted immediately 55X.\"to the new directory access interface, 56X.\"so that they need only be relinked 57X.\"when moved to 4.2bsd. 58X.\"It is obtained with the loader option 59X.\".BR \-lndir . 60X.PP 61X.I Opendir 62Xopens the directory named by 63X.I filename 64Xand associates a 65X.I directory stream 66Xwith it. 67X.I Opendir 68Xreturns a pointer to be used to identify the 69X.I directory stream 70Xin subsequent operations. 71XThe pointer 72X.SM 73X.B NULL 74Xis returned if 75X.I filename 76Xcannot be accessed or is not a directory. 77X.PP 78X.I Readdir 79Xreturns a pointer to the next directory entry. 80XIt returns 81X.B NULL 82Xupon reaching the end of the directory or detecting 83Xan invalid 84X.I seekdir 85Xoperation. 86X.PP 87X.I Telldir 88Xreturns the current location associated with the named 89X.I directory stream. 90X.PP 91X.I Seekdir 92Xsets the position of the next 93X.I readdir 94Xoperation on the 95X.I directory stream. 96XThe new position reverts to the one associated with the 97X.I directory stream 98Xwhen the 99X.I telldir 100Xoperation was performed. 101XValues returned by 102X.I telldir 103Xare good only for the lifetime of the DIR pointer from 104Xwhich they are derived. 105XIf the directory is closed and then reopened, 106Xthe 107X.I telldir 108Xvalue may be invalidated 109Xdue to undetected directory compaction in 4.2BSD. 110XIt is safe to use a previous 111X.I telldir 112Xvalue immediately after a call to 113X.I opendir 114Xand before any calls to 115X.I readdir. 116X.PP 117X.I Rewinddir 118Xresets the position of the named 119X.I directory stream 120Xto the beginning of the directory. 121X.PP 122X.I Closedir 123Xcauses the named 124X.I directory stream 125Xto be closed, 126Xand the structure associated with the DIR pointer to be freed. 127X.PP 128XA 129X.I direct 130Xstructure is as follows: 131X.PP 132X.RS 133X.nf 134Xstruct direct { 135X /* unsigned */ long d_ino; /* inode number of entry */ 136X unsigned short d_reclen; /* length of this record */ 137X unsigned short d_namlen; /* length of string in d_name */ 138X char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */ 139X}; 140X.fi 141X.RE 142X.PP 143XThe 144X.I d_reclen 145Xfield is meaningless in non-4.2BSD systems and should be ignored. 146XThe use of a 147X.I long 148Xfor 149X.I d_ino 150Xis also a 4.2BSDism; 151X.I ino_t 152X(see 153X.IR types (5)) 154Xshould be used elsewhere. 155XThe macro 156X.I DIRSIZ(dp) 157Xgives the minimum memory size needed to hold the 158X.I direct 159Xvalue pointed to by 160X.IR dp , 161Xwith the minimum necessary allocation for 162X.IR d_name . 163X.PP 164XThe preferred way to search the current directory for entry ``name'' is: 165X.PP 166X.RS 167X.nf 168X len = strlen(name); 169X dirp = opendir("."); 170X if (dirp == NULL) { 171X fprintf(stderr, "%s: can't read directory .\\n", argv[0]); 172X return NOT_FOUND; 173X } 174X while ((dp = readdir(dirp)) != NULL) 175X if (dp->d_namlen == len && strcmp(dp->d_name, name) == 0) { 176X closedir(dirp); 177X return FOUND; 178X } 179X closedir(dirp); 180X return NOT_FOUND; 181X.RE 182X.\".SH LINKING 183X.\"This library is accessed by specifying ``-lndir'' as the 184X.\"last argument to the compile line, e.g.: 185X.\".PP 186X.\" cc -I/usr/include/ndir -o prog prog.c -lndir 187X.SH "SEE ALSO" 188Xopen(2), 189Xclose(2), 190Xread(2), 191Xlseek(2) 192X.SH HISTORY 193XWritten by 194XKirk McKusick at Berkeley (ucbvax!mckusick). 195XMiscellaneous bug fixes from elsewhere. 196XThe size of the data structure has been decreased to avoid excessive 197Xspace waste under V7 (where filenames are 14 characters at most). 198XFor obscure historical reasons, the include file is also available 199Xas 200X.IR <ndir/sys/dir.h> . 201XThe Berkeley version lived in a separate library (\fI\-lndir\fR), 202Xwhereas ours is 203Xpart of the C library, although the separate library is retained to 204Xmaximize compatibility. 205X.PP 206XThis manual page has been substantially rewritten to be informative in 207Xthe absence of a 4.2BSD manual. 208X.SH BUGS 209XThe 210X.I DIRSIZ 211Xmacro actually wastes a bit of space due to some padding requirements 212Xthat are an artifact of 4.2BSD. 213X.PP 214XThe returned value of 215X.I readdir 216Xpoints to a static area that will be overwritten by subsequent calls. 217X.PP 218XThere are some unfortunate name conflicts with the \fIreal\fR V7 219Xdirectory structure definitions. 220! 221echo 'dir.h': 222sed 's/^X//' >'dir.h' <<'!' 223X/* dir.h 4.4 82/07/25 */ 224X 225X/* 226X * A directory consists of some number of blocks of DIRBLKSIZ 227X * bytes, where DIRBLKSIZ is chosen such that it can be transferred 228X * to disk in a single atomic operation (e.g. 512 bytes on most machines). 229X * 230X * Each DIRBLKSIZ byte block contains some number of directory entry 231X * structures, which are of variable length. Each directory entry has 232X * a struct direct at the front of it, containing its inode number, 233X * the length of the entry, and the length of the name contained in 234X * the entry. These are followed by the name padded to a 4 byte boundary 235X * with null bytes. All names are guaranteed null terminated. 236X * The maximum length of a name in a directory is MAXNAMLEN. 237X * 238X * The macro DIRSIZ(dp) gives the amount of space required to represent 239X * a directory entry. Free space in a directory is represented by 240X * entries which have dp->d_reclen >= DIRSIZ(dp). All DIRBLKSIZ bytes 241X * in a directory block are claimed by the directory entries. This 242X * usually results in the last entry in a directory having a large 243X * dp->d_reclen. When entries are deleted from a directory, the 244X * space is returned to the previous entry in the same directory 245X * block by increasing its dp->d_reclen. If the first entry of 246X * a directory block is free, then its dp->d_ino is set to 0. 247X * Entries other than the first in a directory do not normally have 248X * dp->d_ino set to 0. 249X */ 250X#define DIRBLKSIZ 512 251X#ifdef VMUNIX 252X#define MAXNAMLEN 255 253X#else 254X#define MAXNAMLEN 14 255X#endif 256X 257Xstruct direct { 258X /* unsigned */ long d_ino; /* inode number of entry */ 259X unsigned short d_reclen; /* length of this record */ 260X unsigned short d_namlen; /* length of string in d_name */ 261X char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */ 262X}; 263X 264X/* 265X * The DIRSIZ macro gives the minimum record length which will hold 266X * the directory entry. This requires the amount of space in struct direct 267X * without the d_name field, plus enough space for the name with a terminating 268X * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary. 269X */ 270X#undef DIRSIZ 271X#define DIRSIZ(dp) \ 272X ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) 273X 274X#ifndef KERNEL 275X/* 276X * Definitions for library routines operating on directories. 277X */ 278Xtypedef struct _dirdesc { 279X int dd_fd; 280X long dd_loc; 281X long dd_size; 282X char dd_buf[DIRBLKSIZ]; 283X} DIR; 284X#ifndef NULL 285X#define NULL 0 286X#endif 287Xextern DIR *opendir(); 288Xextern struct direct *readdir(); 289Xextern long telldir(); 290X#ifdef void 291Xextern void seekdir(); 292Xextern void closedir(); 293X#endif 294X#define rewinddir(dirp) seekdir((dirp), (long)0) 295X#endif KERNEL 296! 297echo 'makefile': 298sed 's/^X//' >'makefile' <<'!' 299XDIR = closedir.o opendir.o readdir.o seekdir.o telldir.o 300XCFLAGS=-O -I. -Dvoid=int 301XDEST=.. 302X 303Xall: $(DIR) 304X 305Xmv: $(DIR) 306X mv $(DIR) $(DEST) 307X 308Xcpif: dir.h 309X cp dir.h /usr/include/ndir.h 310X 311Xclean: 312X rm -f *.o 313! 314echo 'closedir.c': 315sed 's/^X//' >'closedir.c' <<'!' 316Xstatic char sccsid[] = "@(#)closedir.c 4.2 3/10/82"; 317X 318X#include <sys/types.h> 319X#include <dir.h> 320X 321X/* 322X * close a directory. 323X */ 324Xvoid 325Xclosedir(dirp) 326X register DIR *dirp; 327X{ 328X close(dirp->dd_fd); 329X dirp->dd_fd = -1; 330X dirp->dd_loc = 0; 331X free((char *)dirp); 332X} 333! 334echo 'opendir.c': 335sed 's/^X//' >'opendir.c' <<'!' 336X/* Copyright (c) 1982 Regents of the University of California */ 337X 338Xstatic char sccsid[] = "@(#)opendir.c 4.4 11/12/82"; 339X 340X#include <sys/types.h> 341X#include <sys/stat.h> 342X#include <dir.h> 343X 344X/* 345X * open a directory. 346X */ 347XDIR * 348Xopendir(name) 349X char *name; 350X{ 351X register DIR *dirp; 352X register int fd; 353X struct stat statbuf; 354X char *malloc(); 355X 356X if ((fd = open(name, 0)) == -1) 357X return NULL; 358X if (fstat(fd, &statbuf) == -1 || !(statbuf.st_mode & S_IFDIR)) { 359X close(fd); 360X return NULL; 361X } 362X if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) { 363X close (fd); 364X return NULL; 365X } 366X dirp->dd_fd = fd; 367X dirp->dd_loc = 0; 368X dirp->dd_size = 0; /* so that telldir will work before readdir */ 369X return dirp; 370X} 371! 372echo 'readdir.c': 373sed 's/^X//' >'readdir.c' <<'!' 374X/* Copyright (c) 1982 Regents of the University of California */ 375X 376Xstatic char sccsid[] = "@(#)readdir.c 4.3 8/8/82"; 377X 378X#include <sys/types.h> 379X#include <dir.h> 380X 381X/* 382X * read an old stlye directory entry and present it as a new one 383X */ 384X#define ODIRSIZ 14 385X 386Xstruct olddirect { 387X ino_t od_ino; 388X char od_name[ODIRSIZ]; 389X}; 390X 391X/* 392X * get next entry in a directory. 393X */ 394Xstruct direct * 395Xreaddir(dirp) 396X register DIR *dirp; 397X{ 398X register struct olddirect *dp; 399X static struct direct dir; 400X 401X for (;;) { 402X if (dirp->dd_loc == 0) { 403X dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, 404X DIRBLKSIZ); 405X if (dirp->dd_size <= 0) { 406X dirp->dd_size = 0; 407X return NULL; 408X } 409X } 410X if (dirp->dd_loc >= dirp->dd_size) { 411X dirp->dd_loc = 0; 412X continue; 413X } 414X dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc); 415X dirp->dd_loc += sizeof(struct olddirect); 416X if (dp->od_ino == 0) 417X continue; 418X dir.d_ino = dp->od_ino; 419X strncpy(dir.d_name, dp->od_name, ODIRSIZ); 420X dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */ 421X dir.d_namlen = strlen(dir.d_name); 422X dir.d_reclen = DIRBLKSIZ; 423X return (&dir); 424X } 425X} 426! 427echo 'seekdir.c': 428sed 's/^X//' >'seekdir.c' <<'!' 429Xstatic char sccsid[] = "@(#)seekdir.c 4.9 3/25/83"; 430X 431X#include <sys/param.h> 432X#include <dir.h> 433X 434X/* 435X * seek to an entry in a directory. 436X * Only values returned by "telldir" should be passed to seekdir. 437X */ 438Xvoid 439Xseekdir(dirp, loc) 440X register DIR *dirp; 441X long loc; 442X{ 443X long curloc, base, offset; 444X struct direct *dp; 445X extern long lseek(); 446X 447X curloc = telldir(dirp); 448X if (loc == curloc) 449X return; 450X base = loc & ~(DIRBLKSIZ - 1); 451X offset = loc & (DIRBLKSIZ - 1); 452X (void) lseek(dirp->dd_fd, base, 0); 453X dirp->dd_size = 0; 454X dirp->dd_loc = 0; 455X while (dirp->dd_loc < offset) { 456X dp = readdir(dirp); 457X if (dp == NULL) 458X return; 459X } 460X} 461! 462echo 'telldir.c': 463sed 's/^X//' >'telldir.c' <<'!' 464Xstatic char sccsid[] = "@(#)telldir.c 4.1 2/21/82"; 465X 466X#include <sys/types.h> 467X#include <dir.h> 468X 469X/* 470X * return a pointer into a directory 471X */ 472Xlong 473Xtelldir(dirp) 474X DIR *dirp; 475X{ 476X long lseek(); 477X 478X return (lseek(dirp->dd_fd, 0L, 1) - dirp->dd_size + dirp->dd_loc); 479X} 480! 481echo done 482