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