readdir() не работает должным образом для подкаталогов

У меня есть эта функция, которая использует readdir(). Я использую stat(), чтобы получить информацию о файлах, которые находятся в каталоге, который я предоставляю в качестве параметра.

имя_папки [] фактически является абсолютным путем к каталогу, который я хочу прочитать

Функция отлично работает для таких имен, как . или же ./lfac но это не работает должным образом для имен, таких как ./lfac/comp, Я проверяю его, и он читает некоторые файлы из этого каталога, но не все из них. Исполняемый файл помещается в корневой каталог.

У меня есть другая функция (рекурсивная функция), которая также использует readdir () и хранит список с абсолютными путями файлов, которые находятся в каталоге (я даю в качестве параметра) и его подкаталогах. Эта функция имеет ту же проблему.

void content(char folder_name[], char *answer)
{                               
    DIR *diropen;
    struct dirent *dirread;

    if ((diropen = opendir(folder_name)) == NULL)
    {
        printf ("Error opening directory %s\n",folder_name);
        exit(EXIT_FAILURE);
    }

    while ((dirread = readdir (diropen)) != NULL)
    {
        struct stat sb;
        memset(&sb, 0, sizeof sb);
        char *temp;
        temp = (char*) malloc (sizeof(char));
        temp[0] = 0;
        sprintf(temp,"%s/%s",folder_name,dirread->d_name);
        if(strcmp(dirread->d_name,".")==0 || strcmp(dirread->d_name,".")==0)
            continue;
        if (stat(temp, &sb) == -1) {
            perror("stat");
            exit(EXIT_FAILURE);
        }

        strcat(answer,"File name:                ");
        strcat(answer,dirread->d_name);
        strcat(answer,"\n");
        strcat(answer,"File type:                ");
        switch (sb.st_mode & S_IFMT) {
        case S_IFBLK:  strcat(answer,"block device\n");            break;
        case S_IFCHR:  strcat(answer,"character device\n");        break;
        case S_IFDIR:  strcat(answer,"directory\n");               break;
        case S_IFIFO:  strcat(answer,"FIFO/pipe\n");               break;
        case S_IFLNK:  strcat(answer,"symlink\n");                 break;
        case S_IFREG:  strcat(answer,"regular file\n");            break;
        case S_IFSOCK: strcat(answer,"socket\n");                  break;
        default:       strcat(answer,"unknown?\n");                break;
        }
        sprintf(temp,"I-node number:            %ld\n", (long) sb.st_ino); strcat(answer,temp);
        .......
    }
}

1 ответ

Решение

Вы попираете тяжелые ботинки через память вашего компьютера, поэтому вы получаете неопределенное поведение.

Эта часть

char *temp;
temp = (char*) malloc (sizeof(char));
temp[0] = 0;
sprintf(temp,"%s/%s",folder_name,dirread->d_name);

выделяет всего 1 байт памяти, за sizeof(char), но следующее, что вы делаете, это пишете в него более длинные строки.

Вам нужно выделить больше, чем это - по крайней мере, столько же, сколько длина пути к вашей папке, плюс разделитель и максимально допустимая длина имени файла. Есть несколько констант, таких как MAX_FILE_PATH Вы можете использовать, но это зависит от компилятора и системы; Я обычно использую что-то "достаточно большой, кашель", такой как 1024,

Однако мне не совсем понятно, почему вы выделяете эту память в цикле. (Главным образом потому, что вы нигде не освобождаете его, поэтому я не знаю предполагаемой области видимости.) Вы можете сделать это до цикла, а затем вы можете использовать

char temp[1024];

вместо динамического распределения.

К сожалению, это не решает проблему... Как я уже говорил, у меня есть другая функция, которая имеет ту же проблему, и она не использует динамическое распределение.

void print_files(char folder_name[], char *answer)
{
    DIR *diropen;
    struct dirent *dirread;
    char innerpath[100];

    if ((diropen = opendir(folder_name)) == NULL)
    {
        printf ("Error opening directory %s\n",folder_name);
        exit(EXIT_FAILURE);
    }

    while ((dirread = readdir (diropen)) != NULL)
    {   
        if(strcmp(dirread->d_name,".") != 0 && strcmp(dirread->d_name,"..") != 0)
        {
            strcat(answer,folder_name);
            strcat(answer,"/");
            strcat(answer,dirread->d_name);
            strcat(answer,"\n");
        }

        if (dirread->d_type == DT_DIR && strcmp(dirread->d_name,".") != 0 && strcmp(dirread->d_name,"..") != 0)
        {
            strcpy(innerpath,folder_name);
            strcat(innerpath,"/");
            strcat(innerpath,dirread->d_name);
            print_files(innerpath,answer);
        }
    }

    closedir(diropen);
}
Другие вопросы по тегам