-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[功能增强]:增加Linux平台目录监控支持
fanotify
,提升监控能力
- 在`.github/workflows/build.yml`中,扩展了构建类型选项,新增了"Debug"、"Release"、"MinSizeRel"三种构建类型,以适应不同的构建需求。 - 在`MonitorDir/CMakeLists.txt`中,通过预处理器指令检查`fanotify_init`符号是否存在,根据检查结果选择使用`monitordir_linux_fanotify.cc`或`monitordir_linux_inotify.cc`作为Linux平台的目录监控实现,增强了目录监控的灵活性和兼容性。 - 在`MonitorDir/main.cc`中,增加了使用`std::filesystem`获取并打印当前路径的功能,并修改了`MonitorDir`类的构造函数,使其可以接受一个路径参数,提高了程序的可用性和灵活性。 - 新增`MonitorDir/monitordir_linux_fanotify.cc`文件,实现了基于`fanotify`的目录监控功能,增强了Linux平台下的目录监控能力。 - 将原有的`MonitorDir/monitordir_linux.cc`重命名为`MonitorDir/monitordir_linux_inotify.cc`,并进行了相应的代码调整,以支持`inotify`监控机制。 - 在`README.md`中,更新了`MonitorDir`的描述,增加了对`fanotify`的支持说明,并解释了`fanotify`在全局监控方面相较于`inotify`的优势。 - 在`scripts/windows/setVsDev.ps1`中,增加了对`arm64`架构的支持,并调整了`Enter-VsDevShell`命令的参数,以适应不同的架构需求。 - 在`vcpkg.json`中,更新了`builtin-baseline`的值,以确保依赖项的一致性。
- Loading branch information
Showing
8 changed files
with
320 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,267 @@ | ||
#include "monitordir.hpp" | ||
|
||
#include <cassert> | ||
#include <cstring> | ||
#include <fcntl.h> | ||
#include <iostream> | ||
#include <limits.h> | ||
#include <string> | ||
#include <sys/fanotify.h> | ||
#include <sys/stat.h> | ||
#include <thread> | ||
#include <unistd.h> | ||
|
||
#define BUF_SIZE 256 | ||
|
||
std::string getPathFromFd(int fd) | ||
{ | ||
char path[PATH_MAX]; | ||
char procfd_path[PATH_MAX]; | ||
snprintf(procfd_path, sizeof(procfd_path), "/proc/self/fd/%d", fd); | ||
ssize_t len = readlink(procfd_path, path, sizeof(path) - 1); | ||
if (len >= 0) { | ||
path[len] = '\0'; // 确保字符串以空字符结尾 | ||
return std::string(path); | ||
} | ||
return "Unknown"; // 读取失败时的处理 | ||
} | ||
|
||
class MonitorDir::MonitorDirPrivate | ||
{ | ||
public: | ||
explicit MonitorDirPrivate(MonitorDir *q) | ||
: q_ptr(q) | ||
{} | ||
|
||
~MonitorDirPrivate() = default; | ||
|
||
auto createFd() -> bool | ||
{ | ||
mountFd = open(dir.c_str(), O_DIRECTORY | O_RDONLY); | ||
if (mountFd == -1) { | ||
std::cerr << "mountFd open failed" << std::endl; | ||
return false; | ||
} | ||
std::cout << "mountFd: " << mountFd << std::endl; | ||
|
||
unsigned int flags = FAN_CLOEXEC | FAN_UNLIMITED_QUEUE | FAN_UNLIMITED_MARKS | ||
| FAN_ENABLE_AUDIT | FAN_REPORT_FID | FAN_REPORT_DFID_NAME | ||
| FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME; | ||
unsigned int event_f_flags = O_RDONLY | O_LARGEFILE | O_CLOEXEC; | ||
// flags = FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME; | ||
// event_f_flags = 0; | ||
fanotifyFd = fanotify_init(flags, event_f_flags); | ||
if (fanotifyFd == -1) { | ||
std::cerr << "fanotify_init failed" << std::endl; | ||
return false; | ||
} | ||
std::cout << "fanotifyFd: " << fanotifyFd << std::endl; | ||
return true; | ||
} | ||
|
||
void closeFd() | ||
{ | ||
if (mountFd != -1) { | ||
close(mountFd); | ||
mountFd = -1; | ||
} | ||
if (fanotifyFd != -1) { | ||
close(fanotifyFd); | ||
fanotifyFd = -1; | ||
} | ||
} | ||
|
||
auto addWatch() -> bool | ||
{ | ||
// FAN_MARK_FILESYSTEM 全局监控 | ||
unsigned int flags = FAN_MARK_ADD | FAN_MARK_FILESYSTEM; | ||
unsigned int mask = FAN_ACCESS | FAN_MODIFY | FAN_CLOSE_WRITE | FAN_MOVED_FROM | ||
| FAN_MOVED_TO | FAN_CREATE | FAN_DELETE | FAN_DELETE_SELF | ||
| FAN_MOVE_SELF | FAN_OPEN_EXEC | FAN_EVENT_ON_CHILD | FAN_ONDIR; | ||
// FAN_CLOSE_NOWRITE | FAN_OPEN; | ||
// flags = FAN_MARK_ADD | FAN_MARK_ONLYDIR; | ||
// mask = FAN_CREATE | FAN_ONDIR; | ||
if (fanotify_mark(fanotifyFd, flags, mask, AT_FDCWD, dir.c_str()) == -1) { | ||
std::cerr << "fanotify_mark failed" << std::endl; | ||
return false; | ||
} | ||
std::cout << "add watch: " << dir << std::endl; | ||
|
||
return true; | ||
} | ||
|
||
void removeWatch() | ||
{ | ||
// Fanotify 不需要显式移除监控,关闭文件描述符时会自动清理 | ||
} | ||
|
||
void monitor() | ||
{ | ||
char buf[BUF_SIZE]; | ||
auto len = read(fanotifyFd, buf, sizeof(buf)); | ||
if (!isRunning.load()) { | ||
return; | ||
} | ||
if (len <= 0) { | ||
std::cerr << "read failed" << std::endl; | ||
return; | ||
} | ||
|
||
std::string fileEvent; | ||
fanotify_event_metadata *event = nullptr; | ||
for (event = reinterpret_cast<struct fanotify_event_metadata *>(buf); | ||
FAN_EVENT_OK(event, len); | ||
event = FAN_EVENT_NEXT(event, len)) { | ||
const auto *fid = reinterpret_cast<const struct fanotify_event_info_fid *>(event + 1); | ||
auto *file_handle = (struct file_handle *) fid->handle; | ||
|
||
std::string path; | ||
auto event_fd = open_by_handle_at(mountFd, file_handle, O_RDONLY); | ||
if (event_fd >= 0) { | ||
path = getPathFromFd(event_fd); | ||
close(event_fd); | ||
if (path.find(dir.string()) == std::string::npos) { | ||
continue; // 全局监控,不在目标目录下的文件不处理 | ||
} | ||
} else { | ||
std::cerr << "Failed to open file by handle: " << event_fd << std::endl; | ||
} | ||
|
||
std::string filename; | ||
if (fid->hdr.info_type == FAN_EVENT_INFO_TYPE_DFID_NAME) { | ||
auto *file_name = file_handle->f_handle + file_handle->handle_bytes; | ||
filename = std::string(file_name, | ||
file_name | ||
+ strlen(reinterpret_cast<const char *>(file_name))); | ||
} else { | ||
std::cerr << "Received unexpected event info type: " << fid->hdr.info_type | ||
<< std::endl; | ||
} | ||
|
||
if ((event->mask & FAN_ACCESS) != 0U) { | ||
fileEvent = "FAN_ACCESS: "; | ||
} else if ((event->mask & FAN_MODIFY) != 0U) { | ||
fileEvent = "FAN_MODIFY: "; | ||
} else if ((event->mask & FAN_ATTRIB) != 0U) { | ||
fileEvent = "FAN_ATTRIB: "; | ||
} else if ((event->mask & FAN_CLOSE_WRITE) != 0U) { | ||
fileEvent = "FAN_CLOSE_WRITE: "; | ||
} else if ((event->mask & FAN_CLOSE_NOWRITE) != 0U) { | ||
fileEvent = "FAN_CLOSE_NOWRITE: "; | ||
} else if ((event->mask & FAN_OPEN) != 0U) { | ||
fileEvent = "FAN_OPEN: "; | ||
} else if ((event->mask & FAN_MOVED_FROM) != 0U) { | ||
fileEvent = "FAN_MOVED_FROM: "; | ||
} else if ((event->mask & FAN_MOVED_TO) != 0U) { | ||
fileEvent = "FAN_MOVED_TO: "; | ||
} else if ((event->mask & FAN_CREATE) != 0U) { | ||
fileEvent = "FAN_CREATE: "; | ||
} else if ((event->mask & FAN_DELETE) != 0U) { | ||
fileEvent = "FAN_DELETE: "; | ||
} else if ((event->mask & FAN_DELETE_SELF) != 0U) { | ||
fileEvent = "FAN_DELETE_SELF: "; | ||
} else if ((event->mask & FAN_MOVE_SELF) != 0U) { | ||
fileEvent = "FAN_MOVE_SELF: "; | ||
} else if ((event->mask & FAN_OPEN_EXEC) != 0U) { | ||
fileEvent = "FAN_OPEN_EXEC: "; | ||
} else if ((event->mask & FAN_Q_OVERFLOW) != 0U) { | ||
fileEvent = "FAN_Q_OVERFLOW: "; | ||
} else if ((event->mask & FAN_FS_ERROR) != 0U) { | ||
fileEvent = "FAN_FS_ERROR: "; | ||
} else if ((event->mask & FAN_OPEN_PERM) != 0U) { | ||
fileEvent = "FAN_OPEN_PERM: "; | ||
} else if ((event->mask & FAN_ACCESS_PERM) != 0U) { | ||
fileEvent = "FAN_ACCESS_PERM: "; | ||
} else if ((event->mask & FAN_OPEN_EXEC_PERM) != 0U) { | ||
fileEvent = "FAN_OPEN_EXEC_PERM: "; | ||
} else if ((event->mask & FAN_EVENT_ON_CHILD) != 0U) { | ||
fileEvent = "FAN_EVENT_ON_CHILD: "; | ||
} else if ((event->mask & FAN_RENAME) != 0U) { | ||
fileEvent = "FAN_RENAME: "; | ||
} else if ((event->mask & FAN_ONDIR) != 0U) { | ||
fileEvent = "FAN_ONDIR: "; | ||
} else if ((event->mask & FAN_CLOSE) != 0U) { | ||
fileEvent = "FAN_CLOSE: "; | ||
} else if ((event->mask & FAN_MOVE) != 0U) { | ||
fileEvent = "FAN_MOVE: "; | ||
} else { | ||
fileEvent = "Unknown: " + std::to_string(event->mask); | ||
} | ||
|
||
fileEvent += path; | ||
if (!filename.empty()) { | ||
fileEvent += "/" + filename; | ||
} | ||
std::cout << fileEvent << std::endl; | ||
} | ||
} | ||
|
||
void run() | ||
{ | ||
if (!createFd()) { | ||
return; | ||
} | ||
|
||
if (!addWatch()) { | ||
closeFd(); | ||
return; | ||
} | ||
isRunning.store(true); | ||
while (isRunning.load()) { | ||
monitor(); | ||
} | ||
|
||
closeFd(); | ||
} | ||
|
||
MonitorDir *q_ptr; | ||
|
||
int mountFd = -1; | ||
int fanotifyFd = -1; | ||
|
||
std::filesystem::path dir; | ||
std::atomic_bool isRunning; | ||
std::thread monitorThread; | ||
}; | ||
|
||
MonitorDir::MonitorDir(const std::filesystem::path &dir) | ||
: d_ptr(std::make_unique<MonitorDirPrivate>(this)) | ||
, m_dir(dir) | ||
, m_isRunning(false) | ||
{ | ||
assert(std::filesystem::is_directory(dir) && std::filesystem::exists(dir)); | ||
d_ptr->dir = dir; | ||
} | ||
|
||
MonitorDir::~MonitorDir() | ||
{ | ||
stop(); | ||
} | ||
|
||
auto MonitorDir::start() -> bool | ||
{ | ||
if (m_isRunning) { | ||
std::cerr << "MonitorDir is already running" << std::endl; | ||
return false; | ||
} | ||
|
||
m_isRunning.store(true); | ||
d_ptr->monitorThread = std::thread([this] { | ||
d_ptr->run(); | ||
m_isRunning.store(false); | ||
}); | ||
|
||
return true; | ||
} | ||
|
||
void MonitorDir::stop() | ||
{ | ||
if (!m_isRunning.load()) { | ||
std::cerr << "MonitorDir is not running" << std::endl; | ||
return; | ||
} | ||
d_ptr->isRunning.store(false); | ||
if (d_ptr->monitorThread.joinable()) { | ||
d_ptr->monitorThread.join(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.