Linux программирование в примерах
Шрифт:
};
Параметр
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->bas
e действует в качестве индекса в 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);
62 printf("Starting dir: %s\n", start);
63 printf("Finishing dir: %s\n", finish);
64 }
65
66 return (errors != 0);
67 }
Строки 3–11 включают заголовочные файлы. По крайней мере в GLIBC 2.3.2 перед включением любого заголовочного файла необходимы
#define
для _XOPEN_SOURCE
и _XOPEN_SOURCE_EXTENDED
. Они дают возможность получить объявления и значения флагов, которые nftw
предоставляет свыше предоставляемых ftw
. Это специфично для GLIBC. Потребность в этом в конечном счете исчезнет, когда GLIBC станет полностью совместимой со стандартом POSIX 2001.
Поделиться с друзьями: