[comp.os.minix] BSD style dir access

dono@killer.DALLAS.TX.US (Don OConnell) (12/15/88)

This is from an old archive that I had at home - there is a more recent one
in comp.sources.unix archives. These work fine for my uses.

Compile closedir opendir seekdir readdir telldir and put them at the end of 
libca in the order listed above. 

These routines were originally done by D. A. Gwyn - if I am not mistaken.

-----------------------------CUT HERE-------------------------------------

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  READ_ME closedir.c dir.h directory.3c opendir.c readdir.c
#   seekdir.c telldir.c testdir.c
# Wrapped by dono@killer on Wed Dec 14 12:33:20 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f READ_ME -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"READ_ME\"
else
echo shar: Extracting \"READ_ME\" \(3777 characters\)
sed "s/^X//" >READ_ME <<'END_OF_READ_ME'
X	NOTES FOR C LIBRARY EXTENSIONS FOR DIRECTORY ACCESS
X
X
XThe standard C library lacks support for reading UNIX directories, so
Xhistorically programs had knowledge of UNIX directory structure hard-
Xwired into them.  When Berkeley changed the format of directories for
X4.2BSD, it became necessary to change programs to work with the new
Xstructure.  Fortunately Berkeley designed a small set of directory
Xaccess routines to encapsulate knowledge of the new directory format
Xso that user programs could deal with directory entries as an abstract
Xdata type.  The interface to these routines is independent of the
Xparticular implementation of directories on any given UNIX system.
X
XTherefore it becomes possible to write portable applications that
Xsearch directories by restricting all directory access to these new
Xinterface routines.  The sources supplied here are a total rewrite of
XBerkeley's code and are in the PUBLIC DOMAIN.  They simulate the new
X4.2BSD directory entries on systems having the original UNIX directory
Xstructure.  These routines should be added to the standard C library
Xon ALL non-BSD UNIX systems and all existing and future code changed to
Xuse this interface.  Once this is done, there will be no portability
Xproblems associated with the difference in underlying directory
Xstructures between 4.2BSD and other UNIX systems.
X
XAn additional benefit of these routines is that they buffer directory
Xinput, which provides improved access speed.
X
X
X			INSTALLATION INSTRUCTIONS
X
X
XIf your system predates 7th Edition UNIX you have problems.  Adapt the
Xinstructions and source code as required, or better still upgrade your
Xsystem (a modern compiler and library can be made to run on an older
Xkernel with a modest amount of work).
X
X
XFor systems (such as pre-System III UNIXes) that do not support C's
X"void" data type:
X
X0)  Edit the file ./include/dir.h to insert the following line before
X    the first occurrence of the word "void":
X
X	typedef int	void;
X
X
XFor 7th Edition or later UNIXes (but NOT 4.2BSD):
X
X1)  Copy the file ./include/dir.h to /usr/include (note that there is
X    NOT a conflict with /usr/include/sys/dir.h).
X
X2)  Copy the file ./man/directory.3c to /usr/man/p_man/man3,
X    /usr/man/u_man/man3, or /usr/man/man3; then print the manual page
X    via the command
X
X	man 3 directory
X
X    to see what the new routines are like.  (If you have a "catman"
X    type of on-line manual, adapt these instructions accordingly.)
X
X3)  Copy the files ./src/* to the "gen" subdirectory of your C library
X    source directory, then remake the C library.  Alternatively you
X    might just compile the new sources and insert their objects near
X    the front of the C library /lib/libc.a using the archiver (seekdir
X    must precede telldir and readdir).
X
X4)  To verify installation, try compiling, linking, and running the
X    program test/testdir.c.  This program searches the current
X    directory "." for each file named as a program argument and prints
X    `"FOO" found.' or `"FOO" not found.' where FOO is replaced by the
X    name being looked for in the directory.  Try something like
X
X	cd /usr/bin			# a multi-block directory
X	WHEREVER/testdir FOO lint BAR f77 XYZZY
X
X    which should produce the output
X
X	"FOO" not found.
X	"lint" found.
X	"BAR" not found.
X	"f77" found.
X	"XYZZY" not found.
X
X5)  Notify your users that all directory access must be through the
X    new routines, and that documentation is available via
X
X	man 3 directory
X
X6)  Change all system sources that were accessing directories to use
X    the new routines.  Nearly all such sources contain the line
X
X	#include <sys/dir.h>
X
X    so they should be easy to find.
X
X7)  After a suitable changeover period, remove /usr/include/sys/dir.h
X    to force use of the new routines for all directory access.
END_OF_READ_ME
if test 3777 -ne `wc -c <READ_ME`; then
    echo shar: \"READ_ME\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f closedir.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"closedir.c\"
else
echo shar: Extracting \"closedir.c\" \(271 characters\)
sed "s/^X//" >closedir.c <<'END_OF_closedir.c'
X/*
X	closedir -- C library extension routine
X
X	last edit:	21-Jan-1984	D A Gwyn
X*/
X
X#include	<dir.h>
X
Xextern void	free();
Xextern int	close();
X
Xvoid
Xclosedir( dirp )
X	register DIR	*dirp;		/* stream from opendir() */
X	{
X	(void)close( dirp->dd_fd );
X	free( (char *)dirp );
X	}
END_OF_closedir.c
if test 271 -ne `wc -c <closedir.c`; then
    echo shar: \"closedir.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f dir.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"dir.h\"
else
echo shar: Extracting \"dir.h\" \(927 characters\)
sed "s/^X//" >dir.h <<'END_OF_dir.h'
X/*
X	<dir.h> -- definitions for 4.2BSD-compatible directory access
X
X	last edit:	09-Jul-1983	D A Gwyn
X*/
X
X#define DIRBLKSIZ	512		/* size of directory block */
X#define MAXNAMLEN	15		/* maximum filename length */
X	/* NOTE:  MAXNAMLEN must be one less than a multiple of 4 */
X
Xstruct direct				/* data from readdir() */
X	{
X	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 of file */
X	};
X
Xtypedef struct
X	{
X	int	dd_fd;			/* file descriptor */
X	int	dd_loc;			/* offset in block */
X	int	dd_size;		/* amount of valid data */
X	char	dd_buf[DIRBLKSIZ];	/* directory block */
X	}	DIR;			/* stream data from opendir() */
X
Xextern DIR		*opendir();
Xextern struct direct	*readdir();
Xextern long		telldir();
Xextern void		seekdir();
Xextern void		closedir();
X
X#define rewinddir( dirp )	seekdir( dirp, 0L )
END_OF_dir.h
if test 927 -ne `wc -c <dir.h`; then
    echo shar: \"dir.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f directory.3c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"directory.3c\"
else
echo shar: Extracting \"directory.3c\" \(2748 characters\)
sed "s/^X//" >directory.3c <<'END_OF_directory.3c'
X.TH DIRECTORY 3 "Standard Extension"
X.SH NAME
Xopendir, readdir, telldir, seekdir, rewinddir, closedir \- directory operations
X.SH SYNOPSIS
X.B #include <dir.h>
X.PP
X.B DIR \(**opendir (filename)
X.br
X.B char \(**filename;
X.PP
X.B struct direct \(**readdir (dirp)
X.br
X.B DIR \(**dirp;
X.PP
X.B long telldir (dirp)
X.br
X.B DIR \(**dirp;
X.PP
X.B void seekdir (dirp, loc)
X.br
X.B DIR \(**dirp;
X.br
X.B long loc;
X.PP
X.B void rewinddir (dirp)
X.br
X.B DIR
X.B *dirp;
X.PP
X.B void
X.B closedir(dirp)
X.br
X.B DIR
X.B *dirp;
X.SM
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.
XThe pointer
X.SM
X.B NULL
Xis returned if
X.I filename\^
Xcannot be accessed or is not a directory,
Xor if it cannot
X.IR malloc (3)
Xenough memory to hold a
X.SM
X.I DIR\^
Xstructure.
X.PP
X.I Readdir\^
Xreturns a pointer to the next directory entry.
XIt returns
X.SM
X.B NULL
Xupon reaching the end of the directory or
Xupon 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 from which
X.I loc\^
Xwas obtained was performed.
XValues returned by
X.I telldir\^
Xare good only for the lifetime of
Xthe DIR pointer from which they are derived.
XIf the directory is closed and then reopened,
Xthe 
X.I telldir\^
Xvalue may be invalidated
Xdue 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
X.SM
X.I DIR\^
Xstructure.
X.SH EXAMPLE
XSample code which searchs a directory for entry ``name'':
X.PP
X.br
X	dirp = opendir( "." );
X.br
X	while ( (dp = readdir( dirp )) != NULL )
X.br
X		if ( strcmp( dp->d_name, name ) == 0 )
X.br
X			{
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), close(2), read(2), lseek(2),
Xscandir(3B)
X.SH WARNINGS
X.I Rewinddir\^
Xis implemented as a macro,
Xso its function address cannot be taken.
X.PP
XAll UNIX programs which examine directories
Xshould be converted to use this package,
Xsince directory format is no longer the same on all UNIX systems.
XUnfortunately,
Xthis package is not yet
Xsupplied with all UNIX systems,
Xalthough public-domain source code is available
Xfrom BRL.
END_OF_directory.3c
if test 2748 -ne `wc -c <directory.3c`; then
    echo shar: \"directory.3c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f opendir.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"opendir.c\"
else
echo shar: Extracting \"opendir.c\" \(838 characters\)
sed "s/^X//" >opendir.c <<'END_OF_opendir.c'
X/*
X	opendir -- C library extension routine
X
X	last edit:	09-Jul-1983	D A Gwyn
X*/
X
X#include	<dir.h>
X#include	<sys/types.h>
X#include	<sys/stat.h>
X
X#ifdef	BRL
X#define open	_open			/* avoid emulation */
X#endif
X
Xextern char	*malloc();
Xextern int	open(), close(), fstat();
X
X#define NULL	0
X
XDIR *
Xopendir( filename )
X	char		*filename;	/* name of directory */
X	{
X	register DIR	*dirp;		/* -> malloc'ed storage */
X	register int	fd;		/* file descriptor for read */
X	struct stat	sbuf;		/* result of fstat() */
X
X	if ( (fd = open( filename, 0 )) < 0 )
X		return NULL;
X
X	if ( fstat( fd, &sbuf ) < 0
X	  || (sbuf.st_mode & S_IFMT) != S_IFDIR
X	  || (dirp = (DIR *)malloc( sizeof(DIR) )) == NULL
X	   )	{
X		(void)close( fd );
X		return NULL;		/* bad luck today */
X		}
X
X	dirp->dd_fd = fd;
X	dirp->dd_loc = dirp->dd_size = 0;	/* refill needed */
X
X	return dirp;
X	}
END_OF_opendir.c
if test 838 -ne `wc -c <opendir.c`; then
    echo shar: \"opendir.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f readdir.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"readdir.c\"
else
echo shar: Extracting \"readdir.c\" \(1259 characters\)
sed "s/^X//" >readdir.c <<'END_OF_readdir.c'
X/*
X	readdir -- C library extension routine for non-BSD UNIX
X
X	last edit:	09-Jul-1983	D A Gwyn
X*/
X
X#include	<dir.h>
X#include	<sys/types.h>
X
Xextern char	*strncpy();
Xextern int	read(), strlen();
X
X#define NULL	0
X
X#define DIRSIZ	14
Xstruct olddir
X	{
X	ino_t	od_ino; 		/* inode */
X	char	od_name[DIRSIZ];	/* filename */
X	};
X
Xstruct direct *
Xreaddir( dirp )
X	register DIR		*dirp;	/* stream from opendir() */
X	{
X	register struct olddir	*dp;	/* -> directory data */
X
X	for ( ; ; )
X		{
X		if ( dirp->dd_loc >= dirp->dd_size )
X			dirp->dd_loc = dirp->dd_size = 0;
X
X		if ( dirp->dd_size == 0 	/* refill buffer */
X		  && (dirp->dd_size = read( dirp->dd_fd, dirp->dd_buf, 
X					    DIRBLKSIZ
X					  )
X		     ) <= 0
X		   )
X			return NULL;	/* error or EOF */
X
X		dp = (struct olddir *)&dirp->dd_buf[dirp->dd_loc];
X		dirp->dd_loc += sizeof(struct olddir);
X
X		if ( dp->od_ino != 0 )	/* not deleted entry */
X			{
X			static struct direct	dir;	/* simulated */
X
X			dir.d_ino = dp->od_ino;
X			(void)strncpy( dir.d_name, dp->od_name, DIRSIZ
X				     );
X			dir.d_name[DIRSIZ] = '\0';
X			dir.d_namlen = strlen( dir.d_name );
X			dir.d_reclen = sizeof(struct direct)
X				     - MAXNAMLEN + 3
X				     + dir.d_namlen - dir.d_namlen % 4;
X			return &dir;	/* -> simulated structure */
X			}
X		}
X	}
END_OF_readdir.c
if test 1259 -ne `wc -c <readdir.c`; then
    echo shar: \"readdir.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f seekdir.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"seekdir.c\"
else
echo shar: Extracting \"seekdir.c\" \(670 characters\)
sed "s/^X//" >seekdir.c <<'END_OF_seekdir.c'
X/*
X	seekdir -- C library extension routine
X
X	last edit:	21-Jan-1984	D A Gwyn
X*/
X
X#include	<dir.h>
X
Xextern long	lseek();
X
X#define NULL	0
X
Xvoid
Xseekdir( dirp, loc )
X	register DIR	*dirp;		/* stream from opendir() */
X	long		loc;		/* position from telldir() */
X	{
X	long		base;		/* file location of block */
X	long		offset; 	/* offset within block */
X
X	if ( telldir( dirp ) == loc )
X		return; 		/* save time */
X
X	offset = loc % DIRBLKSIZ;
X	base = loc - offset;
X
X	(void)lseek( dirp->dd_fd, base, 0 );	/* change blocks */
X	dirp->dd_loc = dirp->dd_size = 0;
X
X	while ( dirp->dd_loc < offset ) /* skip entries */
X		if ( readdir( dirp ) == NULL )
X			return; 	/* "can't happen" */
X	}
END_OF_seekdir.c
if test 670 -ne `wc -c <seekdir.c`; then
    echo shar: \"seekdir.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f telldir.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"telldir.c\"
else
echo shar: Extracting \"telldir.c\" \(276 characters\)
sed "s/^X//" >telldir.c <<'END_OF_telldir.c'
X/*
X	telldir -- C library extension routine
X
X	last edit:	09-Jul-1983	D A Gwyn
X*/
X
X#include	<dir.h>
X
Xextern long	lseek();
X
Xlong
Xtelldir( dirp )
X	DIR	*dirp;			/* stream from opendir() */
X	{
X	return lseek( dirp->dd_fd, 0L, 1 ) - (long)dirp->dd_size
X	     + (long)dirp->dd_loc;
X	}
END_OF_telldir.c
if test 276 -ne `wc -c <telldir.c`; then
    echo shar: \"telldir.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f testdir.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"testdir.c\"
else
echo shar: Extracting \"testdir.c\" \(889 characters\)
sed "s/^X//" >testdir.c <<'END_OF_testdir.c'
X/*
X	testdir -- test for C library directory access extensions
X
X	last edit:	09-Jul-1983	D A Gwyn
X*/
X
X#include	<dir.h>
X#include	<stdio.h>
X
Xextern void	exit();
Xextern int	strcmp(), strlen();
X
Xmain( argc, argv )
X	int			argc;
X	char			**argv;
X	{
X	register DIR		*dirp;
X	register struct direct	*dp;
X	int			nerrs = 0;	/* total not found */
X
X	if ( (dirp = opendir( "." )) == NULL )
X		{
X		(void)fprintf( stderr, "Cannot open \".\" directory\n"
X			     );
X		exit( 1 );
X		}
X
X	while ( --argc > 0 )
X		{
X		register int	len = strlen( *++argv );
X
X		while ( (dp = readdir( dirp)) != NULL )
X			if ( dp->d_namlen == len
X			  && strcmp( dp->d_name, *argv ) == 0
X			   )	{
X				(void)printf( "\"%s\" found.\n",
X					      *argv
X					    );
X				break;
X				}
X		if ( dp == NULL )
X			{
X			(void)printf( "\"%s\" not found.\n", *argv );
X			++nerrs;
X			}
X
X		rewinddir( dirp );
X		}
X
X	closedir( dirp );
X	exit( nerrs );
X	}
END_OF_testdir.c
if test 889 -ne `wc -c <testdir.c`; then
    echo shar: \"testdir.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0