[net.wanted] directory functions

netnews@wnuxb.UUCP (Ron Heiby) (08/10/84)

I am running on Unix System V, and find myself in need of a copy of
the functions for directory manipulation (opendir, readdir, closedir, other?)
and their man pages (if possible).  Thanks much.
-- 
-- 
	________________
	| __________   |	from the overlapping windows
	| | ksh!   |   |		of
	| |__________  |
	|  | gmacs! |  |	Ronald W. Heiby
	|  | _________ |	AT&T Technologies, Inc.
	|  | |dstar! | |	Lisle, IL  (CU-D21)
	|  | |       | |  __	...!ihnp4!wnuxa!heiby
	|  --|       | |_/  \_____
	|    --------- |    /\    \_
	|              |    \/      \+++
	|TTY_______5620|            /   \
	----------------            (red)
                                    \___/

steffen@ihu1h.UUCP (Joe Steffen) (08/11/84)

I just ported 4 programs that read directories to BSD 4.2, so I recoded
them to use the directory functions and then #include a file containing
---------
#ifdef BSD4_2
#ifndef MAXNAMLEN
#include <sys/dir.h>
#endif
#define	statdir(file, statp)	fstat(file->dd_fd, statp)
#else
#ifndef DIRSIZ
#include <sys/dir.h>
#endif
#define MAXNAMLEN	DIRSIZ
#define	DIR		FILE
#define opendir(name)		fopen(name, "r")
#define closedir(file)		fclose(file)
#define rewinddir(file)		rewind(file)
#define	statdir(file, statp)	fstat(fileno(file), statp)
#define readdir(file)		(struct direct *) \
	(fread(entrybuf, (int) sizeof(struct direct), 1, file) == 1 ? \
	entrybuf : NULL)
/* allow for a terminating null on the name */
/* note: the last structure field must be the name */
static	char	entrybuf[sizeof(struct direct) + 1];
#endif
---------

statdir() below is not a BSD routine but I found it useful when recoding
fstat() calls on an open directory file descriptor.

MAXNAMLEN replaces the use of DIRSIZ, which is a macro in BSD 4.2.

The macros are better than functions because you don't lose any speed,
which is important in a routine that figures out the current working
directory.  I have such a routine that is faster than getcwd(3), curdir()
in -lPW, and even the getwd() posted recently to the net.  There is no
noticable pause when starting a program that calls this routine.  For those
interested here it is:
---------
#ifndef BSD4_2
/*
 *	getwd(dir)
 *
 *	Get the full pathname of the current directory.
 *
 *	returns: a pointer to dir on success.
 *		 NULL on failure.
 *
 *	Current directory upon return from getwd:
 *
 *		success: same as on entry
 *		failure: If a failure is noted during processing getwd
 *			backs out of it's traversal and restores the
 *			current directory to what it was upon entry.
 *			Of course there are pathological corruptions
 *			to the file system which can totally confuse
 *			getwd.
 *
*/

#include <sys/types.h>	/* used by stat.h */
#include <sys/stat.h>	/* stat */
#include <sys/dir.h>	/* direct */
#include <sys/param.h>	/* ROOTINO */
#include <stdio.h>	/* NULL */
#include "ndir.h"	/* directory access macros */

#define YES	1
#define NO 	0

extern char	*strcat(), *strcpy(), *strncpy();

char *
getwd(dir)
register char	*dir; 	/* destination buffer for name so far */
{
	register DIR *dirfile;		/* directory file descriptor */
	char	namebuf[256+1];		/* buffer for recursivly building path */
	char	cofp[MAXNAMLEN + 5]; 	/* child of parent name */
	char	*child;			/* child name */
	struct	stat	d_sb;  		/* current directory status */
	struct	stat	dd_sb; 		/* parent directory status */
	struct	stat	tmp_sb; 	/* temporary stat buffer */
	int	atmount = NO;		/* at root of a mounted file system */
	struct	direct	*p;

	if ((dirfile = opendir("..")) == NULL)
		return(NULL);

	if (stat(".", &d_sb) < 0 || statdir(dirfile, &dd_sb) < 0) {
		(void) closedir(dirfile);
		return(NULL);
	}
	/*
	 * Determine if at a mount point or at the root of the root 
	 * file system.
	 */
	if (d_sb.st_ino == ROOTINO) {
		atmount = YES;
		if ((d_sb.st_ino == dd_sb.st_ino)
		     && (d_sb.st_dev == dd_sb.st_dev)) {
			(void) strcpy(dir, "/"); /* start out right */
			(void) closedir(dirfile);
			return(dir);  		/* start to unwind */
		}
	}
	/*  find the name of "."  in ".." */
	(void) strcpy(cofp, "../");
	child = cofp + 3;
	for (;;) {
		if ((p = readdir(dirfile)) == NULL) {
			(void) closedir(dirfile);
			return(NULL);
		}
		if (p->d_ino == 0)
			continue;
		if (p->d_ino == d_sb.st_ino || atmount == YES) {
			(void) strcpy(child, p->d_name);
			/* 
			 * Must stat all the files in the parent 
			 * directory if the current directory is a mount
			 * point because stat returns a different inode
			 * number than is in the parent's directory.
			 */
			if (stat(cofp, &tmp_sb) < 0)  {
				(void) closedir(dirfile);
				return(NULL);
			}
			if ((tmp_sb.st_ino == d_sb.st_ino)
			    && (tmp_sb.st_dev == d_sb.st_dev))
				break;  /* found it */
		}
	}
	(void) closedir(dirfile);
	if (chdir("..") < 0)
		return(NULL);

	/* namebuf used as destination for invoking child */
	if (getwd(namebuf) == NULL)  {

		/* failure - backout by changing to child directory */
		(void) chdir(child);
		return(NULL);
	} else {
		/* 
		 * As the tail recursion unwinds add the current
		 * directoriy's name to the end of 'namebuf',
		 * and copy 'namebuf' to 'dir', while 
		 * descending the tree to the directory of 
		 * invocation.
		 */
		(void) strcpy(dir, namebuf);
		if (*(namebuf + strlen(namebuf) - 1) != '/') {
			/* previous call didn't find root */
			(void) strcat(dir, "/");
		}
		(void) strcat(dir, child);

		/* return to directory of invocation */
		(void) chdir(child);
		return(dir);
	}
}
#endif

-- 


	Joe Steffen, AT&T Bell Labs, Naperville, IL, (312) 979-5381