Основы программирования в Linux
Программа превращает каталог в подкаталоги, чтобы у найденных файлов были пригодные для использования имена, т.е. они могут передаваться непосредственно в функцию opendir. Программа будет давать сбои при просмотре структур с большим числом уровней вложенности, поскольку есть ограничение на разрешенное число открытых потоков каталогов.
Мы могли бы сделать программу более универсальной, принимая в качестве аргумента командной строки начальную точку просмотра.
Для того чтобы познакомиться с методами повышения универсальности программ, посмотрите исходный код таких утилит Linux, как
иls.findУпражнение 3.4. Программа просмотра каталога1. Начните с соответствующих заголовочных файлов и функции
, которая выводит содержимое текущего каталога. Она будет рекурсивно вызываться для вывода подкаталогов, применяя параметрprintdirдля задания отступа.depth#include <unistd.h>#include <stdio.h>#include <dirent.h>#include <string.h>#include <sys/stat.h>#include <stdlib.h>void printdir(char *dir, int depth) {DIR *dp;struct dirent *entry;struct stat statbuf;if ((dp = opendir(dir)) == NULL) {fprintf(stderr, "cannot open directory: %s\n", dir);return;}chdir(dir);while((entry = readdir(dp)) != NULL) {lstat(entry->d_name, &statbuf);if (S_ISDIR(statbuf.st_mode)) {/* Находит каталог, но игнорирует . и .. */if (strcmp(".", entry->d_name) == 0 || strcmp("..", entry->d_name) == 0)continue;printf("%*s%s/\n", depth, "", entry->d_name);/* Рекурсивный вызов с новый отступом */printdir(entry->d_name, depth+4);} else printf("%*s%s\n", depth, " ", entry->d_name);}chdir("..");closedir(dp);}2. Теперь переходите к функции
.mainint main() {/* Обзор каталога /home */printf("Directory scan of /home:\n");printdir("/home", 0);printf("done.\n");exit(0);}Программа просматривает исходные каталоги и формирует вывод, похожий на приведенный далее (отредактированный для краткости). Для того чтобы заглянуть в каталоги других пользователей, вам могут понадобиться права доступа суперпользователя.
$ <b>./printdir</b>Directory scan of /home:neil/.Xdefaults.Xmodmap.Xresources.bash_history.bashrc.kde/share/apps/konqueror/dirtree/public_html.desktoptoolbar/bookmarks.xmlkonq_historykdisplay/color-schemes/BLP4e/Gnu_Public_Licensechapter04/argopt.сargs.сchapter03/file.outmmap.сprintdirdone.Как это работает
Большинство операций сосредоточено в функции
. После некоторой начальной проверки ошибок с помощью функцииprintdir, проверяющей наличие каталога,opendirвыполняет вызов функцииprintdirдля заданного каталога. До тех пор пока элементы, возвращаемые функциейchdir, не нулевые, программа проверяет, не является ли очередной элемент каталогом. Если нет, она печатает элемент-файл с отступом, равнымreaddir.depthЕсли элемент — каталог, вы встречаетесь с рекурсией. После игнорирования элементов
и.(текущего и родительского каталогов) функция..вызывает саму себя и повторяет весь процесс снова. Как она выбирается из этих повторений? Как только циклprintdirзаканчивается, вызовwhileвозвращает программу вверх по дереву каталогов, и предыдущий перечень можно продолжать. Вызовchdir("..")гарантирует, что количество открытых потоков каталогов не больше того, которое должно быть.closedir(dp)Для того чтобы составить представление об окружении в системе Linux, обсуждаемом в главе 4, познакомьтесь с одним из способов, повышающих универсальность программы. Рассматриваемая программа ограничена, потому что привязана каталогу /home. Следующие изменения в функции
могли бы превратить эту программу в полезный обозреватель каталогов:main