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

C++ 以编程方式防止重命名或删除文件,但仍使其可写,c++,linux,file-handling,fcntl,C++,Linux,File Handling,Fcntl,我有一个应用程序(比方说应用程序A),我无法控制,也无法修改、写入文件,并且能够重命名和删除它 我有另一个应用程序(比如应用程序B)正在读取应用程序A编写的文件。我完全控制应用程序B中的代码 我应该做什么(即,设置文件的权限,或者在应用程序B打开文件时我应该在应用程序B中使用什么锁),以便应用程序A可以继续写入文件,但不能重命名或删除它 我试图在应用程序B中使用fcntl()设置文件的读写锁,但应用程序A仍然可以重命名文件 下面是从应用程序B获取锁定的示例代码(fd是文件的文件描述符): int

我有一个应用程序(比方说应用程序A),我无法控制,也无法修改、写入文件,并且能够重命名和删除它

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

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

我试图在应用程序B中使用
fcntl()
设置文件的读写锁,但应用程序A仍然可以重命名文件

下面是从应用程序B获取锁定的示例代码(
fd
是文件的文件描述符):

int fd=open(仅限文件路径);
结构群锁;
lock_it.l_type=F_WRLCK;//我也试过F_RDLCK。
lock_it.l_where=SEEK_SET;
lock_it.l_start=0;
lock_it.l_len=0;//我想锁定整个文件。
int lockingreult=fcntl(fd、F_SETLK和lock_it);

cout要写入文件,您必须对该文件具有写入权限,但要删除或重命名文件,您必须对该目录具有写入权限


注意:即使无法删除文件,也可以将其截断,除非您的文件系统支持仅附加文件的概念。

要写入文件,您必须具有文件的写入权限,但要删除或重命名文件,您必须具有目录的写入权限

注意:即使无法删除文件,也可以将其截断,除非您的文件系统支持仅附加文件的概念。

注意:以下假设appB的速度足以完成此操作(即存在一点争用条件)

appB可以使用其他名称创建指向文件项的硬链接。这将阻止appA删除该文件(请参见
man 2链接
):

现在,如果appA删除[或重命名]该文件,则仍可通过
appBfile

当第一次创建文件时,它会为该文件创建一个目录条目,即所谓的inode

索引节点有一个引用计数。初始创建inode时,其引用计数为1。当程序打开文件时,inode的引用计数递增,当程序关闭文件描述符时,inode的引用计数递减

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

目录项[或多或少]只是:
filename | inode number
。inode具有文件大小、文件数据块列表、权限等信息

inode位于文件系统中的一个单独的表中,由
inode number
索引

如果appB能够在appA重命名或删除它之前打开
appAfile
(更恰当的是,它会取消目录项的链接,这就是为什么系统调用是
unlink
,而不是(例如
delete
),数据仍然可以访问,因为当appB打开时,inode的引用计数会增加。也就是说,refcount现在是2。如果appA删除该文件,inode的refcount将递减为1。它仍然是非零的,因此appB可以读取数据

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

当appB执行硬链接操作时,它会创建具有相同inode编号的第二个目录条目,并增加该inode的refcount。也就是说,对于给定的inode,如果没有程序持有打开的文件描述符,inode的refcount是具有指向它的链接的目录条目数。这通常为1,但appB创建硬链接后,引用计数将为2。可以创建许多这样的硬链接(使用不同的“别名”)并且inode的refcount会相应增加

这样,即使appA已删除该文件、关闭了该文件描述符,并且appB已关闭了其文件描述符,该文件也可以保持不变。inode的refcount为1,来自
appBfile
。如果appB有一个打开的描述符,则refcount将为2(当appB关闭文件时返回到1)

请注意,如果appA重命名目录项(例如,
rename(appAfile,appAfile2)
),则重命名不会减少引用计数。appB在新名称下查找它可能会有困难,但数据仍然存在(即inode尚未删除)

因此,只要应用程序有一个打开的描述符,或者有一个带有inode的inode编号的目录条目,inode就会保持不变。换句话说,在任何给定时间,inode的refcount是链接到它的目录项数+在它上面打开的文件描述符数之和。要删除/删除inode数据,refcount必须变为0。

警告:以下假设appB足够快,可以执行此操作(即存在一点竞争条件)

appB可以使用其他名称创建指向文件项的硬链接。这将阻止appA删除该文件(请参见
man 2链接
):

现在,如果appA删除[或重命名]该文件,则仍可通过
appBfile

当第一次创建文件时,它会为该文件创建一个目录条目,即所谓的inode

索引节点有一个引用计数。初始创建inode时,其引用计数为1。当程序打开文件时,inode的引用计数递增;当程序关闭文件描述符时,inode的引用计数递增
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;
link("appAfile","appBfile");