C++ 删除文件后的mmap()
有人告诉我,如果有人删除原始文件,mmap()可能会有麻烦。我想知道这是否真的发生了。所以我创建了一些小测试程序。我正在使用linuxC++ 删除文件后的mmap(),c++,C++,有人告诉我,如果有人删除原始文件,mmap()可能会有麻烦。我想知道这是否真的发生了。所以我创建了一些小测试程序。我正在使用linux #include <iostream> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/stat.h> #include <unis
#include <iostream>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
int main(int, char**)
{
char const * const fileName = "/tmp/demo-file.dat";
size_t size;
{
struct stat st;
stat(fileName, &st);
size = st.st_size;
}
int fd = open(fileName, O_RDWR);
if (fd == -1)
{
std::cout << "open() failed, errno = " << errno << ":" << strerror(errno) << std::endl;
return (-1);
}
else
{
std::cout << "open() done (ok)" << std::endl;
}
for (int i = 20; i > 0; --i)
{
std::cout << "file open()'ed, wait #" << i << " seconds before mmap()" << std::endl;
sleep(1);
}
void *data = mmap((void*)0L, size, PROT_READ, MAP_SHARED, fd, (off_t)0);
if (data == (void*)-1)
{
std::cout << "mmap() failed, errno = " << errno << ":" << strerror(errno) << std::endl;
}
else
{
std::cout << "mmap() done (ok)" << std::endl;
}
for (int i = 20; i > 0; --i)
{
std::cout << "going to close() socket in #" << i << " seconds" << std::endl;
sleep (1);
}
close(fd);
for (int i = 30; i > 0; --i)
{
std::cout << "going to umap() files in #" << i << " seconds (still accessing the data)" << std::endl;
for (unsigned int x = 0; x < size; ++x)
{
char cp = *(char*) (data + x);
(void) cp;
}
sleep(1);
}
munmap(data, size);
for (int i = 30; i > 0; --i)
{
std::cout << "going to terminate #" << i << " seconds" << std::endl;
sleep(1);
}
return 0;
}
程序的其余部分工作正常
即使在close()之后删除文件,它仍能成功访问mmap()数据。
但是在这两种情况下,在关闭()之后,我看不到
lrwx------ 1 frank frank 64 Mär 22 20:28 3 -> /tmp/demo-file.dat (deleted)
再也没有了。(顺便说一句:然后注意到,这个文件“不知何故仍然存在”?)
那么,是否恰恰相反,即使文件被手动删除(在shell中或通过其他过程),mmap()仍能对数据进行操作呢 首先要检查的是
$ls -i /tmp/demo-file.dat
65 /tmp/demo-file.dat
请注意,文件的inode编号为65
在启动程序时,以下是它的lsof
输出中的内容(除了与当前论述无关的其他条目)
这是已完成的open()
操作的结果。请注意,inode编号与另一个文件相同。open()
增加了同一inode上的ref计数。另外,请注意,REG
表示常规文件
现在如果文件被删除(使用rm
等),下面是lsof
的样子
a.out 29271 zoso 3u REG 0,21 5 65 /tmp/demo-file.dat (deleted)
这是预期的,因为已打开的文件已被删除,但其inode的句柄在此过程中仍处于打开状态
转到mmap,这里是lsof
输出
a.out 29271 zoso DEL REG 0,21 65 /tmp/demo-file.dat
a.out 29271 zoso 3u REG 0,21 5 65 /tmp/demo-file.dat (deleted)
现在有另一个新条目,但请注意,这是类型DEL
,表示(从手册页提升):
已删除的Linux映射文件的“DEL”
由于lsof
无法再统计原始文件,它将此映射设置为DEL
,当然没有大小,但请注意inode编号仍然保持不变,即65
现在,在fd上调用close()
后,下面是lsof
显示的内容
a.out 29271 zoso DEL REG 0,21 65 /tmp/demo-file.dat
请注意,(已删除)
条目已消失,因为REG
文件的fd已关闭,现在只剩下mmap的内存
在
munmap()
之后,这个条目也消失了(不再引用/tmp/demo file.dat
,程序最终结束。文件仍将有一个活动的索引节点。索引节点通过引用计数保持活动状态。打开的文件句柄是一个引用。打开文件时,进程将接收指向文件索引节点的描述符或文件流。删除该文件只会重新启动。)移动目录中的文件项。在关闭最后一个引用之前,索引节点不会返回到文件系统。目录中的文件名不是该文件。Unix不是Windows。我知道文件描述符,因此显示在/proc/[pid]/fd/…如何为mmap()建模此引用计数?
a.out 29271 zoso DEL REG 0,21 65 /tmp/demo-file.dat
a.out 29271 zoso 3u REG 0,21 5 65 /tmp/demo-file.dat (deleted)
a.out 29271 zoso DEL REG 0,21 65 /tmp/demo-file.dat