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.