mit O_CREAT öffnen – wurde es geöffnet oder erstellt?

Lesezeit: 5 Minuten

Benutzeravatar von Sergey
Sergej

Ich habe 10 Prozesse, die versuchen, dieselbe Datei mehr oder weniger gleichzeitig mit dem Aufruf open(O_CREAT) zu öffnen und sie dann zu löschen. Gibt es einen robusten Weg, um herauszufinden, welcher Prozess die Datei tatsächlich erstellt hat und welcher Prozess die bereits erstellte Datei geöffnet hat, wenn ich beispielsweise genau zählen möchte, wie oft diese Datei in einem solchen Szenario geöffnet wurde?

Ich denke, ich könnte einen globalen Mutex auf den Dateiöffnungsvorgang setzen und eine Folge von open () -Aufrufen mit O_CREAT- und O_EXCL-Flags ausführen, aber das passt nicht zu meiner Definition von “robust”.

  • Verwenden (O_CREAT|O_EXCL) um einen Fehler zu erhalten, wenn die Datei bereits existiert. Wenn Sie den Fehler erhalten, überprüfen Sie die errno um zu sehen, ob es existiert, dann öffnen Sie es erneut, wie Sie es öffnen möchten, da Sie wissen, dass es bereits existiert.

    – jxh

    3. April 2013 um 21:29 Uhr


  • Und dann was tun? Aber was ist, wenn ein anderer Prozess es nach meiner Überprüfung, aber vor meinem “erneut öffnen, wie ich möchte” öffnet?

    – Sergej

    3. April 2013 um 21:30 Uhr


  • Dein Problem ist in deiner Beschreibung dann nicht vollständig spezifiziert. Aktualisieren Sie Ihre Frage mit dem tatsächlichen Problem, mit dem Sie konfrontiert sind. Zeigen Sie etwas Code und weisen Sie darauf hin, wo etwas nicht so abläuft, wie Sie es erwarten.

    – jxh

    3. April 2013 um 21:37 Uhr


  • Danke, den wichtigen Teil habe ich fett markiert.

    – Sergej

    3. April 2013 um 21:38 Uhr

  • Die klassische Redewendung, bevor es ein O_CREAT gab, war zu callen open() um eine vorhandene Datei zu öffnen und creat() um es zu schaffen, wenn die open() gescheitert. Das creat() Die Funktion soll so implementiert werden, als ob sie es wäre int creat(const char *path, mode_t mode) { return open(path, O_WRONLY|O_CREAT|O_TRUNC, mode); } Daher empfehle ich es nicht besonders, aber es gibt keine andere Möglichkeit zu wissen, ob Sie eine neue Datei erstellt oder eine vorhandene geöffnet haben (während Sie beides tun). Es gibt ein TOCTOU-Problem mit der Open/Creat- oder Open/Open-Technik.

    – Jonathan Leffler

    3. April 2013 um 21:38 Uhr


Benutzer-Avatar vonverdächtiger
Verdächtiger

Verwenden O_EXCL Flagge mit O_CREAT. Dies schlägt fehl, wenn die Datei existiert und errno auf gesetzt wird EEXIST. Wenn dies fehlschlägt, versuchen Sie es erneut ohne O_CREAT und ohne O_EXCL Modi.

z.B

int fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644);
if ((fd == -1) && (EEXIST == errno))
{
    /* open the existing file with write flag */
    fd = open(path, O_WRONLY);
}

  • können Sie bitte “versuchen, ohne O_CREAT erneut zu öffnen” klären. Wenn ich O_CREAT aus Ihrem Code weglasse, bleibt mir nur O_EXCL und entsprechend Dies “Im Allgemeinen ist das Verhalten von O_EXCL undefiniert, wenn es ohne O_CREAT verwendet wird.”

    – Sergej

    3. April 2013 um 21:36 Uhr


  • Wenn die O_EXCL-Erstellung fehlschlägt, weil EEXISTS, versuchen Sie es erneut ohne die O_EXCL und ohne die O_CREAT! Beachten Sie, dass wenn Sie O_CREAT haben, open() nimmt 3 Argumente; der dritte ist der Dateiberechtigungsmodus (0644 oder ähnlich). Sie brauchen auch einen von O_RDONLY, O_WRONLY oder O_RDWR (obwohl das Weglassen von ihnen O_RDONLY entspricht, aber das Erstellen einer Datei im schreibgeschützten Modus bescheiden sinnlos ist).

    – Jonathan Leffler

    3. April 2013 um 21:43 Uhr


  • Ich habe den Beitrag geändert, was hoffentlich Klarheit bringt.

    – Verdächtiger

    3. April 2013 um 21:44 Uhr

  • ok, aber während der Prozessor die Kommentare direkt nach der if-Prüfung ausführt und jemand anderes meine Datei öffnet, was mache ich dann?

    – Sergej

    3. April 2013 um 21:45 Uhr

  • @Sergey: Dann ist Ihre Problembeschreibung nicht vollständig, daher können wir sie nicht beantworten.

    – jxh

    3. April 2013 um 21:46 Uhr

Benutzeravatar von jxh
jxh

Basierend auf Ihren Kommentaren möchten Sie etwas in der Art dieser Funktion:

/* return the fd or negative on error (check errno);
   how is 1 if created, or 0 if opened */
int create_or_open (const char *path, int create_flags, int open_flags,
                    int *how) {
    int fd;
    create_flags |= (O_CREAT|O_EXCL);
    open_flags &= ~(O_CREAT|O_EXCL);
    for (;;) {
        *how = 1;
        fd = open(path, create_flags);
        if (fd >= 0) break;
        if (errno != EEXIST) break;
        *how = 0;
        fd = open(path, open_flags);
        if (fd >= 0) break;
        if (errno != ENOENT) break;
    }
    return fd;
}

Diese Lösung ist nicht kugelsicher. Es kann Fälle geben (symbolische Links vielleicht?), die zu einer Endlosschleife führen würden. Außerdem kann es in bestimmten Parallelitätsszenarien zu einer Live-Sperre kommen. Ich lasse die Lösung solcher Probleme als Übung. 🙂


In Ihrer bearbeiteten Frage stellen Sie:

Ich habe 10 Prozesse, die versuchen, dieselbe Datei mehr oder weniger gleichzeitig mit dem Aufruf open(O_CREAT) zu öffnen und sie dann zu löschen.

Eine hackige, aber kugelsicherere Lösung wäre, jedem Prozess eine andere Benutzer-ID zu geben. Dann verwenden Sie einfach die regulären open(path, O_CREAT|...) Anruf. Anschließend können Sie die Datei mit abfragen fstat() auf dem Dateideskriptor, und überprüfen Sie die st_uid Feld der stat Struktur. Wenn das Feld der Benutzer-ID des Prozesses entspricht, dann war es der Ersteller. Ansonsten war es ein Opener. Das funktioniert, da jeder Prozess die Datei nach dem Öffnen löscht.

  • Um die Live-Sperre zu bekämpfen, würde ich nach ein paar Iterationen auf eine Art global gemeinsam genutzten Mutex zurückgreifen. Aber dann wird die Lösung zu etwas, das ich zu vermeiden hoffte.

    – Sergej

    3. April 2013 um 22:36 Uhr

  • Ich akzeptiere diese Antwort, da dies dem, was ich erreichen wollte, am nächsten kommt.

    – Sergej

    4. April 2013 um 10:49 Uhr

  • Erwägen Sie in diesem Fall, aber auch im Allgemeinen, Ihre Programme mit zu kompilieren _FORTIFY_SOURCE auf 1 setzen, was nur zur Kompilierzeit einige Überprüfungen hinzufügt.

    Benutzer11509478

    20. Mai 2019 um 10:29 Uhr

1432270cookie-checkmit O_CREAT öffnen – wurde es geöffnet oder erstellt?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy