/**
@file dirFastC.cc
@author Mitch Richling <http://www.mitchr.me/>
@Copyright Copyright 1995 by Mitch Richling. All rights reserved.
@brief traversal of UNIX directory trees@EOL
@Keywords UNIX readdir directory traversal
@Std ISOC POSIX UNIX98 BSD4.3 SYSV3
This C++ program is intended to illustrate how to
traverse a directory with only one directory open at a
time and with a fast data structure. The traversal is
not depth first.
This program reads all the file names in a directory and
places any subdirectory names into an STL vector to be
traversed later. A C version of this program uses a home
grown linked list (dirDepth.c).
The string handling is C-style, as that is what natively
works with the UNIX C APIs. chdir'ing instead of
constructing strings might be faster on some systems.
On many systems a memcpy function will operate faster
than a strcpy/strcat. The lengths of the strings are
computed anyway, so a memcpy is the way to go.
The functions used are all POSIX or ISO C++ and thus
this program will run on most BSD and SRV
implementations of UNIX.
@Tested
- Solaris 2.8
- MacOS X.2
- Linux (RH 7.3)
*/
#include <vector> /* STL vector C++ */
#include <stdio.h> /* I/O lib ISOC */
#include <string.h> /* Strings ISOC */
#include <sys/types.h> /* UNIX types POSIX */
#include <dirent.h> /* UNIX dirs POSIX */
#include <errno.h> /* error stf POSIX */
#include <utime.h> /* utime POSIX */
#include <sys/stat.h> /* UNIX stat POSIX */
#include <time.h> /* time ISOC */
#include <stdlib.h> /* Standard Lib ISOC */
int main(int argc, char *argv[]);
int main(int argc, char *argv[]) {
DIR *dp; /** The directory pointer. */
struct dirent *dep; /** The directory entry. */
struct stat s; /** Used to stat each file. */
char *name; /** Holds the complete path name of the current file. */
char *wrkBuf;
char *curDir;
long len_d_name, len_curDir; /** Integers used to hold the lengths of file names. */
std::vector<char *> listOdirs;
/* Stat the root of the tree we are to traverse. */
if((argc == 2) && (lstat(argv[1], &s) < 0)) {
printf("ERROR: Bad first argument\n");
exit(1);
}
/* Now that we have stat'ed the thing, we add it as the list of directories */
wrkBuf = (char *)malloc(strlen(argv[1]) + 1);
strcpy(wrkBuf, argv[1]);
listOdirs.push_back(wrkBuf);
while(!(listOdirs.empty())) {
curDir = listOdirs.back();
listOdirs.pop_back();
if((dp = opendir(curDir)) == NULL) {
printf("ERROR: dirDepth: %s: %s\n", curDir, strerror(errno));
} else {
/* We have opened the directory, now we read each file name from
it and store the file names that correspond to sub
directories in our linked list for traversal later. */
len_curDir = strlen(curDir);
while((dep = readdir(dp)) != NULL) {
/* Make sure we don't process .. and . */
if((strcmp(dep->d_name, "..") != 0) && (strcmp(dep->d_name, ".") != 0)) {
/* Allocate space for and construct the complete path name. */
len_d_name = strlen(dep->d_name);
name = (char *)malloc(len_d_name + len_curDir + 2);
strcpy(name, curDir);
strcat(name, "/");
strcat(name, dep->d_name);
/* Now that we have a complete path name, let's stat the file in question. */
if(lstat(name, &s) < 0) {
printf("ERROR: dirDepth: %s: %s\n", name, strerror(errno));
free(name);
} else {
/* We have successfully stated the file, now let's process it: */
if(S_ISDIR(s.st_mode)) { /* Process directories. */
/* This is a directory, so we must add it to our list of directories to traverse. */
listOdirs.push_back(name);
printf(" D: %s\n", name);
} else { /* Process non-directories. */
printf("ND: %s\n", name);
/* Free up the space for the pathname. */
free(name);
} /* end if/else */
} /* end if/else */
} /* end if */
} /* end while */
closedir(dp);
} /* end if/else */
/* We have finished walking the current directory, so we remove it from the list. */
free(curDir);
} /* end while */
return 0;
} /* end func main */
Generated by GNU Enscript 1.6.5.2.