Here is a program I made this program has segmentation fault I checked it in gdb in the second last of code free(somepath); .I do not have any reason for why is this segmentation fault coming?
Some one please suggest some thing.
#include<dirent.h>
#include<unistd.h>
#include<string.h>
#include<sys/stat.h>
#include<stdlib.h>
#include<stdio.h>
char *directs[20], *files[20];
int i = 0;
int j = 0;
int count = 0;
void printdir(char *);
int count_dirs(char *);
int count_files(char *);
void new_printdir(int ,int ,char *);
int main()
{
char startdir[20];
printf("Scanning user directories\n");
scanf("%s", startdir);
printdir(startdir);
}
void printdir(char *dir)
{
DIR *dp = opendir(dir);
int nDirs, nFiles, nD, nF;
nDirs = 0;
nFiles = 0;
nD = 0;
nF = 0;
if (dp) {
struct dirent *entry = 0;
struct stat statBuf;
nDirs = count_dirs(dir);
nFiles = count_files(dir);
new_printdir(nDirs,nFiles,dir);
while ((entry = readdir(dp)) != 0) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
char * filepath = malloc(strlen(dir) + strlen(entry->d_name) + 2);
if (filepath) {
sprintf(filepath, "%s/%s", dir, entry->d_name);
if (lstat(filepath, &statBuf) == 0) {
if (S_ISDIR(statBuf.st_mode)) {
printdir(filepath);
}
else {
}
}
}
free(filepath);
} //2nd while
closedir(dp);
}
else {
fprintf(stderr, "Error, cannot open directory %s\n", dir);
}
} //printdir
int count_dirs(char *dir)
{
DIR *dp = opendir(dir);
int nD;
nD = 0;
if (dp) {
struct dirent *entry = 0;
struct stat statBuf;
while ((entry = readdir(dp)) != 0) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
char *filepath = malloc(strlen(dir) + strlen(entry->d_name) + 2);
if (filepath) {
sprintf(filepath, "%s/%s", dir, entry->d_name);
if (lstat(filepath, &statBuf) != 0) {
fprintf(stderr, "File Not found? %s\n",filepath);
}
if (S_ISDIR(statBuf.st_mode)) {
nD++;
} else {
continue;
}
free(filepath);
}
}
closedir(dp);
} else {
fprintf(stderr, "Error, cannot open directory %s\n", dir);
}
return nD;
}
int count_files(char *dir)
{
DIR *dp = opendir(dir);
int nF;
nF = 0;
if (dp) {
struct dirent *entry = 0;
struct stat statBuf;
while ((entry = readdir(dp)) != 0) {
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
char *filepath =
malloc(strlen(dir) + strlen(entry->d_name) + 2);
if (filepath) {
sprintf(filepath, "%s/%s", dir, entry->d_name);
if (lstat(filepath, &statBuf) != 0) {
fprintf(stderr, "File Not found? %s\n", filepath);
}
if (S_ISDIR(statBuf.st_mode)) {
continue;
} else {
nF++;
}
free(filepath);
}
}
closedir(dp);
} else {
fprintf(stderr, "Error, cannot open file %s\n", dir);
}
return nF;
}
void new_printdir(int nDirs,int nFiles,char *dir)
{
struct dirent **namelist;
DIR *dop;
int i, j,t,re,nD,nF;
char userd[20],*somepath;
i = scandir(dir, &namelist, 0, alphasort);
t=0;
if (i < 0)
perror ("Scandir failed to open directory I hope you understand \n");
else {
for (j = 0; j < i; j++) {
if(strcmp(".",namelist[j]->d_name)==0||strcmp("..",namelist[j]->d_name)==0)
continue;
somepath = malloc(strlen(dir)+strlen(namelist[j]->d_name)+2);
sprintf(somepath,"%s/%s",dir,namelist[j]->d_name);
dop=opendir(somepath);
if(dop)
{
nD++;
if ((nDirs-nD)<3)
{printf("%s ",namelist[j]->d_name);}
}
else {
nF++;
if ((nFiles-nF)<3)
printf("%s ",namelist[j]->d_name);
}
closedir(dop);
free(namelist[j]);
}
}
free(namelist);
free(somepath);
}
Why is this segmentation fault happening this is not clear to me.
What can I do to get rid of it?
In your code, you are not guaranteed to allocate memory and assign it to somepath (you also fail to free somepath except for the last iteration of the loop). You should put your free(somepath) statement at the end of the for-loop, and you should initialize somepath to NULL both at the very beginning of the function and at the start of each for loop to avoid similar careless errors.
You're not initializing the somepath variable - it has an undefined value unless the malloc() executes (i.e. for empty folders). You should initialize it to NULL at the place of definition.
You do not initialize somepath to 0 (NULL), but you could under some circumstances release the value. This means you release a random value - which is not a good idea.
Related
I'm trying to display the contents of the directory, I am adding the directory name to the array of strings and printing it, but instead of printing the array the program prints "tmp".
void do_ls(char * dir){
struct dirent * entry;
DIR * dp = opendir(dir);
if(dp == NULL){
fprintf(stderr, "Can not open directory:%s\n", dir);
return;
}
setLenAndNum(dir);
char fileNames[totalNumOfFiles][lenOfLongestFile]; //array to store all file names
int i = 0; //index to iterate through filenames
errno = 0;
while((entry = readdir(dp)) != NULL){
if(entry == NULL && errno != 0){
perror("readdir failed");
exit(errno);
}
else{
if(entry->d_name[0] == '.')
continue;
while(i < totalNumOfFiles){
for(int j=0; j<lenOfLongestFile; j++){
fileNames[i][j] = entry->d_name[j];
}
i++;
}
}
}
i = 0;
while(i < totalNumOfFiles){
printf("%s\n", fileNames[i++]);
}
closedir(dp);
}
This is the function in question, the variables totalNumOfFiles and lenOfLongestFile are global variables and they work correctly I have tested them.
Let's see what we have here... My comments... well, in the comments ;)
void do_ls(char * dir) {
struct dirent *entry;
DIR *dp = opendir(dir);
if (dp == NULL){
fprintf(stderr, "Can not open directory:%s\n", dir);
return;
}
// I don't know what function below does
// I assume it sets totalNumOfFiles and lenOfLongestFile;
setLenAndNum(dir);
char fileNames[totalNumOfFiles][lenOfLongestFile]; //array to store all file names
int i = 0; //index to iterate through filenames
// You don't have to set errno to zero
errno = 0;
while ((entry = readdir(dp)) != NULL) {
// Statement above guarantees that the loop won't be run
// when entry == NULL, so what for is the if statement below?
// It's a dead code. get rid of it.
if (entry == NULL && errno != 0) {
perror("readdir failed");
exit(errno);
} else {
if(entry->d_name[0] == '.')
continue;
// Ok, so here we are with a SINGLE file entry, and with this
// SINGLE file entry you fill the WHOLE table with it.
// This is clearly wrong.
while (i < totalNumOfFiles) {
// Also, you should use a strcpy function to copy string.
// It will copy necessary number of bytes and trailing 0.
for(int j=0; j<lenOfLongestFile; j++){
fileNames[i][j] = entry->d_name[j];
}
i++;
}
}
// So here all rows in the table are filled with the last read
// file name
}
i = 0;
while(i < totalNumOfFiles){
printf("%s\n", fileNames[i++]);
}
closedir(dp);
}
Here is corrected code:
void do_ls(char *dir) {
struct dirent *entry;
DIR *dp = opendir(dir);
if (dp == NULL){
fprintf(stderr, "Can not open directory:%s\n", dir);
return;
}
setLenAndNum(dir);
char fileNames[totalNumOfFiles][lenOfLongestFile]; //array to store all file names
int i = 0; //index to iterate through filenames
while ((entry = readdir(dp)) != NULL) {
if (entry->d_name[0] == '.')
continue;
strcpy(fileNames[i], entry->d_name);
i++;
}
i = 0;
while (i < totalNumOfFiles) {
printf("%s\n", fileNames[i++]);
}
closedir(dp);
}
I'm trying to make a C program that will display all the files and folders containing a given search term. The search term is given as an argument when executing the program. A folder / file is displayed to standard output if its name contains the search term (case insensitive).
The difficulty though is that I do not want to output files and subfolders that are contained in a folder that contains the search term. Here's an example:
Let's assume my search term is docker, this is the current output:
"/Users/me/.docker"
"/Users/me/.docker/contexts"
"/Users/me/.docker/contexts/meta"
"/Users/me/.docker/config.json"
"/Users/me/.docker/scan"
"/Users/me/.docker/scan/config.json"
"/Users/me/.docker/application-template"
"/Users/me/.docker/application-template/logs"
"/Users/me/.docker/application-template/logs/com.docker.log"
"/Users/me/.docker/daemon.json"
"/Users/me/.docker/run"
"/Users/me/Library/Application Support/Docker Desktop"
"/Users/me/Library/Application Support/Docker Desktop/blob_storage"
"/Users/me/Library/Application Support/Docker Desktop/blob_storage/6965e70b-e33a-4415-b9a8-e19996fe221d"
But this is the output I'm trying to achieve:
"/Users/me/.docker"
"/Users/me/Library/Application Support/Docker Desktop"
Here's my code so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
static int display_info(const char *fpath, const char * fname, const char * term) {
int what_len = strlen(term);
int count = 0;
char *where = fpath;
if (what_len){
while ((where = strcasestr(where, term))) {
where += what_len;
count++;
}
if (count == 1) {
printf("\"%s/%s\"\n", fpath, fname);
}
}
return 0;
}
static void listFilesRecursively(char * basePath, const char * searchTerm) {
char path[1000];
struct dirent * dp;
DIR * dir = opendir(basePath);
// Unable to open directory stream
if (!dir)
return;
while ((dp = readdir(dir)) != NULL) {
if (strcmp(dp -> d_name, ".") != 0 && strcmp(dp -> d_name, "..") != 0) {
// printf("%s %hhu %s\n", basePath, dp->d_type, dp -> d_name);
display_info(basePath, dp->d_name, searchTerm);
// Construct new path from our base path
strcpy(path, basePath);
strcat(path, "/");
strcat(path, dp -> d_name);
listFilesRecursively(path, searchTerm);
}
}
closedir(dir);
}
int main(int argc, const char * argv[]) {
char * home = getenv("HOME");
if (argc == 2) {
listFilesRecursively(home, argv[1]);
} else {
printf("Please provide one argument");
}
return 0;
}
Any feedback is greatly appreciated thanks!
I am not sure I understand the logic of display_info()
On listFilesRecursively() you can not reuse path from call to call
main() should the the first function in your code, maybe in a separate file
an alternative
I will add a C example, changing a bit of your listFilesRecursively()...
not using void() so you can return -1 for an error
testing for . and .. at the beginning of the loop and just using continue may lead into code easier to read
path is allocated locally and free() on return
strstr_ign() is a case insensitive version of strstr() for use in the pattern search
code for list_files() after change
int list_files(char* pattern, char* base_path)
{
struct dirent* dp;
DIR* dir = opendir(base_path);
if (!dir) return -1; // Unable to open directory stream
while ((dp = readdir(dir)) != NULL)
{
if (strcmp(dp->d_name, ".") == 0) continue;
if (strcmp(dp->d_name, "..") == 0) continue;
if ( strstr_ign((const char*)dp->d_name, pattern) != NULL )
{
display_info(base_path, dp->d_name);
}
else
{
char* path = (char*)malloc(1 + strlen(dp->d_name) + strlen(base_path) + 1);
sprintf(path, "%s/%s", base_path, dp->d_name);
list_files(pattern, path);
free(path); // ok with path
}
}; // while()
closedir(dir);
return 0;
}; // list_files()
code for strstr_ign()
I hate the arguments order for strstr() but kept it here just to have things equal. This way one can use strstr_ign() as a drop-in replacement for strstr() without changing the order of the arguments. I believe needle should come first :) an in the language: search for a needle in a haystack is far more common than search the haystack for a needle but Ken and Dennis had their reasons to write strstr() the way they did it...
//
// strstr() ignoring case
//
char* strstr_ign(const char* haystack, const char* needle)
{
if (needle == NULL) return NULL;
if (haystack == NULL) return NULL;
if (*needle == 0)
{
if (*haystack == 0)
return (char*) haystack;
else
return NULL;
}
int limit = strlen(haystack) - strlen(needle);
for (int x = 0; x <= limit; x += 1)
{ // search for needle at position 'x' of 'haystack'
int here = 1;
for (unsigned y = 0; y < strlen(needle); y += 1)
{
if ( tolower(haystack[x + y]) != tolower(needle[y]) )
{
here = 0; break;
};
};
if ( here == 1) return (char*)(haystack + x);
}
return NULL;
};
a new display_info()
changed to show last access for folders and file size for regular files that match the search pattern (case insensitive). Below is an example of the output for files and folders. Note the '-' and the 'd' as in the ls -l output.
- "./hms.c" [size: 1546]
d "./sub/1/xyzHMSxyz" [last access: Sat Apr 24 12:38:04 2021]
int display_info(const char* base, const char* file)
{
struct stat Stats;
char* path = (char*)malloc(1 + strlen(base) + strlen(file) + 1);
char atime[40];
sprintf(path, "%s/%s", base, file);
if ( stat(path, &Stats) < 0)
{
perror("Inside display_info()");
free(path);
return -1;
}
if ( S_ISDIR(Stats.st_mode) )
{
strftime( atime, sizeof(atime), "%a %b %d %H:%M:%S %Y", localtime(&Stats.st_atime) );
printf("\td \"%s/%s\"\t[last access: %s]\n", base, file, atime );
}
else
{
if ( S_ISREG(Stats.st_mode) )
printf("\t- \"%s/%s\"\t[size: %ld]\n", base, file, Stats.st_size );
else
printf("is somthing else\n");
}
free(path);
return 0;
}
sample output
Search pattern is "hms" (case is ignored)
- "./hms" [size: 16848]
- "./hms-soma.c" [size: 1379]
- "./hms.c" [size: 1546]
d "./sub/1/xyzHMSxyz" [last access: Sat Apr 24 12:38:04 2021]
d "./sub/2/xyzHMS" [last access: Sat Apr 24 12:21:11 2021]
d "./sub/hMs" [last access: Sat Apr 24 12:21:11 2021]
C code for this test
miminally tested :)
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
int display_info(const char*, const char*);
int list_files(char*, char*);
char* strstr_ign(const char*, const char*);
int main(int argc, const char * argv[])
{
char search_term[80];
if (argc >= 2)
{
if ( strlen(argv[1]) > (sizeof(search_term)-1) )
{
printf("Size of substring (%zd) must not be greater than %zd\n",
strlen(argv[1]), sizeof(search_term)-1 );
return -1;
}
for ( int i = 0; i<= strlen(argv[1]); search_term[i] = (char)(tolower(argv[1][i])), i+=1 );
printf("Search pattern is \"%s\" (case is ignored) \n", search_term );
list_files(search_term,".");
} else {
printf("Please provide pattern to search for.\n");
}
return 0;
}; // main()
int display_info(const char* base, const char* file)
{
struct stat Stats;
char* path = (char*)malloc(1 + strlen(base) + strlen(file) + 1);
char atime[40];
sprintf(path, "%s/%s", base, file);
if ( stat(path, &Stats) < 0)
{
perror("Inside display_info()");
free(path);
return -1;
}
if ( S_ISDIR(Stats.st_mode) )
{
strftime( atime, sizeof(atime), "%a %b %d %H:%M:%S %Y", localtime(&Stats.st_atime) );
printf("\td \"%s/%s\"\t[last access: %s]\n", base, file, atime );
}
else
{
if ( S_ISREG(Stats.st_mode) )
printf("\t- \"%s/%s\"\t[size: %ld]\n", base, file, Stats.st_size );
else
printf("is somthing else\n");
}
free(path);
return 0;
}
int list_files(char* pattern, char* base_path)
{
struct dirent* dp;
DIR* dir = opendir(base_path);
if (!dir) return -1; // Unable to open directory stream
while ((dp = readdir(dir)) != NULL)
{
if (strcmp(dp->d_name, ".") == 0) continue;
if (strcmp(dp->d_name, "..") == 0) continue;
if ( strstr_ign((const char*)dp->d_name, pattern) != NULL )
{
display_info(base_path, dp->d_name);
}
else
{
char* path = (char*)malloc(1 + strlen(dp->d_name) + strlen(base_path) + 1);
sprintf(path, "%s/%s", base_path, dp->d_name);
list_files(pattern, path);
free(path); // ok with path
}
}; // while()
closedir(dir);
return 0;
}; // list_files()
//
// strstr() ignoring case
//
char* strstr_ign(const char* haystack, const char* needle)
{
if (needle == NULL) return NULL;
if (haystack == NULL) return NULL;
if (*needle == 0)
{
if (*haystack == 0)
return (char*) haystack;
else
return NULL;
}
int limit = strlen(haystack) - strlen(needle);
for (int x = 0; x <= limit; x += 1)
{ // search for needle at position 'x' of 'haystack'
int here = 1;
for (unsigned y = 0; y < strlen(needle); y += 1)
{
if ( tolower(haystack[x + y]) != tolower(needle[y]) )
{
here = 0; break;
};
};
if ( here == 1) return (char*)(haystack + x);
}
return NULL;
};
Thanks to #KamilCuk I was able to solve my issue. Here's my final listFilesRecursively function:
static void listFilesRecursively(char * basePath, const char * searchTerm) {
char path[1000];
struct dirent * dp;
DIR * dir = opendir(basePath);
// Unable to open directory stream
if (!dir)
return;
while ((dp = readdir(dir)) != NULL) {
if (strcmp(dp -> d_name, ".") != 0 && strcmp(dp -> d_name, "..") != 0) {
if (strcasestr(dp->d_name, searchTerm)) {
printf("%s/%s\n",basePath,dp->d_name);
listFilesRecursively(path, searchTerm);
} else {
// Construct new path from our base path
strcpy(path, basePath);
strcat(path, "/");
strcat(path, dp -> d_name);
listFilesRecursively(path, searchTerm);
}
}
}
closedir(dir);
}
EDIT : Note that It's not that I can't access the memory allocated by storeContents() in main() if you think so. Program crashes during the execution of storeContents()
The program fails here :
strcpy(contents[count], dir->d_name);
printf("Stored %s(out hiddenVisible)\n", dir->d_name); // for testing
It's strcpy() not the printf(), I added it just for the reference.
The debugger(gdb) says :
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7f3cd72 in __strcpy_ssse3 () from /usr/lib/libc.so.6
I am making a program that involves the following function "storeContents"(It stores contents' names of a directory in a dynamic array). There are two issues with this function : (1) It says "Stored file_name" twice for the first file and (2) says "Segmentation fault". I can't figure out either of them. Thanks for your efforts!
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#include <sys/types.h>
#include <limits.h>
static short hiddenVisible = 0;
/* Store directory's contents in **contents */
static char ** storeContents(struct dirent *dir, DIR *dirp, unsigned numOfContents);
/* Count files/directories in a directory */
static unsigned getNumOfContents(struct dirent *dir, DIR *dirp);
int main(int argc, char const *argv[])
{
char **contents;
DIR *dirp;
struct dirent *dir;
unsigned numOfContents;
dirp = opendir("/home/gaurav");
if((dir = readdir(dirp)) == NULL) {
perror("readdir");
exit(1);
}
/* Getting number of files/directories */
numOfContents = getNumOfContents(dir, dirp);
printf("There are %u files.\n", numOfContents);
/* To position again to the first entry */
rewinddir(dirp);
contents = storeContents(dir, dirp, numOfContents);
/* Print contents */
for(unsigned i = 0; i < numOfContents; ++i)
printf("%s\n", contents[i]);
closedir(dirp);
return 0;
}
char **
storeContents(struct dirent *dir, DIR *dirp, unsigned numOfContents) {
char **contents;
unsigned count = 0;
/* Allocating memory for entries */
contents = malloc(numOfContents * sizeof(*contents));
/* Allocating memory for each '*contents' */
for(unsigned i = 0; i < numOfContents; i++)
contents[i] = (char *)malloc(NAME_MAX); /* we know char is 1 byte, so no "sizeof" */
while(count < numOfContents) {
/* Ignore "." and ".." */
if(!(strcmp(dir->d_name, ".")) || !(strcmp(dir->d_name, ".."))) {
if((dir = readdir(dirp)) == NULL) {
perror("readdir");
exit(1);
}
continue;
}
if(hiddenVisible) {
strcpy(contents[count], dir->d_name);
if((dir = readdir(dirp)) == NULL) {
perror("readdir");
exit(1);
}
count++;
} else {
if(dir->d_name[0] == '.')
if((dir = readdir(dirp)) == NULL) {
perror("readdir");
exit(1);
}
else {
strcpy(contents[count], dir->d_name);
if((dir = readdir(dirp)) == NULL) {
perror("readdir");
exit(1);
}
count++;
}
}
}
return contents;
}
unsigned
getNumOfContents(struct dirent *dir, DIR *dirp) {
unsigned count = 0;
while(dir) {
if(hiddenVisible) {
/* Ignore "." and ".." */
if(!(strcmp(dir->d_name, ".")) || !(strcmp(dir->d_name, ".."))) {
if((dir = readdir(dirp)) == NULL) {
perror("readdir a");
exit(1);
}
continue;
}
count++;
if((dir = readdir(dirp)) == NULL) {
perror("readdir b");
exit(1);
}
} else {
if(dir->d_name[0] == '.') {
if((dir = readdir(dirp)) == NULL) {
perror("readdir c");
exit(1);
}
}
else {
count++;
if((dir = readdir(dirp)) == NULL) {
perror("readdir d");
exit(1);
}
}
}
}
return count;
}
contents in the function storeContents is a local copy of contents from main.
Changing it in the function does not change the variable in main.
You should return the array. Change
static void storeContents(struct dirent *dir, DIR *dirp, char **contents, unsigned numOfContents);
to
static char **storeContents(struct dirent *dir, DIR *dirp, unsigned numOfContents);
,return contents; in the function and call it like char **contents = storeContents(...);
Some bugs:
contents is a local parameter to the function, it will not get returned to main(). See Dynamic memory access only works inside function.
contents = (char **)malloc(numOfContents); is wrong, you need to allocate room for numOfContents pointers. Change this to contents = malloc(numOfContents * sizeof(*contents)).
You should check each call to readdir and make sure it doesn't return NULL.
I am trying to count only the directories from a path, but it doesn't work. So, i don't want to number both files and directories, i want only the directories. Could you help me, please?
The code:
int listdir(char *dir) {
struct dirent *dp;
struct stat s;
DIR *fd;
int count = 0;
if ((fd = opendir(dir)) == NULL) {
fprintf(stderr, "listdir: can't open %s\n", dir);
}
while ((dp = readdir(fd)) != NULL) {
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
continue;
stat(dp->d_name, &s);
if (S_ISDIR(s.st_mode))
count++;
}
closedir(fd);
return count;
}
your stat() call will fail, since you are not in the correct directory. This you can solve by either changing the current directory, or generate full paths and give to stat as argument.
Some Unixes, you can optimize away the stat call by looking at struct dirent, the d_type field
int listdir(char *dir) {
struct dirent *dp;
struct stat s;
DIR *fd;
int count = 0;
if ((fd = opendir(dir)) == NULL) {
fprintf(stderr, "listdir: can't open %s\n", dir);
}
chdir (dir); /* needed for stat to work */
while ((dp = readdir(fd)) != NULL) {
if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
continue;
#ifdef _DIRENT_HAVE_D_TYPE
switch (dp->d_type)
{
case DT_UNKNOWN:
stat(dp->d_name, &s);
if (S_ISDIR(s.st_mode)) count++;
break;
case DT_DIR:
count++;
break;
}
#else
stat(dp->d_name, &s);
if (S_ISDIR(s.st_mode)) count++;
#endif
}
closedir(fd);
return count;
}
I think you want...
written in C
count the number of directoriesfrom a path.
the counting function will returns int value.
I have no idea about your environment, so it is just a example solution.
If you can use glob, it is so easy to count the number of directories. that is: main.c
#include <stdio.h>
#include <glob.h>
#include <string.h>
#define MAX_PATH 1023
int countDirectories(char* dir)
{
char path[MAX_PATH] = "";
strcat(path, dir);
strcat(path, "/*");
glob_t globbuf;
long i, count = 0;
if (glob(path, GLOB_NOSORT | GLOB_ONLYDIR, NULL, &globbuf) == 0)
{
count = globbuf.gl_pathc;
for (i = 0; i < globbuf.gl_pathc; i++)
{
count += countDirectories(globbuf.gl_pathv[i]);
}
}
globfree(&globbuf);
return count;
}
int main(int argc, char* argv[])
{
int count;
if (argc > 1)
{
count = countDirectories(argv[1]);
}
else
{
count = countDirectories(".");
}
printf("there are %d directories.\n", count);
return 0;
}
and you can try this like:
> gcc main.c -o testglob
> ./testglob /path/to/target/dir
then you'll receive output like this:
path = /path/to/target/dir/*, there are N directories
thanks.
I have to implement the tree command from DOS on Linux in C, so that when I run ./tree in a directory it prints it like this:
adir
bdir
cdir
d.java
edir
fdir
g.c
hdir
My current code looks like this, but it's not even terminating when I run it, but I don't know how to fix it. Please help me solve it!
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
#define MAXLEN 256
char currentDir[256];
const char *pathname;
void tree(DIR *dp, struct dirent *dp1, char currentDir[256], int spaces);
void treeHelper(DIR *dp, struct dirent *dp1, char currentDir[256], int spaces);
int main(int argc, char* argv[]) {
DIR *dp = opendir(".");
struct dirent *dp1 = readdir(dp);
int spaces = 0;
//char currentDir[256];
getcwd(currentDir, sizeof(currentDir));
while(dp1 != NULL) {
if (strcmp(dp1->d_name, ".") == 0 || strcmp(dp1->d_name, "..") == 0) {
continue;
}
if (dp1->d_type == DT_REG) {
printf("%s\n", dp1->d_name);
}
if (dp1->d_type == DT_DIR) {
tree(dp, dp1, currentDir, spaces);
}
}
closedir(dp);
}
void tree(DIR *dp, struct dirent *dp1, char currentDir[256], int spaces) {
int i = 0;
strcat(currentDir, "/");
strcat(currentDir, dp1->d_name);
if((chdir(currentDir)) == -1){
chdir("..");
getcwd(currentDir, sizeof(currentDir));
strcat(currentDir, "/");
strcat(currentDir, dp1->d_name);
for(i = 0; i < spaces; i++) {
printf (" ");
}
printf("%s (subdirectory)\n", dp1->d_name);
spaces++;
treeHelper(dp, dp1, currentDir, spaces);
}
else {
for(i = 0; i < spaces; i++) {
printf(" ");
}
printf("%s (subdirectory)\n", dp1->d_name);
chdir(currentDir);
spaces++;
treeHelper(dp, dp1, currentDir, spaces);
}
}
void treeHelper(DIR *dp, struct dirent *dp1, char currentDir[256], int spaces) {
int i = 0;
while((dp1 = readdir(dp)) != NULL){
if(strcmp(dp1->d_name, ".") == 0 || strcmp(dp1->d_name, "..") == 0)
continue;
//stat(currentPath, &statbuf);
/*if(dit->d_type == 8 && argv[1] != NULL){*/
if(dp1->d_type == DT_REG){
for(i = 0; i < spaces; i++) {
printf(" ");
}
printf("%s\n", dp1->d_name);
}
/*if(dit->d_type == 4)*/
if(dp1->d_type == DT_DIR)
tree(dp, dp1, currentDir, spaces);
}
}
Thank you!
My current code looks like this, but it's not even terminating when I
run it…
struct dirent *dp1 = readdir(dp);
…
while(dp1 != NULL) {
You call readdir() only once and then have an endless loop operating on the same dirent again and again. Change that to
struct dirent *dp1;
…
while (dp1 = readdir(dp))
{