【问题标题】:Atomic `ln -sf` in python (symlink overwriting exsting file)python中的原子`ln -sf`(符号链接覆盖现有文件)
【发布时间】:2019-04-20 14:21:41
【问题描述】:

我想创建一个符号链接,如果需要,覆盖现有文件或符号链接。

我发现os.path.exists 只为未损坏的符号链接返回True,所以我猜任何测试都必须包含os.path.lexists

在 python 中实现ln -sf 的最原子方式是什么? (即,防止文件在删除和符号链接创建之间被另一个进程创建)


区分:This question 没有指定原子需求

【问题讨论】:

  • 如果你准备ln -s file tmplink,那么mv tmplink link是原子的。
  • @Amadan 感谢您的建议。我仍然看到一个安全漏洞,但我希望我在my answer 中尽可能地做到这一点。
  • FWIW,ln -sf 本身实际上并不是原子的。 GNU Coreutils internally implements @Amadan 提出的解决方案(以及当前接受的答案实现); FreeBSD 和 Busybox 只需在链接之前删除目标文件。所以“par”实际上很容易清除。

标签: python atomic symlink


【解决方案1】:

此代码试图最小化竞争条件的可能性:

import os
import tempfile

def symlink_force(target, link_name):
    '''
    Create a symbolic link link_name pointing to target.
    Overwrites link_name if it exists.
    '''

    # os.replace() may fail if files are on different filesystems
    link_dir = os.path.dirname(link_name)

    while True:
        temp_link_name = tempfile.mktemp(dir=link_dir)
        try:
            os.symlink(target, temp_link_name)
            break
        except FileExistsError:
            pass
    try:
        os.replace(temp_link_name, link_name)
    except OSError:  # e.g. permission denied
        os.remove(temp_link_name)
        raise

注意:

  1. 如果功能被中断(例如计算机崩溃),可能会存在一个额外的随机链接到目标。

  2. 一个不太可能的竞争条件仍然存在:在随机命名的 temp_link_name 创建的符号链接可能会在替换 link_name 之前被另一个进程修改。

我提出了python issue 来强调os.symlink() 要求目标不存在的问题。

归功于Robert Seimer's input

【讨论】:

  • 我针对上述安全漏洞提出了issue
  • 您可以通过将mktemp+symlink 调用放入循环中来处理(不太可能的)比赛,重试直到赢得比赛。显然,您需要检查symlink 是否因为EEXIST 而失败,而不是因为其他一些永远不会让它成功的原因。为了提高效率,您可能希望将嵌入式 dirname 调用提升到循环上方。
  • @ottomeister 谢谢,您的建议有帮助。但是如何防止 mktemp-named 文件在创建后和替换符号链接之前被更改?
  • 你无法阻止。任何对该目录具有写访问权限的行为不端的进程都可能破坏整个安排。某些东西可能会在重命名之后替换或删除新的符号链接,因为某些东西可能会在重命名之前替换或删除它。但是,如果您担心并发 mktemps 不小心在同一个名称上发生冲突,那么您可以 mkdtemp 一个目录,在该目录中创建新的符号链接,然后 rename 符号链接覆盖原来的符号链接(然后 @987654337 @临时目录)。文件系统中的rename 是原子的。
  • 我有点吃惊,这不是 OOTB。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-12
  • 2011-07-12
  • 2020-07-25
相关资源
最近更新 更多