以编程方式防止文件被重命名或删除,但仍可写

时间:2018-08-20 21:21:10

标签: c++ linux file-handling fcntl

我有一个无法控制的应用程序(例如 App A ),我无法修改,写入文件并能够重命名和删除该文件。

我有另一个应用程序(例如 App B )正在读取由App A编写的文件。我对App B中的代码拥有完全控制权。

我该怎么做(即设置文件的权限,或者在打开文件B时在App B中使用什么锁),以便App A可以继续写入文件,但不能重命名或删除它。 / p>

我尝试在App B中使用fcntl()来设置文件的读写锁定,但是App A仍然可以重命名该文件。

以下是从App B获取锁定的示例代码(fd是文件的文件描述符):

int fd = open(filePath, O_RDONLY);
struct flock lock_it;
lock_it.l_type = F_WRLCK; // I've tried F_RDLCK as well.
lock_it.l_whence = SEEK_SET;
lock_it.l_start = 0;
lock_it.l_len = 0; // I want to lock the entire file. 
int lockingResult = fcntl(fd,F_SETLK,&lock_it);
cout << "Got a fcntl lock: " << lockingResult << " on  FD: " << fd << endl;

但是上面的代码不会阻止App A重命名文件。

任何想法我该怎么办?我的代码是C ++,我的应用程序在RedHat Linux上运行。

2 个答案:

答案 0 :(得分:2)

注意事项:以下内容假定appB足够快[em] 来执行此操作(即有些竞争条件)。

appB可以使用其他名称创建指向文件条目的 hard 链接。这将阻止appA删除文件(请参见man 2 link

link("appAfile","appBfile");

现在,如果appA删除[或重命名]文件,仍可以通过appBfile来访问它

首次创建文件时,它会为文件(称为 inode )创建一个目录条目。

Inode具有参考计数。最初创建一个索引节点时,其引用计数为1。当程序打开文件时,索引节点的引用计数将递增,而当程序关闭文件描述符时,索引节点的引用计数将递减。

appA删除文件(通过unlink(2))时,目录条目将被删除,并且inode的引用计数将减少。如果appA仍具有打开的文件,则在appA关闭打开的文件描述符之前(即引用计数必须为0),不会删除inode的内容。

目录条目只是[{或多或少]:filename|inode-number。它是inode,具有诸如文件大小,作为文件数据的块列表,权限等信息。

inodes位于文件系统的单独表中,并由inode-number索引。

如果appB能够在appA重命名或删除它之前打开appAfile(更正确地说,它取消链接目录条目,这就是syscall是unlink而不是{ (例如delete),因为当appB打开时,该inode的引用计数增加了,所以仍然可以访问该数据。也就是说,引用计数现在为2。如果appA删除文件,则inode的引用计数将减为1。它仍然非零,因此appB可以读取数据。

只要appB拥有一个打开的描述符,数据就将保留。但是,其他任何应用程序都无法访问它,因为目录条目丢失了。而且,当appB关闭文件时,inode的refcount变为0,并回收数据块。

appB执行硬链接操作时,它将创建第二个目录条目,并带有 same 索引节点编号,并递增该索引节点的引用计数。也就是说,对于给定的inode,如果 no 程序保存打开的文件描述符,则inode的refcount是具有指向它的链接的目录条目的数量。通常为1,但在appB创建硬链接后,引用计数将为2。可以创建许多此类硬链接(使用不同的“别名”名称),并且inode的引用计数将相应增加。

即使appA删除了文件,关闭了文件描述符,而appB关闭了其文件描述符,这也使文件得以保留。索引节点的引用计数为1,来自appBfile。如果appB具有打开的描述符,则引用计数将为2(当appB关闭文件时,引用计数将返回1)。

请注意,如果appA重命名目录条目(例如rename(appAfile,appAfile2)),则重命名不会减少引用计数。 appB可能无法在新名称下找到它,但是数据仍然存在(即inode已被删除)。

因此,只要应用程序具有打开的描述符,或者存在带有索引节点的索引节点编号的目录条目,索引节点便会保留。换句话说,在任何给定时间,inode的refcount是与其链接的目录条目的数量与在其上打开的文件描述符的数量之和。要删除/删除索引节点数据,引用计数必须为0。

答案 1 :(得分:1)

要写入文件,必须具有对文件的写许可权,但是要删除或重命名文件,必须具有对目录的写许可权。

注意:即使您不能删除文件,也仍然可以截断它,除非您的文件系统支持仅附加文件的概念。