Листинг 18.3. Использование функции для обхода дерева каталога
dirs_links/nftw_dir_tree.c
#define _XOPEN_SOURCE 600
/* Получаем объявление функции nftw() и макроопределение S_IFSOCK */
#include
#include "tlpi_hdr.h"
static void
usageError(const char *progName, const char *msg)
{
if (msg!= NULL)
fprintf(stderr, "%s\n", msg);
fprintf(stderr, "Usage: %s [-d] [-m] [-p]
[directory-path]\n", progName);
fprintf(stderr, "\t-d Use FTW_DEPTH flag\n");
fprintf(stderr, "\t-m Use FTW_MOUNT flag\n");
fprintf(stderr, "\t-p Use FTW_PHYS flag\n");
exit(EXIT_FAILURE);
}
static int /* Функция, вызываемая функцией nftw() */
dirTree(const char *pathname, const struct stat *sbuf, int type,
struct FTW *ftwb)
{
switch (sbuf->st_mode & S_IFMT) { /* Выводим тип файла */
case S_IFREG: printf("-"); break;
case S_IFDIR: printf("d"); break;
case S_IFCHR: printf("c"); break;
case S_IFBLK: printf("b"); break;
case S_IFLNK: printf("l"); break;
case S_IFIFO: printf("p"); break;
case S_IFSOCK: printf("s"); break;
default: printf("?"); break;
/* Такое не должно произойти (в Linux) */
}
printf(" %s",
(type == FTW_D)? "D": (type == FTW_DNR)? "DNR":
(type == FTW_DP)? "DP": (type == FTW_F)? "F":
(type == FTW_SL)? "SL": (type == FTW_SLN)? "SLN":
(type == FTW_NS)? "NS": " ");
if (type!= FTW_NS)
printf("%7ld", (long) sbuf->st_ino);
else
printf(" ");
printf(" %*s", 4 * ftwb->level, ""); /* Добавляем подходящий отступ */
printf("%s\n", &pathname[ftwb->base]); /* Выводим базовое имя */
return 0;
/* Даем команду на продолжение работы функции nftw() */
}
int
main(int argc, char *argv[])
{
int flags, opt;
flags = 0;
while ((opt = getopt(argc, argv, "dmp"))!= -1) {
switch (opt) {
case 'd': flags |= FTW_DEPTH; break;
case 'm': flags |= FTW_MOUNT; break;
case 'p': flags |= FTW_PHYS; break;
default: usageError(argv[0], NULL);
}
}
if (argc > optind + 1)
usageError(argv[0], NULL);
if (nftw((argc > optind)? argv[optind]: ".", dirTree, 10, flags)
== -1) {
perror("nftw");
exit(EXIT_FAILURE);
}
exit(EXIT_SUCCESS);
}
dirs_links/nftw_dir_tree.c
Программа в листинге 18.3 отображает снабженную отступами иерархию имен файлов в дереве каталога, по одному имени файла на строку, а также тип файла и номер индексного дескриптора. Можно использовать параметры командной строки, чтобы указать параметры аргумента flags, примененного для вызова функции nftw(). Следующий сеанс работы в оболочке демонстрирует примеры того, что мы увидим при запуске данной программы. Создадим сначала пустой подкаталог, который заполним файлами разных типов:
$ mkdir dir
$ touch dir/a dir/b
$ ln — s a dir/sl
$ ln — s x dir/dsl
$ mkdir dir/sub
$ touch dir/sub/x
$ mkdir dir/sub2
$ chmod 0 dir/sub2
Используем теперь нашу программу для вызова функции nftw() с нулевым аргументом flags:
$ ./nftw_dir_tree dir
d D 2327983 dir
— F 2327984 a
— F 2327985 b
— F 2327984 sl
l SLN 2327987 dsl
d D 2327988 sub
— F 2327989 x
d DNR 2327994 sub2
Из приведенного выше фрагмента видно, что для символической ссылки sl был выполнен разбор.
Применим теперь нашу программу для вызова функции nftw() с аргументом flags, который содержит значения FTW_PHYS и FTW_DEPTH:
$ ./nftw_dir_tree — p — d dir
— F 2327984 a
— F 2327985 b
l SL 2327986 sl
l SL 2327987 dsl
— F 2327989 x
d DP 2327988 sub
d DNR 2327994 sub2
d DP 2327983 dir
Из приведенного выше фрагмента видно, что разбор символической ссылки sl не был выполнен.
Начиная с версии 2.3.3, библиотека glibc позволяет использовать дополнительный нестандартный флаг flags. Этот флаг, FTW_ACTIONRETVAL, изменяет способ интерпретации функцией nftw() значения, которое возвращено после вызова функции func(). Если указан данный флаг, функция func() должна возвращать одно из следующих значений:
• FTW_CONTINUE — продолжить обработку записей в дереве каталога, как при обычном возврате нулевого значения от функции func();
• FTW_SKIP_SIBLINGS — не обрабатывать остальные записи в данном каталоге; возобновить обработку родительского каталога;
• FTW_SKIP_SUBTREE — если аргумент pathname является каталогом (то есть значение typeflag равно FTW_D), то не вызывать функцию func() для записей в этом каталоге. Обработка возобновляется в следующем каталоге, родительский каталог которого такой же, как у текущего;