Wie kann man mit inotify bearbeitete Dateien zuverlässig überwachen?

Wie kann man mit inotify bearbeitete Dateien zuverlässig überwachen?

Ich möchte eine Datei mit überwachen inotifyund Code auslösen, wenn jemand den Inhalt ändert ( IN_MODIFYoder IN_CLOSE_WRITE), aber ich stoße auf Probleme, bei denen inotifykeine Ereignisse mehr zurückgegeben werden, wenn Benutzer die Datei mit ihrem bevorzugten Tool bearbeiten. Die Datei soll einfach sein (eine Zeile, keine Leerzeichen, maximal 20 Zeichen). Ich würde ihre Verwendung lieber nicht einschränken, bin mir aber nicht sicher, wie ich mit verschiedenen Situationen umgehen soll.

Ich verwende inotifyund dies sind die Ereignisse, die ich erhalte, wenn verschiedene Anwendungen die Datei bearbeiten:

Aktion inotify-Ereignisse
touch file IN_OPEN
echo "data" > file IN_MODIFY, IN_OPEN, IN_ACCESS, DannIN_CLOSE_NOWRITE
nano file(beim Öffnen) IN_OPEN
nano file(An ^O) IN_MODIFY, IN_CLOSE_WRITE, IN_OPEN,IN_ACCESS
vim file(beim Öffnen) IN_OPEN,IN_CLOSE_NOWRITE
vim file(An :w) IN_MOVE_SELF, IN_ATTRIB, dann kommen keine Ereignisse mehr aus dieser Datei
gedit file(beim Öffnen) IN_OPEN, IN_CLOSE_NOWRITE,IN_ACCESS
gedit file(beim Speichern) IN_OPEN, IN_CLOSE_WRITE, IN_ATTRIB, dann kommen keine Ereignisse mehr aus dieser Datei
mv newfile file IN_ATTRIB, dann kommen keine Ereignisse mehr aus dieser Datei

An einem Punkt dachte ich, ich hätte geditden Auslöser und auch den Auslöser gesehen IN_DELETE_SELF, bevor es still wurde.

Wenn ein Benutzer vimund verwendet gedit, erhalte ich keine inotifyEreignisse mehr, nachdem der Benutzer die Änderungen abgeschlossen hat. Wie soll ich damit umgehen?

Das einzige Gemeinsame, das ich sehe, ist das IN_ATTRIBEreignis. Ich vermute, dass ich, wenn ich das Ereignis erhalte , dies IN_ATTRIBtun und dann basierend auf demselben Pfad ein neues erstellen sollte . Aber ist das der richtige Ansatz?inotify_rm_watch()wdinotify_add_watch()

Eine andere Möglichkeit wäre, das übergeordnete Verzeichnis zu überwachen. Der betroffene Dateiname ist in enthalten , sodass ich nach der gewünschten Datei filtern und alle oder inotify_event::nameauslösen kann, bei denen die mit meiner gewünschten Datei übereinstimmt.IN_MODIFYIN_CLOSE_WRITEname

Antwort1

Wie ikkachu erwähnt, erstellen einige Editoren eine neue Datei und ersetzen dann die ursprüngliche, wobei der Inode geändert wird. Das bedeutet, dass alle Überwachungen des ursprünglichen Überwachungsdeskriptors ablaufen.

Die Antwort besteht darin, sich das übergeordnete Verzeichnis anzusehen und nach Änderungen an allen Dateien mit dem Zielnamen zu suchen. Etwa so:

namespace fs = std::filesystem;
fs::path path = "./file1";
assert( !path.is_directory() );

int fd = inotify_init();

int wd = inotify_add_watch(
    fd, 
    path.parent_path().c_str(),
    IN_MODIFY | IN_CREATE | IN_CLOSE_WRITE
);  

...

inotify_event event;
read(fd, &event, BUF_SIZE);

if (wd == event->wd && path.filename() == event->name) {
    emit_file_changed();
}

Diese Ereignisse ( IN_MODIFY|IN_CREATE|IN_CLOSE_WRITE) erfassen die Techniken, die ich oben ausprobiert habe ( touch, echo "" >, vim, nano, gedit). Ich wette, ich könnte damit auch geänderte symbolische Links erfassen.

Antwort2

Oder Sie könnten Fatrace verwenden, das viel schneller ist und keine derartigen Probleme hat, z. B. etwas in dieser Art:

fatrace --timestamp --filter='WD<>+'

verwandte Informationen