0

I wrote a "recursive" readdir function but if I want to check the files in a subdirectory errno is set to ENOENT. If it finds a directory, the directory name is given to the function and printing DIR->d_name gives me the fullpath to the subdirectory. I could not figure it out why this is happening. I wrote this function an it works (for the first subdirectory) but I think checking for stat will fail in a subdir of a subdir too. Has this something to do with recursion?

!!!SOLUTION BELOW CODE!!!

Here is my code: (Probably a bad Error handler but I dont know better yet. Still learning.)

#include <stdio.h>
#include <stdlib.h>

#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>

DIR *Directory_Error_Handler(DIR *directory_return)
{
    //const char[] = "dirname";

    if(directory_return == 0){
        switch(errno){
            case EACCES: printf("Permission denied.\n"); return 0;
            case EBADF:  printf("Not a valid files descriptor opened for reading.\n"); return 0;
            case EMFILE: printf("The per-process limit on the number of open file descriptors has been reached.\n"); return 0;
            case ENFILE: printf("The system-wide limit on the total number of open files has been reached.\n"); return 0;
            case ENOENT: printf("Directory does not exist, or name is an empty string.\n"); return 0;
            case ENOMEM: printf("Insufficient memory to complete the operation.\n"); return 0;
            case ENOTDIR: printf("'name' is not a directory.\n"); return 0;
            default: return directory_return;
        }
    }
    return directory_return;
}

int Stat_Error_Handler(const char *path, struct stat* file_info)
{
    if(stat(path, file_info)){
        switch (errno)
        {
        case EACCES: printf("Search permission is denied for one of the directories in the path prefix of pathname.\n"); return -1;
        case EBADF:  printf("fd is not a valid open file descriptor.\n"); return -1;
        case EFAULT: printf("Bad address.\n"); return -1;
        case EINVAL: printf("fstatat() Invalid flag specified.\n"); return -1;
        case ELOOP:  printf("Too many symbolic links encountered while traversing the path.\n"); return -1;
        case ENAMETOOLONG: printf("pathname is too long.\n"); return -1;
        case ENOENT: printf("A component of pathname does not exist or is a dangling symbolic link. or pathname is an empty string and AT_EMPTY_PATH was not specified in flags.\n"); return -1;
        case ENOMEM: printf("Out of memory.\n"); return -1;
        case ENOTDIR: printf("A component of the path prefix of pathname is not a directory.\n"); return -1;
        case EOVERFLOW: printf("pathname or fd refers to a file whose size, inode number,\n \
              or number of blocks cannot be represented in,\n   \
              respectively, the types off_t, ino_t, or blkcnt_t.  This\n \
              error can occur when, for example, an application compiled\n \
              on a 32-bit platform without -D_FILE_OFFSET_BITS=64 calls\n \
              stat() on a file whose size exceeds (1<<31)-1 bytes.\n"); return -1;
        default: return 0;
        }
    }
    return 0;
}

void walk(DIR *root_directory)
{
    struct dirent *dir_entry;
    struct stat file_info;

    printf("Directory: %s\n", root_directory->dd_name);
    while((dir_entry = readdir(root_directory)) != NULL) {

        if(Stat_Error_Handler(dir_entry->d_name, &file_info) != 0){
            continue;
        }
        if(S_ISDIR(file_info.st_mode)){
            if(dir_entry->d_name[0] == '.' || (dir_entry->d_name[0] == dir_entry->d_name[1])) 
                continue;
            walk(Directory_Error_Handler(opendir(dir_entry->d_name)));
        }
        printf("\t-> %s\n", dir_entry->d_name);
    }
    closedir(root_directory);
}

int main(void)
{
    walk(Directory_Error_Handler(opendir(".")));

    return 0;
}

Solution: with help from this posts first answer

Replaced the hardcoded **** with strerror(). Thx to zwol.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <errno.h>

DIR *Directory_Error_Handler(DIR *directory_return)
{
    //const char[] = "dirname";

    if(directory_return == 0){
        printf("%s\n", strerror(errno));
    }
    return directory_return;
}

int Stat_Error_Handler(const char *path, struct stat* file_info)
{
    if(stat(path, file_info) != 0){
        printf("%s\n", strerror(errno));
        return -1;
    }
    return 0;
}

void walk(DIR *root_directory)
{
    struct dirent *dir_entry;
    struct stat file_info;
    char *EndPtr;
    char Path[256] = {0}; EndPtr = Path;
    
    strncpy(Path, root_directory->dd_name, strlen(root_directory->dd_name)-1); // because i get a * after the last /
    EndPtr += strlen(Path);

    while((dir_entry = readdir(root_directory)) != NULL) {
        strcpy(EndPtr, dir_entry->d_name);

        if(Stat_Error_Handler(Path, &file_info) != 0){      // give the fullpath to stat()
            continue;
        }
        if(S_ISDIR(file_info.st_mode)){
            if(dir_entry->d_name[0] == '.' || (dir_entry->d_name[0] == dir_entry->d_name[1])) 
                continue;
            walk(Directory_Error_Handler(opendir(Path)));   // replaceing the dir_entry->d_name with Path
        } else                         // <-
            printf("\t-> %s\n", Path); // putting this into else because i only need filenames
    }
    closedir(root_directory);
}

int main(void)
{
    walk(Directory_Error_Handler(opendir(".")));

    return 0;
}
4c1d
  • 5
  • 2
  • 4
    You're probably missing that d_name is just the name, not the whole path – user253751 Apr 05 '22 at 12:50
  • 2
    Unrelated to your problem but the C library has a function called [strerror](https://man7.org/linux/man-pages/man3/strerror.3.html) that you might find useful. – zwol Apr 05 '22 at 13:05
  • You are probably running into the problems described in [`stat()` error "no such file or directory" when file name is returned by `readdir()`](https://stackoverflow.com/questions/5125919/stat-error-no-such-file-or-directory-when-file-name-is-returned-by-readdir). – Jonathan Leffler Apr 05 '22 at 14:00
  • Thanks to all of u. Was just wondering why opening the first subdir with the name works but its just because its located in the the current directory. Learned something! – 4c1d Apr 05 '22 at 14:29

0 Answers0