2017-02-21 6 views
4

Gibt es in Linux mit eine Möglichkeit, ein diff/Patch aus zwei Dateien zu erzeugen, die im Speicher abgelegt sind, unter Verwendung eines gemeinsamen Formats (zB: Unified Diff , wie mit der Befehlszeile diff Dienstprogramm)?Vergleichen/Vergleichen zweier Dateien nach Dateideskriptor (fd) anstelle des Dateinamens

Ich arbeite an einem System, wo ich zwei Textdateien im Speicher generieren, und kein externer Speicher verfügbar ist, oder gewünscht. Ich muss eine Zeile-für-Zeile Unterschied der zwei Dateien erstellen, und da sie mmap 'ed sind, haben sie keine Dateinamen, die mich davon abhalten, einfach system("diff file1.txt file2.txt") aufzurufen.

Ich habe Dateideskriptoren (fd s) zur Verfügung, und das ist mein einziger Einstiegspunkt zu den Daten. Gibt es eine Möglichkeit, ein Diff/Patch zu generieren, indem Sie die beiden geöffneten Dateien vergleichen? Wenn die Implementierung MIT/BSD lizenziert ist (dh: Nicht-GPL), umso besser.

Vielen Dank.

+0

Ich kann nicht den Weg finden, 'Diff' mit 2 Standardeingabeargumenten als Dateien aufzurufen, aber das wäre eine Möglichkeit, dies zu tun. –

+0

ein anderer Weg wäre, 'comm - -' zu verwenden und Zeilen alternativ zu übertragen, aber es funktioniert nur, wenn die Dateien synchronisiert sind. –

+0

Ich weiß, Sie sagten, "kein externer Speicher verfügbar oder gewünscht".Aber haben Sie darüber nachgedacht, ein einfaches In-Memory-Dateisystem wie Ramfs zu verwenden? Es kommt im Grunde alle Linux-Distributionen und AFAIK seine Hauptanwendung ist es, ein temporäres Dateisystem während des frühen Boot-up zu werfen. –

Antwort

2

In Anbetracht der Anforderungen wäre die beste Option, Ihren eigenen In-Memory diff -au zu implementieren. Sie könnten vielleicht die relevanten Teile von OpenBSD diff an Ihre Bedürfnisse anpassen.


Hier ist ein Überblick über ein, wie Sie den /usr/bin/diff Befehl über Leitungen verwenden, um die einheitliche diff zwischen zwei Strings im Speicher zu erhalten:

  1. drei Rohre erstellen: I1, I2 und O.

  2. Fork ein Kind Prozess.

  3. Im Kindprozesse:

    1. Verschieben der Lese Enden der Rohre I1 und I2 zu Deskriptoren 3 und 4, und das Schreibende des Rohres O auf Deskriptor 1

    2. Schließen Sie die anderen Enden dieser Pipes im untergeordneten Prozess. Öffnen Sie den Deskriptor 0 zum Lesen von/dev/null und den Deskriptor 2 zum Schreiben in/dev/null.

    3. Execute execl("/usr/bin/diff", "diff", "-au", "/proc/self/fd/3", "/proc/self/fd/4", NULL);

      Dies führt die diff binär in den untergeordneten Prozess. Es liest die Eingaben von den zwei Rohren I1 und I2 und gibt die Unterschiede zu Rohr O aus.

  4. Der Eltern-Prozess schließt die Lese Ende der I1 und I2 Rohre, und das Schreibende des Rohres O.

  5. Der Eltern-Prozess schreibt die Vergleichsdaten zu den Schreibenden I1 und I2 Rohre, und liest die Unterschiede von dem Leseende des Rohres O.

    Beachten Sie, dass der übergeordnete Prozess select() oder poll() oder eine ähnliche Methode (vorzugsweise mit nicht blockierenden Deskriptoren) verwenden muss, um Deadlock zu vermeiden. (Deadlock tritt auf, wenn Eltern und Kind gleichzeitig versuchen, zu lesen oder gleichzeitig zu schreiben.) In der Regel muss der Elternprozess die Blockierung um jeden Preis vermeiden, da dies wahrscheinlich zu einem Deadlock führt.

    Wenn die Eingabedaten vollständig geschrieben wurden, muss der übergeordnete Prozess das entsprechende Schreibende der Pipe schließen, sodass der untergeordnete Prozess das Ende der Eingabe erkennt. (Es sei denn, ein Fehler auftritt, muss die Schreib Enden geschlossen werden, bevor das Kind-Prozess sein Ende des O Rohr schließt.)

    Wenn die Eltern-Prozess feststellt, dass keine weiteren Daten in dem O Rohr verfügbar ist (read()0), entweder hat es bereits die Schreibenden der I1 und I2 Rohre geschlossen, oder es gab einen Fehler. Wenn kein Fehler vorliegt, ist die Datenübertragung abgeschlossen, und der untergeordnete Prozess kann abgefragt werden.

  6. Der Elternprozess erntet das Kind unter Verwendung z.B. waitpid(). Beachten Sie, dass, wenn es irgendwelche Unterschiede, diff kehrt mit Exit-Status 1.

Sie ein viertes Rohr verwenden können, den Standardfehler Strom aus dem untergeordneten Prozess zu empfangen; diff gibt normalerweise nichts an Standardfehler aus.

Sie können ein fünftes Rohr verwenden, schreiben Sie Ende O_CLOEXEC mit fcntl() in das Kind, um execl() Fehler zu erkennen. O_CLOEXEC Flag bedeutet, dass der Deskriptor geschlossen ist, wenn eine andere Binärdatei ausgeführt wird, sodass der Elternprozess den erfolgreichen Start des Befehls diff erkennen kann, indem er das Ende der Daten im Leseende erkennt (read() mit 0). Wenn die execl() fehlschlägt, kann das Kind z. Schreiben Sie den Wert errno (als Dezimalzahl oder als int) in diese Pipe, damit der übergeordnete Prozess die genaue Ursache für den Fehler lesen kann.

Insgesamt verwendet die vollständige Methode (die Standardfehler aufzeichnet und Exec-Fehler erkennt) 10 Deskriptoren. Dies sollte in einer normalen Anwendung kein Problem sein, kann aber wichtig sein. Betrachten Sie zum Beispiel einen Server mit Internetzugang, dessen Deskriptoren von eingehenden Verbindungen verwendet werden.

4

Unter Linux können Sie das/dev/fd/Pseudo-Dateisystem (eine symbolische Verbindung zu/proc/self/fd) verwenden. Verwenden Sie snprintf(), um den Pfad für beide Dateideskriptoren wie snprintf(path1, PATH_MAX, "/dev/fd/%d", fd1); dito für fd2 zu erstellen, und führen Sie diff auf ihnen.

Verwandte Themen