echo 'directory.3': sed 's/^X//' >'directory.3' <<'!' X.TH DIRECTORY 3 imported X.DA 9 Oct 1985 X.SH NAME Xopendir, readdir, telldir, seekdir, rewinddir, closedir \- high-level directory operations X.SH SYNOPSIS X.B #include X.br X.B #include X.PP X.SM X.B DIR X.B *opendir(filename) X.br X.B char *filename; X.PP X.SM X.B struct direct X.B *readdir(dirp) X.br X.B DIR *dirp; X.PP X.SM X.B long X.B telldir(dirp) X.br X.B DIR *dirp; X.PP X.SM X.B seekdir(dirp, loc) X.br X.B DIR *dirp; X.br X.B long loc; X.PP X.SM X.B rewinddir(dirp) X.br X.B DIR *dirp; X.PP X.SM X.B closedir(dirp) X.br X.B DIR *dirp; X.SH DESCRIPTION XThis library provides high-level primitives for directory scanning, Xsimilar to those available for 4.2BSD's (very different) directory system. X.\"The purpose of this library is to simulate X.\"the new flexible length directory names of 4.2bsd UNIX X.\"on top of the old directory structure of v7. XIt incidentally provides easy portability to and from 4.2BSD (insofar Xas such portability is not compromised by other 4.2/VAX dependencies). X.\"It allows programs to be converted immediately X.\"to the new directory access interface, X.\"so that they need only be relinked X.\"when moved to 4.2bsd. X.\"It is obtained with the loader option X.\".BR \-lndir . X.PP X.I Opendir Xopens the directory named by X.I filename Xand associates a X.I directory stream Xwith it. X.I Opendir Xreturns a pointer to be used to identify the X.I directory stream Xin subsequent operations. XThe pointer X.SM X.B NULL Xis returned if X.I filename Xcannot be accessed or is not a directory. X.PP X.I Readdir Xreturns a pointer to the next directory entry. XIt returns X.B NULL Xupon reaching the end of the directory or detecting Xan invalid X.I seekdir Xoperation. X.PP X.I Telldir Xreturns the current location associated with the named X.I directory stream. X.PP X.I Seekdir Xsets the position of the next X.I readdir Xoperation on the X.I directory stream. XThe new position reverts to the one associated with the X.I directory stream Xwhen the X.I telldir Xoperation was performed. XValues returned by X.I telldir Xare good only for the lifetime of the DIR pointer from Xwhich they are derived. XIf the directory is closed and then reopened, Xthe X.I telldir Xvalue may be invalidated Xdue to undetected directory compaction in 4.2BSD. XIt is safe to use a previous X.I telldir Xvalue immediately after a call to X.I opendir Xand before any calls to X.I readdir. X.PP X.I Rewinddir Xresets the position of the named X.I directory stream Xto the beginning of the directory. X.PP X.I Closedir Xcauses the named X.I directory stream Xto be closed, Xand the structure associated with the DIR pointer to be freed. X.PP XA X.I direct Xstructure is as follows: X.PP X.RS X.nf Xstruct direct { X /* unsigned */ long d_ino; /* inode number of entry */ X unsigned short d_reclen; /* length of this record */ X unsigned short d_namlen; /* length of string in d_name */ X char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */ X}; X.fi X.RE X.PP XThe X.I d_reclen Xfield is meaningless in non-4.2BSD systems and should be ignored. XThe use of a X.I long Xfor X.I d_ino Xis also a 4.2BSDism; X.I ino_t X(see X.IR types (5)) Xshould be used elsewhere. XThe macro X.I DIRSIZ(dp) Xgives the minimum memory size needed to hold the X.I direct Xvalue pointed to by X.IR dp , Xwith the minimum necessary allocation for X.IR d_name . X.PP XThe preferred way to search the current directory for entry ``name'' is: X.PP X.RS X.nf X len = strlen(name); X dirp = opendir("."); X if (dirp == NULL) { X fprintf(stderr, "%s: can't read directory .\\n", argv[0]); X return NOT_FOUND; X } X while ((dp = readdir(dirp)) != NULL) X if (dp->d_namlen == len && strcmp(dp->d_name, name) == 0) { X closedir(dirp); X return FOUND; X } X closedir(dirp); X return NOT_FOUND; X.RE X.\".SH LINKING X.\"This library is accessed by specifying ``-lndir'' as the X.\"last argument to the compile line, e.g.: X.\".PP X.\" cc -I/usr/include/ndir -o prog prog.c -lndir X.SH "SEE ALSO" Xopen(2), Xclose(2), Xread(2), Xlseek(2) X.SH HISTORY XWritten by XKirk McKusick at Berkeley (ucbvax!mckusick). XMiscellaneous bug fixes from elsewhere. XThe size of the data structure has been decreased to avoid excessive Xspace waste under V7 (where filenames are 14 characters at most). XFor obscure historical reasons, the include file is also available Xas X.IR . XThe Berkeley version lived in a separate library (\fI\-lndir\fR), Xwhereas ours is Xpart of the C library, although the separate library is retained to Xmaximize compatibility. X.PP XThis manual page has been substantially rewritten to be informative in Xthe absence of a 4.2BSD manual. X.SH BUGS XThe X.I DIRSIZ Xmacro actually wastes a bit of space due to some padding requirements Xthat are an artifact of 4.2BSD. X.PP XThe returned value of X.I readdir Xpoints to a static area that will be overwritten by subsequent calls. X.PP XThere are some unfortunate name conflicts with the \fIreal\fR V7 Xdirectory structure definitions. ! echo 'dir.h': sed 's/^X//' >'dir.h' <<'!' X/* dir.h 4.4 82/07/25 */ X X/* X * A directory consists of some number of blocks of DIRBLKSIZ X * bytes, where DIRBLKSIZ is chosen such that it can be transferred X * to disk in a single atomic operation (e.g. 512 bytes on most machines). X * X * Each DIRBLKSIZ byte block contains some number of directory entry X * structures, which are of variable length. Each directory entry has X * a struct direct at the front of it, containing its inode number, X * the length of the entry, and the length of the name contained in X * the entry. These are followed by the name padded to a 4 byte boundary X * with null bytes. All names are guaranteed null terminated. X * The maximum length of a name in a directory is MAXNAMLEN. X * X * The macro DIRSIZ(dp) gives the amount of space required to represent X * a directory entry. Free space in a directory is represented by X * entries which have dp->d_reclen >= DIRSIZ(dp). All DIRBLKSIZ bytes X * in a directory block are claimed by the directory entries. This X * usually results in the last entry in a directory having a large X * dp->d_reclen. When entries are deleted from a directory, the X * space is returned to the previous entry in the same directory X * block by increasing its dp->d_reclen. If the first entry of X * a directory block is free, then its dp->d_ino is set to 0. X * Entries other than the first in a directory do not normally have X * dp->d_ino set to 0. X */ X#define DIRBLKSIZ 512 X#ifdef VMUNIX X#define MAXNAMLEN 255 X#else X#define MAXNAMLEN 14 X#endif X Xstruct direct { X /* unsigned */ long d_ino; /* inode number of entry */ X unsigned short d_reclen; /* length of this record */ X unsigned short d_namlen; /* length of string in d_name */ X char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */ X}; X X/* X * The DIRSIZ macro gives the minimum record length which will hold X * the directory entry. This requires the amount of space in struct direct X * without the d_name field, plus enough space for the name with a terminating X * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary. X */ X#undef DIRSIZ X#define DIRSIZ(dp) \ X ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) X X#ifndef KERNEL X/* X * Definitions for library routines operating on directories. X */ Xtypedef struct _dirdesc { X int dd_fd; X long dd_loc; X long dd_size; X char dd_buf[DIRBLKSIZ]; X} DIR; X#ifndef NULL X#define NULL 0 X#endif Xextern DIR *opendir(); Xextern struct direct *readdir(); Xextern long telldir(); X#ifdef void Xextern void seekdir(); Xextern void closedir(); X#endif X#define rewinddir(dirp) seekdir((dirp), (long)0) X#endif KERNEL ! echo 'makefile': sed 's/^X//' >'makefile' <<'!' XDIR = closedir.o opendir.o readdir.o seekdir.o telldir.o XCFLAGS=-O -I. -Dvoid=int XDEST=.. X Xall: $(DIR) X Xmv: $(DIR) X mv $(DIR) $(DEST) X Xcpif: dir.h X cp dir.h /usr/include/ndir.h X Xclean: X rm -f *.o ! echo 'closedir.c': sed 's/^X//' >'closedir.c' <<'!' Xstatic char sccsid[] = "@(#)closedir.c 4.2 3/10/82"; X X#include X#include X X/* X * close a directory. X */ Xvoid Xclosedir(dirp) X register DIR *dirp; X{ X close(dirp->dd_fd); X dirp->dd_fd = -1; X dirp->dd_loc = 0; X free((char *)dirp); X} ! echo 'opendir.c': sed 's/^X//' >'opendir.c' <<'!' X/* Copyright (c) 1982 Regents of the University of California */ X Xstatic char sccsid[] = "@(#)opendir.c 4.4 11/12/82"; X X#include X#include X#include X X/* X * open a directory. X */ XDIR * Xopendir(name) X char *name; X{ X register DIR *dirp; X register int fd; X struct stat statbuf; X char *malloc(); X X if ((fd = open(name, 0)) == -1) X return NULL; X if (fstat(fd, &statbuf) == -1 || !(statbuf.st_mode & S_IFDIR)) { X close(fd); X return NULL; X } X if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) { X close (fd); X return NULL; X } X dirp->dd_fd = fd; X dirp->dd_loc = 0; X dirp->dd_size = 0; /* so that telldir will work before readdir */ X return dirp; X} ! echo 'readdir.c': sed 's/^X//' >'readdir.c' <<'!' X/* Copyright (c) 1982 Regents of the University of California */ X Xstatic char sccsid[] = "@(#)readdir.c 4.3 8/8/82"; X X#include X#include X X/* X * read an old stlye directory entry and present it as a new one X */ X#define ODIRSIZ 14 X Xstruct olddirect { X ino_t od_ino; X char od_name[ODIRSIZ]; X}; X X/* X * get next entry in a directory. X */ Xstruct direct * Xreaddir(dirp) X register DIR *dirp; X{ X register struct olddirect *dp; X static struct direct dir; X X for (;;) { X if (dirp->dd_loc == 0) { X dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, X DIRBLKSIZ); X if (dirp->dd_size <= 0) { X dirp->dd_size = 0; X return NULL; X } X } X if (dirp->dd_loc >= dirp->dd_size) { X dirp->dd_loc = 0; X continue; X } X dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc); X dirp->dd_loc += sizeof(struct olddirect); X if (dp->od_ino == 0) X continue; X dir.d_ino = dp->od_ino; X strncpy(dir.d_name, dp->od_name, ODIRSIZ); X dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */ X dir.d_namlen = strlen(dir.d_name); X dir.d_reclen = DIRBLKSIZ; X return (&dir); X } X} ! echo 'seekdir.c': sed 's/^X//' >'seekdir.c' <<'!' Xstatic char sccsid[] = "@(#)seekdir.c 4.9 3/25/83"; X X#include X#include X X/* X * seek to an entry in a directory. X * Only values returned by "telldir" should be passed to seekdir. X */ Xvoid Xseekdir(dirp, loc) X register DIR *dirp; X long loc; X{ X long curloc, base, offset; X struct direct *dp; X extern long lseek(); X X curloc = telldir(dirp); X if (loc == curloc) X return; X base = loc & ~(DIRBLKSIZ - 1); X offset = loc & (DIRBLKSIZ - 1); X (void) lseek(dirp->dd_fd, base, 0); X dirp->dd_size = 0; X dirp->dd_loc = 0; X while (dirp->dd_loc < offset) { X dp = readdir(dirp); X if (dp == NULL) X return; X } X} ! echo 'telldir.c': sed 's/^X//' >'telldir.c' <<'!' Xstatic char sccsid[] = "@(#)telldir.c 4.1 2/21/82"; X X#include X#include X X/* X * return a pointer into a directory X */ Xlong Xtelldir(dirp) X DIR *dirp; X{ X long lseek(); X X return (lseek(dirp->dd_fd, 0L, 1) - dirp->dd_size + dirp->dd_loc); X} ! echo done