jejones@ea.UUCP (10/31/84)
Attached is, in shar form, header files and code for a directory tree
walker. There are some perhaps dubious design decisions therein, notably
the decision about how to treat files one can't open (but then, one
shouldn't pass them by--what if you want to walk the file system to
find exactly those files you can't open?), but on the whole it seems
a reasonable tool. (Perhaps someone out there will write and post a
find before I do...) An rdump indicates that the compiled code is
a hair over 1K (if memory serves), which seems rather nice.
Share and enjoy,
James Jones
------------------------------TARE HEAR------------------------------
# This is a shell archive. Remove anything before this line, then
# unpack it by saving it in a file and typing "sh file". (Files
# unpacked will be owned by you and have default permissions.)
#
# This archive contains:
# bool.h WalkFS.h WalkFS.c
echo x - bool.h
sed 's/^ //' > "bool.h" << '//E*O*F bool.h//'
/*
* bool.h -- for those who, like me, would really like to have
* something approaching a Boolean type in C, when we are forced
* to use C.
*/
typedef int bool;
#define TRUE 1
#define FALSE 0
//E*O*F bool.h//
echo x - WalkFS.h
sed 's/^ //' > "WalkFS.h" << '//E*O*F WalkFS.h//'
/*
* WalkFS.h -- definitions for values returned from and parameters for
* the WalkFS() function.
*/
#define OK 0 /* WalkFS() succeeded */
#define TooDeep 1 /* tree too deep for WalkFS() */
#define Stymie 2 /* WalkFS() couldn't even start walking */
#define BadDir 3 /* directory opened, but looks wrong */
#define MungDir 4 /* directory tweaked behind our backs */
#define VisitSuccess 5 /* visit returned non-zero value for */
/* pathname (see AsSoonAs) */
#define VisitDir -1 /* visit only directories */
#define VisitNDir 1 /* visit only non-directories */
#define VisitAll 0 /* visit files whether directory or not */
#define PreOrder 0 /* do a pre-order traversal */
#define PostOrder 1 /* do a post-order traversal */
#define Ignore 0 /* ignore results of visit function */
#define AsSoonAs 1 /* return as soon as visit returns */
/* non-zero value */
//E*O*F WalkFS.h//
echo x - WalkFS.c
sed 's/^ //' > "WalkFS.c" << '//E*O*F WalkFS.c//'
/*
* WalkFS -- file system walker, or an iterator if you will.
*
* Parameters:
* a string with the pathname of the file to consider the root, a pointer
* to the function to use to visit files, an indicator of which files
* (directories, non-directories, or all files) to visit, an indicator
* of whether to do a pre-order or post-order walk, and an indicator of
* whether to quit early.
*
* "Visiting" a file, to WalkFS, means invoking the referenced
* function, with a pointer to the pathname of the file as argument.
* The visiting function is presumed to return an int; depending on
* the parameters passed, WalkFS can quit the first time the function
* returns a non-zero value.
*
* Method:
* WalkFS does a (non-recursive) traversal. This implies that we must
* remember where we are in each of the directories in the path down
* to where we are looking at any given moment. We can't always keep
* all those directories open, since a process is limited in the number
* of files it can have open concurrently, so when we run out, we re-
* member our position in the highest-level (nearest the root) directory
* we have open and then close it, making room for a new low-level
* directory to open.
*
* Warnings:
* 1. We do some checking if we re-open directories to make sure
* that nothing horrible happened behind our backs. This checking
* isn't as thorough as it might be.
* 2. If you visit directories in pre-order, then WalkFS() will have
* them open while you visit them. In all other cases, WalkFS()
* won't have the file being visited open. This is important if
* Visit() modifies (or deletes, for that matter) the file!
* 3. If we can't open a file, we can't tell whether it's a directory.
* By fiat, we will treat such files as "non-directories."
*/
#include <stdio.h>
#include <errno.h>
#include <direct.h>
#include <modes.h>
#include <WalkFS.h>
#include <bool.h>
#define MAXPATH 512
#define NOFL 20
#define DESIZE sizeof(struct dirent)
int
WalkFS(Root, Visit, Itinerary, Order, QuitEarly)
char *Root;
int (*Visit)();
int Itinerary, Order, QuitEarly;
{
bool DirVisit, NDirVisit;
int PathNo, PathStack[_NFILE];
long OflStack[NOFL];
int PathTop, OflTop;
char PathName[MAXPATH];
int PNEnd;
struct dirent DEntry;
int i;
PathTop = OflTop = -1;
DirVisit = Itinerary <= 0;
NDirVisit = Itinerary >= 0;
if ((PNEnd = strlen(Root)) >= MAXPATH)
return(TooDeep);
strcpy(PathName, Root);
if ((PathNo = open(PathName, S_IREAD | S_IFDIR)) < 0 &&
(PathNo = open(PathName, S_IREAD) < 0)
)
return(Stymie);
close(PathNo);
for (;;) {
PathNo = open(PathName, S_IREAD | S_IFDIR);
if (PathNo < 0 && errno == E_PTHFUL) {
if (OflTop >= NOFL) {
BigClose(PathStack, PathTop);
return(TooDeep);
}
OflStack[++OflTop] = lseek(PathStack[0], 0L, 1);
close(PathStack[0]);
for (i = 0; i < PathTop; i++)
PathStack[i] = PathStack[i + 1];
PathNo = open(PathName, S_IREAD | S_IFDIR);
}
if (PathNo >= 0) {
if (DirVisit && Order == PreOrder)
if ((*Visit)(PathName) && QuitEarly) {
BigClose(PathStack, PathTop);
return(VisitSuccess);
}
if (lseek(PathNo, (long) (2 * DESIZE), 0) < 0) {
BigClose(PathStack, PathTop);
return(BadDir);
}
PathStack[++PathTop] = PathNo;
} else {
if (NDirVisit)
if ((*Visit)(PathName) && QuitEarly) {
BigClose(PathStack, PathTop);
return(VisitSuccess);
}
PNEnd = DelEntry(PathName, PNEnd);
}
for (;;) {
if (PathTop < 0 && OflTop < 0)
return(OK);
if (read(PathStack[PathTop], &DEntry, DESIZE) != DESIZE)
{
close(PathStack[PathTop--]);
if (DirVisit && Order == PostOrder)
if ((*Visit)(PathName) && QuitEarly)
{
BigClose(PathStack, PathTop);
return(VisitSuccess);
}
PNEnd = DelEntry(PathName, PNEnd);
if (PathTop < 0 && OflTop >= 0) {
PathNo = open(PathName, S_IREAD);
if (PathNo < 0 ||
lseek(PathNo, OflStack[OflTop--], 0) < 0)
{
BigClose(PathStack, PathTop);
return(MungDir);
}
PathStack[++PathTop] = PathNo;
}
} else if (DEntry.dir_name[0] != '\0') {
PNEnd = AddEntry(PathName, &DEntry, PNEnd);
if (PNEnd < 0) {
BigClose(PathStack, PathTop);
return(TooDeep);
}
break;
}
}
}
}
/*
* BigClose -- close all the files that WalkFS has sitting around open;
* called in case of problems that we want to get out of immediately.
* (In the normal course of events, the directories that WalkFS opens
* are closed after they've been read in their entirety.)
*/
static
BigClose(PList, Top)
int PList[];
int Top;
{
int i;
for (i = 0; i <= Top; i++)
close(PList[i]);
}
/*
* AddEntry, DelEntry--adding and deleting bottom-level branches
* from pathnames
*
* These functions expect someone to keep track of the index in the
* pathname of the terminating '\0', and return a new value for that
* index (or -1 in case of error). Perhaps this is too specialized.
* Note also that the incoming entry in AddEntry is a real live
* directory entry, with high-order bit terminated string and all.
*/
static int
AddEntry(Path, Entry, Tail)
char Path[];
struct dirent *Entry;
int Tail;
{
int i;
if (Tail < MAXPATH) {
Path[Tail++] = '/';
for (i = 0; Tail < MAXPATH; i++) {
if (Entry->dir_name[i] & 0x80) {
Path[Tail++] = Entry->dir_name[i] & 0x7f;
if (Tail >= MAXPATH)
break;
Path[Tail] = '\0';
return(Tail);
} else
Path[Tail++] = Entry->dir_name[i];
}
}
return(-1);
}
static int
DelEntry(Path, Tail)
char Path[];
int Tail;
{
for (; Tail > 0; Tail--)
if (Path[Tail] == '/')
break;
Path[Tail] = '\0';
return(Tail);
}
//E*O*F WalkFS.c//
exit 0