joey@tessi.UUCP (Joe Pruett) (12/10/89)
Original-posting-by: joey@tessi.UUCP (Joe Pruett) Reposted-by: emv@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@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); }
brian@hpausla.aso.hp.com (Brian Coogan) (12/12/89)
Joe Pruett <joey@tessi.UUCP> writes in alt.sources: > 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. A clever trick. Worth keeping in mind that it won't work for symbolic links (usually you don't want it to anyway).
mvp@v7fs1.UUCP (Mike Van Pelt) (12/13/89)
I just had reason to use ftw in a program, and I thought I'd pass this little tidbit along. For some reason, ftw calls stat, which returns information on the file pointed to by a symbolic link, rather than information about the link itself. Sometimes you may want to do this, but not (as in my case) when you're trying to produce a report of disk usage. The solution: Supply a function stat which calls lstat. It will be used by ld instead of the system stat. -- Mike Van Pelt "Something is happening here, Headland Technology/Video 7 What it is ain't exactly clear..." ...ames!vsi1!v7fs1!mvp -- Pons & Fleischmann