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