Linux/VLFN
VLFN (Very Long FileName) — проблема, заключающаяся в том, что в большинстве Unix-систем (и в GNU/Linux в частности) применено ограничение в 255 байт на длину имени файла, что при использовании UTF-8 даёт для русских букв не более 127 символов.
В статье рассматриваются способы увеличения допустимой длины имени файлов в Linux и проблемы, с этим связанные.
- 1 Имена файлов в Windows и Linux
- 2 Причины проблемы
- 3 Постановка задачи
- 4 Решение
- 4.1 NAME_MAX free
- 6.1 Изменения
- 6.2 Тестирование
- 6.3 Применение
- 7.1 Пакеты
- 7.2 Тестирование mc
- 7.3 Ссылки
Имена файлов в Windows и Linux
В Windows для именования файлов принята кодировка UTF-16, то есть каждый символ в названии файла кодируется двумя байтами (16 бит). Максимальная длина имени файла — 255 символов (510 байт). В Linux же для именования файлов принята кодировка UTF-8, при этом максимальная длина файла составляет 255 байт (а не символов).
Причины проблемы
- Ядро внутри себя не имеет общей константы для ограничения длины имени файла. NAME_MAX в include/linux/limits.h нужна только для программ (попадает в glibc-headers).
- Файловые системы в ядре имеют ограничения по размеру (в ext3/4 вообще взяли и оставили 1 байт на хранение длины имени файла). В некоторых системах ограничение жёсткое (ext4), в некоторых — номинальное (btrfs).
- glibc нигде не касается данных, связанных с ограничением длины.
Постановка задачи
Так как в UTF-8 для кодирования русских букв используется два байта, то максимальная длина имени файла, состоящего из русских букв, фактически составляет 127 символов. В связи с этим появляется проблема — длинные имена файлов (от 128 до 255 русских символов) не влезают в установленные для них ограничения в Linux.
Решение
Необходимо увеличить возможную длину файлов в Linux.
Выбранная длина нового максимального предела имени файла — 1023 байта.
- нет привязки к Windows, поэтому нет необходимости задавать размер ровно 511 байт;
- имя файла задается с запасом, что позволит адаптировать ОС и ФС к иероглифической, к примеру письменности, где знаки могут занимать в районе 4 байт.
NAME_MAX free
Радикальным правильным решением для userspace является отказ от использования констант, задающих размер буфера под имя файла.
Файловые системы должны быть устроены таким образом, чтобы длина имени файла была переменной и не имела ограничений (кроме временных соображений совместимости).
Уже сделано
Был проведен тест файловой системы NTFS. Оказалось, что на данной можно создавать файлы с длинным русским именем, из чего следовало, что ограничение задается самой ФС, а не ядром или библиотекой glibc: https://bugs.etersoft.ru/show_bug.cgi?id=9266
Было решено выбрать файловую систему, которую легче всего было бы адаптировать для решения данной проблемы. Затем было проведено сравнение самых распространенных и перспективных файловых систем: http://wiki.etersoft.ru/Comparison_of_file_systems
Стоит рассмотреть такие системы как btrfs, xfs, ext4.
В итоге, благодаря гибкости и динамичности развития, была выбрана файловая система BTRFS.
BTRFS
B TRee File System — файловая система, основанная на структуре Б-деревьев и работающая по принципу «копирование при записи».
Изменения
Изначально изменен предел BTRFS_NAME_LEN, заданный в файле /fs/btrfs/ctree.h. Аналогичный предел был изменен в пакете BTRFS-progs.
Изменения:diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index d6dd49b..3ae04d0 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h @@ -154,7 +154,7 @@ struct btrfs_ordered_sum; * we can actually store much bigger names, but lets not confuse the rest * of linux */ -#define BTRFS_NAME_LEN 255 +#define BTRFS_NAME_LEN 1023 /* * Theoretical limit is larger, but we keep this down to a sane diff --git a/include/linux/compat.h b/include/linux/compat.h index 7f0c1dd..9bbf0d9 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -202,7 +202,7 @@ struct compat_dirent u32 d_ino; compat_off_t d_off; u16 d_reclen; - char d_name[256]; + char d_name[1024]; >; struct compat_ustat < diff --git a/include/uapi/linux/limits.h b/include/uapi/linux/limits.h index 2d0f941..ca17cbe 100644 --- a/include/uapi/linux/limits.h +++ b/include/uapi/linux/limits.h @@ -8,7 +8,7 @@ #define LINK_MAX 127 /* # links a file may have */ #define MAX_CANON 255 /* size of the canonical input queue */ #define MAX_INPUT 255 /* size of the type-ahead buffer */ -#define NAME_MAX 255 /* # chars in a file name */ +#define NAME_MAX 1023 /* # chars in a file name */ #define PATH_MAX 4096 /* # chars in a path name including nul */ #define PIPE_BUF 4096 /* # bytes in atomic write to a pipe */ #define XATTR_NAME_MAX 255 /* # chars in an extended attribute name */
Тестирование
Проведено тестирование основной функциональности новой файловой системы. Для граничных значение — 1024 и 1023 байта:
Testing glibc functions with 1023-byte filename FAILED: 0, PASSED: 20 Testing glibc functions with 1024-byte filename FAILED: 0, PASSED: 20
Testing glibc functions with 1023-byte filename [root@host-35 btrfs]# /home/guest/glibc_vlfn_test Testing glibc functions with 1023-byte filename FAILED: 0, PASSED: 20 Testing glibc functions with 1024-byte filename FAILED: 0, PASSED: 20
Testing glibc functions with 1023-byte filename Error in line:190; file: glibc_vlfn_test.c: File name too long Error in line:191; file: glibc_vlfn_test.c: File name too long Error in line:192; file: glibc_vlfn_test.c: File name too long Error in line:193; file: glibc_vlfn_test.c: File name too long Error in line:194; file: glibc_vlfn_test.c: File name too long Error in line:195; file: glibc_vlfn_test.c: File name too long Error in line:196; file: glibc_vlfn_test.c: Success Error in line:197; file: glibc_vlfn_test.c: File name too long Error in line:198; file: glibc_vlfn_test.c: File name too long Error in line:201; file: glibc_vlfn_test.c: File name too long Error in line:202; file: glibc_vlfn_test.c: No such file or directory Error in line:203; file: glibc_vlfn_test.c: File name too long Error in line:204; file: glibc_vlfn_test.c: File name too long Error in line:205; file: glibc_vlfn_test.c: File name too long Error in line:206; file: glibc_vlfn_test.c: File name too long Error in line:207; file: glibc_vlfn_test.c: No such file or directory Error in line:208; file: glibc_vlfn_test.c: File name too long Error in line:209; file: glibc_vlfn_test.c: File name too long Error in line:210; file: glibc_vlfn_test.c: Success Error in line:211; file: glibc_vlfn_test.c: File name too long FAILED: 20, PASSED: 0 Testing glibc functions with 1024-byte filename FAILED: 0, PASSED: 20
Применение
Для того, чтобы использовать файловую систему BTRFS с увеличенным пределом имени файла, необходимо:
- Установить исправленную версию ядра ( git.eter:/people/reprofy/packages/kernel_sis.git -> btrfs_new_bound );
- Отформатировать дисковый раздел, используя исправленную версию btrfs-progs ( git.eter:/people/reprofy/public/btrfs_progs.git -> filename_bound );
- Для обеспечения полной функциональности необходимо изменить предел в файле limits.h:
- Установить исправленный пакет kernel-source-3.9 ( git.eter:/people/reprofy/public/kernel_source_3.9.git -> namelength_increased );
- Установить пакет glibc-kernheaders(из репозитория git.alt );
Glibc
В самой glibc вносить изменения не нужно, единственное, что требуется — изменить предел в файле limits.h.
Пакеты
Пакеты для ALT Linux в LINUX@Etersoft:
- glibc-kernheaders даёт возможность собирать программы с увеличенным ограничением
- btrfs-utils не будет ругаться на длинные имена при проверке ФС
- ядро с увеличенным ограничением для btrfs
Тестирование mc
При использовании mc было обнаружено, что несмотря на исправленные пределы в файловой системе, midnight commander не отображает длинные имена файлов. Как оказалось далее, mc берет значения констант из файла /usr/include/linux/limits.h. Последний, в свою очередь, принадлежит пакету glibc-kernheaders. После сборки с исправленным glibc-kernheaders mc стал корректно отображать длинные имена.
Ссылки
Длинные имена файлов
Всем привет переношу файлопомойку с винды на линукс. Столкнулся с проблемой «очень длинных имён файлов». Похоже, счёт идет не на символы, а на байты (гугление это подтверждает). Внимание, вопрос: мне таки придётся использовать винду или есть какое-то решение этой проблемы? (усекновение имени — не решение в данной ситуации)
ext2/3/4,reiser,xfs,jfs — все поддерживают 255 символов в имени файла (или 127 в UTF8) — куда вам больше??
Поправочка: 127 русских букв, закодированных в UTF8.
UTF8 — однобайтовая кодировка, так что ASCII в UTF8 = ASCII 🙂
ФС те, которые поддерживаются CentOS 5.4 — то есть ext2/3, ext4 без mkfs.ext4, xfs на положении ext4.
127 букв — внезапно оказалось мало. Есть у пользователей такие имена файлов:
«Котов АН Моделирование дорожного движения на многополосной магистрали при помощи двумерного вероятностного клеточного автомата с тремя состояниями, 2008 (диссертация)»
Усекновение — не вариант. На винде такое имя файла обрабатвается корректно
$ echo «Котов АН Моделирование дорожного движения на многополосной магистрали при помощи двумерного вероятностного клеточного автомата с тремя состояниями, 2008 (диссертация)» | wc -c
$ touch «Котов АН Моделирование дорожного движения на многополосной магистрали при помощи двумерного вероятностного клеточного автомата с тремя состояниями, 2008 (диссертация)»
$ ls Котов*
Котов АН Моделирование дорожного движения на многополосной магистрали при помощи двумерного вероятностного клеточного автомата с тремя состояниями, 2008 (диссертация)Если очень нужно, то можно поставить однобайтную локаль. Хотя да, не решение.
megabaks@localhost ~ $ touch "Котов АН Моделирование дорожного движения на многополосной магистрали при помощи двумерного вероятностного клеточного автомата с тремя состояниями, 2008 (диссертация)" touch: невозможно выполнить touch для «Котов АН Моделирование дорожного движения на многополосной магистрали при помощи двумерного вероятностного клеточного автомата с тремя состояниями, 2008 (диссертация)»: Слишком длинное имя файла
localhost / # touch "Котов АН Моделирование дорожного движения на многополосной магистрали при помощи двумерного вероятностного клеточного автомата с тремя состояниями, 2008 (диссертация)" touch: невозможно выполнить touch для «Котов АН Моделирование дорожного движения на многополосной магистрали при помощи двумерного вероятностного клеточного автомата с тремя состояниями, 2008 (диссертация)»: Слишком длинное имя файла
localhost boot # touch "Котов АН Моделирование дорожного движения на многополосной магистрали при помощи двумерного вероятностного клеточного автомата с тремя состояниями, 2008 (диссертация)" touch: невозможно выполнить touch для «Котов АН Моделирование дорожного движения на многополосной магистрали при помощи двумерного вероятностного клеточного автомата с тремя состояниями, 2008 (диссертация)»: Слишком длинное имя файла
+1 ext3, debian lenny, создался
> у кого-то из нас перацкий линукс ^_^ ext3
А, это у меня, как x3al заметил, кодировка однобайтная.
$ echo «Котов АН Моделирование дорожного движения на многополосной магистрали при помощи двумерного вероятностного клеточного автомата с тремя состояниями, 2008 (диссертация)» | wc -c
167ааа — ну тогда понятно, молчу
не перацкий ).-(~)---------------------------------------------------------(gotf@persephone)- `--> touch "Котов АН Моделирование дорожного движения на многополосной магистрали при помощи двумерного вероятностного клеточного автомата с тремя состояниями, 2008 (диссертация)" touch: cannot touch `Котов АН Моделирование дорожного движения на многополосной магистрали при помощи двумерного вероятностного клеточного автомата с тремя состояниями, 2008 (диссертация)': File name too long
Хотя, если верить педивикии, ограничений в XFS (равно, как и ext*) нету.
Т.е. ограничений нет в самой ФС, но они могут устанавливаться драйвером.
А ведь проблема, если на имя файла что-то завязано. значит, если переделать никак, то Win. Вообще, как-то криво реализация UTF сделана, получается. Не зря оно мне доверия не внушает всё ещё.