在确定文件是否存在时,如何使用try语句避免“竞争条件”?
我问,因为一个高度赞成的answer(更新:它被删除)似乎意味着使用os.path.exists()
创造了一个不存在的机会。
给出的例子是:
try:
with open(filename): pass
except IOError:
print 'Oh dear.'
但我不理解如何避免竞争条件:
if not os.path.exists(filename):
print 'Oh dear.'
如何调用os.path.exists(filename)
允许攻击者对他们无法执行的文件执行某些操作?
答案 0 :(得分:29)
竞争条件当然是在您的程序和其他一些在文件上运行的代码之间(竞争条件总是需要至少两个并行进程或线程,有关详细信息,请参阅this)。这意味着使用open()
代替exists()
可能只对两种情况有帮助:
exists()
只执行一次检查。如果文件存在,则可能会在exists()
返回True
后的一微秒内删除。如果文件不存在,可以立即创建。
然而,open()
不仅测试文件是否存在,而且还打开文件(并以原子方式执行这两个操作,因此在检查和开始之间不会发生任何事情)。通常,文件在某人打开时无法删除。这意味着在with
内你可能完全确定:文件现在确实存在,因为它是开放的。虽然它只在with
内部存在,并且文件仍然可以在with
块退出后立即删除,但将需要文件的代码存在于with
内可以保证代码不会失败。
答案 1 :(得分:9)
以下是一个使用示例:
try:
with open('filename') as f:
do_stuff_that_depends_on_the_existence_of_the_file(f)
except IOError as e:
print 'Trouble opening file'
如果您打开任何访问权限的文件,那么操作系统将保证该文件存在,否则它将失败并显示错误。如果访问权限是独占的,那么任何其他争用该文件的进程都将被您阻止或阻止您。
try
只是检测打开文件的错误或成功的一种方法,因为Python中的文件I / O API通常没有返回代码(而是使用异常)。所以要真正回答你的问题,不是try
避免竞争条件,而是open
。它在C(Python所基于的)中基本相同,但没有例外。请阅读this以获取更多信息。
请注意,您可能希望执行依赖于对try块内文件的访问的代码。关闭文件后,不再保证其存在。
调用os.path.exists
仅在文件可能存在或不存在的时刻给出快照,并且在os.path.exists
返回后您不知道文件是否存在。恶意代码或意外逻辑可能会在您不期望时删除或更改文件。它类似于在开车前检查道路是否清晰。一旦你转过头来,你只能猜测你不再寻找的地方。保持文件打开可确保延长的一致状态,这在开车时是不可能的(无论好坏)。 :)
由于try/open
的快照特性,您建议检查文件是否存在而不是使用os.path.exists
仍然不够。不幸的是,我知道在所有情况下都无法防止在目录中创建文件,因此我认为最好检查文件是否存在,而不是缺少文件。
答案 2 :(得分:0)
我认为你所问的是特定的竞争条件:
在这种情况下,您受“保护”的方式是将所有文件处理代码放在try
块中,如果在任何时候文件变得不可访问/损坏,您的文件操作将能够失败“优雅地“通过catch
块。
当然注意现代操作系统无论如何都不会发生这种情况,当文件被“删除”时,只有解析(释放)文件上的所有打开句柄才会发生删除