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

Joe Pruett joey at tessi.UUCP
Sun Dec 10 15:33:40 AEST 1989


Original-posting-by: joey at tessi.UUCP (Joe Pruett)
Reposted-by: emv at math.lsa.umich.edu (Edward Vielmetti)
Posting-id: 891210.0435
Posting-number: Volume TEST, Number TEST
Archive-name: descend

[This is an experimental alt.sources re-posting from the
newsgroup(s) comp.unix.wizards.
No attempt has been made to edit, clean, modify, or otherwise
change the contents of the original posting, or to contact the
author.  Please consider cross-posting all sources postings to
alt.sources as a matter of course.]

[Comments on this service to emv at math.lsa.umich.edu (Edward Vielmetti)]

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 Alt.sources mailing list