probleme to list with readdir - c

I want to list a folder but when I want to print the filename only \n are print
void liste_folder(void)
{
DIR *dir;
struct dirent *test;
dir = opendir(".");
while (readdir(dir) != NULL)
{
test = malloc(sizeof(*test));
printf("%s\n", test->d_name);
free(test);
}
}
int main()
{
liste_folder();
}

You're allocating memory for test, but that doesn't fill it with the directory info. readdir allocates the memory for the dirent structure for you, so it isn't even necessary. Assign the return-value of readdir to test instead:
while((test = readdir(dir)) != NULL){
printf("%s\n", test->d_name);
// the man page says you may not free the dirent
}

Related

How to count all the subdirectories that are present in a directory?

In this code, I am getting all the subdirectories paths from a directory. It is working fine but I want to add something more and that is to count all the subdirectories and print them. How to do this in this function. I used the count variable to make it work but the result is like this.
Given result:
/home/runner/TestC1/file
15775232
/home/runner/TestC1/dsf
15775233
/home/runner/TestC1/main.c
15775234
/home/runner/TestC1/main
15775235
Expected result:
/home/runner/TestC1/file
/home/runner/TestC1/dsf
/home/runner/TestC1/main.c
/home/runner/TestC1/main
Counted: 4 subdirectories.
Code
void listdir(void){
DIR *dir;
struct dirent *entry;
size_t count;
if (!(dir = opendir(path))) {
perror ("opendir-path not found");
return;
}
while ((entry = readdir(dir)) != NULL) {
char *name = entry->d_name;
if (entry->d_type == DT_DIR)
if (!strcmp(name, ".") || !strcmp(name, ".."))
continue;
snprintf (path1, 100, "%s/%s\n", path, name);
printf("%s", path1);
printf("%zu\n", count);
count++;
}
closedir (dir);
}
There are a few problems with your code:
As Thomas says above:
You didn't initialize count. And you are printing inside the loop
You do not initialize count to zero.
You print inside the loop.
You count everything except . and .., without checking whether it is a file or a directory
Here's a (hopefully) fixed version of your code
void listdir(void){
DIR *dir;
struct dirent *entry;
unsigned count = 0;
if (!(dir = opendir(path))) {
perror ("opendir-path not found");
return;
}
while ((entry = readdir(dir)) != NULL) {
char *name = entry->d_name;
if (entry->d_type == DT_DIR) {
if (!strcmp(name, ".") || !strcmp(name, ".."))
continue;
count++;
snprintf (path1, 100, "%s/%s\n", path, name);
printf("%s", path1);
}
}
printf("\nCounted: %u subdirectories.\n", count);
closedir (dir);
}
Edit:
Edited my code following the comment by chux-ReinstateMonica
Minor: Little reason for size_t count when unsigned count is certainly fine. size_t depends on memory - not file space. Pedantically could use uintmax_t. IAC, "%d" is not the specified matching specifier to go with size_t - a step backwards from OP's matching "%zu"

save readdir into a buffer in C

I'm using readdir() to read to output all the files in a directory. The problem is that I need to save the strings into a buffer. Is there any way to save the output into a buffer or file descriptor etc?
Here is my code:
DIR *directory;
struct dirent *dir;
directory = opendir();
while ((dir = readdir(directory)) != NULL) {
printf("%s\n", dir->d_name);
}
closedir(directory);
Use scandir How to use scandir
It allocates the memory for you. Here is an example
/**code to print all the files in the current directory **/
struct dirent **fileListTemp;
char *path = ".";//"." means current directory , you can use any directory path here
int noOfFiles = scandir(path, &fileListTemp, NULL, alphasort);
int i;
printf("total: %d files\n",noOfFiles);
for(i = 0; i < noOfFiles; i++){
printf("%s\n",fileListTemp[i]->d_name);
you can modify it to suit your need . Also do not forget to free memory allocated by scandir
In this case you will have to work with a data structure, like a linked list or a tree.
Here's a short example, an idea to work on:
pDir = readdir(directory);
while ( pDir != NULL ){
strcpy(dirStruct[iCtFile]->FileName, pp->d_name);
}
Looking ahead, you should consider path treatment and other issues.
Note that you'll need to pass a directory name to opendir().
This is simple example of how to read and save them into a buffer. It doubles the pointers every time it hits the limit. Modern operating systems will clean up the memory allocated once process dies. Ideally, you should also call free() in case of failures.
#include<stdio.h>
#include <dirent.h>
#include <sys/types.h>
#include<string.h>
#include<stdlib.h>
int main(void)
{
size_t i = 0, j;
size_t size = 1;
char **names , **tmp;
DIR *directory;
struct dirent *dir;
names = malloc(size * sizeof *names); //Start with 1
directory = opendir(".");
if (!directory) { puts("opendir failed"); exit(1); }
while ((dir = readdir(directory)) != NULL) {
names[i]=strdup(dir->d_name);
if(!names[i]) { puts("strdup failed."); exit(1); }
i++;
if (i>=size) { // Double the number of pointers
tmp = realloc(names, size*2*sizeof *names );
if(!tmp) { puts("realloc failed."); exit(1); }
else { names = tmp; size*=2; }
}
}
for ( j=0 ; j<i; j++)
printf("Entry %zu: %s\n", j+1, names[j]);
closedir(directory);
}

How to list all files from subfolders?

I've been trying for a few days now to write a code which will inspect all subfolders from C:\Users, and print their files, for example:
C:\Users\Public
files
C:\Users\Somefolder
files
Here is my code:
main() {
DIR *dr,*dirp;
struct dirent *dr_ent,*sec;
char *buf,*baf;
char get[50],x[50];
char folder[] = "C:\\Users\\";
dr = opendir(folder);
if (dr != NULL)
goto next;
else return -1;
next:
while ((dr_ent = readdir(dr))!=NULL) {
buf=dr_ent->d_name;
strcpy(get,buf);
if (strstr(get,".")==NULL && strstr(get,"..")==NULL) {
strcpy(x,folder);
strcat(x,get);
printf("%s\n",x);
continue;
goto read;
Sleep(300);
}
}
read:
dirp = opendir(get);
while ((sec = readdir(dirp))!=NULL) {
baf=sec->d_name;
printf("%s\n",baf);
Sleep(300);
}
system("PAUSE");
return EXIT_SUCCESS;
}`enter code here`
And in this case, only one folder was read. So am I actually making mistake by taking a variable from loop before so only one line was taken? And why is second label completely ignored by program? By the way, I'm sort of beginner in C programming, so don't get surprised by potential errors.
The second label is completely ignored because before the goto read; you use continue; which takes you to the next iteration of the while loop ignoring everything else after it.
Also in your code you don't check if the directory's entry is a file or a directory to handle it appropriately. What I mean is you should descend into a directory but you should print a file's name when you encounter one (as you do).
You can use a recursive function to avoid the use of goto, as goto is a bad practice.
void list_dir(char const* dirName)
{
DIR* dir;
if ((dir = opendir(dirName)) == NULL) {
fprintf(stderr, "Cannot open directory '%s': %s\n", dirName, strerror(errno));
exit(EXIT_FAILURE);
}
struct dirent* entry;
// For every entry in the directory
while ((entry = readdir(dir)) != NULL) {
char* path; // path = dirName/entryName
int pathLength; // length of the path in chars
struct stat entryStats; // info of the entry
char* entryName = entry->d_name; // entry filename
pathLength = strlen(dirName) + 1 + strlen(entryName);
path = malloc((pathLength + 1) * sizeof(char));
strcpy(path, dirName);
strcat(path, "/");
strcat(path, entryName);
if (stat(path, &entryStats) == 0) {
// If the entry is a directory
if (entryStats.st_mode & S_IFDIR) {
// If the directory is not "." or ".." get its entries
if (strcmp(entryName, ".") != 0 &&
strcmp(entryName, "..") != 0) {
list_dir(path);
}
}
// If the entry is a file
else if (entryStats.st_mode & S_IFREG) {
printf("%s\n",path);
}
}
free(path);
}
closedir(dir);
}
The above code works on Unix but on Windows you may have to change stat and struct stat to _stat and struct _stat if you are using Visual Studio.

C Recursive Directory copy of sub folders

I'm having issues getting the following code to run to recursively copy sub-folders in C. I saw this in another post but the code seem to not run the if statement to check if the current file is a directory.
void SearchDirectory(const char *name) {
DIR *dir = opendir(name);
if(dir) {
char Path[256], *EndPtr = Path;
struct dirent *e;
strcpy(Path, name);
EndPtr += strlen(name);
while((e = readdir(dir)) != NULL) {
struct stat info;
strcpy(EndPtr, e->d_name);
if(!stat(Path, &info)) { //code stops here and won't check if the current file is a directory or not..
if(S_ISDIR(info.st_mode)) {
SearchDirectory(Path);
} else if(S_ISREG(info.st_mode) {
//Copy routine
}
}
}
}
}
Edit
So I added a slash on the the end of the path and it seem to find the directory but is crashing with stack error on execution. I think it is recursing without end. New code is:
void SearchDirectory(const char *name) {
DIR *dir = opendir(name);
if(dir) {
char Path[256], *EndPtr = Path;
struct dirent *e;
strcpy(Path, name);
strcat(Path, slash);
EndPtr += (strlen(name)+1);
while((e = readdir(dir)) != NULL) {
struct stat info;
strcpy(EndPtr, e->d_name);
if(!stat(Path, &info)) { //code stops here and won't check if the current file is a directory or not..
if(S_ISDIR(info.st_mode)) {
SearchDirectory(Path);
} else if(S_ISREG(info.st_mode) {
//Copy routine
}
}
}
}
}
It looks like it's failing to insert the directory separator character (/) between the base directory and the appended part.
Assuming name = "/home/foo/bar", EndPtr will point at the '\0' at the end, and then e->d_name is copied there, without anything in-between. This is wrong, it will create a mashed-up filename.
I could not test your code myself, I do not have the right libraries installed., but
there is an example that may be helpful here of using opendir et. al.

Do I need to Allocate Memory for a Dirent Structure

Platform: Windows XP Service Pack 3
Compiler: Code::Blocks version 12.11
I am currently writing a program that will recursively delete a given directory using the POSIX directory functions. But I am having a problem with readdir() and its counterpart the dirent structure. I read in readdir's documentation that multiple calls to the function will overwrite the data held in the structure returned by the function. So I thought readdir() must allcoate memmory for the struct itself and then simply reassign the pointer address to the structure that captures it's return value. I tested this theory and I was correct readdir() allocated memmory for it's member d_name. The problem I am having is that readdir returns a NULL pointer when the directory stream is empty, so I use a while loop with the condition (dirent_ptr != NULL) to iterate the entire directory. But because readdir() will handle the memmory allocation of the structure I simply declare a dirent structure and let readdir() do its job. Unfourtatnly for some reason dirent structures are initialized to NULL(or it might be my complier) so my loop never starts because it's conditional statement is not initialy true. So I guess my question is what am I doing wrong here?
Here are important variable declarations and the included librarys. Please note that all of these variables are declared globaly.
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
int recursive_delete(const char *path);
int file_delete(const char *path, int file_size);
struct dirent *direntp;
struct stat *statp;
struct switches
{
int verbose;
int no_prompt;
int continue_if_error;
int files_only;
}; struct switches switches;
Rather than resolving relative paths I simply cd to the path given as an argument and then I use the . and .. wildcards to move threw the directorys so that relative paths(d_names) are valid. Also the switches structure simply contains command line switches and should be ignored and I am aware of errors in the following code but unfourtantly I cannot fix them because I cannot get past the above mentioned problem.
int recursive_delete(const char *path)
{
DIR *dirp;
int return_value = 0;
int recursive_return_value = 0;
if((chdir(path)) == -1)
{
perror("ERROR(3)");
return 1;
}
printf("CDED to \"%s\"\n", path);
dirp = opendir(".");
if(dirp == NULL)
{
perror("ERROR(4)");
return 1;
}
printf("OPENED \"%s\"\n", path);
while(direntp != NULL)
{
direntp = readdir(dirp);
if( (direntp == NULL) && (errno != 0) )
{
perror("ERROR(5)");
return 1;
}
printf("READ \"%s\" FROM \"%s\"\n", direntp->d_name, path);
if( (strcmp(direntp->d_name, ".")!=0) && (strcmp(direntp->d_name, "..")!=0) )
{
if((stat(direntp->d_name, statp)) == -1)
{
perror("ERROR(6)");
return 1;
}
printf("STATED \"%s\"\n", direntp->d_name);
if(S_ISREG(statp->st_mode))
{
printf("DELETING \"...\\%s\\%s\"\n", path, direntp->d_name);
return_value += file_delete(direntp->d_name, statp->st_size);
if( (!switches.continue_if_error) && (return_value != 0) )
{
break;
}
}
else if(S_ISDIR(statp->st_mode))
{
printf("\n\n\nCALLING RECURSIVE DELETE with \"%s\"\n", direntp->d_name);
recursive_return_value = recursive_delete(direntp->d_name);
return_value += recursive_return_value;
if( (!switches.continue_if_error) && (recursive_return_value != 0) )
{
break;
}
if( (!switches.files_only) && (recursive_return_value == 0) )
{
if((chdir("..")) == -1)
{
perror("ERROR(6)");
return 1;
}
printf("CDED BACK TO \"%s\" FROM \"%s\"\n", path, direntp->d_name);
if((rmdir(direntp->d_name)) == -1)
{
perror("ERROR(7)");
return 1;
}
if(switches.verbose)
{
printf("DELETED DIRECTORY \"...\\%s\\\"\n\n\n", direntp->d_name);
}
}
}
}
}
return return_value;
}
Your code structure should look something like thhis (with most error checks omitted for clarity):
int recursive_delete(const char *path)
{
DIR* dirp = NULL;
int return_value = 0;
char* initial_cur_dir = malloc(1000);
getcwd(initial_cur_dir, 1000);
chdir(path);
dirp = opendir(".");
while (dirp != NULL)
{
struct dirent* direntp;
struct stat stat;
direntp = readdir(dirp);
if (direntp == NULL)
break;
stat(direntp->d_name, &stat);
if (S_ISDIR(statp->st_mode))
{
if (strcmp(direntp->d_name, ".") && strcmp(direntp->d_name, ".."))
{
return_value += recursive_delete(direntp->d_name);
}
}
else if (S_ISREG(statp->st_mode))
{
unlink(direntp->d_name);
}
}
if (initial_cur_dir != NULL)
{
chdir(initial_cur_dir);
rmdir(path);
}
ErrorLabel: // you should goto here when an error is detected
if (dirp != NULL)
{
closedir(dirp);
}
if (initial_cur_dir != NULL)
{
chdir(initial_cur_dir);
free(initial_cur_dir);
}
return return_value;
}
From the code attached, it's not clear where direntp is being initialized (before the while loop). Possibly try something like:
direntp = readdir(dirp);
while(direntp != NULL)
{
// all your work here
direntp = readdir(dirp);
}
This pattern ensures that direntp is initialized and updated for your while loop. However, on second glance of your code I'm not exactly sure what the while loop is supposed to be doing in the first place. How is direntp or dirp changing in your loop?
It's possible that you can just get away with an if test (instead of the while) and just let the recursive call handle the "looping" effect...

Resources