Linux 在多大程度上支持超过 255 个字节的文件名?

Dam*_*les 28 filesystems

我昨天询问了 Linux 的 255 字节文件名限制,答案是这是一个不能/不会轻易更改的限制。但我记得大多数 Linux 都支持 NTFS,其最大文件名长度为 255 个 UTF-16 字符。

因此,我创建了一个 NTFS 分区,并尝试将文件命名为 160 个字符的日语字符串,其 UTF-8 中的字节数为 480。我预计它不会起作用,但它起作用了,如下所示。当文件名是 480 字节时,它是如何工作的?255 字节限制是否仅适用于某些文件系统,而 Linux 本身可以处理超过 255 字节的文件名?

在此处输入图片说明

----PS-----

该字符串是一篇名为“???”的著名古日本散文的开头部分。. 这是字符串。

?????????????????????????????????????????????????????? ?????????????????????????????????????????????????????? ?????????????????????????????????????????????????????? ?????????

我曾使用此 Web 应用程序来计算 UTF-8 字节数。

在此处输入图片说明

Ste*_*itt 27

答案通常是“视情况而定”。

特别是查看 NTFS 实现,它向statvfs调用者报告最大文件名长度为 255 ,因此将其解释为 255 字节限制的调用者可能会先发制人地避免在 NTFS 上有效的文件名。然而,大多数程序不会NAME_MAX提前检查这个(甚至),而是依靠ENAMETOOLONG错误来捕捉错误。在大多数情况下,重要的限制是PATH_MAX,而不是NAME_MAX;这就是在操作文件名时通常用于分配缓冲区的内容(对于不动态分配路径缓冲区的程序,正如Hurd等没有任意限制的操作系统所期望的那样)。

NTFS 实现本身不会以字节为单位检查文件名长度,而是始终以 2 字节字符为单位;不能在 255 个 2 字节元素的数组中表示的文件名将导致ENAMETOOLONG错误。

请注意,NTFS 通常由 Linux 上的 FUSE 驱动程序处理。内核驱动程序目前仅支持 UCS-2 字符,但FUSE 驱动程序支持 UTF-16 代理对(字符长度相应减少)。


Ned*_*d64 12

文件名长度的限制确实在文件系统内编码,例如ext4,来自https://en.wikipedia.org/wiki/Ext4

最大限度。文件名长度 255 字节

来自https://en.wikipedia.org/wiki/XFS

最大限度。文件名长度 255 字节

来自https://en.wikipedia.org/wiki/Btrfs

最大限度。文件名长度 255 个 ASCII 字符(对于多字节字符编码,例如 Unicode,较少)

来自https://en.wikipedia.org/wiki/NTFS

最大限度。文件名长度 255 个 UTF-16 代码单元

可以在https://en.wikipedia.org/wiki/Comparison_of_file_systems#Limits 中找到对许多文件系统的这些限制的概述。在那里您还可以看到 ReiserFS 具有更高的限制(几乎 4K),但内核本身(在 VFS 中,内核虚拟文件系统)具有 255 字节的限制。

您的文本使用 NTFS 中使用的 160 个 UTF-16 字符:

echo ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? > jp.txt
iconv -f utf-8 -t utf-16 jp.txt > jp16.txt
ls -ld jp*.txt
cat jp16.txt | hexdump -C
Run Code Online (Sandbox Code Playgroud)

这显示 0x140 = 320 个字节(如果使用的话,加上 2 个字节的前置字节顺序标记 (BOM))。换句话说,160 个 UTF-16 字符,因此低于 NTFS 中的 255 个 UTF-16 字符限制,但超过 255 个字节。

(这里忽略换行符)

  • [*最大限度。文件名长度:4032 字节,**Linux VFS 限制为 255 ***](https://en.wikipedia.org/wiki/ReiserFS) 所以看起来内核本身确实有一些限制因素 (4认同)
  • 我不知道 VFS 源代码,但 [`struct dirent`](https://www.man7.org/linux/man-pages/man3/readdir.3.html) 有一个固定的 `char d_name[256] ` 因此您永远无法在目录中找到文件名超过 255 个字节的文件 (2认同)

Art*_*nov 8

所以,这就是我发现的。

Coreutils并不特别关心文件名的长度,它只是简单地处理用户输入而不管它的长度,即零检查。

即这有效(文件名长度为 462 字节!):

name="??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????"
cd /mnt/ntfs
touch "$name"
Run Code Online (Sandbox Code Playgroud)

即使这有效

echo 123 > "$name"
cat "$name"
123
Run Code Online (Sandbox Code Playgroud)

但是,一旦您尝试将所述文件复制到任何经典 Linux 文件系统,操作就会失败:

cp "$name" /tmp
cp: cannot stat '/tmp/??????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????': File name too long
Run Code Online (Sandbox Code Playgroud)

cp实际上已尝试在/tmp/tmp不允许文件名超过 255 个字节。

我还设法在鼠标垫(一个 GTK 应用程序)中打开这个文件,编辑并保存它 - 这一切都有效,这意味着 255 字节限制仅适用于某些 Linux 文件系统。

这并不意味着一切都会奏效。例如,我最喜欢的控制台文件管理器 Midnight Commander,Norton Commander 的克隆版 -无法列出(将文件大小显示为 0)、打开或对此文件执行任何操作:

Error
No such file or directory (2)
Run Code Online (Sandbox Code Playgroud)


phu*_*clv 5

长话短说:

\n

曾经/现在有一些限制,例如readdir_r()无法读取超过 255 个字节的文件名。然而 Linux 确实意识到了这一点,现代 API 可以毫无问题地读取长文件名

\n
\n

ReiserFS wiki中有这一行

\n
\n

最大限度。文件名长度:4032字节,Linux VFS限制为255

\n
\n

因此,尽管我对 Linux VFS 的了解还不够,但 VFS 可能存在一些真正的限制。VFS函数全部工作在struct dentry将名称存储在struct qstr d_name;

\n
extern int vfs_create(struct inode *, struct dentry *, umode_t, bool);\nextern int vfs_mkdir(struct inode *, struct dentry *, umode_t);\nextern int vfs_mknod(struct inode *, struct dentry *, umode_t, dev_t);\nextern int vfs_symlink(struct inode *, struct dentry *, const char *);\nextern int vfs_link(struct dentry *, struct inode *, struct dentry *, struct inode **);\nextern int vfs_rmdir(struct inode *, struct dentry *);\nextern int vfs_unlink(struct inode *, struct dentry *, struct inode **);\nextern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *, struct inode **, unsigned int);\nextern int vfs_whiteout(struct inode *, struct dentry *);\n
Run Code Online (Sandbox Code Playgroud)\n

struct qstr哈希、长度和指向名称的指针,因此我认为不存在任何物理限制,除非 VFS 函数在创建/打开时显式截断名称。我没有检查实现,但我认为长名称应该可以正常工作

\n

更新:

\n

长度检查在linux/fs/libfs.c中完成,ENAMETOOLONG如果名称太长将返回

\n
/*\n * Lookup the data. This is trivial - if the dentry didn\'t already\n * exist, we know it is negative.  Set d_op to delete negative dentries.\n */\nstruct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)\n{\n    if (dentry->d_name.len > NAME_MAX)\n        return ERR_PTR(-ENAMETOOLONG);\n    if (!dentry->d_sb->s_d_op)\n        d_set_d_op(dentry, &simple_dentry_operations);\n    d_add(dentry, NULL);\n    return NULL;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

该限制在linux/limits.h中定义

\n
#define NAME_MAX         255    /* # chars in a file name */\n
Run Code Online (Sandbox Code Playgroud)\n

但我不知道文件名可以打开多长时间而不会出现该错误

\n
\n

然而,有一些系统调用确实有限制。struct dirent有以下成员

\n
struct dirent {\n   ino_t          d_ino;       /* Inode number */\n   off_t          d_off;       /* Not an offset; see below */\n   unsigned short d_reclen;    /* Length of this record */\n   unsigned char  d_type;      /* Type of file; not supported\n                                  by all filesystem types */\n   char           d_name[256]; /* Null-terminated filename */\n};\n
Run Code Online (Sandbox Code Playgroud)\n

由于d_name是一个固定数组,因此许多函数readdir_r()都无法返回长度超过 255 个字节的名称。例如

\n
struct dirent entry;\nstruct dirent *result;\ndir = opendir("/");\nint return_code = readdir_r(dir, &entry, &result);\n
Run Code Online (Sandbox Code Playgroud)\n

这就是readdir_r()被弃用的原因

\n
\n

在某些系统上,readdir_r()无法读取名称很长的目录条目。当 glibc 实现遇到这样的名称时,在读取最终目录条目后readdir_r()会失败并出现错误。ENAMETOOLONG在某些其他系统上,readdir_r()可能会返回成功状态,但返回的d_name字段可能不会以空终止或可能被截断。

\n

readdir_r(3) \xe2\x80\x94 Linux 手册页

\n
\n

readdir()OTOH 为自己分配内存struct dirent,因此名称实际上可以超过 255 个字节,并且您不能使用sizeof(d_name)sizeof(struct dirent)来获取名称和结构长度

\n
\n

请注意,在通话时

\n
fpathconf(fd, _PC_NAME_MAX)\n
Run Code Online (Sandbox Code Playgroud)\n

对于大多数文件系统返回值 255,在某些文件系统(例如 CIFS、Windows SMB 服务器)上,(正确)返回的以 null 结尾的文件名d_name实际上可能超过此大小。在这种情况下,该d_reclen字段将包含超过上面显示的 glibc 结构大小的值dirent

\n

readdir(3) \xe2\x80\x94 Linux 手册页

\n
\n

其他一些函数,例如getdents()use struct linux_direntstruct linux_dirent64它不受固定长度问题的影响

\n
fpathconf(fd, _PC_NAME_MAX)\n
Run Code Online (Sandbox Code Playgroud)\n

strace ls显示ls使用getdents()列出文件,以便它可以处理任意长度的文件名

\n

  • `readdir(3)` 在 Linux `getdents` 系统调用之上实现了可移植的 POSIX 函数。即使应用程序使用“readdir_r”生成 getdents 结果的截断副本,您也始终会看到“getdents”系统调用。 (2认同)