ftw (was Re: Anything faster than stat(S)? ...)

Joe Pruett joey at tessi.UUCP
Sat Dec 9 12:06:48 AEST 1989


A quick hack I've used in a directory traversal program is to use the
link count of . to determine how many subdirectories there are.  If .
has no subdirectories, then you don't have to stat every file name.
Since most of the files tend to be at the end of the tree, you really
save time because none of them get stat'ed.  Here's the program I use
instead of find . -print.  It puts a / at the end of directory names
so you can use egrep '/$' or the like.  It also takes a switch of
-d for depth first printout, or -h for "heighth" first printout.
You can replace the echo function with something else if you
want a canned program, but this combined with an egrep and xargs
fixes most of the problems you want to solve for a directory
tree.  Some quick timings on a sun 3/260 with local disk show:

find . -print > /dev/null			0.4u 3.3s 0:16
descend . > /dev/null				0.4u 1.8s 0:02

With 1485 files (195 of which are directories).

--------

#include <stdio.h>
#include <sys/types.h>
#include <sys/dir.h>
#include <sys/stat.h>
#include <strings.h>

int numErrors;
int depth = 1;

int
echo(s)
char *s;
{
	printf("%s\n", s);
}

void
descend(name, command)
char *name;
int (*command)();
{
	struct stat stb;
	DIR *dirp;
	struct direct *dp;
	int ndirs;
	char buf[1024];

	if (lstat(name, &stb) != 0) {
		perror(name);
		numErrors++;
		return;
	}
	if ((stb.st_mode & S_IFDIR) == 0) {
		(void)strcpy(buf, name);
		(*command)(buf);
		return;
	}
	ndirs = stb.st_nlink - 2;
	if ((dirp = opendir(name)) == NULL) {
		perror(name);
		numErrors++;
		return;
	}
	if (depth == 0) {
		(void)strcpy(buf, name);
		(void)strcat(buf, "/");
		(*command)(buf);
	}
	for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
		if (strcmp(dp->d_name, ".") == 0
		|| strcmp(dp->d_name, "..") == 0) {
			continue;
		}
		(void)strcpy(buf, name);
		(void)strcat(buf, "/");
		(void)strcat(buf, dp->d_name);
		if (ndirs) {
			if (lstat(buf, &stb) != 0) {
				perror(buf);
				numErrors++;
				continue;
			}
			if ((stb.st_mode & S_IFDIR) != 0) {
				ndirs--;
				descend(buf, command);
			} else {
				(*command)(buf);
			}
		} else {
			(*command)(buf);
		}
	}
	if (depth == 1) {
		(void)strcpy(buf, name);
		(void)strcat(buf, "/");
		(*command)(buf);
	}
	closedir(dirp);
}

main(argc, argv)
int argc;
char **argv;
{
	argc--;
	argv++;
	while (argc) {
		if ((*argv)[0] == '-') {
			switch ((*argv)[1]) {
			case 'd':
				depth = 1;
				break;
			case 'h':
				depth = 0;
				break;
			}
		} else {
			descend(*argv, echo);
		}
		argc--;
		argv++;
	}
	exit (numErrors);
}



More information about the Comp.unix.wizards mailing list