当我使用 更改文件的权限时chmod
,现有文件描述符可以继续访问之前权限下的文件。
权限更改后是否可以立即导致这些现有文件描述符关闭或失败或变得不可用?
答案1
内核不检查文件描述的权限。它们甚至可以复制到从未访问过原始文件的其他进程FD 传递。
我认为你唯一可以尝试的就是手动找出流程打开文件描述符,然后用一个狡猾的技巧来关闭它们1。有一个这样的“偷偷摸摸的技巧”的例子,就是附加一个调试器(gdb
)并用它来关闭 fd。
这是一件非常极端的事情。如果进程的 FD 突然关闭,则无法知道该进程将如何表现。在某些情况下,进程可能有一个映射到内存的文件,因此如果您设法关闭该文件并且设法删除任何内存映射,而进程预计它会因分段错误而崩溃。
好多了就是找到哪些进程正在使用文件并手动杀死它们。至少这样你可以要求他们很好地关闭并且不会损坏其他数据。
1 正如评论中提到的,使这项工作有效的最佳方式是调用dup2
而不是close
更改 fd 以指向/dev/null
而不是原始文件。这是因为代码不会期望它已经关闭,并且当 fd(数字)被回收时可能会做一些非常奇怪和不安全的事情。
答案2
您无法使现有文件描述符无效,除非通过 Philip Couling 提到的“偷偷摸摸的技巧”。但是,您可以通过(合理)便携的方式实现类似的效果。
假设您想要阻止已foo
打开的进程继续写入foo
.你能做的是:cp foo foo2; chmod -w foo2; mv foo2 foo
。现在,任何打开旧文件的进程foo
都将继续写入该文件,该文件不再被称为foo
(比以前少了一个硬链接)。这些进程都不会影响 new foo
,因为它们无法打开它进行写入。
如果你想阻止阅读,类似的策略是cp foo foo2; chmod -r foo2; truncate foo; mv foo2 foo
。在这里,旧的foo
被就地截断(IE,减小到零大小而不被删除),因此已打开的进程foo
下次尝试从中读取内容时将看不到任何内容,并且无法打开新的foo
.但是,这并不能保证有效,因为如果任何进程具有mmap
ed foo
,则无法指定截断是否实际上会影响这些映射。
答案3
这是一个超级有趣的问题,研究这个问题实际上比看 Netflix 给周日带来更多乐趣:-)
- 正如其他答案所回答的那样,不在 posix 内
- 肮脏的技巧:YMMV,我很确定调试器技巧需要通过取消文件映射来扩展(天哪,这是邪恶的。文件描述符在一个系统调用和另一个系统调用之间变得无效并不好,但是数据结构的一部分消失是不可能处理的)。
- 在 Linux 下:如果你看一下https://upload.wikimedia.org/wikipedia/commons/f/fb/The_Linux_Storage_Stack_Diagram.svg实际上,一般而言,实现您的建议将需要您查找索引节点的页面缓存位置,并亲自通过未知的方式寻找它们(否则已经映射的内存仍然存在,无需系统调用。)。 (备注:如果不锁定对页面缓存的访问和/或防止进程分叉,可能无法在用户空间中可靠地完成此操作)
- 你可以(linux)尝试使用强制锁定挂载选项+flock,但我不确定你可以“窃取”锁
这意味着:
- 我们不喜欢内存映射
- 我们不喜欢干涉 FS 层以下的事情
根据您的用例,我看到其他可能性:
- 实现覆盖文件系统。这可以防止映射,并且您可以过滤调用 - 实际上应该并不复杂。
- 使用网络文件系统做类似的事情
- 最重要的是:通过服务器进程组织对文件的访问(本质上与“实现覆盖文件系统,但可移植”相同:-))