Я могу cat /dev
, я могу ls /dev
, я не могу less /dev
. Почему cat
мне разрешен cat
этот каталог, а других нет?
Я могу cat /dev
, я могу ls /dev
, я не могу less /dev
. Почему cat
мне разрешен cat
этот каталог, а других нет?
Ответы:
Исторически (до V7 UNIX или около 1979 года) read
системный вызов работал как с файлами, так и с каталогами. read
on каталог вернул бы простую структуру данных, которую пользовательская программа проанализировала бы для получения записей каталога. Действительно, ls
инструмент V7 сделал именно это - read
в каталоге, анализируя результирующую структуру данных, вывод в формате структурированного списка.
Поскольку файловые системы становились все более сложными, эта «простая» структура данных усложнялась до такой степени, что readdir
была добавлена библиотечная функция, чтобы помочь программам анализировать выходные данные read(directory)
. Различные системы и файловые системы могут иметь разные форматы на диске, что становится все сложнее.
Когда Sun представила сетевую файловую систему (NFS), они хотели полностью абстрагироваться от структуры каталогов на диске. Однако вместо того, чтобы сделать их read(directory)
возвращение независимым от платформы представлением каталога, они добавили новый системный вызов getdirents
- и запретили read
устанавливать сетевые каталоги. Этот системный вызов был быстро адаптирован для работы со всеми каталогами в различных версиях UNIX, что сделало его стандартным способом получения содержимого каталогов. (История извлечена из https://utcc.utoronto.ca/~cks/space/blog/unix/ReaddirHistory )
Поскольку readdir
теперь это способ чтения каталогов по умолчанию, read(directory)
он обычно не реализуется (возвращая -EISDIR) в большинстве современных ОС (например, QNX является заметным исключением, которое реализуется readdir
как read(directory)
). Тем не менее, с дизайном «виртуальной файловой системы» в большинстве современных ядер фактически зависит от отдельной файловой системы, работает ли чтение каталога или нет.
И действительно, в macOS devfs
файловая система, лежащая в основе точки /dev
монтирования, действительно поддерживает чтение ( https://github.com/apple/darwin-xnu/blob/xnu-4570.1.46/bsd/miscfs/devfs/devfs_vnops.c#L629 ) :
static int
devfs_read(struct vnop_read_args *ap)
{
devnode_t * dn_p = VTODN(ap->a_vp);
switch (ap->a_vp->v_type) {
case VDIR: {
dn_p->dn_access = 1;
return VNOP_READDIR(ap->a_vp, ap->a_uio, 0, NULL, NULL, ap->a_context);
Это явно вызывается, READDIR
если вы пытаетесь читать /dev
(чтение файлов под /dev
ним обрабатывается отдельной функцией - devfsspec_read
). Итак, если программа вызывает read
системный вызов /dev
, она будет выполнена успешно и получит список каталогов!
Эта функция, по сути, является пережитком с самых первых дней существования UNIX и не затрагивалась в течение очень долгого времени. Часть меня подозревает, что это сохраняется по какой-то причине обратной совместимости, но это может быть так же легко, как тот факт, что никто не заботится о том, чтобы удалить функцию, так как это на самом деле ничего не вредит.
Меньше - средство просмотра текстовых файлов, cat - инструмент для копирования произвольных данных. Таким образом, less выполняет свою собственную проверку, чтобы убедиться, что вы не открываете что-то, что будет содержать большие объемы данных или ведет себя очень странно. С другой стороны, у cat такой проверки вообще нет - если ядро позволяет вам что-то открыть (даже если это канал, устройство или что-то еще хуже), cat прочитает это.
Так почему же ОС позволяет cat открывать каталоги? Традиционно в системах в стиле BSD все каталоги могут быть прочитаны как файлы, и именно так программы будут перечислять каталог в первую очередь: просто интерпретируя структуры директив, хранящиеся на диске.
Позднее эти структуры на диске начали расходиться с директивой, используемой ядром: где ранее каталог представлял собой линейный список, более поздние файловые системы начали использовать хеш-таблицы, B-деревья и так далее. Так что чтение каталогов напрямую стало не простым делом - в ядре появились специальные функции для этого. (Я не уверен, что это было основной причиной, или они были добавлены прежде всего по другим причинам, таким как кеширование.)
Некоторые системы BSD продолжают открывать все каталоги для чтения; Я не знаю, дают ли они вам необработанные данные с диска, или вместо этого они возвращают список эмулированных директив, или позволяют ли они решать драйверу файловой системы.
Так что, возможно, macOS является одной из тех операционных систем, где ядро позволяет это, пока файловая система предоставляет данные. И разница в том, что /dev
в devfs
файловой системе, которая была написана, чтобы позволить это в первые дни, в то время /
как в файловой системе APFS, которая опускала эту функцию как ненужную в наше время.
Отказ от ответственности: я на самом деле не проводил никаких исследований на BSD или MacOS. Я просто обожаю это.
/etc
бы, поэтому я использовал это в качестве ориентира.
mount
или /sbin/mount
посмотреть , что в настоящее время устанавливается , где.
/dev
это виртуальная файловая система, использующая devfs
драйвер, тогда как /etc
является частью /
файловой системы, использующей apfs
драйвер. Так что причина cat
будет читать один и не другая разница между apfs
и devfs
драйверами.
neofetch
для вашей информации :) i.imgur.com/3azpnDt.png