делает всю работу и большую часть кода проверки ошибок. Основой функции являются строки 48 и 49:
while ((ent = readdir(dp)) != NULL)
printf("%8ld %s\n", ent->d_ino, ent->d_name);
Этот цикл читает элементы каталога, по одной за раз, до тех пор, пока
readdir
не возвратит
NULL
. Тело цикла отображает для каждого элемента номер индекса и имя файла. Вот что происходит при запуске программы:
$ ch05-catdir /* По умолчанию текущий каталог */
639063 .
639062 ..
639064 proposal.txt
639012 lightsabers.url
688470 code
638976 progex.texi
639305 texinfo.tex
639007 15-processes.texi
639011 00-preface.texi
639020 18-tty.texi
638980 Makefile
639239 19-i18n.texi
...
Вывод
никаким образом не сортируется; он представляет линейное содержимое каталога. (Как сортировать содержимое каталога мы опишем в разделе 6.2 «Функции сортировки и поиска»).
5.3.1.1. Анализ переносимости
Есть несколько соображений по переносимости. Во-первых, не следует предполагать, что двумя первыми элементами, возвращаемыми
readdir
, всегда будут '
.
' и '
..
'. Многие файловые системы используют организацию каталогов, которые отличаются от первоначального дизайна Unix, и '
.
' и '
..
' могут быть в середине каталога или даже вовсе не присутствовать [55] .
55
В системах GNU/Linux могут монтироваться файловые системы многих операционных систем, не относящихся к Unix. Во многих коммерческих системах Unix также можно смонтировать файловые системы MS-DOS. В таких случаях предположения относительно файловых систем Unix неприменимы — Примеч. автора.
Во-вторых, стандарт POSIX ничего не говорит о возможных значениях
d_info
. Он говорит, что возвращенные структуры представляют элементы каталогов для файлов; это предполагает, что
readdir
не возвращает пустые элементы, поэтому реализация GNU/Linux
readdir
не беспокоится с возвратом элементов, когда '
d_ino == 0
'; она переходит к следующему действительному элементу.
Поэтому по крайней мере на системах GNU/Linux и Unix маловероятно, что
d_ino
когда-нибудь будет равен нулю. Однако, лучше по возможности вообще избегать использования этого поля.
Наконец, некоторые системы используют
d_fileno
вместо
d_ino
в
struct dirent
. Знайте об этом, когда нужно перенести на такие системы код, читающий каталоги.
Косвенные системные вызовы
«Не пробуйте это дома, дети!»
– М-р Wizard -
Многие системные вызовы, такие, как
open
,
read
и
write
, предназначены для вызова непосредственно из кода пользователя: другими словами, из кода, который пишете вы как разработчик GNU/Linux.
Однако, другие системные вызовы существуют лишь для того, чтобы дать возможность реализовать стандартные библиотечные функции более высокого уровня, и никогда не должны вызываться непосредственно. Одним из таких системных вызовов является GNU/Linux
getdents
; он читает несколько элементов каталога в буфер, предоставленный вызывающим — в данном случае, кодом реализации
readdir
. Затем код
readdir
возвращает действительные элементы каталога, по одному за раз, пополняя при необходимости буфер.
Эти системные вызовы только-для-библиотечного-использования можно отличить от вызовов для-использования-пользователем по их представлению в странице справки. Например, из getdents(2).
int getdents(unsigned int fd, struct dirent *dirp,
unsigned int count);
Любой системный вызов, использующий макрос
_syscallX
, не должен вызываться кодом приложения. (Дополнительную информацию об этих вызовах можно найти в справочной странице для intro(2); вам следует прочесть эту справочную страницу, если вы этого еще не сделали.)
В случае
getdents
на многих других системах Unix есть сходный системный вызов; иногда с тем же именем, иногда с другим. Поэтому попытка использования этих вызовов привела бы в любом случае лишь к большому беспорядку с переносимостью; гораздо лучше во всех случаях использовать
readdir
, интерфейс которого хорошо определен, стандартизован и переносим.