Fuse框架可以直接在用户层挂载一个自定义的文件系统,当将挂载点和挂载内容重叠在一起时就形成了一个文件系统过滤层,如fuse mount ~/A to ~/A
此时可以借助挂载命名空间方式在fuse程序内访问原始文件系统,避免递归回fuse(这样回死锁)
cpp
int main(int argc, char *argv[])
{
try
{
// 解析命令行参数<tool> watchingdir
if (argc < 2)
{
std::cerr << "Usage: " << argv[0] << " watchingdir <mount-point>" << std::endl;
return 1;
}
g_Ori_euid = geteuid();
g_Ori_egid = getegid();
std::string mount_point = argv[1];
std::string watch_dir = mount_point;
int ur = fuse_unmount(mount_point.c_str(), 1);
printf("ur=%d,%d\n", ur, errno);
//备份当前的挂载命名空间
// 1. 保存当前挂载命名空间
original_mnt_ns_fd = open("/proc/self/ns/mnt", O_RDONLY);
if (original_mnt_ns_fd == -1)
{
perror("open original mnt ns failed");
exit(EXIT_FAILURE);
}
// 2. 创建新的挂载命名空间
if (unshare(CLONE_NEWNS) == -1)
{
perror("unshare failed");
exit(EXIT_FAILURE);
}
// 3. 在新命名空间中挂载根文件系统为私有
if (mount("/", "/", NULL, MS_REC | MS_PRIVATE, NULL) == -1)
{
perror("mount private failed");
exit(EXIT_FAILURE);
}
//备份新命名空间fd
new_mnt_ns_fd = open("/proc/self/ns/mnt", O_RDONLY);
if (new_mnt_ns_fd == -1)
{
perror("open original mnt ns failed");
exit(EXIT_FAILURE);
}
//切换到原来的空间
if (0 != switch_namespace(original_mnt_ns_fd))
{
perror("switch old");
exit(EXIT_FAILURE);
}
// 创建FuseWatcher实例
FuseWatcher watcher(watch_dir);
// 挂载FUSE文件系统
int ret = watcher.mount(argc, argv);
if (ret != 0)
{
std::cerr << "Failed to mount FUSE filesystem: " << ret << std::endl;
return ret;
}
return 0;
}
catch (const std::exception &e)
{
std::cerr << "Error: " << e.what() << std::endl;
return 1;
}
}
之后在回调时就可以切换命名空间进行访问,也可以模拟调用者身份进行访问,此时默认可以做到一个透明转发的功能,再进行修改就可以完成文件审计功能