jschwart@aecom2.UUCP (03/24/87)
Hi:
I just finished typing in the BSD dir(3) emulation routines for
System V, which are found in the back of J.E. Lapin's "Portable C and
Unix System Programming" Prentice Hall 1987. Well, he seems to have left
off seekdir(3). After five minutes of looking at his code, I have this
as a first approximation. Does this look right??
void seekdir(dirp, offset) /* hack - this proc was missing */
register DIR *dirp;
register long offset;
{
lseek(dirp->dd_fd, offset);
dirp->dd_loc = 0; /* ??? */
}
Eric Safern
...{philabs,cucard,pegasus,rocky2}!aecom!aecom2!jschwart
guy@gorodish.UUCP (03/26/87)
> I just finished typing in the BSD dir(3) emulation routines for >System V, which are found in the back of J.E. Lapin's "Portable C and >Unix System Programming" Prentice Hall 1987. Well, he seems to have left >off seekdir(3). After five minutes of looking at his code, I have this >as a first approximation. Does this look right?? Beats me. However, just so nobody else wears their fingers out typing all that stuff in, I'll repost Kirk McKusick's original directory library for V7 file systems (originally posted by Kirk lo, these many years ago): From: sun!decwrl!decvax!ucbvax!mckusick (Kirk Mckusick) Newsgroups: net.sources Title: directory access compatibility routines Article-I.D.: ucbvax.191 Posted: Sat Apr 2 18:36:51 1983 Received: Sun Apr 3 00:38:10 1983 #!/bin/csh # Run this file as shell script mkdir libndir chdir libndir echo extracting README cat > README <<'EOF' The purpose of this library is to simulate the new flexible length directory names on top of the old directory structure. It allows programs to be converted to the new directory access interface, so that they need only be relinked when 4.2bsd becomes available. 'EOF' echo extracting Makefile cat > Makefile <<'EOF' # @(#)Makefile 4.8 (Berkeley) 3/21/83 DESTDIR = CFLAGS= -O OBJS= closedir.o opendir.o readdir.o seekdir.o telldir.o DIST= README Makefile dir.h closedir.c opendir.c readdir.c \ seekdir.c telldir.c directory.3s .c.o: ${CC} ${CFLAGS} -I. -c $*.c -ld -x -r $*.o mv a.out $*.o libndir: ${OBJS} ar cru libndir ${OBJS} ranlib libndir install: libndir cp dir.h ${DESTDIR}/usr/include/dir.h cp libndir ${DESTDIR}/usr/lib/libndir.a ranlib ${DESTDIR}/usr/lib/libndir.a cp directory.3s /usr/man/man3/directory.3s clean: rm -f libndir ${OBJS} dist: ${DIST} echo "#!/bin/csh" >dist echo "# Run this file as shell script" >> dist echo "mkdir libndir" >> dist echo "chdir libndir" >> dist for i in ${DIST}; do ( \ echo "echo extracting $$i" >> dist; \ echo "cat > $$i <<'EOF'" >> dist; \ cat $$i >> dist; \ echo "'EOF'" >> dist); done chmod 775 dist 'EOF' echo extracting dir.h cat > dir.h <<'EOF' /* dir.h 4.4 82/07/25 */ /* * A directory consists of some number of blocks of DIRBLKSIZ * bytes, 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 * a struct direct at the front of it, containing its inode number, * the length of the entry, and the length of the name contained in * the entry. These are followed by the name padded to a 4 byte boundary * with null bytes. All names are guaranteed null terminated. * The maximum length of a name in a directory is MAXNAMLEN. * * The macro DIRSIZ(dp) gives the amount of space required to represent * a directory entry. Free space in a directory is represented by * entries which 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_ino is set to 0. * Entries other than the first in a directory do not normally have * dp->d_ino set to 0. */ #define DIRBLKSIZ 512 #define MAXNAMLEN 255 #ifdef pdp11 #define u_long long #endif struct direct { u_long d_ino; /* inode number of entry */ u_short d_reclen; /* length of this record */ u_short d_namlen; /* length of string in d_name */ char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */ }; /* * The DIRSIZ macro gives the minimum record length which will hold * the directory entry. This requires the amount of space in struct direct * without the d_name field, plus enough space for the name with a terminating * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary. */ #undef DIRSIZ #define DIRSIZ(dp) \ ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) #ifndef KERNEL /* * Definitions for library routines operating on directories. */ typedef struct _dirdesc { int dd_fd; long dd_loc; long dd_size; char dd_buf[DIRBLKSIZ]; } DIR; #ifndef NULL #define NULL 0 #endif extern DIR *opendir(); extern struct direct *readdir(); extern long telldir(); extern void seekdir(); #define rewinddir(dirp) seekdir((dirp), (long)0) extern void closedir(); #endif KERNEL 'EOF' echo extracting closedir.c cat > closedir.c <<'EOF' static char sccsid[] = "@(#)closedir.c 4.2 3/10/82"; #include <sys/types.h> #include <dir.h> /* * close a directory. */ void closedir(dirp) register DIR *dirp; { close(dirp->dd_fd); dirp->dd_fd = -1; dirp->dd_loc = 0; free(dirp); } 'EOF' echo extracting opendir.c cat > opendir.c <<'EOF' static char sccsid[] = "@(#)opendir.c 4.4 11/12/82"; #include <sys/param.h> #include <dir.h> extern char *malloc(); /* * open a directory. */ DIR * opendir(name) char *name; { register DIR *dirp; register int fd; if ((fd = open(name, 0)) == -1) return NULL; if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) { close (fd); return NULL; } dirp->dd_fd = fd; dirp->dd_loc = 0; return dirp; } 'EOF' echo extracting readdir.c cat > readdir.c <<'EOF' static char sccsid[] = "@(#)readdir.c 4.1 (Berkeley) 83/03/21"; #include <sys/types.h> #include <dir.h> /* * read an old stlye directory entry and present it as a new one */ #define ODIRSIZ 14 struct olddirect { ino_t od_ino; char od_name[ODIRSIZ]; }; /* * get next entry in a directory. */ struct direct * readdir(dirp) register DIR *dirp; { register struct olddirect *dp; static struct direct dir; for (;;) { if (dirp->dd_loc == 0) { dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ); if (dirp->dd_size <= 0) return NULL; } if (dirp->dd_loc >= dirp->dd_size) { dirp->dd_loc = 0; continue; } dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc); dirp->dd_loc += sizeof(struct olddirect); if (dp->od_ino == 0) continue; dir.d_ino = dp->od_ino; strncpy(dir.d_name, dp->od_name, ODIRSIZ); dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */ dir.d_namlen = strlen(dir.d_name); dir.d_reclen = DIRBLKSIZ; return (&dir); } } 'EOF' echo extracting seekdir.c cat > seekdir.c <<'EOF' static char sccsid[] = "@(#)seekdir.c 4.9 3/25/83"; #include <sys/param.h> #include <dir.h> /* * seek to an entry in a directory. * Only values returned by "telldir" should be passed to seekdir. */ void seekdir(dirp, loc) register DIR *dirp; long loc; { long curloc, base, offset; struct direct *dp; extern long lseek(); curloc = telldir(dirp); if (loc == curloc) return; base = loc & ~(DIRBLKSIZ - 1); offset = loc & (DIRBLKSIZ - 1); (void) lseek(dirp->dd_fd, base, 0); dirp->dd_loc = 0; while (dirp->dd_loc < offset) { dp = readdir(dirp); if (dp == NULL) return; } } 'EOF' echo extracting telldir.c cat > telldir.c <<'EOF' static char sccsid[] = "@(#)telldir.c 4.1 2/21/82"; #include <sys/types.h> #include <dir.h> /* * return a pointer into a directory */ long telldir(dirp) DIR *dirp; { return (lseek(dirp->dd_fd, 0L, 1) - dirp->dd_size + dirp->dd_loc); } 'EOF' echo extracting directory.3s cat > directory.3s <<'EOF' ..TH DIRECTORY 3 "OGC Revision 8/02/82" .TH DIRECTORY 3X 8/1/82 .UC 4.1b Compatability .SH NAME opendir, readdir, telldir, seekdir, rewinddir, closedir \- flexible length directory operations .SH SYNOPSIS .B #include <dir.h> .PP .SM .B DIR .B *opendir(filename) .br .B char *filename; .PP .SM .B struct direct .B *readdir(dirp) .br .B DIR *dirp; .PP .SM .B long .B telldir(dirp) .br .B DIR *dirp; .PP .SM .B seekdir(dirp, loc) .br .B DIR *dirp; .br .B long loc; .PP .SM .B rewinddir(dirp) .br .B DIR *dirp; .PP .SM .B closedir(dirp) .br .B DIR *dirp; .PP .SM .B cc ... -lndir .SH DESCRIPTION The purpose of this library is to simulate the new flexible length directory names of 4.2bsd Unix on top of the old directory structure of 4.1bsd. It allows programs to be converted immediately to the new directory access interface, so that they need only be relinked when 4.2bsd becomes available. .PP .I opendir opens the directory named by .I filename and associates a .I directory stream with it. .I opendir returns a pointer to be used to identify the .I directory stream in subsequent operations. The pointer .SM .B NULL is returned if .I filename cannot be accessed or is not a directory. .PP .I readdir returns a pointer to the next directory entry. It returns .B NULL upon reaching the end of the directory or detecting an invalid .I seekdir operation. .PP .I telldir returns the current location associated with the named .I directory stream. .PP .I seekdir sets the position of the next .I readdir operation on the .I directory stream. The new position reverts to the one associated with the .I directory stream when the .I telldir operation was performed. Values returned by .I telldir are good only for the lifetime of the DIR pointer from which they are derived. If the directory is closed and then reopened, the .I telldir value may be invalidated due to undetected directory compaction. It is safe to use a previous .I telldir value immediately after a call to .I opendir and before any calls to .I readdir. .PP .I rewinddir resets the position of the named .I directory stream to the beginning of the directory. .PP .I closedir causes the named .I directory stream to be closed, and the structure associated with the DIR pointer to be freed. .PP See /usr/include/dir.h for a description of the fields available in a directory entry. The preferred way to search the current directory for entry "name" is: .br .sp len = strlen(name); .br dirp = opendir("."); .br for (dp = readdir(dirp); dp != NULL; dp = readdir(dir)) .br if (dp->d_namlen == len && !strcmp(dp->d_name, name)) { .br closedir(dirp); .br return FOUND; .br } .br closedir(dirp); .br return NOT_FOUND; .SH LINKING This library is accessed by specifying "-lndir" as the last argument to the compile line, e.g.: .br .sp cc -o prog prog.c -lndir .SH "SEE ALSO" /usr/include/dir.h, open(2), close(2), read(2), lseek(2) .SH AUTHOR Kirk McKusick. Report problems to mckusick@berkeley or ucbvax!mckusick. 'EOF'
david@ukma.UUCP (03/27/87)
On a related note ... I was moving rn over to a 3b2 running SysVr3 and found that it's already got the directory reading stuff in /lib/libc.a (A first!). HOWEVER (argh! argh! argh!) they changed the names: #include <sys/dir.h> -> #include <dirent.h> struct direct xxx; -> struct dirent xxx; Oh well. -- ----- David Herron, cbosgd!ukma!david, david@UKMA.BITNET, david@ms.uky.csnet ----- (also "postmaster", "news", and the Usenet map maintainer for Kentucky.) ----- /*EOF
bostic@ucbvax.UUCP (03/28/87)
> > I just finished typing in the BSD dir(3) emulation routines for > >System V, which are found in the back of J.E. Lapin's "Portable C and > >Unix System Programming" Prentice Hall 1987. Well, he seems to have left > >off seekdir(3). After five minutes of looking at his code, I have this > >as a first approximation. Does this look right?? > > Beats me. However, just so nobody else wears their fingers out > typing all that stuff in, I'll repost Kirk McKusick's original > directory library for V7 file systems (originally posted by Kirk lo, > these many years ago): I've been meaning to post these for some time, and since the subject seems to have come up naturally in the conversation... ... cut here ... Subject: V7 directory reading routines Index: lib/libc/gen Description: There is a problem in the directory reading compatibility routines as originally distributed by Berkeley; readdir fails if you have more than one directory open at a time. Repeat-By: Run the program bug.c, provided in the attached shar, in any directory containing several files. Fix: Unshar and install the attached; make sure you read the README. ... cut here ... echo x - Makefile sed 's/^X//' >Makefile << 'END-of-Makefile' X# @(#)Makefile 4.8 (Berkeley) 3/21/83 X XDESTDIR = XCFLAGS= -O X XOBJS= closedir.o opendir.o readdir.o scandir.o seekdir.o telldir.o XDIST= README Makefile dir.h closedir.c opendir.c readdir.c \ X scandir.c seekdir.c telldir.c directory.3 scandir.3 X X.c.o: X ${CC} ${CFLAGS} -I. -c $*.c X -ld -x -r $*.o X mv a.out $*.o X Xlibndir: ${OBJS} X ar cru libndir.a ${OBJS} X ranlib libndir.a X Xinstall: libndir X cp ndir.h ${DESTDIR}/usr/include/ndir.h X cp libndir.a ${DESTDIR}/usr/lib/libndir.a X ranlib ${DESTDIR}/usr/lib/libndir.a X cp directory.3 /usr/man/man3/directory.3 X cp scandir.3 /usr/man/man3/scandir.3 X Xclean: X rm -f libndir.a ${OBJS} END-of-Makefile echo x - README sed 's/^X//' >README << 'END-of-README' X The purpose of this library is to simulate the new, flexible Xlength directory names on top of the V7 style directory format, as well Xas to provide compatibility routines for systems that do not intend to Xconvert to the new directory format. X These are copies of Kirk McKusick's original routines, with the Xaddition of scandir(3), a major fix to readdir(3), and minor hacks. We Xhave also added a define for the V7 directory structure, "struct v7direct" Xso that both the old and new directory structures can coexist. You can Xreplace your current system "dir.h" with "ndir.h", if you want to, Xas long as you change every instance of "struct direct" in your current Xsystem to "struct v7direct". This is a pain, but desirable if you want Xthe directory reading routines to be a part of your standard library and Xnot require special effort to access. X There are a couple of fairly interesting situations you can get Xinto with this package; if you are having difficulties, check to make Xsure you're using the correct "dir.h" include file and that you're using Xthe "DIRSIZ" macro correctly, since it changed in meaning in the new file Xsystem. The simplest way to deal with the "DIRSIZ" problem is to change Xevery occurrence in your system to "MAXNAMLEN"; this is compatible with X4.3BSD. X This package also requires that you have an entry of the form X"typedef long u_long;" in your sys/types.h file. X In any case, if you have problems using or installing this Xpackage, contact me. X Oh, yes, "bug.c" demonstrates the bug in the old readdir(3) Xroutine. X X Keith Bostic 3/27/87 X seismo!keith +1 415 642 4948 X ucbvax!bostic X bostic@ucbvax.berkeley.edu END-of-README echo x - bug.c sed 's/^X//' >bug.c << 'END-of-bug.c' X#include <sys/types.h> X#include <ndir.h> X Xmain() X{ X DIR *one,*two; X struct direct *e_one; X X one = opendir("."); X two = opendir("."); X (void)readdir(one); X (void)readdir(one); X do { X e_one = readdir(one); X } X while (!e_one->d_ino); X printf("one -- %ld %s\n",e_one->d_ino,e_one->d_name); X (void)readdir(two); X puts("should be identical to the last print..."); X printf("one -- %ld %s\n",e_one->d_ino,e_one->d_name); X} END-of-bug.c echo x - closedir.c sed 's/^X//' >closedir.c << 'END-of-closedir.c' X/* X * Copyright (c) 1987 Regents of the University of California. X * This file may be freely redistributed provided that this X * notice remains attached. X */ X X#include <sys/types.h> X#include <ndir.h> X X/* X * close a directory. X */ Xclosedir(dirp) X register DIR *dirp; X{ X close(dirp->dd_fd); X dirp->dd_fd = -1; X dirp->dd_loc = 0; X free(dirp); X} END-of-closedir.c echo x - directory.3 sed 's/^X//' >directory.3 << 'END-of-directory.3' X.\" Copyright (c) 1983 Regents of the University of California. X.\" All rights reserved. The Berkeley software License Agreement X.\" specifies the terms and conditions for redistribution. X.\" X.\" @(#)directory.3 6.3 (Berkeley) 12/22/86 X.\" X.TH DIRECTORY 3 "December 22, 1986" X.UC 5 X.SH NAME Xopendir, readdir, telldir, seekdir, rewinddir, closedir, dirfd \- directory operations X.SH SYNOPSIS X.B #include <sys/types.h> X.br X.B #include <sys/dir.h> X.PP X.SM X.B DIR X.B *opendir(filename) X.br X.B char *filename; X.PP X.B struct direct X.B *readdir(dirp) X.br X.SM X.B DIR X.B *dirp; X.PP X.B long X.B telldir(dirp) X.br X.SM X.B DIR X.B *dirp; X.PP X.B seekdir(dirp, loc) X.br X.SM X.B DIR X.B *dirp; X.br X.B long loc; X.PP X.B rewinddir(dirp) X.br X.SM X.B DIR X.B *dirp; X.PP X.B closedir(dirp) X.br X.SM X.B DIR X.B *dirp; X.PP X.B dirfd(dirp) X.br X.SM X.B DIR X.B *dirp; X.SH DESCRIPTION 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. The pointer X.SM X.B NULL Xis returned if X.I filename Xcannot be accessed, or if it cannot X.IR malloc (3) Xenough memory to hold the whole thing. X.PP X.I Readdir Xreturns a pointer to the next directory entry. It returns X.B NULL Xupon reaching the end of the directory or detecting an 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. Values returned by X.I telldir Xare good only for the lifetime of the DIR pointer from which they are derived. XIf the directory is closed and then reopened, the X.I telldir Xvalue may be invalidated due to undetected directory compaction. 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 Xcloses the named X.I directory stream Xand frees the structure associated with the DIR pointer. X.PP X.I Dirfd Xreturns the integer file descriptor associated with the named X.I directory stream, Xsee open(2). X.PP XSample code which searchs a directory for entry ``name'' is: X.PP X.br X len = strlen(name); X.br X dirp = opendir("."); X.br X for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) X.br X if (dp->d_namlen == len && !strcmp(dp->d_name, name)) { X.br X closedir(dirp); X.br X return FOUND; X.br X } X.br X closedir(dirp); X.br X return NOT_FOUND; X.SH "SEE ALSO" Xopen(2), Xclose(2), Xread(2), Xlseek(2), Xdir(5) END-of-directory.3 echo x - ndir.h sed 's/^X//' >ndir.h << 'END-of-ndir.h' X/* X * Copyright (c) 1987 Regents of the University of California. X * This file may be freely redistributed provided that this X * notice remains attached. X */ X X#ifndef MAXNAMLEN X#define MAXNAMLEN 14 X#endif X X/* X * Actual directory structure as it appears on disk. For use by programs X * and routines which need to know what a directory really looks like. X * Don't use it unless you absolutely have to. X */ Xstruct v7direct { X ino_t d_ino; X char d_name[MAXNAMLEN]; X}; X X#ifndef KERNEL X#define DIRBLKSIZ 512 X Xstruct direct { X u_long d_ino; /* inode number of entry */ X u_short d_reclen; /* length of this record */ X u_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/* 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 struct direct dd_cur; X} DIR; X#ifndef NULL X#define NULL 0 X#endif Xextern DIR *opendir(); Xextern struct direct *readdir(); Xextern long telldir(); X#define rewinddir(dirp) seekdir((dirp), (long)0) X#define dirfd(dirp) ((dirp)->dd_fd) X#endif END-of-ndir.h echo x - opendir.c sed 's/^X//' >opendir.c << 'END-of-opendir.c' X/* X * Copyright (c) 1987 Regents of the University of California. X * This file may be freely redistributed provided that this X * notice remains attached. X */ X X#include <sys/param.h> X#include <ndir.h> X Xextern char *malloc(); X X/* X * open a directory. X */ XDIR * Xopendir(name) X char *name; X{ X register DIR *dirp; X register int fd; X char *malloc(); X X if ((fd = open(name, 0)) == -1) X return NULL; 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 return dirp; X} END-of-opendir.c echo x - readdir.c sed 's/^X//' >readdir.c << 'END-of-readdir.c' X/* X * Copyright (c) 1987 Regents of the University of California. X * This file may be freely redistributed provided that this X * notice remains attached. X */ X X#include <sys/param.h> X#include <ndir.h> X X/* X * read a V7 directory entry and present it as a BSD4.X entry. X */ X X/* X * get next entry in a directory. X */ Xstruct direct * Xreaddir(dirp) X register DIR *dirp; X{ X register struct v7direct *dp; 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 return NULL; X } X if (dirp->dd_loc >= dirp->dd_size) { X dirp->dd_loc = 0; X continue; X } X dp = (struct v7direct *)(dirp->dd_buf + dirp->dd_loc); X dirp->dd_loc += sizeof(struct v7direct); X if (dp->d_ino == 0) X continue; X /* X * format V7 directory structure into BSD4.X X */ X dirp->dd_cur.d_ino = dp->d_ino; X bcopy(dp->d_name, dirp->dd_cur.d_name, MAXNAMLEN); X /* insure null termination */ X dirp->dd_cur.d_name[MAXNAMLEN] = '\0'; X dirp->dd_cur.d_namlen = strlen(dirp->dd_cur.d_name); X dirp->dd_cur.d_reclen = DIRBLKSIZ; X return (&dirp->dd_cur); X } X} END-of-readdir.c echo x - scandir.3 sed 's/^X//' >scandir.3 << 'END-of-scandir.3' X.\" Copyright (c) 1983 Regents of the University of California. X.\" All rights reserved. The Berkeley software License Agreement X.\" specifies the terms and conditions for redistribution. X.\" X.\" @(#)scandir.3 6.2 (Berkeley) 9/17/85 X.\" X.TH SCANDIR 3 "September 17, 1985" X.UC 5 X.SH NAME Xscandir, alphasort \- scan a directory X.SH SYNOPSIS X.nf X.B #include <sys/types.h> X.B #include <sys/dir.h> X.PP X.B scandir(dirname, namelist, select, compar) X.B char *dirname; X.B struct direct *(*namelist[]); X.B int (*select)(); X.B int (*compar)(); X.PP X.B alphasort(d1, d2) X.B struct direct **d1, **d2; X.fi X.SH DESCRIPTION X.I Scandir Xreads the directory X.I dirname Xand builds an array of pointers to directory Xentries using X.IR malloc (3). XIt returns the number of entries in the array and a pointer to the Xarray through X.IR namelist . X.PP XThe X.I select Xparameter is a pointer to a user supplied subroutine which is called by X.I scandir Xto select which entries are to be included in the array. XThe select routine is passed a Xpointer to a directory entry and should return a non-zero Xvalue if the directory entry is to be included in the array. XIf X.I select Xis null, then all the directory entries will be included. X.PP XThe X.I compar Xparameter is a pointer to a user supplied subroutine which is passed to X.IR qsort (3) Xto sort the completed array. If this pointer is null, the array is not sorted. X.I Alphasort Xis a routine which can be used for the X.I compar Xparameter to sort the array alphabetically. X.PP XThe memory allocated for the array can be deallocated with X.I free X(see X.IR malloc (3)) Xby freeing each pointer in the array and the array itself. X.SH "SEE ALSO" Xdirectory(3), Xmalloc(3), Xqsort(3), Xdir(5) X.SH DIAGNOSTICS XReturns \-1 if the directory cannot be opened for reading or if X.IR malloc (3) Xcannot allocate enough memory to hold all the data structures. END-of-scandir.3 echo x - scandir.c sed 's/^X//' >scandir.c << 'END-of-scandir.c' X/* X * Copyright (c) 1987 Regents of the University of California. X * This file may be freely redistributed provided that this X * notice remains attached. X */ X X/* X * Scan the directory dirname calling select to make a list of selected X * directory entries then sort using qsort and compare routine dcomp. X * Returns the number of entries and a pointer to a list of pointers to X * struct direct (through namelist). Returns -1 if there were any errors. X */ X X#include <sys/types.h> X#include <sys/stat.h> X#include <ndir.h> X Xscandir(dirname, namelist, select, dcomp) X char *dirname; X struct direct *(*namelist[]); X int (*select)(), (*dcomp)(); X{ X register struct direct *d, *p, **names; X register int nitems; X register char *cp1, *cp2; X struct stat stb; X int arraysz; X DIR *dirp; X X if ((dirp = opendir(dirname)) == NULL) X return(-1); X if (fstat(dirp->dd_fd, &stb) < 0) X return(-1); X X /* X * estimate the array size by taking the size of the directory file X * and dividing it by a multiple of the minimum size entry. X */ X arraysz = (stb.st_size / 24); X names = (struct direct **)malloc(arraysz * sizeof(struct direct *)); X if (names == NULL) X return(-1); X X nitems = 0; X while ((d = readdir(dirp)) != NULL) { X if (select != NULL && !(*select)(d)) X continue; /* just selected names */ X /* X * Make a minimum size copy of the data X */ X p = (struct direct *)malloc(DIRSIZ(d)); X if (p == NULL) X return(-1); X p->d_ino = d->d_ino; X p->d_reclen = d->d_reclen; X p->d_namlen = d->d_namlen; X for (cp1 = p->d_name, cp2 = d->d_name; *cp1++ = *cp2++; ); X /* X * Check to make sure the array has space left and X * realloc the maximum size. X */ X if (++nitems >= arraysz) { X if (fstat(dirp->dd_fd, &stb) < 0) X return(-1); /* just might have grown */ X arraysz = stb.st_size / 12; X names = (struct direct **)realloc((char *)names, X arraysz * sizeof(struct direct *)); X if (names == NULL) X return(-1); X } X names[nitems-1] = p; X } X closedir(dirp); X if (nitems && dcomp != NULL) X qsort(names, nitems, sizeof(struct direct *), dcomp); X *namelist = names; X return(nitems); X} X X/* X * Alphabetic order comparison routine for those who want it. X */ Xalphasort(d1, d2) X struct direct **d1, **d2; X{ X return(strcmp((*d1)->d_name, (*d2)->d_name)); X} END-of-scandir.c echo x - seekdir.c sed 's/^X//' >seekdir.c << 'END-of-seekdir.c' X/* X * Copyright (c) 1987 Regents of the University of California. X * This file may be freely redistributed provided that this X * notice remains attached. X */ X X#include <sys/param.h> X#include <ndir.h> X X/* X * seek to an entry in a directory. X * Only values returned by "telldir" should be passed to seekdir. X */ 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 lseek(dirp->dd_fd, base, 0); X dirp->dd_loc = 0; X while (dirp->dd_loc < offset) { X dp = readdir(dirp); X if (dp == NULL) X return; X } X} END-of-seekdir.c echo x - telldir.c sed 's/^X//' >telldir.c << 'END-of-telldir.c' X/* X * Copyright (c) 1987 Regents of the University of California. X * This file may be freely redistributed provided that this X * notice remains attached. X */ X X#include <sys/types.h> X#include <ndir.h> X X/* X * return a pointer into a directory X */ Xlong Xtelldir(dirp) X DIR *dirp; X{ X return (lseek(dirp->dd_fd, 0L, 1) - dirp->dd_size + dirp->dd_loc); X} END-of-telldir.c exit
gwyn@brl-smoke.UUCP (03/28/87)
In article <264@aecom2.UUCP> jschwart@aecom2.UUCP (Joseph Schwartz) writes: >... Well, he seems to have left off seekdir(3). You might as well nuke seekdir() and telldir(). On some systems (such as 4.3BSD), no simple implementation of these routines will work right in all circumstances. I've had quite a time trying to make "rm -r" work, and keep stumbling over interesting phenomena such as directories being reshuffled by the kernel while I'm still using them, etc. I think this sort of thing is what led IEEE 1003.1 to drop these specific routines from the POSIX spec.
guy@gorodish.UUCP (03/30/87)
>I was moving rn over to a 3b2 running SysVr3 and found that it's >already got the directory reading stuff in /lib/libc.a (A first!). >HOWEVER (argh! argh! argh!) they changed the names: "They" didn't change the names. The IEEE P1003.1 committee did, and they had a good reason; some systems (like all the ones with V7 file systems, including S5) already *have* a "struct direct" which is the native directory entry structure. The 4BSD one used the same format for on-disk directory entries and entries as returned by "readdir", so they could get away with this.
rbj@icst-cmr.arpa (03/30/87)
From: Guy Harris <guy%gorodish@Sun.COM> I'll repost Kirk McKusick's original directory library... #!/bin/csh # Run this file as shell script I thought we didn't post csh scripts. And this one would seem to run just as well with /bin/sh. And if we *do* use csh, -f would work better, unless it's a setuid lpd script :-) (Root Boy) Jim "Just Say Yes" Cottrell <rbj@icst-cmr.arpa> I just remembered something about a TOAD!
guy@gorodish.UUCP (03/31/87)
> I thought we didn't post csh scripts. And this one would seem to > run just as well with /bin/sh. And if we *do* use csh, -f would > work better, unless it's a setuid lpd script :-) Fine. Tell Kirk; I don't give a damn, I just reposted it *verbatim*. If you want to unwrap and rewrap it, feel free.