2015-10-15 1 views
1

у меня есть USB-накопитель fat32 со следующей структурой:readdir_r вдаваясь в бесконечный цикл для длинных имен файлов

/media/pendrive/ 
├── a 
│   ├── 1.mp4 
│   ├── 2.mp4 
│   └── 3.mp4 
└── Data 
    ├── files 
    │   └── file.txt 
    └── 千千千千刻千千千千刻千刻千阙歌陈慧娴啊深刻千千阙歌陈慧娴啊深刻千千阙歌陈慧娴啊深刻千千阙歌陈慧娴啊深刻千千阙歌陈慧娴啊深刻千千阙歌陈慧娴啊深刻千千阙歌陈慧娴啊深刻千千阙歌陈慧娴啊深刻千千阙歌陈慧娴啊深刻千千阙歌陈慧娴啊深刻千千阙歌陈慧娴啊深刻千千阙歌陈慧娴啊深刻千千阙歌陈慧娴啊深刻千千阙歌陈慧娴啊深刻千千阙歌陈慧娴啊深刻千千阙歌陈慧娴啊深刻千千阙歌陈慧娴啊深刻千千阙歌陈慧娴啊深刻千千阙歌陈慧娴啊深刻千千阙歌陈慧娴啊深刻千千阙歌陈慧娴啊深刻千千阙歌陈慧娴啊深刻千千阙歌陈慧娴啊深刻千千千阙千歌陈慧娴啊.mp3 

3 directories, 5 files 

Моя следующая программа для чтения записей в каталоге:

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

int count_files(char *path) 
{ 
    int sum = 0; 
    DIR *dir; 

    dir = opendir(path); 
    if (!dir) { 
     perror("opendir"); 
     exit(EXIT_FAILURE); 
    } 

    for (;;) { 
     struct dirent entry; 
     struct dirent *result; 
     char *name; 
     char sub_path[256]; 

     int error = readdir_r(dir, &entry, &result); 

     if(error == 36) //36 = ENAMETOOLONG 
     { 
      printf("Ignoring current file, name too long\n"); 
      continue; 
     } 
     else if (error != 0) { 
      printf("error code : %d\n", error); 
      perror("readdir"); 
     } 

     // readdir_r returns NULL in *result if the end 
     // of the directory stream is reached 
     if (result == NULL) 
     { 
      printf("NULL returned\n"); 
      break; 
     } 

     name = result->d_name; 
     if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0)) 
      continue; 
     printf("%s\n",name); 
     sum++; 
     if (result->d_type == DT_DIR) { 
      sprintf(sub_path, "%s/%s", path, name); 
      sum += count_files(sub_path); 
     } 
    } 
    closedir(dir); 

    return sum; 
} 

int main() 
{ 
    char *path = "/media/pendrive"; 
    int sum = count_files(path); 
    printf("There are %d files in '%s'\n", sum, path); 
    return 0; 
} 

Это собирается в бесконечный цикл:

Data 
files 
file.txt 
NULL returned 
Ignoring current file, name too long 
Ignoring current file, name too long 
Ignoring current file, name too long 
Ignoring current file, name too long 
Ignoring current file, name too long 
Ignoring current file, name too long 
Ignoring current file, name too long 
Ignoring current file, name too long 
Ignoring current file, name too long 
Ignoring current file, name too long 
Ignoring current file, name too long 
. 
. 
. 

Как я могу обращаться с таким случаем, чтобы пропустить файлы с длинными файлами и перейдите к следующему файлу?

+0

Моего быстрое чтение [страница руководства 'readdir_r()'] (http://linux.die.net/man/3/readdir_r) Didn Нельзя сказать, что можно исправить ошибки, поэтому я думаю, вам не повезло с этим подходом. Также кажется, что данная ошибка является расширением GNU? – unwind

+0

После исправления исправлена ​​проблема, но она не была объединена/выпущена с реализацией 'glibc/readdir_r'. Поскольку спецификация не упоминает 'ENAMETOOLONG' как возможную ошибку возврата. https://sourceware.org/ml/libc-alpha/2013-05/msg00445.html – deimus

+0

Не связанный с вашей проблемой, но вы должны проверить 'errno' (или использовать функцию, которая делает, например' perror') * напрямую * после неудавшаяся функция, потому что вы не знаете, будет ли изменен код errno измененным кодом. Кроме того, ['readdir_r'] (http://pubs.opengroup.org/onlinepubs/9699919799/functions/readdir.html) на самом деле не задано для установки' errno'. –

ответ

1

Пер с man page, я вижу две потенциальные проблемы с вашим кодом:

Первое:

В настоящее время только некоторые файловые системы (среди них: Btrfs, ext2, ext3, и ext4) имеют полный поддержка для возврата типа файла в d_type. Все приложения должны должным образом обрабатывать возврат DT_UNKNOWN.

Ваш код не обрабатывает DT_UNKNOWN.

Также, что возвращает pathconf(path, _PC_NAME_MAX) для этого каталога? Опять же на странице человека:

Поскольку POSIX.1 не определяет размер поля d_name и другие нестандартные поля могут предшествовать поле в структуре Dirent , портативные приложения, которые используют readdir_r() следует выделить буфер, адрес которого передается в записи следующим образом: (. POSIX.1 требует, чтобы d_name это последнее поле в STRUCT Dirent)

name_max = pathconf(dirpath, _PC_NAME_MAX); 
    if (name_max == -1)   /* Limit not defined, or error */ 
     name_max = 255;   /* Take a guess */ 
    len = offsetof(struct dirent, d_name) + name_max + 1; 
    entryp = malloc(len); 

Кроме того, это потенциальное переполнение буфера:

char sub_path[256]; 
    ... 
     sprintf(sub_path, "%s/%s", path, name); 
Смежные вопросы