Code:
/* flcnt.c */
#include <stdio.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#define VALIDIR 1
#define TOP_DIR 0
#define SUB_DIR 1
int do_open(char *dname, int dtype);
int do_tally(char *fname);
void updt_path_str(char *curpath, char *dname);
unsigned int filecount = 0;
unsigned int dircount = 0;
unsigned int totalfiles = 0;
unsigned int totaldirs = 0;
int verbose = 0;
char fullpath[PATH_MAX];
/* we need long long to support totals over 4gigs */
unsigned long long int totalbytes = 0;
int main(int argc, char *argv[])
{
int c;
/* get opts */
while ( (c = getopt(argc, argv, "v")) != -1)
switch (c) {
case 'v':
verbose = 1;
break;
default:
break;
}
if (!(optind < argc)) {
fprintf(stderr, "Usage flcnt [-v] directory ...\n");
exit(1);
}
/* process each directory given as argument */
while (optind < argc) {
printf("processing directory %s, please wait ...\n\n",
argv[optind]);
if ((do_open(argv[optind], TOP_DIR)) == 1) {
fprintf(stderr, "Can't open %s: %s\n",
argv[optind], strerror(errno));
} else {
printf("%s contains %d files and %d sub-directories\n",
argv[optind], filecount, dircount);
totalfiles = totalfiles + filecount;
totaldirs = totaldirs + dircount;
filecount = dircount = 0;
}
++optind;
}
printf("\ntotal size in bytes of directories and files is %llu\n",
totalbytes);
printf("total files are %u, and total sub-directories are %u\n",
totalfiles, totaldirs);
return 0;
}
int do_open(char *dname, int dtype)
{
DIR *p;
char curdir[PATH_MAX];
char lastdir[PATH_MAX];
char curpath[PATH_MAX];
char lastpath[PATH_MAX];
struct stat l;
struct dirent *t;
int filetype;
if ((p = opendir(dname)) == NULL)
return 1;
/* save our last current directory, so that when we leave do_open()
* we return to it with chdir()
*/
getcwd(lastdir, PATH_MAX);
/* if we're verbose, we update our path strings */
if (verbose) {
if (dtype == SUB_DIR) {
strcpy(lastpath, fullpath);
strcpy(curpath, fullpath);
updt_path_str(curpath, dname);
} else {
updt_path_str(curpath, dname);
}
}
/* if we have a TOP_DIR (meaning one given as argument), we have to
* call stat() to get the directory's size for totalbytes tally and
* we don't count this directory as a sub-directory
*/
if (dtype == SUB_DIR) {
++dircount;
} else {
stat(dname, &l);
totalbytes = totalbytes + (unsigned long long int) l.st_size;
}
chdir(dname);
if (verbose)
printf("Reading directory %s ... %u files ...\n",
fullpath, filecount);
/* process directory at *p */
while ((t = readdir(p)) != NULL) {
if ((filetype = do_tally(t->d_name)) == -1) {
fprintf(stderr, "Couldn't stat %s: %s\n",
t->d_name, strerror(errno));
} else if (filetype == VALIDIR) {
if ((do_open(t->d_name, SUB_DIR)) == 1)
fprintf(stderr, "Can't open %s: %s\n",
t->d_name, strerror(errno));
}
}
chdir(lastdir);
strcpy(fullpath, lastpath);
/* VERY IMPORTANT - program will crash if not included */
closedir(p);
return 0;
}
int do_tally(char *fname)
{
struct stat t;
/* don't do tallies or stat() for these directories */
if (strcmp(fname, ".") == 0 || strcmp(fname, "..") == 0)
return 0;
if (stat(fname, &t) == -1)
return -1;
switch (t.st_mode & S_IFMT) {
case S_IFDIR:
totalbytes = totalbytes + (unsigned long long int) t.st_size;
return VALIDIR;
break;
default:
++filecount;
totalbytes = totalbytes + (unsigned long long int) t.st_size;
break;
}
return 0;
}
void updt_path_str(char *curpath, char *dname)
{
strcpy(curpath, dname);
strcat(curpath, "/");
strcat(fullpath, curpath);
}