Seite 1 von 2

tempfile.mkstemp: Wie auf die Datei zugreifen?

Verfasst: Mittwoch 14. Mai 2008, 13:17
von ChrisGTJ
Hallo Leute,

ich möchte eine Datei mit tempfile.mkstemp anlegen und sie benutzen, wie man eine Datei eben benutzt: Öffnen, schließen, schreiben und lesen. Die Frage ist nur: wie?

Die Doku sagt:
"mkstemp() returns a tuple containing an OS-level handle to an open file (as would be returned by os.open()) and the absolute pathname of that file, in that order."

Das heißt, ich habe den handle zu einer geöffneten Datei. Und nun?

- In welchem modus ist sie geöffnet?
- Wie mache ich aus einem handle (ein int!) eine file-Instanz, die ich benutzen kann?

Eigentlich möchte ich das Teil schließen und dann selbst wieder öffnen ("wb"), ich habe ja einen Namen und einen Pfad bekommen.

Gruß und Danke,

Christoph

Verfasst: Mittwoch 14. Mai 2008, 13:36
von ChrisGTJ
Bin ich deppert? Entschuldigt, daß dieses Posting im falschen Forum gelandet ist. Würde es mal bitte jemand verschieben? :oops:

Danke,

Christoph

Verfasst: Mittwoch 14. Mai 2008, 15:04
von Toni83

Code: Alles auswählen

import tempfile
tempfile.mkstemp(".mkstemp","temp","C:/")
Dies zum anlegen der Datei!

Code: Alles auswählen

f=file("C:/temp.mkstemp","r+")
f.read()
Und dies zum lesen der Daten. Danach kannst split oder strip anwenden,...
Für das Schreiben einfach statt "r+", "w+" schreiben und dann f.write()

Gruß,
Toni

Verfasst: Mittwoch 14. Mai 2008, 15:41
von lunar
Dein Code funktioniert nicht. Der Name der Datei lautet nämlich nicht ``temp.mkstemp``, da ``mkstemp`` noch zufällige Zeichen hinzufügt, um den Namen eindeutig zu machen! Wenn du die Datei erneut öffnen willst, dann solltest du die Namen nehmen, der von ``mkstemp`` zurückgegeben wird.

Allerdings kannst du so eigentlich auch gleich auf ``mkstemp`` verzichten, da du eine Race Condition erzeugst. ;)

Der Prozess kann zwischen ``mkstemp`` und ``file`` nämlich schlafen gelegt werden. In der Zwischenzeit kann ein anderer Prozess diese Datei löschen. Dann erzeugt der ``file``-Aufruf nämlich eine neue Datei! Das kann man dann wieder für Symlink-Attacken nutzen.

Entweder nutzt man ``os.fdopen``, um den von ``mkstemp`` zurückgegeben Dateideskriptor in ein Dateiobjekt zu verwandeln, oder – noch besser – man nimmt gleich ``tempfile.TemporaryFile`` oder tempfile.NamedTemporaryFile``.

Verfasst: Mittwoch 14. Mai 2008, 16:23
von ChrisGTJ
Hallo,

danke erstmal für's Verschieben und für die Antworten.

Mein Ziel ist es eigentlich nur, eine Datei zu haben, die ich benutzen kann und die ich dann einfach wieder lösche, wenn ich sie nicht mehr brauche. Ich könnte natürlich einfach eine beliebige Datei an dem Ort, an dem ich gerade bin, öffnen, aber ich finde es ungeschickt, irgendwo im Filesystem eine Datei hinzulegen (vor allem, wenn ich an dem Ort vielleicht gar nicht schreiben darf).

In die Datei werden einige Daten geschrieben, die an anderer Stelle benutzt werden sollen, daher die Geschichte mit open und close. Ich könnte die Datei geöffnet lassen, müßte dann aber mit seek und so rumeiern.

Vor allem:
In der Doku steht, die Datei ist geöffnet nach mkstemp() und ich bekomme einen Handle darauf zurück. Wie mache ich aus dem handle ein Fileobjekt, das ich nutzen kann?

Die Symlinkattacke vernachlässige ich jetzt mal, laut Wikipedia (das macht ja schlau ;)) wird sie verhindert, indem eben mkstemp() benutzt wird.

Gruß,

Christoph

Verfasst: Mittwoch 14. Mai 2008, 16:27
von ChrisGTJ
....ah halt, wer liest, ist klar im Vorteil...

os.fdopen() öffnet also eine Datei, auf die der Descriptor zeigt.

Aber:
Die Datei ist laut Doku schon geöffnet. Habe ich was falsch verstanden?

Verfasst: Mittwoch 14. Mai 2008, 18:16
von lunar
``os.fdopen`` erzeugt aus einem Dateideskriptor ein Dateiobjekt, mehr nicht.

Die Symlink-Attacke wird durch mkstemp verhindert. Allerdings nur, wenn du den zurückgebenen Dateideskriptor zum Öffnen nutzt. Öffnest du die Datei erneut – wie von Toni83 vorgeschlagen – ist folgender Ablauf denkbar:

1. ``mkstemp`` öffnet die Datei
2. Der Kernel legt den Prozess schlafen
3. Ein anderer Prozess löscht die temporäre Datei und erzeugt stattdessen einen Symlink
4. Der Kernel weckt den Prozess wieder auf
5. ``file`` öffnet nun den Symlink und **nicht** mehr die in Schritt 1 per ``mkstemp`` geöffnete Datei!

Ich frage dich aber nochmal: Warum nutzt du nicht ``tempfile.TemporaryFile`` oder ``tempfile.NamedTemporaryFile``?

Diese Klassen übernehmen nicht nur das Öffnen der Dateideskriptoren, sondern sorgen beispielsweise auch dafür, dass die Datei beim Schließen automatisch gelöscht wird.

Verfasst: Freitag 16. Mai 2008, 16:53
von ChrisGTJ
Hallo Lunar,

wie ich schon sagte: Ich will nicht mit seek() und so herumdoktoren.

Bei genauerem Lesen der Doku zu tempfile.TemporaryFile fällt mir auf, daß ich sie einfach geöffnet lassen könnte, das Fileobjekt weiterreichen könnte und sie am Ende wieder schließen könnte, damit wäre alles erledigt. Damit wäre auch das Problem der symlink-Attacke erledigt.

Also doch einmal seek(...) um wieder vom Anfang lesen zu können, oder?

Gruß,

Christoph

Verfasst: Freitag 16. Mai 2008, 17:26
von lunar
ChrisGTJ hat geschrieben:Bei genauerem Lesen der Doku zu tempfile.TemporaryFile fällt mir auf, daß ich sie einfach geöffnet lassen könnte, das Fileobjekt weiterreichen könnte und sie am Ende wieder schließen könnte, damit wäre alles erledigt. Damit wäre auch das Problem der symlink-Attacke erledigt.
Hältst du es tatsächlich für eine gute Idee, *eine* Datei für *mehrere* Aufgaben zu verwenden?

Ich würde ja einfach mehrere temporäre Dateien erzeugen, je eine für eine bestimmte Aufgabe.
Also doch einmal seek(...) um wieder vom Anfang lesen zu können, oder?
Wenn du so willst, ja.

Verfasst: Freitag 16. Mai 2008, 20:33
von BlackJack
@Lunar: Wo steht was von mehreren Aufgaben? Ich lese da nur das etwas in die Datei geschrieben werden soll und an anderer Stelle im Programm wieder ausgelesen werden soll.

Verfasst: Freitag 16. Mai 2008, 20:38
von lunar
Explizit steht das nirgendwo, da hast du schon recht. Ich schließe das allein aus folgendem:
In die Datei werden einige Daten geschrieben, die an anderer Stelle benutzt werden sollen, daher die Geschichte mit open und close. Ich könnte die Datei geöffnet lassen, müßte dann aber mit seek und so rumeiern.
Da er an dieser Stelle von ``seek`` spricht, liegt es ja offenbar in seinem Interesse, bereits geschriebene Daten wieder zu überschreiben. Das allerdings ergibt für mich wiederum nur dann Sinn, wenn das unterschiedliche Daten sind. In diesem Fall wären mehrere temporäre Dateien imho die bessere Lösung.

Verfasst: Freitag 16. Mai 2008, 21:02
von BlackJack
Das lese ich da überhaupt nicht, im Gegenteil. Es sollen Daten *gelesen* werden. Und wenn nicht `open()` und `close()` verwendet werden, sondern die geöffnete Datei herum gereicht wird, *dann* braucht man `seek()`.

Verfasst: Freitag 16. Mai 2008, 21:05
von lunar
Stimmt auch wieder ;)

Verfasst: Sonntag 18. Mai 2008, 23:18
von ChrisGTJ
Wozu die Sache gebraucht wird:

Aus einem Gerät wird eine zip-Datei gelesen. Dieses Archiv enthält Dateien, von denen eine benötigt wird, aber auch (meist) nur einmal (da sind Infos zum Gerät drin, die sich unter Umständen ändern können, je nach Applikation, die auf dem Gerät läuft).

Ich muß das Zip also auspacken und die Infos lesen. Dazu verwende ich eine Bibliothek, die filebasiert arbeitet -> Ergo brauche ich ein temporäres File.

Danke für Eure Unterstützung :).

Gruß,

Christoph

Verfasst: Montag 19. Mai 2008, 07:42
von jens
IMHO kannst du auch alles im Speicher auspacken und brauchst nicht zwingend eine Datei. Kommt darauf an, wie groß die Daten sind...

Verfasst: Montag 19. Mai 2008, 10:01
von ChrisGTJ
jens hat geschrieben:IMHO kannst du auch alles im Speicher auspacken und brauchst nicht zwingend eine Datei. Kommt darauf an, wie groß die Daten sind...
Kann ich, nur brauche ich eine Datei für die nachfolgende Bearbeitung, da es eben eine dateibasierte Schnittstelle ist.

Christoph

Verfasst: Montag 19. Mai 2008, 13:28
von Leonidas
Wenn die Bibliothek file-like-Objects verwendet, dann kannst du StringIO verwenden.

Verfasst: Montag 19. Mai 2008, 15:14
von ChrisGTJ
Leonidas hat geschrieben:Wenn die Bibliothek file-like-Objects verwendet, dann kannst du StringIO verwenden.
Hm, aber die Bibothek möchte doch eine Datei öffnen, ich benutze ctypes.create_string_buffer().

os.fdopen() scheint der richtige Weg zu sein, aber wie ist das damit, daß die Datei schon geöffnet ist? Im Prinzip öffne ich doch eine schon geöffnete Datei... Ich kapier es nicht.


Gruß,

Christoph

Verfasst: Montag 19. Mai 2008, 15:26
von lunar
ChrisGTJ hat geschrieben:
Leonidas hat geschrieben:Wenn die Bibliothek file-like-Objects verwendet, dann kannst du StringIO verwenden.
Hm, aber die Bibothek möchte doch eine Datei öffnen, ich benutze ctypes.create_string_buffer().
Welche Bibliothek ist das denn?
os.fdopen() scheint der richtige Weg zu sein, aber wie ist das damit, daß die Datei schon geöffnet ist? Im Prinzip öffne ich doch eine schon geöffnete Datei... Ich kapier es nicht.
Du öffnest die Datei nicht nochmal, du erzeugst nur ein Dateiobjekt aus dem Dateideskriptor. Das habe ich dir aber schon mal gesagt...

Verfasst: Montag 19. Mai 2008, 16:02
von ChrisGTJ
lunar hat geschrieben:
os.fdopen() scheint der richtige Weg zu sein, aber wie ist das damit, daß die Datei schon geöffnet ist? Im Prinzip öffne ich doch eine schon geöffnete Datei... Ich kapier es nicht.
Du öffnest die Datei nicht nochmal, du erzeugst nur ein Dateiobjekt aus dem Dateideskriptor. Das habe ich dir aber schon mal gesagt...
Ups... :oops: , Du hast recht. aber mal ehrlich: fdOPEN suggeriert doch ein öffnen, oder?

ctypes:

http://docs.python.org/lib/module-ctypes.html

14.14 ctypes -- A foreign function library for Python.
New in version 2.5.

ctypes is a foreign function library for Python. It provides C compatible data types, and allows to call functions in dlls/shared libraries. It can be used to wrap these libraries in pure Python.

Gruß,

Christoph