Перемещение по иерархии файлов — КиберПедия 

Эмиссия газов от очистных сооружений канализации: В последние годы внимание мирового сообщества сосредоточено на экологических проблемах...

Типы оградительных сооружений в морском порту: По расположению оградительных сооружений в плане различают волноломы, обе оконечности...

Перемещение по иерархии файлов

2021-01-29 88
Перемещение по иерархии файлов 0.00 из 5.00 0 оценок
Заказать работу

 

Несколько системных вызовов и стандартных библиотечных функций дают возможность изменять текущий каталог и определять полный путь к текущему каталогу. Более сложные функции позволяют осуществлять произвольные действия с каждым объектом файловой системы в иерархии каталогов.

 

Смена каталога: и

 

В разделе 1.2 «Модель процессов Linux/Unix» мы говорили:

 

Текущим каталогом является каталог, относительно которого отсчитываются относительные пути (те, которые не начинаются с). Это каталог, «в» котором вы находитесь, когда даете оболочке команду ' некоторое_место '.

 

У каждого процесса есть текущий рабочий каталог. Каждый новый процесс наследует свой текущий каталог от процесса, который его запустил (своего родителя). Две функции позволяют перейти в другой каталог:

 

 

Функция принимает строку с названием каталога, тогда как ожидает дескриптор файла, который был открыт для каталога с помощью.[83] Обе возвращают 0 при успехе и ‑1 при ошибке (с, установленной соответствующим образом). Обычно, если для каталога завершается успешно, также достигает цели, если кто‑то не изменил права доступа к каталогу между вызовами, (сравнительно новая функция; на старых системах Unix ее нет.)

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

 

Строка 15 открывает текущий каталог. Строка 16 вызывает для открытого каталога, так что мы получаем копию его прав доступа. Строка 17 использует для перемещения на один уровень в иерархии файлов. Строка 18 выполняет грязную работу, отменяя все права доступа первоначального каталога.

Строки 20–21 пытаются перейти обратно в первоначальный каталог. Ожидается, что эта попытка будет безуспешной, поскольку текущие права доступа не позволяют это. Строка 23 восстанавливает первоначальные права доступа, '' получает младшие 12 битов прав доступа; это обычные 9 битов rwxrwxrwx и биты setuid, setgid и «липкий» бит, которые мы обсудим в главе 11 «Права доступа и ID пользователя и группы». Наконец, строка 24 заканчивает работу, закрывая открытый дескриптор файла. Вот что происходит при запуске программы.

ls ‑ld.

 

ch08‑chdir

 

ls ‑ld.

 

 

Получение текущего каталога:

 

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

 

 

Функция заносит в путь; ожидается, что размер равен байтам. При успешном завершении функция возвращает свой первый аргумент. В противном случае, если требуется более байтов, она возвращает и устанавливает в. Смысл в том, что если случится, следует попытаться выделить буфер большего размера (с помощью или) и попытаться снова.

Если любой из компонентов каталога, ведущих к текущему каталогу, не допускает чтения или поиска, может завершиться неудачей, а будет установлен в. Следующая простая программа демонстрирует ее использование:

 

Эта простая программа выводит текущий каталог, переходит в родительский каталог, затем выводит новый текущий каталог. (Переменная здесь на самом деле не нужна, но в реальной программе она была бы использована для проверки ошибок). При запуске программа создает следующий вывод:

ch08‑getcwd

 

Формально, если аргумент равен, поведение не определено. В данном случае версия GLIBC вызовет за вас, выделяя буфер с размером. Идя даже дальше, если равен 0, выделяется «достаточно большой» буфер для вмещения возвращенного имени пути. В любом случае вы должны вызвать для возвращенного указателя после завершения работы с буфером.

Поведение GLIBC полезно, но не переносимо. Для кода, который должен работать на разных платформах, вы можете написать замещающую функцию, которая предоставляет те же самые возможности, в то же время заставив ее непосредственно вызывать на системе с GLIBC.

Системы GNU/Linux предоставляют файл. Этот файл является символической ссылкой на текущий каталог:

Cd /tmp

ls ‑l /рroc/self/cwd

 

cd

ls ‑l /proc/self/cwd

 

Это удобно на уровне оболочки, но представляет проблему на уровне программирования. В частности, размер файла равен нулю! (Это потому, что это файл в, который продуцирует ядро; это не настоящий файл, находящийся на диске.)

Почему нулевой размер является проблемой? Если вы помните из раздела 5.4.5 «Работа с символическими ссылками», для символической ссылки возвращает в поле структуры число символов в имени связанного файла. Это число может затем использоваться для выделения буфера соответствующего размера для использования с. Здесь это не будет работать, поскольку размер равен нулю. Вам придется использовать (или выделять) буфер, который, как вы полагаете, достаточно большой. Однако, поскольку не выдает символов больше, чем вы предоставили места, невозможно сказать, достаточен буфер или нет; не завершается неудачей, когда недостаточно места. (См. в разделе 5.4.5 «Работа с символическими ссылками» функцию Coreutils, которая решает проблему.)

В дополнение к GLIBC имеет несколько других непереносимых процедур. Они избавляют вас от хлопот по управлению буферами и обеспечивают совместимость со старыми системами BSD. Подробности см в getcwd (3).

 

Перемещение по иерархии:

 

Обычной задачей программирования является обработка целых иерархий каталогов: выполнение действий над каждым файлом и каждым каталогом и подкаталогом в целостном дереве. Рассмотрите, например, команду, которая выводит сведения об использовании диска, '', которая рекурсивно изменяет владельцев, или программу, которая находит файлы, подходящие по определенным критериям.

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

 

Интерфейс

 

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

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

 

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

 

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

 

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

 

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

 

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

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

 

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

 

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

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

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

 

Функция обратного вызова

 

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

 

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

 

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

 

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

 

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

 

 

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

 

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

 

 Флаг Значение
  Объект является обычным файлом
  Объект является каталогом
  Объект является каталогом, который нельзя прочесть
  Объект является символической ссылкой
  Объект не является символической ссылкой, а потерпела неудачу
  Объект является каталогом, элементы которого были уже обработаны. Это может случиться, лишь когда в вызове использовался
  Объект является символической ссылкой, указывающей на несуществующий файл. Это может случиться, лишь когда в вызове не используется

 предоставляет дополнительную информацию, которая может быть полезной. e действует в качестве индекса в; является полным путем обрабатываемого объекта (относительно точки отсчета), '' указывает на первый символ компонента имени файла.

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

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

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

Pwd

 

code/ch08/ch08‑nftw code

 

 

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

 

Строки 3–11 включают заголовочные файлы. По крайней мере в GLIBC 2.3.2 перед включением любого заголовочного файла необходимы для и. Они дают возможность получить объявления и значения флагов, которые предоставляет свыше предоставляемых. Это специфично для GLIBC. Потребность в этом в конечном счете исчезнет, когда GLIBC станет полностью совместимой со стандартом POSIX 2001.

Строки 35–44 обрабатывают опции. Опция добавляет к флагам. Это эксперимент с целью увидеть, сможете ли вы оказаться где‑то в другом месте от того, где начинали. Кажется, это возможно, если завершается неудачей, в противном случае вы заканчиваете там же, где начинали. (POSIX не документирует это явным образом, но целью, похоже, было действительно заканчивать там же, где начинали. Стандарт не говорит, что функция обратного вызова не должна менять текущий каталог.)

Строка 49 сохраняет начальный каталог для дальнейшего использования, пользуясь.

Строка 51 вычисляет число дескрипторов, которые может использовать. Мы не хотим, чтобы она использовала все доступные дескрипторы файлов, если функция обратного вызова также хочет открывать файлы. В вычислении используется (см. раздел 4.4.1 «Понятие о дескрипторах файлов») для получения максимально возможного числа и вычета из него, который был вычислен ранее в строке 13.

Эта процедура служит основанием для больших объяснений. В обычном случае по крайней мере три дескриптора уже используются для стандартного ввода, стандартного вывода и стандартной ошибки. нужно некоторое количество дескрипторов файлов для открытия и чтения каталогов; внутри себя использует при открытии каталогов для чтения. Если функции обратного вызова также нужно открывать файлы, мы должны предотвратить израсходование функцией всех доступных дескрипторов файлов для открывания каталогов. Мы делаем это, вычитая некоторое число из максимально допустимого. Для данного примера мы выбрали пять, но если функции обратного вызова нужно открывать файлы, должно использоваться большее число, (знает, как восстановиться при израсходовании дескрипторов файлов; мы не должны беспокоиться о таком случае.)

Строки 52–58 являются главным циклом над нашими аргументами; строки 53–57 проверяют ошибки; когда они появляются, код выводит диагностическое сообщение и увеличивает значение переменной.

Строки 60–64 являются частью эксперимента с, выводящего начальный и конечный каталоги, если было использовано.

По‑настоящему интересной функцией является; это функция обратного вызова, которая обрабатывает каждый файл. Она использует базовый шаблон для функции обратного вызова, который является оператором для значения.

 

Строка 75 использует '' для получения имени из полного пути. Это значение указателя сохраняется в переменной для повторного использования в функции.

Строка 77 делает отступ нужного размера, используя красивый трюк. Используя, получает от первого аргумента ширину поля. Это вычисляется динамически как ''. Строка, которая должна быть выведена – «», пустая строка. Конечным результатом является то, что создает для нас отступ нужного размера без необходимости запуска цикла.

Строки 79–104 являются оператором. В данном случае он не делает ничего весьма интересного, кроме вывода имени файла и его типа (файл, каталог и т.д.)

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

 

ЗАМЕЧАНИЕ. Джим Мейеринг (Jim Meyering), сопроводитель GNU Coreutils, замечает, что дизайн несовершенен из‑за ее рекурсивной природы. (Она рекурсивно вызывает себя при обработке подкаталогов.) Если иерархия каталогов становится действительно глубокой, в диапазоне уровней 20 000–40 000 (!), может выйти за пределы размера стека, уничтожив программу. Есть также и другие проблемы, связанные с дизайном. Версия GNU Coreutils после 5.0 исправляет это путем использования набора процедур (см. fts (3)).

 

 

Обход дерева файлов: GNU

 

GNU версия в GNU Coreutils использует для обхода одной или более иерархии файлов, собирая и выводя сведения, касающиеся количества используемого дискового пространства. У нее большое число опций, которые управляют ее поведением но отношению к символическим ссылкам, форматом вывода чисел и т.д. Это делает разбор кода труднее, чем могло бы быть при более простой версии. (Однако, мы не собираемся позволить этому остановить нас.) Вот сводка опций, которые вскоре будут полезны, когда мы рассмотрим код.

du ‑‑help

 

 

Чтобы еще больше усложнить дело, использует частную версию, у которой есть несколько расширений. Сначала имеются дополнительные значения флагов для функции обратного вызова:

 

Это значение означает, что не может выполнять ''.

 

Это значение означает, что не может использовать для перехода в сам каталог.

 

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

Частная добавляет также в новый член,. Если текущий объект является каталогом и функция обратного вызова устанавливает в поле ненулевое значение, не будет больше обрабатывать этот каталог. (Функция обратного вызова должна установить таким образом, когда равен; делать это для слишком поздно.)

С этим объяснением за поясом, вот функция из. Номера строк приведены относительно начала функции:

 

Эта функция делает многое, поскольку ей приходится реализовать все опции. Строка 17 устанавливает в true (1); по умолчанию выводятся сведения о каждом файле. Дальнейший код устанавливает ее при необходимости в false (0).

Строка 20 устанавливает на основе опции. Обратите внимание, что это исключает подкаталоги, если каталог совпадает с шаблоном для.

 

Строки 22–51 являются стандартным оператором. Ошибки, для которых нет информации о размере, устанавливают глобальную переменную в 1 и возвращают 0, чтобы продолжить обработку (см строки 24–27 и 29–33). Ошибки, для которых есть размер, также устанавливают, но затем прерывают для того, чтобы обработать статистику (см. строки 35–40 и 42–47).

Строки 55–56 сразу завершают функцию, если это первая встреча с каталогом

 

Теперь становится интересно. По умолчанию подсчитывает пространство, занимаемое прямыми ссылками, лишь одни раз. Опция заставляет ее подсчитывать пространство для каждой ссылки; переменная равна true, когда указана. Для отслеживания ссылок содержит хэш‑таблицу[87] уже встречавшихся пар (устройство, индекс).

Строки 60–63 проверяют, следует ли не включать файл в подсчет, либо из‑за того, что он был исключен (равно true, строка 60), либо потому что не была указана (строка 61) и у файла несколько ссылок (строка 62) и файл уже находится в хеш‑таблице (строка 63). В этом случае размер устанавливается в 0, поэтому он не входит в конечную сумму, a также устанавливается в false (строки 68–69).

Если ни одно из этих условий не отмечается, размер вычисляется либо в соответствии с размером в, либо в соответствии с числом блоков диска (строки 73–75) Это решение основывается на переменной, которая установлена при использовании опции.

 

 

Строки 78–97 управляют динамической памятью, используемой для хранения статистики о размере файла, является статической переменной (строка 12), которая равна true при первом вызове. В этом случае вызывается (через упаковывающий макрос в строках 81–82; это обсуждалось в разделе 3.2.1.8 «Пример чтение строк произвольной длины»). Остальную часть времени равно false, и используется (снова через упаковывающий макрос, строки 91–96).

Строка 99 заносит значение в; эта переменная может обновляться в зависимости от того, должна ли она включать размеры дочерних элементов. Хотя могла бы использоваться повторно, отдельная переменная упрощает чтение кода.

 

 

Строки 101–132 сравнивают текущий уровень с предыдущим. Возможны три случая.

Уровни те же самые

В этом случае нет необходимости беспокоиться о статистике дочерних элементов. (Строки 103–106.)

Текущий уровень выше предыдущего

В этом случае мы спустились по иерархии, и статистику нужно восстановить (строки 107–116). Термин «аккумулятор» в комментарии подходящий: каждый элемент аккумулирует общее дисковое пространство, использованное на этом уровне. (На заре вычислительной техники регистры центрального процессора часто назывались «аккумуляторами».)

Текущий уровень ниже предыдущего

В этом случае мы завершили обработку всех дочерних элементов каталога и только что вернулись обратно в родительский каталог (строки 117–131). Код обновляет суммы, включая.

 

 

Строки 134–135 устанавливают статические переменные и таким образом, что они содержат правильные значения для последующего вызова, гарантируя, что весь предыдущий код работает правильно.

Строки 137–144 выверяют статистику на основе опций и типа файла. Комментарии и код достаточно просты. Строки 146–155 сразу завершают функцию, если сведения не должны выводиться.

 

Условие в строках 158–160 сбивает с толку, и комментарий в строке 157 указывает на это. Условие утверждает: «Если (1a) файл является каталогом и (1b) уровень меньше максимального для вывода (переменные – и) или нулевой, или (2a) должны быть выведены все файлы и уровень меньше, чем максимальный для вывода, или (2b) уровень нулевой», тогда вывести файл. (Версия после 5.0 использует в этом случае несколько менее запутанное условие.)

Строки 162–179 осуществляют вывод. Строки 162–163 выводят размер и символ TAB Строки 164–173 обрабатывают специальный случай. Это объяснено далее в, в строках файла 524–529:

 

 

В этом случае равен true, поэтому строки 164–173 должны вывести первоначальное имя, а не измененное В противном случае строки 174–177 могут вывести имя как есть.

Фу! Куча кода. Мы находим, что это верхний уровень спектра сложности, по крайней мере, насколько это может быть просто представлено в книге данного содержания. Однако, он демонстрирует, что код из реальной жизни часто бывает сложным. Лучшим способом справиться с этой сложностью является ясное именование переменных и подробные комментарии в этом отношении хорош; мы довольно легко смогли извлечь и изучить код без необходимости показывать все 735 строк программы!

 


Поделиться с друзьями:

Опора деревянной одностоечной и способы укрепление угловых опор: Опоры ВЛ - конструкции, предназначен­ные для поддерживания проводов на необходимой высоте над землей, водой...

История развития хранилищ для нефти: Первые склады нефти появились в XVII веке. Они представляли собой землянные ямы-амбара глубиной 4…5 м...

Своеобразие русской архитектуры: Основной материал – дерево – быстрота постройки, но недолговечность и необходимость деления...

Археология об основании Рима: Новые раскопки проясняют и такой острый дискуссионный вопрос, как дата самого возникновения Рима...



© cyberpedia.su 2017-2024 - Не является автором материалов. Исключительное право сохранено за автором текста.
Если вы не хотите, чтобы данный материал был у нас на сайте, перейдите по ссылке: Нарушение авторских прав. Мы поможем в написании вашей работы!

0.102 с.