Golang

关注公众号 jb51net

关闭
首页 > 脚本专栏 > Golang > Golang文件系统事件监听

详解Golang中文件系统事件监听

作者:科目三什么时候过

文件系统事件是指文件系统相关的各种操作和状态变化,当一个应用层的进程操作文件或目录时,会触发system call,内核的notification子系统可以守在那里,把该进程对文件的操作上报给应用层的监听进程,这篇文章主要介绍了Golang之文件系统事件监听,需要的朋友可以参考下

基本介绍

文件系统事件是指文件系统相关的各种操作和状态变化,当一个应用层的进程操作文件或目录时,会触发system call,内核的notification子系统可以守在那里,把该进程对文件的操作上报给应用层的监听进程。这些事件可以包括文件和目录的创建、修改、删除和文件权限的更改等。

Linux中常用的有两种机制能够监听这些文件事件,分别为inotify和fanotify。

inotify和fanotify最大的区别就是fanotify能够监听到是哪个进程对文件或目录进行操作,并且能够阻止该操作。

fanotify

fanotify:Linux 2.6.37版本引入,能够通知用户哪个进程触发了哪些事件,并且能够对其进行干预。

Golang中fanotify有两个函数:

func FanotifyInit(flags uint, event_f_flags uint) (fd int, err error)
func FanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname string) (err error)

函数介绍

示例

package main
import (
	"bytes"
	"encoding/binary"
	"errors"
	"fmt"
	"io"
	"log"
	"os"
	"path/filepath"
	"unsafe"
	"golang.org/x/sys/unix"
)
func handle_perm(initFd int, fanfd int32) error {
	fd := unix.FanotifyResponse{
		Fd:       fanfd,
		Response: uint32(unix.FAN_DENY),
	}
	buf := new(bytes.Buffer)
	err := binary.Write(buf, binary.LittleEndian, fd)
	if err != nil {
		log.Println(err)
	}
	ret, err := unix.Write(initFd, buf.Bytes())
	if err != nil {
		log.Println("handle_perm:err", err)
	}
	if ret < 0 {
		return err
	}
	return nil
}
func main() {
	path := "/root/testapp2/"
	name := filepath.Clean(path)
	initFd, err := unix.FanotifyInit(unix.FAN_CLOEXEC|unix.FAN_NONBLOCK|unix.FAN_CLASS_PRE_CONTENT, unix.O_RDONLY)
	if err != nil {
		log.Panicln("FanotifyInit err : ", err)
	}
	inotifyFile := os.NewFile(uintptr(initFd), "")
	if initFd == -1 {
		log.Println("fanFd err", err)
	}
	defer unix.Close(initFd)
	mask := uint64(unix.FAN_EVENT_ON_CHILD | unix.FAN_OPEN_PERM)
	err = unix.FanotifyMark(initFd, unix.FAN_MARK_ADD, mask, unix.AT_FDCWD, name)
	if err != nil {
		log.Panicln("FanotifyMark err : ", err)
	}
	fmt.Println("start:")
	fmt.Println("监控目录:", name)
	var (
		buf [unix.FAN_EVENT_METADATA_LEN * 4096]byte
	)
	for {
		n, err := inotifyFile.Read(buf[:])
		if err != nil {
			continue
		}
		if n < unix.FAN_EVENT_METADATA_LEN {
			if n == 0 {
				err = io.EOF
			} else if n < 0 {
				err = errors.New("notify: short ")
			} else {
				err = errors.New("notify: short read in readEvents()")
			}
			continue
		}
		var offset int
		for offset <= int(n-unix.FAN_EVENT_METADATA_LEN) {
			var (
				raw       = (*unix.FanotifyEventMetadata)(unsafe.Pointer(&buf[offset]))
				pid       = int32(raw.Pid)
				event_len = uint32(raw.Event_len)
				fd        = int32(raw.Fd)
			)
			fdPath := fmt.Sprintf("/proc/self/fd/%d", fd)
			f, err := os.Readlink(fdPath)
			if err != nil {
				log.Println(err)
			} else {
				fmt.Println("fdpath:", f)
			}
			proName := fmt.Sprintf("/proc/%d/comm", pid)
			pN, err := os.ReadFile(proName)
			if err != nil {
				log.Println(err)
				continue
			}
			if err := handle_perm(initFd, fd); err != nil {
				continue
			}
			fmt.Printf("阻止程序: %v", string(pN))
			offset += int(unix.FAN_EVENT_METADATA_LEN + event_len)
		}
	}
}

示例代码能够拒绝程序打开该目录下文件

升级成为会员

« 上一篇: tool

posted @ 2024-01-18 13:49  科目三什么时候过  阅读(17)  评论(0)  编辑  收藏  举报

会员力量,点亮园子希望

您可能感兴趣的文章:
阅读全文