Категории
Самые читаемые
PochitayKnigi » Компьютеры и Интернет » Программное обеспечение » Linux программирование в примерах - Арнольд Роббинс

Linux программирование в примерах - Арнольд Роббинс

Читать онлайн Linux программирование в примерах - Арнольд Роббинс

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 61 62 63 64 65 66 67 68 69 ... 165
Перейти на страницу:

8.4.3.1. Интерфейс nftw()

Чтобы избавиться от проблем, System V предложила функцию ftw() («file tree walk» — обход дерева файлов), ftw() осуществляла всю работу по «прохождению» дерева (иерархии) файлов. Вы предоставляете ей указатель на функцию, и она вызывает эту функцию для каждого объекта файла, с которым сталкивается. Ваша функция должна затем обработать каждый объект файловой системы, как считает нужным.

Со временем стало ясно, что интерфейс ftw() не вполне выполнял свою работу;[84] например, первоначально он не поддерживал символические ссылки. По этим причинам к X/Open Portability Guide, который теперь является частью POSIX, была добавлена nftw() («new (новая) ftw()» [важно]). Вот прототип:

#include <ftw.h> /* XSI */

int nftw(const char *dir,    /* Отправная точка */

 int (*fn)(const char *file, /* Указатель функции на */

  const struct stat *sb,     /* функцию из четырех аргументов */

  int flag, struct FTW *s),

 int depth, int flags);      /* Максимум открытых fds, флаги */

А вот аргументы:

const char *dir

Строка с именем отправной точки иерархии для обработки.

int (*fn)(const char *file, const struct stat *sb, int flag, struct FTW *s)

Указатель на функцию с данными аргументами. Эта функция вызывается для каждого объекта в иерархии. Подробности ниже.

int depth

Этот аргумент назван неверно. Чтобы избежать выхода за пределы дескрипторов файлов, nftw() держит открытыми не более, чем depth одновременно открытых каталогов. Это не препятствует обработке nftw() иерархий, которые глубже уровня depth, но меньшие значения depth означают, что nftw() придется делать больше работы.

flags

Набор флагов, объединяемых побитовым ИЛИ, которые указывают, как nftw() должна обрабатывать иерархию.

Интерфейс nftw() имеет два отдельных набора флагов. Одни набор контролирует саму nftw() (аргумент flags функции nftw()). Другой набор передается предоставленной пользователем функции, которую вызывает nftw() (аргумент flags для (*fn)()). Однако, интерфейс запутывает, поскольку имена обоих наборов флагов начинаются с префикса 'FTW_'. Мы постараемся сделать все, чтобы это прояснить по ходу дела. В табл. 8.3 представлены флаги, которые контролируют nftw().

Таблица 8.3. Управляющие флаги для nftw()

Флаг Значение FTW_CHDIR При установке перед открытием каждого из каталогов сначала осуществляется переход в него. Это действие более эффективно, но вызывающее приложение должно быть готово оказаться в другом каталоге, когда nftw() завершится FTW_DEPTH При установке осуществляется «сначала глубокий поиск». Это означает, что все файлы и подкаталоги обрабатываются до того, как будет обработан сам каталог FTW_MOUNT При установке остается в той же самой смонтированной файловой системе. Это более специализированная опция FTW_PHYS При установке не следует по символическим ссылкам

FTW_CHDIR предоставляет большую эффективность; при обработке глубоких иерархий файлов ядру не приходится обрабатывать снова и снова полные пути имен при осуществлении stat() или открытии каталога. Экономия времени для больших иерархий может быть вполне ощутимой.[85]

FTW_DEPTH может быть, а может и не быть тем, что вам нужно; для некоторых приложений это безусловно справедливо. Рассмотрите 'chmod -R u-rx .'. Эта команда удаляет права чтения и исполнения для владельца для всех файлов и подкаталогов в текущем каталоге. Если это изменение прав доступа применено к каталогу до того, как оно применено к содержимому каталога, любые последующие попытки обработки содержимого потерпят неудачу! Поэтому команда должна применяться к каталогу после обработки его содержимого.[86] Справочная страница GNU/Linux nftw(3) отмечает для FTW_PHYS, что «это то, что вам нужно». Это позволяет вам обрабатывать сами символические ссылки, что обычно бывает нужно (Рассмотрите du, она должна подсчитывать занимаемое ссылками пространство отдельно от связанных с ними файлов.)

8.4.3.2. Функция обратного вызова nftw()

После запуска nftw() она вызывает функцию, указатель для которой предоставляете вы. (Такие функции называются функциями обратного вызова (callback functions), поскольку они «вызываются обратно» из библиотечного кода.) Функция обратного вызова получает четыре аргумента:

const char *file

Имя текущего обрабатываемого файла (каталога, символической ссылки и т.д.).

const struct stat *sb

Указатель на struct stat для файла.

int flag

Одно из нескольких значений флагов (описанных ниже), указывающих, какой это вид файла или была ли ошибка для объекта.

struct FTW *s

Эта структура предоставляет две отдельные части информации:

struct FTW {

 int base;  /* Индекс в файле базовой части имени файла */

 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' */

1 ... 61 62 63 64 65 66 67 68 69 ... 165
Перейти на страницу:
Тут вы можете бесплатно читать книгу Linux программирование в примерах - Арнольд Роббинс.
Комментарии