Выбрать главу

 int level; /* Глубина этого элемента относительно точки отсчета */

};

Параметр flag имеет одно из перечисленных в табл. 8.4 значений.

Таблица 8.4. Значения флагов для функции обратного вызова nftw()

Флаг Значение
FTW_F Объект является обычным файлом
FTW_D Объект является каталогом
FTW_DNR Объект является каталогом, который нельзя прочесть
FTW_SL Объект является символической ссылкой
FTW_NS Объект не является символической ссылкой, а stat() потерпела неудачу
FTW_DP Объект является каталогом, элементы которого были уже обработаны. Это может случиться, лишь когда в вызове nftw() использовался FTW_DEPTH
FTW_SLN Объект является символической ссылкой, указывающей на несуществующий файл. Это может случиться, лишь когда в вызове nftw() не используется FTW_PHYS

struct FTW* s предоставляет дополнительную информацию, которая может быть полезной. s->base действует в качестве индекса в file; file является полным путем обрабатываемого объекта (относительно точки отсчета), 'file + s->base' указывает на первый символ компонента имени файла.

s->level указывает текущую глубину иерархии; считается, что первоначальная точка отсчета находится на уровне 0.

Функция обратного вызова должна вернуть 0, если все нормально. Любое ненулевое возвращенное значение заставляет nftw() прекратить свою обработку и вернуть то самое ненулевое значение. Справочная страница отмечает, что функция обратного вызова должна останавливать обработку только путем возвращаемого значения, чтобы у nftw() был шанс произвести очистку: т.е. освободить динамически выделенную память, закрыть открытые дескрипторы файлов и т.д. Функции обратного вызова не следует использовать longjmp(), если только программа не завершается немедленно, (longjmp() является продвинутой функцией, которую мы опишем в разделе 12.5 «Нелокальные goto».) Рекомендуемой методикой обработки ошибок является установка глобальной переменной, указывающей на наличие проблем, возвращение 0 из функции обратного вызова и обработка ошибок после завершения перемещения nftw() по иерархии файлов. (GNU du это делает, как мы вскоре увидим.)

Давайте свяжем все это воедино в примере программы. ch08-nftw.c обрабатывает каждый файл или каталог, указанный в командной строке, запуская для них nftw(). Функция, обрабатывающая каждый файл, выводите отступом имя и тип файла, показывая иерархическое положение каждого файла. Для разнообразия мы сначала покажем результаты, а затем покажем и обсудим программу:

$ pwd /* Где мы находимся */

/ home/аrnold/work/prenhall/progex

$ code/ch08/ch08-nftw code /* Обойти каталог 'code' */

code (directory) /* Каталог верхнего уровня */

  ch02 (directory) /* Подкаталоги с отступом на один уровень */

    ch02-printenv.c (file) /* Файлы в подкаталоге с отступом

                              на два уровня */

  ch03 (directory)

    ch03-memaddr.c (file)

  ch04 (directory)

    ch04-holes.c (file)

    ch04-cat.с (file)

    ch04-maxfds.c (file)

    v7cat.c (file)

...

Вот сама программа:

1  /* ch08-nftw.c --- демонстрирует nftw() */

2

3  #define _XOPEN_SOURCE 1 /* Требуется под GLIBC для nftw() */

4  #define _XOPEN_SOURCE_EXTENDED 1 /* To же */

5

6  #include <stdio.h>

7  #include <errno.h>

8  #include <getopt.h>

9  #include <ftw.h> /* получает для нас <sys/types.h> и <sys/stat.h> */

10 #include <limits.h> /* для PATH_MAX */

11 #include <unistd.h> /* для объявлений getdtablesize(), getcwd() */

12

13 #define SPARE_FDS 5 /* fds для использования другими функциями, см. текст */

14

15 extern int process(const char *file, const struct stat *sb,

16  int flag, struct FTW *s);

17

18 /* usage --- print message and die */

19

20 void usage(const char *name)

21 {

22  fprintf(stderr, "usage: %s (-c) directory ...\n", name);

23  exit(1);

24 }

25

26 /* main --- вызвать nftw() для каждого аргумента командной строки */

27

28 int main(int argc, char **argv)

29 {

30  int i, c, nfds;

31  int errors = 0;

32  int flags = FTW_PHYS;

33  char start[PATH_MAX], finish[PATH_MAX];

34

35  while ((c = getopt(argc, argv, "с")) != -1) {

36   switch (c) {

37   case 'c':

38    flags |= FTW_CHDIR;

39    break;

40   default:

41    usage(argv[0]);

42    break;

43   }

44  }

45

46  if (optind == argc)

47   usage(argv[0]);

48

49  getcwd(start, sizeof start);

50

51  nfds = getdtablesize() - SPARE_FDS; /* оставить несколько запасных дескрипторов */

52  for (i = optind; i < argc; i++) {

53   if (nftw(argv[i], process, nfds, flags) != 0) {

54    fprintf(stderr, "%s: %s: stopped early\n",

55     argv[0], argv[i]);

56    errors++;

57   }

58  }

59

60  if ((flags & FTW_CHDIR) != 0) {

61   getcwd(finish, sizeof finish);