Рейтинговые книги
Читем онлайн Разработка приложений в среде Linux. Второе издание - Майкл Джонсон

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 66 67 68 69 70 71 72 73 74 ... 150

14.7.2. Обход дерева файлов с помощью nft()

Новая версия ftw() — nftw() — решает неоднозначность символических ссылок, присущих ftw(), и содержит несколько дополнительных свойств. С целью правильного определения nftw() заголовочными файлами значение _XOPEN_SOURCE в приложении должно быть определено 500 или больше. Ниже показан прототип nftw().

#define _XOPEN_SOURCE 600

#include <ftw.h>

int nftw(const char * dir, ftwFunctionPointer callback, int depth, int flags);

int nftwCallbackFunction(const char *file, const struct stat * sb,

 int flag, struct FTW * ftwInfo);

Сравнивая nftw() с ftw(), легко заметить новый параметр — flags. Это может быть один или несколько следующих флагов, объединенных с помощью логического "ИЛИ".

FTW_CHDIR Функция nftw() обычно не меняет текущий каталог программы. Если определен флаг FTW_CHDIR функция nftw() меняет текущий каталог на любой другой каталог, читаемый в данный момент. Иначе говоря, при активизации обратного вызова имя файла, передаваемое ему, всегда относится к текущему каталогу. FTW_DEPTH По умолчанию nftw() выводит имя каталога перед списком имен файлов в этом каталоге. Этот флаг вызывает изменение порядка на обратный, то есть содержимое каталога выводится перед его именем. (Примечание. Этот флаг заставляет nftw() выполнять поиск в глубину. Подобного флага для поиска в ширину не существует.) FTW_MOUNT Это флаг запрещает nftw() переходить границу файловой системы во время обхода. Более подробно файловые системы описаны в [32]. FTW_PHYS Вместо следования символическим ссылкам nftw() сообщает о ссылках, но не следует по ним. Побочный эффект заключается в том, что обратный вызов получает результат вызова lstat(), а не stat().

Аргумент обратного вызова flag может принимать два новых значения для nftw() вдобавок к значениям, уже упомянутым для ftw().

FTW_DP Этот элемент является каталогом, об оглавлении которого уже сообщили (это может произойти только в случае установки FTW_DEPTH). FTW_SLN Этот элемент является символической ссылкой, указывающей на несуществующий файл (поврежденная ссылка). Это происходит только в том случае, если FTW_PHYS не был установлен; если же он был установлен, передается FTW_SL.

Эти дополнительные значения flag надлежащим образом определяют nftw() для символических ссылок. При использовании FTW_PHYS все символические ссылки возвращают FTW_SL. Без nftw() поврежденные ссылки выдают FTW_NS, а другие символические ссылки дают тот же результат, что и цель ссылки.

Обратный вызов для nftw() принимает еще один аргумент, ftwInfо. Это указатель на struct FTW, которая определяется следующим образом.

#define _XOPEN_SOURCE 600

#include <ftw.h>

struct FTW {

 int base;

 int level;

};

Элемент base — это смещение имени файла в полном пути, передаваемое обратному вызову. Например, если переданный полный путь выглядит как /usr/bin/ls, base будет равно 9, a file + ftwInfo->base даст имя файла ls. level — это количество каталогов под текущим каталогом. Если ls был найден в nftw(), начинающемся с /usr, уровень будет равен 1. Если поиск начался с /usr/bin, уровень будет равен 0.

14.7.3. Реализация find

Команда find выполняет в одном или нескольких деревьях каталогов поиск файлов, соответствующих определенным характеристикам. Ниже приведена простая реализация find, реализованная на основе nftw(). Она использует fnmatch() (см. главу 23) для реализации переключателя -name и иллюстрирует многие флаги, воспринимаемые nftw().

 1: /* find.с */

 2:

 3: #define _XOPEN_SOURCE 600

 4:

 5: #include <fnmatch.h>

 6: #include <ftw.h>

 7: #include <limits.h>

 8: #include <stdio.h>

 9: #include <stdlib.h>

10: #include <string.h>

11:

12: const char * name = NULL;

13: int minDepth = 0, maxDepth = INT_MAX;

14:

15: int find (const char * file, const struct stat * sb, int flags,

16:  struct FTW * f) {

17:  if (f->level < minDepth) return 0;

18:  if (f->level > maxDepth) return 0;

19:  if (name && fnmatch(name, file + f->base, FNM_PERIOD)) return 0;

20:

21:  if (flags == FTW_DNR) {

22:   fprintf(stderr, "find: %s: недопустимые полномочияn", file);

23:  } else {

24:   printf("%sn", file);

25:  }

26:

27:  return 0;

28: }

29:

30: int main(int argc, const char ** argv) {

31:  int flags = FTW_PHYS;

32:  int i;

33:  int problem = 0;

34:  int tmp;

35:  int rc;

36:  char * chptr;

37:

38:  /* поиск первого параметры командной строки (который должен

39:     находиться после списка путей */

40:  i = 1;

41:  while (i < argc && *argv[i] != '-') i++;

42:

43:  /* обработать опции командной строки */

44:  while (i < argc && !problem) {

45:   if (!strcmp(argv[i], "-name")) {

46:    i++;

47:    if (i == argc)

48:     problem = 1;

49:    else

50:     name = argv[i++];

51:   } else if (!strcmp(argv[i], "-depth")) {

52:    i++;

53:    flags |= FTW_DEPTH;

54:   } else if (!strcmp (argv[i], "-mount") ||

55:    !strcmp(argv[i], "-xdev")) {

56:    i++;

57:    flags |= FTW_MOUNT;

58:   } else if (!strcmp (argv[i], "-mindepth") ||

59:    !strcmp (argv[i], "-maxdepth")) {

60:    i++;

61:    if (i == argc)

62:     problem = 1;

63:    else {

64:     tmp = strtoul(argv[i++], &chptr, 10);

65:     if (*chptr)

66:      problem = 1;

67:     else if (!strcmp(argv[i - 2], "-mindepth"))

68:      minDepth = tmp;

69:     else

70:      maxDepth = tmp;

71:    }

72:   }

73:  }

74:

75:  if (problem) {

76:   fprintf(stderr, "использование: find <пути> [-name <строка>]"

77:    "[-mindepth <целое>] [-maxdepth <целое>]n");

78:   fprintf(stderr, " [-xdev] [-depth]n");

79:   return 1;

80:  }

81:

82:  if (argc == 1 || *argv[1] == '-') {

83:   argv[1] = ".";

84:   argc = 2;

85:  }

86:

87:  rc = 0;

88:  i = 1;

89:  flags = 0;

90:  while (i < argc && *argv[i] != '-')

91:   rc |= nftw (argv [i++], find, 100, flags);

92:

93:  return rc;

94: }

14.8. Уведомление о смене каталога

Иногда приложения желают получать уведомления об изменении оглавления каталога. Например, диспетчеры файлов могут выводить оглавление каталога в окне и обновлять это окно каждый раз при изменении каталога другими программами. В то время как приложение регулярно перепроверяет каталог, Linux может послать программе сигнал о модификации каталога, позволяя своевременные обновления без накладных расходов и задержек на страничный обмен.

Системный вызов fcntl() используется для регистрации уведомлений об обновлениях каталога. В главе 11 уже говорилось о том, что этот системный вызов принимает три аргумента. Первый аргумент — это интересующий файловый дескриптор, второй — это команда, которую необходимо выполнить fcntl(), а последний — это целое число, специфическое для этой команды. Для уведомлений каталогов первый аргумент является файловым дескриптором, относящимся к интересующему каталогу. Это единственный случай, при котором каталог следует открывать с помощью нормального системного вызова open() вместо opendir(). Командой регистрации уведомлений является F_NOTIFY, а последний аргумент определяет, какие типы событий вызывают отправку сигнала. Это должен быть один или несколько перечисленных ниже флагов, объединенных по логическому "ИЛИ".

DN_ACCESS Файл в каталоге, который читается. DN_ATTRIB Права владения или доступа к файлу в каталоге были изменены. DN_CREATE В каталоге создан новый файл (включая новые жесткие ссылки на уже существующие файлы). DN_DELETE Файл удален из каталога. DN_MODIFY Файл в каталоге был модифицирован (тип модификации — усечение). DN_RENAME Файл в каталоге был переименован.

Для отмены уведомления о событии вызовите fcntl() с командой F_NOTIFY и последним аргументом, равным нулю.

1 ... 66 67 68 69 70 71 72 73 74 ... 150
На этой странице вы можете бесплатно читать книгу Разработка приложений в среде Linux. Второе издание - Майкл Джонсон бесплатно.
Похожие на Разработка приложений в среде Linux. Второе издание - Майкл Джонсон книги

Оставить комментарий