我昨天询问了 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 个字节。
(这里忽略换行符)
所以,这就是我发现的。
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)
长话短说:
\n曾经/现在有一些限制,例如readdir_r()
无法读取超过 255 个字节的文件名。然而 Linux 确实意识到了这一点,现代 API 可以毫无问题地读取长文件名
ReiserFS wiki中有这一行
\n\n\n最大限度。文件名长度:4032字节,Linux VFS限制为255
\n
因此,尽管我对 Linux VFS 的了解还不够,但 VFS 可能存在一些真正的限制。VFS函数全部工作在struct dentry
将名称存储在struct qstr d_name;
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长度检查在linux/fs/libfs.c中完成,ENAMETOOLONG
如果名称太长将返回
/*\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\n#define NAME_MAX 255 /* # chars in a file name */\n
Run Code Online (Sandbox Code Playgroud)\n但我不知道文件名可以打开多长时间而不会出现该错误
\n然而,有一些系统调用确实有限制。struct dirent
有以下成员
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 个字节的名称。例如
struct dirent entry;\nstruct dirent *result;\ndir = opendir("/");\nint return_code = readdir_r(dir, &entry, &result);\n
Run Code Online (Sandbox Code Playgroud)\n\n\n\n在某些系统上,
\n\nreaddir_r()
无法读取名称很长的目录条目。当 glibc 实现遇到这样的名称时,在读取最终目录条目后readdir_r()
会失败并出现错误。ENAMETOOLONG
在某些其他系统上,readdir_r()
可能会返回成功状态,但返回的d_name
字段可能不会以空终止或可能被截断。
readdir()
OTOH 为自己分配内存struct dirent
,因此名称实际上可以超过 255 个字节,并且您不能使用sizeof(d_name)
和sizeof(struct dirent)
来获取名称和结构长度
\n\n请注意,在通话时
\nRun Code Online (Sandbox Code Playgroud)\nfpathconf(fd, _PC_NAME_MAX)\n
对于大多数文件系统返回值 255,在某些文件系统(例如 CIFS、Windows SMB 服务器)上,(正确)返回的以 null 结尾的文件名
\n\nd_name
实际上可能超过此大小。在这种情况下,该d_reclen
字段将包含超过上面显示的 glibc 结构大小的值dirent
。
其他一些函数,例如getdents()
use struct linux_dirent
,struct linux_dirent64
它不受固定长度问题的影响
fpathconf(fd, _PC_NAME_MAX)\n
Run Code Online (Sandbox Code Playgroud)\nstrace ls
显示ls
使用getdents()
列出文件,以便它可以处理任意长度的文件名