glibc 函数在大文件上失败

glibc function fails on large file

我有一个几年前用 C++ 编写的实用程序,它获取给定目录的所有子目录中的所有文件,并根据文件的数量将它们移动到新的编号子目录中。它已经工作了几年没有错误。

昨天第一次失败。它总是在 2.7Gig 视频文件上失败,这可能是该实用程序遇到过的最大视频文件。文件本身没有损坏。它将在视频播放器中播放。我可以毫无问题地使用命令行或文件管理器应用程序移动它。

我使用 ntfw() 遍历目录子树。在此文件上,ntfw() returns 在调用我的回调函数之前遇到该文件时的错误代码为 -1。因为(我认为)代码只处理文件名而不是实际打开或读取文件,所以我不明白为什么文件大小应该是一个问题。

打开文件描述符的数量不是问题。也不是文件的数量。它在一个包含 5,000 多个文件的子树中,但是当将它移动到仅有的 50 个文件之一时它仍然失败,而原始子树的处理没有错误。文件权限不是问题。该文件与所有其他文件相同。这包括 ACL 权限。

问题是:文件大小是问题所在吗?为什么?

文件系统为ext4。

ldd --version /usr/lib/i386-linux-gnu/libc.so
ldd (Ubuntu GLIBC 2.27-3ubuntu1.4) 2.27
Linux version 4.15.0-161-generic (buildd@lgw01-amd64-050)
(gcc version 7.5.0 (Ubuntu 7.5.0-3ubuntu1~18.04))
#169-Ubuntu SMP Fri Oct 15 13:39:59 UTC 2021

由于您使用的是 32 位应用程序,为了正确处理大于 2 GB 的文件,您应该使用 -D_FILE_OFFSET_BITS=64 进行编译,以便使用 64 位文件处理系统调用和类型。

特别是,如果文件大小超过 2 GB,nftw() 调用 stat() 会失败并显示 EOVERFLOW:https://man7.org/linux/man-pages/man2/stat.2.html

此外,对于使用 mmap()(您似乎没有使用它,但以防万一评论提到它),您不能分配全部 4 GB,一些地址 space 为内核保留(通常在 Linux 上为 1 GB)。然后一些 space 被堆栈、共享库等使用。如果幸运的话,也许你一次可以映射 2 GB。