Обход файловой системы с помощью fts(3)

У меня вопрос по fts(3). Я получаю ошибку сегментации всякий раз, когда пытаюсь получить доступ к любым членам функции fts_children(). Когда я читаю справочную страницу по адресу http://www.kernel.org/doc/man-pages/online/pages/man3/fts.3.html он утверждает, что заполняет себя после запуска функции чтения и возвращает связанный список, связанный через поле link в структуре . Я подозреваю, что child_function ничего не возвращает, но я чувствую, что это не совпадает с справочной страницей. Должен ли я добавлять эти файлы в дочерний буфер, потому что я думал, что это делается автоматически? Мой код ниже, спасибо!

#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fts.h>
#include<string.h>

int compare (const FTSENT**, const FTSENT**);

int main(int argc, char* const argv[])
{

        FTS* file_system = NULL;
        FTSENT* child = NULL;
        FTSENT* parent = NULL;
        FTSENT* temp = NULL;

        file_system = fts_open(argv + 1,FTS_COMFOLLOW | FTS_NOCHDIR,&compare);

        while( (parent = fts_read(file_system)) != NULL)
        {

             child = fts_children(file_system,0);
             printf("%s\n", child->fts_path);


        }
//      while (child ->fts_link != NULL)
      //         child = child->fts_link;
        fts_close(file_system);
        return 0;
}

int compare(const FTSENT** one, const FTSENT** two){
        return (strcmp((*one)->fts_name, (*two)->fts_name));
}
"test_fs.c" 43L, 1108C  

person tpar44    schedule 26.09.2012    source источник


Ответы (2)


Вам просто нужно добавить проверку NULL.

Вы можете захотеть

  • добавить один для file_system
  • проверить аргументы командной строки
  • #P3# <блочная цитата> #P4#

Обновить к новым вопросам в комментарии:

  • Цикл while для обхода связанного списка был неуместен (вне внешнего цикла?)
  • Printf отображал только путь... а не имя файла.

пока вы на нем:

#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fts.h>
#include<string.h>
#include<errno.h>

int compare (const FTSENT**, const FTSENT**);

int main(int argc, char* const argv[])
{
    FTS* file_system = NULL;
    FTSENT* child = NULL;
    FTSENT* parent = NULL;

    if (argc<2)
    {
        printf("Usage: %s <path-spec>\n", argv[0]);
        exit(255);
    }

    file_system = fts_open(argv + 1,FTS_COMFOLLOW | FTS_NOCHDIR,&compare);

    if (NULL != file_system)
    {
        while( (parent = fts_read(file_system)) != NULL)
        {
            child = fts_children(file_system,0);

            if (errno != 0)
            {
                perror("fts_children");
            }

            while ((NULL != child)
                && (NULL != child->fts_link))
            {
                child = child->fts_link;
                printf("%s%s\n", child->fts_path, child->fts_name);
            }
        }
        fts_close(file_system);
    }
    return 0;
}

int compare(const FTSENT** one, const FTSENT** two)
{
    return (strcmp((*one)->fts_name, (*two)->fts_name));
}

Пример выходного фрагмента:

./.profiles/sehe/.opera/icons/cache/g_0000
./.profiles/sehe/.opera/icons/cache/g_0000/opr00002.tmp
./.profiles/sehe/.opera/icons/cache/g_0000/opr00003.tmp
./.profiles/sehe/home/sehe/.mozilla
fts_children: Permission denied
./.vbox-sehe-ipc/lock
person sehe    schedule 26.09.2012
comment
Также добавлена ​​правильная обработка errno. - person sehe; 27.09.2012
comment
Спасибо. На самом деле это была просто программа, чтобы увидеть, знаю ли я, как ее использовать, но я не знал. Чего я не понимаю, так это почему файлы не распечатываются, только каталоги и почему я не могу пройти по связанному списку (закомментированный цикл while)? - person tpar44; 27.09.2012
comment
@ tpar44 Эм, да, я не обратил на это особого внимания, потому что ты ничего об этом не спрашивал. Я теперь исправил и эту часть кода (обновил ответ) - person sehe; 27.09.2012
comment
Большое спасибо! Тем не менее, могу я спросить вас еще об одном? Моя цель состояла не в том, чтобы кто-то другой сделал пример за меня, а в том, чтобы научиться использовать fts(3), поскольку это похоже на функцию, которую я должен знать. Мой вопрос: почему вы переместили второй цикл while внутрь первого? Я думал, что функция function возвращает связанный список для всего прочитанного, я ошибаюсь? - person tpar44; 27.09.2012
comment
@ tpar44 Я переместил его внутрь цикла while, так как вызов fts_children также был там ... Было бы разумно повторять один раз для каждого результата, который вы получаете от fts_read, а не только для последнего. - person sehe; 27.09.2012
comment
@tpar Для получения дополнительной информации man fts(3) Похоже, это гораздо более тонкий источник. FWIW: я предпочитаю интерфейсы *ftw, основанные на обратном вызове, см., например. этот ответ stackoverflow.com/a/7672081/85371 - person sehe; 27.09.2012

Если вас интересует только просмотр всех каталогов и файлов по указанному пути (путям), просто повторно вызовите fts_read.

Если вы хотите только перебирать поток, пример @sehe можно переписать так:

#include<stdlib.h>
#include<stdio.h>
#include<sys/types.h>
#include<fts.h>
#include<string.h>
#include<errno.h>

int compare (const FTSENT**, const FTSENT**);
void indent (int i);

int main(int argc, char* const argv[])
{
    FTS* file_system = NULL;
    FTSENT *node,    = NULL;

    if (argc<2)
    {
        printf("Usage: %s <path-spec>\n", argv[0]);
        exit(255);
    }

    file_system = fts_open(argv + 1,FTS_COMFOLLOW|FTS_NOCHDIR,&compare);

    if (NULL != file_system)
    {
        while( (node = fts_read(file_system)) != NULL)
        {
            switch (node->fts_info) 
            {
                case FTS_D :
                case FTS_F :
                case FTS_SL:
                    indent(node->fts_level);
                    printf("%s\n", node->fts_name);
                    break;
                default:
                    break;
            }
        }
        fts_close(file_system);
    }
    return 0;
}

int compare(const FTSENT** one, const FTSENT** two)
{
    return (strcmp((*one)->fts_name, (*two)->fts_name));
}

void indent(int i)
{
    for (; i > 0; i--) 
        printf("    ");
}

Когда вы запускаете его, он перебирает поток и перечисляет все файлы и каталоги по порядку:

★ mkdir -p test/A/1 test/A/2 test/B/1 test/B/2

★ tree test                                   
test
├── A
│   ├── 1
│   └── 2
└── B
    ├── 1
    └── 2

★ ./fts test                                  
test
    A
        1
        2
    B
        1
        2

Вызывайте fts_children, только если вам нужен список дочерних узлов определенного каталога. В этом случае вы должны вызвать fts_read по крайней мере один раз перед вызовом fts_children; в противном случае fts_children вернет только узлы, указанные в параметре argv, в fts_open.

person Mr. Curious    schedule 12.03.2014
comment
Голосование за, потому что man fts явно не указывает, что последующий вызов fts_read будет проходить по файловой системе. Это подразумевается, но это вовсе не очевидно. - person retrodev; 01.02.2016
comment
Привет, есть ли способ использовать fts, чтобы получить общее количество обычных файлов в корневом каталоге, не просматривая их сначала (что может занять некоторое время...) - person Zohar81; 11.04.2018
comment
Думаю нет. Вам нужно будет вызвать fts_read() один раз, затем fts_children() и перебрать связанный список, который он возвращает, и проверить, является ли каждый дочерний элемент обычным файлом или чем-то еще. - person Mr. Curious; 16.04.2018
comment
На странице руководства указано Either FTS_LOGICAL or FTS_PHYSICAL must be provided to the fts_open() function. man7.org/linux/man-pages/man3 /fts.3.html - person ishmael; 26.09.2019