web-dev-qa-db-fra.com

Créer un FIFO (pipe nommé) temporaire en Python?

Comment pouvez-vous créer un FIFO (canal nommé) temporaire en Python? Cela devrait fonctionner:

import tempfile

temp_file_name = mktemp()
os.mkfifo(temp_file_name)
open(temp_file_name, os.O_WRONLY)
# ... some process, somewhere, will read it ...

Cependant, j'hésite à cause du gros avertissement dans Python Docs 11.6 et de la suppression potentielle car elle est obsolète.

[~ # ~] modifier [~ # ~] : il est à noter que j'ai essayé tempfile.NamedTemporaryFile (et par extension tempfile.mkstemp), mais os.mkfifo jette:

OSError -17: le fichier existe déjà

lorsque vous l'exécutez sur les fichiers créés par mkstemp/NamedTemporaryFile.

26
Brian M. Hunt

os.mkfifo() échouera à l'exception OSError: [Errno 17] File exists si le fichier existe déjà, il n'y a donc pas de problème de sécurité ici. Le problème de sécurité avec l'utilisation de tempfile.mktemp() est la condition de concurrence où il est possible pour un attaquant de créer un fichier avec le même nom avant de l'ouvrir vous-même, mais puisque os.mkfifo() échoue si le fichier existe déjà ce n'est pas un problème.

Cependant, comme mktemp() est obsolète, vous ne devez pas l'utiliser. Vous pouvez utiliser tempfile.mkdtemp() à la place:

import os, tempfile

tmpdir = tempfile.mkdtemp()
filename = os.path.join(tmpdir, 'myfifo')
print filename
try:
    os.mkfifo(filename)
except OSError, e:
    print "Failed to create FIFO: %s" % e
else:
    fifo = open(filename, 'w')
    # write stuff to fifo
    print >> fifo, "hello"
    fifo.close()
    os.remove(filename)
    os.rmdir(tmpdir)

EDIT: Je dois préciser que, simplement parce que la vulnérabilité mktemp() est évitée par cela, il y a encore les autres problèmes de sécurité habituels qui doivent être pris en compte; par exemple. un attaquant pourrait créer le fifo (s'il avait les autorisations adéquates) avant que votre programme ne le fasse, ce qui pourrait provoquer le plantage de votre programme si les erreurs/exceptions ne sont pas correctement gérées.

25
mhawke

Vous pouvez trouver pratique d'utiliser le gestionnaire de contexte suivant, qui crée et supprime le fichier temporaire pour vous:

import os
import tempfile
from contextlib import contextmanager


@contextmanager
def temp_fifo():
    """Context Manager for creating named pipes with temporary names."""
    tmpdir = tempfile.mkdtemp()
    filename = os.path.join(tmpdir, 'fifo')  # Temporary filename
    os.mkfifo(filename)  # Create FIFO
    yield filename
    os.unlink(filename)  # Remove file
    os.rmdir(tmpdir)  # Remove directory

Vous pouvez l'utiliser, par exemple, comme ceci:

with temp_fifo() as fifo_file:
    # Pass the fifo_file filename e.g. to some other process to read from.
    # Write something to the pipe 
    with open(fifo_file, 'w') as f:
        f.write("Hello\n")
5
nirvana-msu

Que diriez-vous d'utiliser

d = mkdtemp()
t = os.path.join(d, 'fifo')
3
brendan

Si c'est pour une utilisation dans votre programme, et non avec des externes, jetez un œil au module Queue . Comme avantage supplémentaire, les files d'attente python sont thread-safe.

3
nilamo

En effet, tout ce que mkstemp fait est exécuté mktemp dans une boucle et continue de tenter de créer exclusivement jusqu'à ce qu'il réussisse (voir le code source stdlib ici ). Vous pouvez faire de même avec os.mkfifo:

import os, errno, tempfile

def mkftemp(*args, **kwargs):
    for attempt in xrange(1024):
        tpath = tempfile.mktemp(*args, **kwargs)

        try:
            os.mkfifo(tpath, 0600)
        except OSError as e:
            if e.errno == errno.EEXIST:
                # lets try again
                continue
            else:
                raise
        else:
           # NOTE: we only return the path because opening with
           # os.open here would block indefinitely since there 
           # isn't anyone on the other end of the fifo.
           return tpath
    else:
        raise IOError(errno.EEXIST, "No usable temporary file name found")
1
eestrada