2013-01-29 5 views
20

Wenn Sie feststellen, ob eine Datei existiert oder nicht, wie vermeidet die Verwendung der try-Anweisung eine "Race Condition"?Wie vermeidet die Verwendung der try-Anweisung eine Wettlaufsituation?

Ich frage, weil ein hoch upvoted answer (Update: es wurde gelöscht) scheint implizieren, dass mit os.path.exists() schafft eine Möglichkeit, die sonst nicht existieren würde.

Das Beispiel ist:

try: 
    with open(filename): pass 
except IOError: 
    print 'Oh dear.' 

Aber ich bin nicht zu verstehen, wie das eine Race-Bedingung vermeidet im Vergleich zu:

if not os.path.exists(filename): 
    print 'Oh dear.' 

Wie os.path.exists(filename) ermöglicht es dem Angreifer nicht Aufruf etwas mit dem zu tun, Datei, die sie nicht schon tun konnten?

Antwort

24

Die Race-Bedingung ist natürlich, zwischen Ihrem Programm und einem anderen Code, der auf Datei arbeitet (Race Condition erfordert immer mindestens zwei parallele Prozesse oder Threads, siehe this für Details). Das bedeutet open() statt exists() mit wirklich nur in zwei Situationen helfen kann:

  1. Sie überprüfen die Existenz einer Datei, die durch einen Hintergrundprozess erstellt oder gelöscht wird (jedoch, wenn Sie in einem Web-Server, die oft Dies bedeutet, dass es viele Kopien Ihres Prozesses gibt, die parallel laufen, um HTTP-Anfragen zu verarbeiten, so dass für Web-Apps eine Race-Bedingung möglich ist, selbst wenn es keine anderen Programme gibt).
  2. Es kann sein, dass ein bösartiges Programm ausgeführt wird, das versucht, Ihren Code zum Absturz zu bringen, indem die Datei in dem Moment zerstört wird, in dem Sie erwarten, dass es existiert.

exists() führt nur eine einzige Überprüfung durch. Wenn die Datei existiert, kann sie eine Mikrosekunde nach exists()True gelöscht werden. Wenn die Datei nicht vorhanden ist, kann sie sofort erstellt werden.

Allerdings testet open() nicht nur für die Existenz von Dateien, sondern öffnet auch die Datei (und führt diese beiden Aktionen atomar, so kann nichts zwischen der Prüfung und der Eröffnung passieren). Normalerweise können Dateien nicht gelöscht werden, wenn sie von jemandem geöffnet werden. Das bedeutet, dass Sie innerhalb von with völlig sicher sein können: Die Datei existiert jetzt wirklich, da sie geöffnet ist. Obwohl es nur innerhalb von with wahr ist, und die Datei immer noch sofort nach with Block-Exits gelöscht werden kann, stellt das Setzen von Code, der die Datei innerhalb von with benötigt, sicher, dass der Code nicht fehlschlägt.

9

Hier ist ein Beispiel für die Nutzung:

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' 

Wenn Sie die Datei mit einem beliebigen Zugriff auf alle öffnen, dann das Betriebssystem wird sichergestellt, dass die Datei vorhanden ist, sonst wird es mit einem Fehler fehl. Wenn der Zugriff exklusiv ist, wird jeder andere konkurrierende Prozess für die Datei entweder von Ihnen blockiert oder blockiert.

Die try ist nur eine Möglichkeit, den Fehler oder Erfolg des Öffnens der Datei zu erkennen, da Datei-I/O-APIs in Python normalerweise keine Rückgabecodes haben (Ausnahmen werden stattdessen verwendet). Um Ihre Frage wirklich zu beantworten, ist es nicht die try, die die Race Condition vermeidet, es ist die open. Es ist im Grunde dasselbe in C (auf dem Python basiert), aber ohne Ausnahmen. Lesen Sie this für weitere Informationen.

Beachten Sie, dass Sie wahrscheinlich Code ausführen möchten, der vom Zugriff auf die Datei im try-Block abhängt. Sobald Sie die Datei schließen, ist ihre Existenz nicht mehr garantiert.

Aufruf os.path.exists gibt nur einen Snapshot zu einem Zeitpunkt, wenn die Datei möglicherweise nicht vorhanden ist, und Sie haben keine Kenntnis von der Existenz der Datei, sobald os.path.exists zurückgibt. Falscher Code oder unerwartete Logik kann die Datei löschen oder ändern, wenn Sie sie nicht erwarten. Es ist vergleichbar damit, den Kopf zu drehen, um zu prüfen, ob eine Straße frei ist, bevor man hineinfährt. Sobald Sie Ihren Kopf zurückdrehen, haben Sie nichts als eine Vermutung darüber, was dort vor sich geht, wo Sie nicht länger hinsehen. Das Offenhalten der Datei garantiert einen erweiterten konsistenten Zustand, was beim Fahren nicht möglich ist (gut oder schlecht). :)

Ihr Vorschlag zu überprüfen, dass eine Datei nicht existiert, anstatt try/open zu verwenden, ist immer noch nicht ausreichend wegen der Snapshot-Natur von os.path.exists. Leider kann ich nicht verhindern, dass Dateien in jedem Fall in einem Verzeichnis erstellt werden. Daher denke ich, dass es besser ist, nach der positiven Existenz einer Datei zu suchen, als nach ihrer Abwesenheit.

0

denke ich, was Sie fragen die besondere Race-Bedingung ist, wo:

  1. Datei geöffnet wird
  2. Kontext umgeschaltet wird und die Datei gelöscht wird
  3. Kontext zurückgeschaltet und Dateioperationen versucht werden auf dem „geöffnet“ ist in diesem Fall, indem sie die ganze Datei Behandlungscode in einem try Block, wenn an irgendeiner Stelle der Datei

die Art und Weisen Sie „geschützt“ Datei wird unzugänglich/beschädigt Ihre Dateioperationen können über den Block catch "ordnungsgemäß" fehlschlagen.

Hinweis natürlich modernen OS dies ohnehin nicht passieren kann, wenn eine Datei wird der Lösch „gelöscht“ wird nicht stattfinden, bis alle offenen Handles auf die Datei aufgelöst werden (freigegeben)

+1

@ downvoter - Argumentation? Gibt es ein Problem? – Mike