How to Find number and folder of files in a directory - c

I need to find number of files and folders in a directory. I'm using MinGW compiler before this I tried to use d_type but I couldn't compile my code.
And I don't care about "." and" .. " directory. I don't wanna calculate them.
So I write a program like this. This program can easily find how many files and folders in a directory.
But When I give a new Name a folder instead of New Folder, New Folder(1). This programs calculate that folders as a file.
What can I do? I really stuck. I have to find how many files and how many folders...
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
int
main(int argc, char *argv[])
{
int file_count = 0;
int dir_count = 0;
struct dirent * entry;
struct stat filestat;
size_t nfiles = 0, ndirs = 0;
DIR *dp;
if (argc != 2)
{
printf("usage: put directory_name\n");
exit(-1);
}
if ((dp = opendir(argv[1])) == NULL)
{
printf("Error: can't open %s\n", argv[1]);
exit(-2);
}
while ((entry= readdir(dp)) != NULL){
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) {
continue;
}
stat(entry->d_name,&filestat);
if( S_ISDIR(filestat.st_mode) ){
ndirs++;
}
else
nfiles++;
}
closedir(dp);
printf("%lu Files, %lu Directories\n", nfiles, ndirs);
return(0);
}

entry->d_name will contain the filename only, not the full path, so if call stat() it will fail unless that file happens to exist in the current directory.
Also note that your code is not recursive, so it won't count stuff in the subfolders.

Related

List of all files inside the folder and its subfolders in Windows

I want to list all the files that run under Task Scheduler by accessing all the files in the "C:\windows\system32\Tasks" Directory.
The program should recursively keep opening subfolders in the directory and list all the files. I currently use Windows OS.
I tried using the COM library but it doesn't display the tasks in the subfolders. I have 60 tasks but it displays only 12. So, I'm trying to iterate through the Tasks folder instead.
#include <stdio.h>
#include <dirent.h>
int main(void)
{
DIR *dir;
struct dirent *de;
if ((dir = opendir("C:\\Windows\\System32\\Tasks")) != NULL);
{
printf("The startup Programs are:\n");
while ((de = readdir(dir)) != NULL)
{
printf("%s\n", de->d_name);
}
closedir(dir);
}
getchar();
}
I expected the output to display all the files inside the current folder and the subfolders.
However, the output only displays the name of the first folder and exits.
As there is apparently no full, simple, example of recursively listing directories under windows, here is one:
#include <windows.h>
#include <stdio.h>
void listdirs(char *dir, char *mask)
{
char fspec[1024], fname[1024];
WIN32_FIND_DATA dta;
HANDLE hDta;
sprintf(fspec,"%s/%s",dir, mask);
if ((hDta= FindFirstFile (fspec, &dta)) != INVALID_HANDLE_VALUE) {
do {
if ( !(dta.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
{
printf ("%s/%s\n", dir, dta.cFileName);
}
else
{
if (strcmp(dta.cFileName,".")!=0 && strcmp(dta.cFileName,"..")!=0 )
{
sprintf (fname, "%s\\%s", dir, dta.cFileName);
listdirs(fname, mask);
}
}
} while (FindNextFile (hDta, &dta));
FindClose(hDta);
}
}
int main (int argc, char *argv[])
{
listdirs(argv[1],argv[2]); // Usage: progname c:\MyDir *.*
return 0;
}

Printing directory: chdir not working

I was wondering if someone could tell me what I'm doing wrong. This code is supposed to walk though all the directories and files and print them out exactly the same way the UNIX utility FIND does. But for some reason I cant get chdir to change the working directory. I'm trying to limit the number of file descriptors im using.
MAIN
#include <stdio.h>
#include "sfind.h"
#include <unistd.h>
#include <dirent.h>
int main(int argv, char *argc[]){
char cwd[1024]; /* current working directory limit*/
char *path = NULL;
DIR *dp = NULL;
if (getcwd(cwd, sizeof(cwd)) != NULL){ /*allow us to grab the current working directory*/
fprintf(stdout, "Current working dir: %s\n", cwd);
}
else{
perror("getcwd() error");
}
dp = opendir(cwd);
path = ".";
directoryList(dp,path);
return 0;
}
Directory Method Definition
#include <stdio.h>
#include <stdlib.h>
#include "sfind.h"
#include <unistd.h>
#include <limits.h>
#include <dirent.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
void directoryList(DIR *dp, char *path){
char newPath[PATH_MAX] = {0};/*To store new path*/
struct dirent *element; /*get file name*/
struct stat statbuf;/*determine type of file*/
int status = 0; /*My base case should be once the directory I'm in runs outs out of files I should return;*/
if(dp == NULL){
fprintf(stderr,"FILE DID NOT OPEN!");
exit(-1);
}
/*change the current file directory even if its the first one*/
if((status = chdir(path)) == -1){
printf("ERROOR!");
}/*change the current working directory whether that the same on or not*/
while((element = readdir(dp)) != NULL) /*while current file directory pointer is not equal to zero*/{
/* from here we only have two cases once were reading from the directory either is a file or directory!*/
/*using lstat*/
lstat(element->d_name,&statbuf);
if((S_ISDIR(statbuf.st_mode))) /*is of type directory*/{
if((strcmp(".",element->d_name) == 0) || (strcmp("..",element->d_name) == 0))
continue;
/*create new directory name*/
newPath[0] = '\0';
strcat(newPath,path);/* this will give us the "."*/
strcat(newPath,"/");
strcat(newPath,element->d_name);
printf("%s\n", newPath);
directoryList(dp,newPath); /*recursion*/
file*/
}
else /*Its a file!*/{
printf("%s/%s\n",path,element->d_name);
}
}
}
The issue seems to be with the call to readdir(dp)...
Even though you change the current working directory, you don't update the dp pointer to open the new folder.
Here's a poor-man's working example (I wouldn't do it this way, but it works for small trees).
#include <dirent.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
void directoryList(DIR *dp, char *path) {
char newPath[PATH_MAX] = {0}; /*To store new path*/
struct dirent *element; /*get file name*/
struct stat statbuf; /*determine type of file*/
int status = 0; /*My base case should be once the directory I'm in runs outs
out of files I should return;*/
DIR *dp_tmp;
if (dp == NULL) {
fprintf(stderr, "FILE DID NOT OPEN!");
exit(-1);
}
while ((element = readdir(dp)) !=
NULL) /*while current file directory pointer is not equal to zero*/ {
/* from here we only have two cases once were reading from the directory
* either is a file or directory!*/
/*using lstat*/
lstat(element->d_name, &statbuf);
if ((S_ISDIR(statbuf.st_mode))) /*is of type directory*/ {
if ((strcmp(".", element->d_name) == 0) ||
(strcmp("..", element->d_name) == 0))
continue;
/*create new directory name*/
newPath[0] = '\0';
strcat(newPath, path); /* this will give us the "."*/
strcat(newPath, "/");
strcat(newPath, element->d_name);
printf("%s\n", newPath);
if ((dp_tmp = opendir(newPath)) == NULL) {
perror("hmm?! ");
exit(1);
}
directoryList(dp_tmp, newPath); /*recursion*/
} else /*Its a file!*/ {
printf("* %s/%s\n", path, element->d_name);
}
}
closedir(dp);
}
int main(void) {
char cwd[1024]; /* current working directory limit*/
char *path = NULL;
DIR *dp = NULL;
if (getcwd(cwd, sizeof(cwd)) !=
NULL) { /*allow us to grab the current working directory*/
fprintf(stdout, "Current working dir: %s\n", cwd);
} else {
perror("getcwd() error");
}
dp = opendir(cwd);
path = ".";
directoryList(dp, path);
return 0;
}
EDIT:
To answer the question in the comment...
Open directories (that should be closed using closedir) are different (and quite unrelated) to the current working directory.
The current working directory is mostly used to resolve the path to any file/folder you're referencing.
Open directory pointers (DIR *) are just pointers to data in the memory. That data relates to a specific directory and you can open a number of directories at the same time.
EDIT2:
A few people in the comments recommended nftw (file tree walk) which is a great alternative to doing it yourself.
If this isn't a learning project, I would recommend it's use.
However, note that POSIX.1-2008 marks ftw as obsolete, so make sure to use the nftw flavor.
Is your goal to learn to implement this yourself, or do you just want results? Because you should take a look at fts.h if you want some very powerful stuff to implement something like find.

How to code my own version of mv (rename/move) unix command in C language?

I want to write my own code for move(mv) Unix command. I am completely new to C language and apparently lost on how to fix my code. I want to perform actions like renaming a file if both the inputs are file names. If the the dest_folder is a directory I would like to move the file into the directory.
But I am unable to fix code for the particular problem as I am not much familiar with directories and C in particular. The program takes 2 inputs source and destination after which it performs necessary functions. I am apparently able to rename my files but I am unable to move the file to a particular folder for some reason I don't know?
Need help with moving file to a particular directory.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define SBUF 256
#define DBUF 256
int main(int ac, char *argv[])
{
DIR* dir_ptr; // the directory
struct dirent* direntp;
if( ac == 1 )
{
printf("Usage: %s MOVE\n", argv[0] );
exit(0);
}
if(ac>1 && ac<3)
{
printf("Error! few arguments provided " );
exit(0);
}
char src_folder[SBUF];
char dest_folder[DBUF];
strcpy(src_folder, argv[1]);
strcpy(dest_folder, argv[2]);
dir_ptr = opendir("."); //open directory
if ( dir_ptr == NULL )
{
perror( "." );
exit( 1 );
}
while( (direntp = readdir( dir_ptr )) != NULL )
{
if ( strcmp(direntp->d_name, dest_folder) !=0) //search file or directory
{
printf("found the file %s", dest_folder);
break;
}else
printf("not found");
break;
}
rename(src_folder, dest_folder);
closedir( dir_ptr );
return 0;
}
rename(3) does not work the way you want it to work (I don't know why, ask the committee). You cannot do a rename(some_file, some_directory), just as the man-page says.
Just use stat(2) (or lstat(2) if necessary) and check what you have been given. Here is a short, runnable sketch.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
// check if it is the same inode on the same device
#define SAME_INODE(a, b) ((a).st_ino == (b).st_ino && (a).st_dev == (b).st_dev)
// ALL CHECKS OMMITTED!
int main(int argc, char **argv)
{
struct stat statbuf_src, statbuf_dest;
char *src, *dest, *new_src, *new_dest;
char *current_directory;
if (argc != 3) {
fprintf(stderr, "usage: %s src dest\n", argv[0]);
exit(EXIT_FAILURE);
}
// work on copy
src = malloc(strlen(argv[1]) + 1);
dest = malloc(strlen(argv[2]) + 1);
strcpy(src, argv[1]);
strcpy(dest, argv[2]);
stat(src, &statbuf_src);
stat(dest, &statbuf_dest);
// there are many more, of course
printf("\"%s\" is a ", src);
if (S_ISREG(statbuf_src.st_mode)) {
puts("a regular file");
}
if (S_ISDIR(statbuf_src.st_mode)) {
puts("a directory");
}
printf("\"%s\" is a ", dest);
if (S_ISREG(statbuf_dest.st_mode)) {
puts("a regular file");
}
if (S_ISDIR(statbuf_dest.st_mode)) {
puts("a directory");
}
if (SAME_INODE(statbuf_dest, statbuf_src)) {
printf("%s and %s are the identical\n", src, dest);
}
// if that is not set you have to do it by hand:
// climb up the tree, concatenating names until the inodes are the same
current_directory = getenv("PWD");
printf("current directory is \"%s\"\n", current_directory);
// I'm pretty sure it can be done in a much more elegant way
new_src = malloc(strlen(src) + 1 + strlen(current_directory) + 1);
strcpy(new_src,current_directory);
strcat(new_src,"/");
strcat(new_src,src);
printf("new_src = %s\n",new_src);
new_dest = malloc(strlen(dest) + 1 + strlen(current_directory) + 1 + strlen(src) + 1);
strcpy(new_dest,current_directory);
strcat(new_dest,"/");
strcat(new_dest,dest);
strcat(new_dest,"/");
strcat(new_dest,src);
printf("new_dest = %s\n",new_dest);
if(rename(new_src,new_dest) != 0){
fprintf(stderr,"rename failed with error %s\n",strerror(errno));
}
free(new_src);
free(new_dest);
free(src);
free(dest);
exit(EXIT_SUCCESS);
}
Edit: added code for the desciption below
At the end you have a the path where you are, the information if the arguments given are directories or regular files and the path. If the source is a regular file and the destination a directory, you concatenate the path with the name of the regular file, the path with the name of the directory and the name of the regular file (your source)
Out of
Path = /home/foo
src = bar
dest = coffee
build
new_src = /home/foo/bar
new_dest = /home/foo/coffee/bar
Such that the call to rename() is
rename(new_src, new_dest);
That way you rename a regular file to a regular file which rename() accepts.
Please be aware that rename() does not work across every filesystem, but most.
Like you know, mv is implemented by rename. rename is a atomic system call that can rename a file to a file , an emtpy directory to an empty directory or a directory to a directory(the dest must be nonentity). So there are following situation to deal with:
mv file1 file2 - use rename function
mv dir1 dir2(nonentity or empty) - use rename function
mv dir1 dir2(not empty) - rename dir1 to dir2/dir1
mv file dir(exist) - rename file to dir/file
mv dir file - illegal operation
can you understand?

In C, is there a way to get the size of multiple files with names matching a string?

I have files something like this:
file1_a_etc.txt,
file1_b_etc.txt
file2_a_z.txt
file2_b_z.txt
I want to get the size of files with "a" i.e. file2_a_z.txt & file1_a_etc.txt
I have got a large number of files this way, so cant specify each name individually.
I am a beginner at C.
I know how to read the size of a single file. And I am working on windows.
#include <stdio.h>
#include <sys/stat.h> // For struct stat and stat()
struct stat attr;
void main()
{
if(stat("filename.txt", &attr) == 0)
{
float x;
x=(attr.st_size)/1048576.0; //1MB=1048576 bytes
printf("Filesize: %.2f MB", x);
}
else
{
// couldn't open the file
printf("Couldn't get file attributes...");
}
}
For Windows console there is function _findfirst. For first parameter put *a*.txt.
You need to iterate over the files in a given directory while searching for the substring in each file name.
This answer, under the section (Unix/Linux), specifies how to iterate over each filename while comparing for an exact match, you can modify the strcmp function call to strstr to look for a substring.
You could make an Array of strings to store all filenames. Then you can use the strchr function to test, if an 'a' or other character is the name. The use of this function is explained e.g at http://www.tutorialspoint.com/ansi_c/c_strchr.htm
Reading directories programmatically can be done with readdir.
You could do something like this:
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
static void lookup(const char *dir)
{
DIR *dirp;
struct dirent *dp;
if ((dirp = opendir(dir)) == NULL) {
perror("couldn't open '.'");
return;
}
do {
errno = 0;
if ((dp = readdir(dirp)) != NULL) {
if (strstr(dp->d_name, "_a_") == NULL)
continue;
(void) printf("found %s\n", dp->d_name);
// Add code to handle the file
}
} while (dp != NULL);
if (errno != 0)
perror("error reading directory");
(void) closedir(dirp);
return;
}
readdir is part of POSIX.1-2001, which is supported by unix/linux-type systems (including OS/X) but only some windows compilers. If you are programming in windows you may have to use another solution.

opendir: Too many open files

I write this code to print all files in /home/keep with absolution path:
#include <dirent.h>
#include <sys/stat.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
void catDIR(const char *re_path);
int main(int argc, char *argv[])
{
char *top_path = "/home/keep";
catDIR(top_path);
return 0;
}
void catDIR(const char *re_path)
{
DIR *dp;
struct stat file_info;
struct dirent *entry;
if ((dp = opendir(re_path)) == NULL)
{
perror("opendir");
return;
}
while (entry = readdir(dp))
{
if (entry->d_name[0] == '.')
continue;
//get Absolute path
char next_path[PATH_MAX];
strcpy(next_path, re_path);
strcat(next_path, "/");
strcat(next_path, entry->d_name);
lstat(next_path, &file_info);
if (S_ISDIR(file_info.st_mode))
{
catDIR(next_path);
}
else
{
printf("%s/%s\n", re_path, entry->d_name);
}
}
free(dp);
free(entry);
}
When I run it.
Not only print some file's path, but also print some error message:
opendir: Too many open files
I read man 3 opendir, then realize, I had opened too many files.
I do want to know, how to close it? and how to correct this program
You should probably use closedir when you finish iterating through a directory's contents.
Also, you might want to read the directory's listing into an array, close the directory, and then recurse on the array. This might help with traversing very deep directory structures.
Run
cat /proc/sys/fs/file-nr
what does it give ?
output format is : (number of allocated file handlers) - (number of allocated but unused file handlers) - (maximum number of file handlers)
If you get more number of allocated but unused file handlers, it means that you've to close directories as mentioned by #Matthew Iselin.
You can also change system limit.
More info about changing system limit Can be found here.

Resources