39 return(EXIT_SUCCESS);
40 }
Вот результаты для GNU/Linux:
$ ch05-trymkdir
mkdir("/tmp/t1/t2/t3/t4") returns -1: errno = 2 [No such file or directory)
mkdir("/tmp/t1/t2/t3") returns -1: errno = 2 [No such file or directory)
mkdir("/tmp/t1/t2") returns -1: errno = 2 [No such file or directory]
mkdir("/tmp/t1") returns 0: errno = 0 [Success]
mkdir("/tmp/u1") returns 0: errno = 0 [Success]
mkdir("/tmp/u1/u2") returns 0: errno = 0 [Success]
mkdir("/tmp/u1/u2/u3") returns 0: errno = 0 [Success]
mkdir("/tmp/u1/u2/u3/u4") returns 0: errno = 0 [Success]
mkdir("/tmp/v1/") returns 0: errno = 0 [Success]
mkdir("/tmp/v1/v2/") returns 0: errno = 0 (Success]
mkdir("/tmp/v1/v2/v3/") returns 0: errno = 0 [Success]
mkdir("/tmp/v1/v2/v3/v4/") returns 0: errno = 0 [Success]
Обратите внимание, как GNU/Linux принимает завершающий слеш. Не все системы так делают.
5.3. Чтение каталогов
В оригинальных системах Unix чтение содержимого каталогов было просто. Программа открывала каталог с помощью open()
и непосредственно читала двоичные структуры struct direct
, по 16 байтов за раз. Следующий фрагмент кода из программы V7 rmdir
[53], строки 60–74. Он показывает проверку на пустоту каталога.
60 if ((fd = open(name, 0)) < 0) {
61 fprintf(stderr, "rmdir: %s unreadable\n", name);
62 ++Errors;
63 return;
64 }
65 while (read(fd, (char*)&dir, sizeof dir) == sizeof dir) {
66 if (dir.d_ino == 0) continue;
67 if (!strcmp(dir.d_name, ".") || !strcmp(dir.d_name, ".."))
68 continue;
69 fprintf(stderr, "rmdir: %s not empty\n", name);
70 ++Errors;
71 close(fd);
72 return;
73 }
74 close(fd);
В строке 60 каталог открывается для чтения (второй аргумент равен 0, что означает O_RDONLY
). В строке 65 читается struct direct
. В строке 66 проверяется, не является ли элемент каталога пустым, т. е. с номером индекса 0. Строки 67 и 68 проверяют на наличие '.
' и '..
'. По достижении строки 69 мы знаем, что было встречено какое-то другое имя файла, следовательно, этот каталог не пустой.
(Тест '!strcmp(s1, s2)
' является более короткой формой 'strcmp(s1, s2) == 0
', т.е. проверкой совпадения строк. Стоит заметить, что мы рассматриваем '!strcmp(s1, s2)
' как плохой стиль. Как сказал однажды Генри Спенсер (Henry Spencer), «strcmp()
это не boolean!».)
Когда 4.2 BSD представило новый формат файловой системы, который допускал длинные имена файлов и обеспечивал лучшую производительность, были также представлены несколько новых функций для абстрагирования чтения каталогов. Этот набор функций можно использовать независимо от того, какова лежащая в основе файловая система и как организованы каталоги. Основная ее часть стандартизована POSIX, а программы, использующие ее, переносимы между системами GNU/Linux и Unix.
5.3.1. Базовое чтение каталогов
Элементы каталогов представлены struct dirent
(struct direct
!):
struct dirent {
...
ino_t d_ino; /* расширение XSI --- см. текст */
char d_name[...]; /* О размере этого массива см. в тексте */
...
};
Для переносимости POSIX указывает лишь поле d_name
, которое является завершающимся нулем массивом байтов, представляющим часть элемента каталога с именем файла. Размер d_name
стандартом не указывается, кроме того, что там перед завершающим нулем может быть не более NAME_MAX
байтов. (NAME_MAX
определен в
.) Расширение XSI POSIX предусматривает поле номера индекса d_ino
.