Понимание кодировки имени файла Unix


25

Мне трудно понять, как работает кодировка имени файла. На unix.SE я нахожу противоречивые объяснения.

Имена файлов хранятся в виде символов

Процитирую другой ответ: Несколько вопросов о кодировке символов файловой системы в Linux.

[…] Как вы упоминаете в своем вопросе, имя файла UNIX - это просто последовательность символов; ядро ничего не знает о кодировке, которая полностью является концепцией пользовательского пространства (т.е. уровня приложения).

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

Предположим следующее: пользователь использует случайную кодировку X , которая переводит файл fooв последовательность байтов α и сохраняет его на диск. Другой пользователь использует кодирующий Y . В этой кодировке α переводится как /, что не допускается в качестве имени файла. Однако для первого пользователя файл действителен.

Я предполагаю, что этот сценарий не может произойти.

Имена файлов хранятся в виде двоичных объектов

Процитирую другой ответ: Какая кодировка charset используется для имен файлов и путей в Linux?

Как отмечают другие, на самом деле нет ответа на это: имена файлов и пути не имеют кодировки; ОС работает только с последовательностью байтов. Отдельные приложения могут по своему усмотрению интерпретировать их как кодируемые, но это варьируется.

Если система не работает с символами, как можно запретить использование определенных символов (например, /или NULL) в именах файлов? Там нет понятия / без кодировки.

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

Я также предполагаю, что это неправильно.

Где происходит кодирование и где накладывается ограничение, запрещающее использование определенных символов?


Нуль одинаков (0) во всех кодировках.
Кевин

2
@Kevin Не совсем: не в, скажем, UTF-16 или UCS-4 (= UTF-32) или в большинстве других многобайтовых кодировок, которые не являются расширениями ASCII.
Жиль "ТАК - перестань быть злым"

1
На самом деле, в ответе Риккардо Мурри должны были быть упомянуты байты, а не символы . Большинство файловых систем хранят байты.
Жиль "ТАК - перестань быть злым"

@ Жиль: еще один раз, увидим, ты действительно смотришь, что написано .
Incnis Mrsi

Ответы:


25

Краткий ответ: ограничения, налагаемые в ядре Unix / Linux / BSD, namei()функция. Кодирование происходит в программах уровня пользователя, таких как xterm, firefoxили ls.

Я думаю, что вы начинаете с неправильных посылок. Имя файла в Unix - это строка байтов с произвольными значениями. Несколько значений 0x0 (ASCII Nul) и 0x2f (ASCII '/') просто недопустимы, ни как часть многобайтовой кодировки символов, ни как что-либо еще. «Байт» может содержать число, представляющее символ (в ASCII и некоторых других кодировках), но «символ» может требовать более 1 байта (например, кодовые точки выше 0x7f в представлении Unicode в UTF-8).

Эти ограничения вытекают из соглашений о печати имен файлов и набора символов ASCII. Исходные Unix-ы использовали ASCII '/' (численно 0x2f) байты для разделения частей частично или полностью квалифицированного пути (например, '/ usr / bin / cat' содержит фрагменты "usr", "bin" и "cat") , Оригинальные Unixes использовали ASCII Nul для завершения строк. Помимо этих двух значений, байты в именах файлов могут принимать любые другие значения. Эхо этого можно увидеть в кодировке UTF-8 для Unicode. Печатные символы ASCII, включая «/», занимают в UTF-8 только один байт. UTF-8 для кодовых точек выше не содержит байтов с нулевым значением, кроме управляющего символа Nul. UTF-8 был изобретен для Plan-9, претендента на трон Unix.

В более ранних версиях Unix (и, похоже, в Linux) была namei()функция, которая просто просматривает пути по байту за раз и разбивает пути на части по 0x2F-значным байтам, останавливаясь на нулевом значении. namei()является частью ядра Unix / Linux / BSD, поэтому здесь применяются исключительные байтовые значения.

Обратите внимание, что до сих пор я говорил о значениях байтов, а не символов. namei()не применяет семантику символов в байтах. Это зависит от программ уровня пользователя, например ls, которые могут сортировать имена файлов по байтовым значениям или символьным значениям. xtermрешает, какие пиксели загораться для имен файлов, основываясь на кодировке символов. Если вы не скажете, xtermчто у вас есть имена файлов в кодировке UTF-8, вы увидите много тарабарщины, когда вызовете его. Если vimон не скомпилирован для обнаружения кодировок UTF-8 (или чего-либо другого, UTF-16, UTF-32), вы увидите много бреда при открытии «текстового файла», содержащего символы в кодировке UTF-8.


Правильно, namei()было заброшено около 1986 года. Более новые UNIX-системы используют lookuppn()VFS.
Щил

17

Дело в том, что ядру все равно, как приложения интерпретируют данные, которые ему даны как имя файла.

Давайте представим, что у меня есть приложение на C, которое работает исключительно со строками UTF-16. И я ввожу через правильно настроенный метод ввода символ ∯ (Unicode 0x222F) в подсказку / диалог «Сохранить как».

Если приложение не выполняет какую-либо форму перевода и отправляет ее в простой старой строке C ( char*), скажем, fopenв режиме записи, ядро ​​не увидит ∯ или даже не попытается это представить. Он будет видеть два chars, одно за другим, со значениями 0x22 0x2F(при условии, что 8-битные символы отсутствуют, а в библиотеке C нет ничего смешного ).
То есть, с точки зрения ядра, допустимый char ( "), за которым следует /(ASCII 0x2F). fopenвернется EISDIR(т. е. «это похоже на каталог, и вы запросили режим записи!»).
Если бы я ввел ∮ (Unicode 0x222E), ядро ​​увидело бы два точных символа и создало бы файл, который, как видно из приложения, говорящего на ASCII, был бы назван "..

Если бы я ввел aв приложение имя файла, и приложение передало его в UTF-16 ядру, ядро ​​прочитало бы 0x00 0x61и даже не приняло это во внимание 0x61, потому 0x00что строка уже заканчивает строку, насколько она есть. обеспокоен. Сообщение об ошибке будет таким же, как и для пустого имени файла ( ENOENTя считаю).

Таким образом, ядро ​​действительно воспринимает данные как блоб. Это поток charс. Недопустимые «символы» в выбранной вами кодировке пользовательского пространства - это те, которые генерируют 0x00или 0x2F(«ноль» и /) в своем двоичном объекте (двоичное представление, которое передается ядру).


Если я вас правильно понял, то нет такой вещи как недопустимые символы. Есть только недопустимые последовательности байтов. А значения 0x00и 0x2Fжестко закодированы в ядре. Это, в свою очередь, означает, что каталоги разделены не /символом a , а тем символом, который отображается 0x2Fв используемой кодировке.
Марко

Да, это идея, если вы хотите увидеть это таким образом. (Но это может быть неверно. Ядро может иметь «нативную кодировку», где /не 0x2F - charsфактически не может использовать 8-битный .) «Традиционный» разделитель dir есть /. Это 0x27 в 8-битных системах ASCII (не EBCDIC, например).
Мат

Предполагается, что UTF-16BE, тогда как в UTF-16LE U + 0061 приведет к aстроке с нулевым символом в конце.
Инснис Мрси

4

Разделение байтов и символов произошло после того, как был разработан Unix. Когда это было разработано, использование слов только сообщало о том, как 8 (или 6, или 9) бит интерпретировались, но кодировки слов не упоминались.

Имена файлов - это последовательности байтов. Допускается любой байт, кроме 0x2f "/". Байт, содержащий 0x00, не может даже проникнуть в ядро ​​из-за его использования в качестве ограничителя строки. Приложение может интерпретировать последовательность байтов в соответствии с выбранной кодировкой. Если это звучит грязно, я полагаю, что это так.

Более подробную информацию можно найти по адресу http://www.gtk.org/api/2.6/glib/glib-Character-Set-Conversion.html, который может оказаться полезным.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.