如何使用 inotify 可靠地维护对已编辑文件的监视?

如何使用 inotify 可靠地维护对已编辑文件的监视?

我想使用 来监视文件inotify,并在有人更改内容(IN_MODIFY或)时触发一些代码,但是当用户使用他们喜欢的工具编辑文件时,IN_CLOSE_WRITE我遇到了停止返回事件的问题。inotify该文件应该很简单(单行、无空格、最多 20 个字符)。我不想限制它们的使用,但我不确定如何处理不同的情况。

我正在使用inotify这些是当各种应用程序编辑文件时我收到的事件:

行动 inotify 事件
touch file IN_OPEN
echo "data" > file IN_MODIFYIN_OPENIN_ACCESS, 然后IN_CLOSE_NOWRITE
nano file(打开时) IN_OPEN
nano file(在^O IN_MODIFY, IN_CLOSE_WRITE, IN_OPEN,IN_ACCESS
vim file(打开时) IN_OPEN,IN_CLOSE_NOWRITE
vim file(在:w IN_MOVE_SELF, IN_ATTRIB, 然后事件停止来自该文件
gedit file(打开时) IN_OPEN,,IN_CLOSE_NOWRITEIN_ACCESS
gedit file(保存时) IN_OPEN, IN_CLOSE_WRITE, IN_ATTRIB,然后事件停止来自该文件
mv newfile file IN_ATTRIB,然后事件停止来自该文件

有一次,我以为我看到了gedit触发器,IN_DELETE_SELF然后又沉默了。

vim在用户使用and的情况下gedit,我会inotify在用户完成编辑后停止获取事件。我该如何处理这个问题?

我所看到的唯一共同点是事件IN_ATTRIB。我怀疑当我收到事件时IN_ATTRIB,我应该inotify_rm_watch()这样做,然后基于相同的路径wd重新创建一个新的。inotify_add_watch()但这是正确的方法吗?

另一种选择可能是监视父目录。受影响的文件名包含在 中inotify_event::name,因此我可以过滤感兴趣的文件,并触发任何IN_MODIFY与我感兴趣的文件匹配的IN_CLOSE_WRITE位置。name

答案1

正如 ikkachu 提到的,一些编辑器创建一个新文件,然后替换原始文件,更改 inode。这意味着原始监视描述符上的任何监视都将过期。

答案是查看父目录,并检查具有目标名称的任何文件的更改。像这样的东西:

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();
}

这些事件 ( IN_MODIFY|IN_CREATE|IN_CLOSE_WRITE) 捕获了我在上面尝试过的技术 ( touch, echo "" >, vim, nano, gedit)。我打赌我也可以捕获这些改变的符号链接。

答案2

或者您可以使用 fatrace,它速度快得多并且没有此类问题,例如:

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

相关内容