Каждый вступающий на тропу освоения Линукса, рано или поздно сталкивается с проблемой кодировок. Оказывается, что мир вокруг заполнен файлами, содержащими информацию в самых различных кодировках, и вопросы взаимодействия решены не очень...
Подробнее см. раздел «Причины появления» библиотеки NATSPEC.
В общем случае в системе отсутствует:
указание кодировки названий файлов в системе
указание кодировок файловых систем
указание кодировок в архивах и предположение о них по создателю архива
Стандартизация очень важна, особенно при разработке операционных систем. Все ключевые понятия должны быть определены.
Как написано в руководстве по нашим дистрибутивам, «Файловая система Linux... является единым деревом». Тут нет понятия ext3, reiserfs, FAT32 или NTFS. И фактически все файлы в этом дереве имеют названия в определённой кодировке.
Рекомендации
Общей рекомендацией является (для десктопной машины) ставить систему в такую же кодировку, как в Windows.
Кодировка windows-1251 имеет множество преимуществ перед koi8-r, созданной для решения одной единственной задачи — возможности прочитать сообщение, даже при утрате старшего бита в каждом байте. В настоящее время эта проблема неактуальна. Преимущества же кодировки windows-1251:
наличие символов, отсутствующих в KOI8-R (например '№', кавычки-ёлочки);
облегчение обмена данными с Windows-машинами (текстовые файлы, html) (правда предпочтительным в настоящий момент является хранить текстовые документы в utf-8);
русские буквы идут по порядку (в большинстве случаев это качество не имеет значение);
присутствуют буквы других алфавитов (Украинского языка и пр.)
Предлагается
Достичь цели, когда только в одном конфигурационном файле системы будет указана кодировка. Вторым этапом предлагается установить эту кодировку в UTF-8.
Устанавливать переменную G_FILENAME_ENCODING, которая будет задавать текущую кодировку файловой системы для тех программ, которые к этой переменной обращаются. В настоящий момент такой программой является GLIB и все программы, построенные на этой библиотеке, то есть GTK-программы и GNOME-программы. Если переменная не установлена, программа просто использует умолчание, которое в неё заложено. Рекомендуется значение кодировки получать напрямую из библиотеки libnatspec.
Определиться с полиси, должно ли понятия кодировки быть общесистемным, или возможно разрешить пользователем влиять на это (например, изменением локали), и каков порядок – сейчас имеется конкретная релизация механизма в libnatspec.
Внести соответствующие добавление во все проблемные (или завязанные на кодировки) программы (перечислены в разделе «Программы, где это нужно»)
Добавить в программы, работающие с архивами, определение кодировки названий файлов в архивах (сформулировать критерии для разных систем) и перекодирование названий файлов. Потребуется включенный по умолчанию режим совместимости, когда названия файлов запоминаются в кодировке, принятой в альтернативной системе (Windows).
Что мы получим
В общем: систему, более пригодную к переходу на UTF-8, взаимодействующую с ресурсами UTF-8-систем, и после перехода на UTF-8 – взаимодействующую с другими системами, и данными, не поддерживающими UTF-8.
В частности:
При монтировании ресурсов, поддерживающих указание кодировки, не нужно указывать кодировку нашей файловой системы;
При открытии файлов из GTK/GNOME программ в любой локали диалог выбора файлов будет корректно работать;
При записи файлов на компакт диск с помощью mkisofs/growisofs не нужно указывать кодировку;
При работе с архивами нет проблем с кодировкой названий файлов в них;
При проигрывании mp3-файлов, не будем получать кракозябры в тэгах.
Проблемы
Сюда записываются возражения, даже и не очень обоснованные. Желательно найти им ответ.
Что произойдёт, если в гости к русскому придёт китаец? :)
DenisSmirnov /25.02.2005 15:26/ Как и в любой другой не-unicode системе он будет вынужден пользоваться латиницей
Как быть со случаем, когда на сервере лежат файлы от одного пользователя, названные в CP1251 и от другого – в KOI8-R
DenisSmirnov /25.02.2005 15:26/ Отлавливанием виновного, и поручением ему перекодировки. Внутри организации должны действовать стандарты, и один из них — используемая кодировка хранения данных. Это существенно исключительно для nfs и ftp, в CIFS подобных проблем нет (перекодировка есть штатно);
Алексей Морозов: К тому же, носить в брюхе описание всех возможных кодировок, которые только могут быть доступны в libc, и прочую дрянь – э-э-э, чревато. Не ровен час, проклюнется кто в самый неожиданный момент, потом придется зачищать территорию нажатием на кнопку самоуничтожения. (смысла фразы я не понял – lav)
DenisSmirnov /25.02.2005 15:26/ Описания всех возможных кодировок у нас и так есть — libiconv, на которую уже переползла та же Samba. У неё, правда, есть один серьёзнейший недостаток, из-за которого links на неё не перейдёт никогда — отсутствие возможности преобразовать символы в близкие по смыслу (например русские буквы при перекодировке в iso8859–1 отображать транслитом); /VitalyLipatov // В libnatspec хранится описание *соответствия* всех возможных кодировок, а не просто перечень. К тому же в libnatspec добавлена возможность транслитерировать несоответствующие символы.
Программы, где это нужно
GLIB/GTK/GNOME
Статус: Есть готовый файл для profile
В gtk есть обработка переменной окружения G_FILENAME_ENCODING, которая у нас _не_ устанавливается, поэтому gtk предполагает, что она соответствует локали. При этом всё ломается, если я хочу запустить программу из другой локали (LANG=ru_RU.UTF-8 или LANG=ru_RU.CP1251) при основной koi8-r.
Так же GLIB обрабатывает переменную G_BROKEN_FILENAMES. Если она установлена, GLib предполагает, что названия файлов хранятся в кодировки локали, а не в UTF-8. Но G_FILENAME_ENCODING имеет больший приоритет.
SAMBA
TODO:
пакет samba-server: получение кодировок сервером из natspec по умолчанию
указание умолчаний в smbclient
1. Ни к чему каждый раз после установки раскомментировать в конф. файле строчки про кодировку (unix/display charset), когда они должны устанавливаться в кодировку файловой системы / локаль автоматически. DenisSmirnov /25.02.2005 15:26/Для сервера ручная настройка ещё может иметь какой-то разумный смысл, для клиента же — автоугадав обязателен
2. При монтировании удалённой файловой системы через smbmount (и mount -t cifs скорее всего тоже) опять же требуется указать кодировку своей системы (iocharset) DenisSmirnov /25.02.2005 15:26/ iocharset давно надо брать из текущей локали по-умолчанию
Монтирование файловых систем FAT-32, NTFS, ISO9660/Jouliet
Статус: есть патч для mount
TODO: Одновременно можно внести в mount поддержку /etc/fstab.d Тут я хотел бы пояснить, что в стандартной системе должна быть команда mount и она должна работать правильно. HAL – это хорошо, но это другое решение и надстройка более высокого уровня. Она не отменяет простого использования mount.
Бесконечное количество раз люди бьются с fstab, записывая туда разные iocharset, nls_ и пр. Но ведь можно же брать эти параметры (по умолчанию) из кодировки файловой системы.
TODO: Rock Ridge предполагать в UTF-8, перекодировать, если валидна.
Создание образов дисков
Статус: есть патч для mkisofs и isoinfo
Формировщику mkisofs – перекодировать из локальной кодировки.
Короткие названия наверное нужно транслитерировать или перекодировать в DOS Codepage. Реально они никому не нужны.
DOSEMU
Статус: у меня претензий нет
Там происходит перекодирование названий файлов в досовскую кодировку. Скорее всего, используется кодировка локали.
TODO: автоматизация заполнения config.sys для установки внутренней локали
FTP
Поскольку для FTP никаким образом не определено задание кодировок, обращаться из одной системы в другую за файлами, имеющими название из не ASCII-диапазона, невозможно. В proftp 1.3.1 добавился модуль mod_lang (поддержка команды “LANG” в соответствии с интернационализацией по RFC2640)
Варианты решения:
указывать кодировку сервера в приглашении. Например: «Welcome to FTP site <encoding="UTF-8">". Клиенты должны научиться распознавать указание кодировки.
сервер должен находится в UTF-8 (если клиент видит, что кодировка сервера не UTF, то использует без перекодирования). Клиенты должны перекодировать в свою кодировку.
есть вариант использовать WIN-кодировку по умолчанию (будут проблемы с буквой 'я') и встроить перекодирование для всех свободных клиентов.
Статус: у меня претензий нет
В основном проблема с кодировками названий файлов не возникает (решена за счёт предположения соответствия кодировки локали и файловой системы) – идеально, если бы это решалось вне проекта.
TODO: консольные сообщения не перекодируются в кодировку локали (что с wcmd?)
Архиваторы
Как правило, в Windows для кодирования названий файлов в архивах используется OEM-кодировка (DOS), в то время как в Linux названия записываются в кодировке файловой системы. И ничего не сдвинуто в этом направлении...
Подлежит уточнению:
Предлагается ввести перекодирование названий при работе с подмонтированными файловыми системами, подразумевая в них UTF-8.
Модули поддержки «чужих» файловых систем как правило имеют параметр iocharset, задающий внутреннюю кодировку названий файлов для перекодирования из «чужого» Юникода. Это относится к isofs, udf, vfat, ntfs, jfs
Для vfat имеется умолчание в ядре: FAT_DEFAULT_CHARSET, FAT_DEFAULT_CODEPAGE, по умолчанию присваиваемые iocharset и codepage соответственно, но это константы, что нам не подходит.
DenisSmirnov /25.02.2005 15:31/ Мысль : насколько просто внедрить дополнительный параметр в суперблок ext3, reiserfs4, xfs (основных используемых FS)?
В JFS предусмотрен iocharset, позволяющий перекодирование смонтированной системы (как я понимаю, в JFS подразумевается UTF8). Можно посмотреть, как это сделано там и рекомендовать разработчикам.
Вообще нужно сделать выбор: указывать кодировку в файловой системе или подразумевать, что она – в UTF-8.
Средство перекодирования файловой системы налету (через fuse?)
монтирование одного участка в другой с перекодированием
DenisSmirnov /24.02.2005 19:14/ Использование для этой цели fuse это очень хорошее временное решение
Кодировку на коротких названиях в FAT можно предполагать на основании кодировки файловой системы (для koi8-r/cp1251 будет cp866), для длинных названий на FAT/NTFS известно какая кодировка. А для остальных файловых систем ext?/reiserfs/xfs нужно вводить хранение кодировки или иметь предубеждение, что она там в UTF-8. Также потребуется перекодирование подмонтированной системы.
Получается, ядро должно иметь информацию о кодировке. Кстати, если хранить названия файлов в произвольной кодировке, можно избежать перекодирования, которое будет производится только при различии кодировкой локальной и на монтируемой файловой системе.
Замечания
Вячеслав Диконов:
Имею программу, у которой своя собственная внутренняя система локалей (VDR). Там гвоздями и стандартами DVB-вещания забито, что русский всегда идет в iso8859–5. Нет никаких внутренних средств перекодировки или поддержки системной локали, при этом нужно писать и читать много файлов, а файлам автоматически даются русские имена.
Может быть добавить в библиотеку функцию, позволяющую прозрачно заменять обычные обращения к объектам файловой системы в C и автоматически приводить имена к заданной кодировке, в каком бы виде они не хранились на реальных носителях? А также при записи преобразовывать имя из заданной кодировки в любую, какая используется на диске.
К VDR есть даже свои коммандер и консоль... Задача в том, чтобы видеть через преобразователь кодировок все съемные носители, все разделы с мультимедийными файлами и т.п. Кстати, набирать длинные команды и монтировать через обычный пульт ДУ слишком тяжело, а лавиатуры/мыши у VDR-машин часто вообще нет.
Еще проблема – включение в специаизированные дистрибутивы, которые ставятся на компы-ресиверы. Там все обрезано под ноль. Это я к тому, что решение должно быть маленьким и включаться минимальными движениями пользователя.
Алексей Морозов:
Единственным решением, которое худо-бедно может претендовать на некоторую универсальность (ну, помимо банального использования содержимого /etc/sysconfig/i18n) является организация (через dbus, вестимо, куда ж нынче без него) _обратной связи_ между HAL и пользовательским сеансом. То есть, сценарий использования примерно таков:
HAL, почуяв устройство с подходящей файловой системой, кидает броадкаст сообщение, о том, что-де, обнаружен FAT или там NTFS или еще какой ISO9660 позорный, требуется указать, как его монтировать. Соответствующий _пользовательский_ процесс, запущенный при старте сеанса, сверяется с какой-либо своей настройкой (например, получает значение LC_CTYPE, как вариант или еще что) и отвечает HAL'у, что-де так и так, предпочитаемая локаль пользователя такая-то и такая-то, использовать такой-то и такой-то чарсет для конвертации данных.
(from LAV: пока принцип не очень жизнеспособен, потому что HAL нападёт на первого попавшегося пользователя) DenisSmirnov /25.02.2005 15:31/Думаю речь должна идти о пользователе, коий последний обращался к консоли
Алексей Морозов:
. /etc/sysconfig/i18n
: ${SYSFONTACM:=koi8-r}
: ${SYSMOUNTCHARSET:=$SYSFONTACM}
echo $SYSMOUNTCHARSET
Только нужно учитывать, что рецепт, приведенные там не вполне корректен. Во-первых, нужно проверять на наличие файла /etc/hal/fdi/95userpolicy/system_charset.fdi перед его перезаписью. Во-вторых, формируемый .fdi, боюсь, не вполне корректен, требуется еще некоторый пролог и эпилог. Ну, и в третьих, Антон до сих пор не перенес соответствующие настройки
из /usr/share/hal в /etc/hal. Нужно только помнить, что «системные» настройки, которых там большинство лучше по-прежнему оставлять в /usr, т.к. по размеру они большие, а править их все равно не следует. А вот подкаталог 95userpolicy – явный кандидат в /etc.