Reputation: 31
I'm a complete beginner in programming in C using POSIX. I'm trying to write a program which counts files in each subdirectory starting from the directory given in environmental variable. For each subdirectory the program should write to stdout a short message:
Directory: name_of_dir
Files: num_of_files
I've tried to write such a program with nftw().
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define _XOPEN_SOURCE 500
#include <ftw.h>
#define MAXFD 20
int files = 0; // files count for each subdirectory
int files_main = 0; // files count for the directory from env variable DIR
int k = 0;
int l = 0;
char prev_dir[100];
char current_dir[100];
void print_dir() // helper function to print current directory
{
char current_dir[100];
getcwd(current_dir, 100);
printf("Directory: %s \n", current_dir);
}
void print_files() // helper function to print number of files
{
printf("Files: %d \n", files);
}
int search(const char *name, const struct stat *s, int type, struct FTW *f)
{
getcwd(current_dir, 100);
if(strcmp(prev_dir, current_dir) != 0 && l == 1) // check if the directory has changed, l as a flag to omit printing the same directory path more than once
{
l = 0;
print_files();
files = 0;
strcpy(prev_dir, current_dir);
}
if(strcmp(current_dir, getenv("DIR")) == 0) // counting files in directory from env variable DIR
{
switch (type)
{
case FTW_F: files_main++; break;
}
}
else // counting files for each subdirectory
{
getcwd(prev_dir, 100);
if(l==0)
{
print_dir();
l = 1;
}
switch (type)
{
case FTW_F: files++; break;
}
}
return 0;
}
int main(int argc, char ** argv)
{
strcpy(prev_dir, getenv("DIR")); // getting the dir from env variable
nftw(getenv("DIR"), search, depth, FTW_CHDIR);
printf("Directory: %s \n", getenv("DIR"));
printf("Files: %d \n", files_main);
return EXIT_SUCCESS;
}
This is the output of "find [...] type -f" for the directory in env variable "DIR":
./.DS_Store
./playground2
./playground3
./playground
./playground.c
./test_dir1/test1.txt
./test_dir1/test2.txt
./Makefile
./playground3.c
./test_file.txt
./playground2.c
./test_dir2/test3.tst
./dir1/p.tet
./dir1/sfsdfsdf/dfsd.txt
./dir1/ofi/test
./dir1/ofi/test2
./link_by_link_function
and this is the output when I run the C program:
$ ./playground2
Directory: /Users/<user>/Desktop/C POSIX/Playground
Files: 5
Directory: /Users/<user>/Desktop/C POSIX/Playground/test_dir1
Files: 2
Directory: /Users/<user>/C POSIX/Playground
Files: 4
Directory: /Users/<user>/C POSIX/Playground/test_dir2
Files: 1
Directory: /Users/<user>/C POSIX/Playground/dir1
Files: 1
Directory: /Users/<user>/Desktop/C POSIX/Playground/dir1/sfsdfsdf
Files: 1
Directory: /Users/<user>/Desktop/C POSIX/Playground/dir1/ofi
Files: 2
Directory: /Users/<user>/Desktop/C POSIX/Playground
Files: 1
Directory: /Users/<user>/Desktop/C POSIX/test_dir1
Files: 2
Directory: /Users/<user>/Desktop/C POSIX/test_dir2
Files: 1
Directory: /Users/<user>/Desktop/C POSIX
Files: 19
The program doesn't work as intended, which is obvious after looking at the output. The "files_main" counter works also the counters for subdirectories of [...]/Playground/ seem to work fine. The problem is the [...]/Playground/ directory itself. The counter "files" is reset after detecting the change in a directory which is not a good solution when the program enters [...]/Playground directory multiple times (at least this is what I have concluded at this point).
I've tried to use FTW_CHDIR and FTW_DEPTH flags but the output showed only the directory from env variable "DIR" with count == 0;
At this point, I am lost and have no idea how to write this program in a different way to accomplish the task.
Any ideas/help would be appreciated :) .
Upvotes: 0
Views: 310
Reputation: 14468
Ideally, you want Breadth-first search (BFS) to do the counting. With BFS, each directory is processed before going to the next directory (down or up). Unfortunately, nftw is implementing depth-search first (DFS).
You can work around the counting limitation using the FTW
structure (parameter f
to the search function). It includes the member 'level'. Instead of keep a single counter, which will reset to zero on folder change, you can maintain an array of counters, one per each level.
Also note that the search function is passed enough information so that no need to keep state (current_dir, prev_dir, ...), detect changes, etc.
static int file_count[50] ; // Assuming big enough.
static int search(const char *name, const struct stat *s, int type, struct FTW *f)
{
static int file_count[50] ;
// Count
if ( f->level < 50 ) { file_count[f->level]++ ;} ;
if ( type == FTW_DP ) {
// Last entry for folder
printf("Folder: %s files: %d\n", name, file_count[f->level+1]) ;
file_count[f->level+1] = 0 ;
} ;
return 0 ;
}
main (...)
{
Invoke nftw with FTW_DP
}
Links:
Upvotes: 1