31

ファイルが存在するかどうかを判断する場合、tryステートメントを使用すると「競合状態」をどのように回避できますか?

非常に賛成の回答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)呼び出しにより、攻撃者はファイルに対して、まだ実行できなかったことをどのように実行できますか?

4

3 に答える 3

36

もちろん、競合状態は、プログラムとファイルを操作する他のコードの間です(競合状態には、常に少なくとも2つの並列プロセスまたはスレッドが必要です。詳細についてはこれを参照してください)。つまり、open()の代わりに使用するとexists()、次の2つの状況でのみ実際に役立つ可能性があります。

  1. バックグラウンドプロセスによって作成または削除されたファイルの存在を確認します(ただし、Webサーバー内で実行する場合、HTTP要求を処理するために並行して実行されるプロセスのコピーが多数あることを意味するため、Webアプリの競合他のプログラムがなくても状態は可能です)。
  2. 悪意のあるプログラムが実行されていて、ファイルが存在すると予想される瞬間にファイルを破棄してコードをクラッシュさせようとしている可能性があります。

exists()単一のチェックを実行するだけです。ファイルが存在する場合は、exists()返されてから1マイクロ秒後に削除される可能性がありますTrue。ファイルがない場合は、すぐに作成できます。

ただし、open()ファイルの存在をテストするだけでなく、ファイルを開きます(そして、これら2つのアクションをアトミックに実行するため、チェックとオープンの間に何も起こりません)。通常、ファイルは誰かが開いている間は削除できません。つまり、内部withでは完全に確信している可能性があります。ファイルは開いているので、実際に存在しています。これは内部でのみ当てはまり、ブロックが終了withした直後にファイルが削除される可能性がありますが、ファイルが内部に存在する必要があるコードを配置すると、コードが失敗しないことが保証されます。withwith

于 2013-01-29T04:08:56.297 に答える
10

使用例は次のとおりです。

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'

アクセス権を持ってファイルを開いている場合、OSはファイルが存在することを保証します。そうでない場合、エラーで失敗します。アクセスが排他的である場合、ファイルをめぐって競合している他のプロセスは、あなたによってブロックされるか、あなたをブロックします。

PythonのtryファイルI/O APIには通常リターンコードがないため、これはファイルを開く動作のエラーまたは成功を検出するための単なる方法です(代わりに例外が使用されます)。したがって、実際にあなたの質問に答えるにtryは、競合状態を回避するのではなく、それがopenです。これは基本的にC(Pythonのベース)でも同じですが、例外はありません。詳細については、これをお読みください。

tryブロック内のファイルへのアクセスに依存するコードを実行することをお勧めします。ファイルを閉じると、その存在は保証されなくなります。

呼び出すと、ファイルが存在する場合と存在しない場合がある瞬間のスナップショットが得られるだけであり、一度戻っos.path.existsたときにファイルの存在を知ることはできません。os.path.exists悪意のあるコードまたは予期しないロジックにより、予期しないときにファイルが削除または変更される可能性があります。頭を回して、車を運転する前に道路が空いていることを確認するのと似ています。頭を後ろに向けると、もう見ていない場所で何が起こっているのかを推測する以外に何もありません。ファイルを開いたままにしておくと、運転中に(善悪を問わず)不可能な、拡張された一貫性のある状態が保証されます。:)

try/openのスナップショットの性質のため、使用するのではなくファイルが存在しないことを確認するという提案はまだ不十分ですos.path.exists。残念ながら、すべての場合にファイルがディレクトリに作成されるのを防ぐ方法はわかりません。そのため、ファイルが存在しないかどうかではなく、存在するかどうかを確認するのが最善だと思います。

于 2013-01-29T02:11:20.517 に答える
0

あなたが求めているのは、次のような特定の競合状態だと思います。

  1. ファイルが開かれます
  2. コンテキストが切り替えられ、ファイルが削除されます
  3. コンテキストが元に戻され、「開いた」ファイルに対してファイル操作が試行されます

この場合の「保護」方法は、すべてのファイル処理コードをtryブロックに入れることです。いずれかの時点でファイルにアクセスできなくなったり破損したりすると、ファイル操作はcatchブロックを介して「正常に」失敗する可能性があります。

もちろん、最近のOSの場合、これはとにかく発生しません。ファイルが「削除」されると、ファイルで開いているすべてのハンドルが解決(解放)されるまで削除は行われません。

于 2013-01-29T02:23:02.923 に答える