rjeczalik / notify

File system event notification library on steroids.
MIT License
900 stars 128 forks source link

rm dir actions triggered two remove event #183

Open JK-97 opened 4 years ago

JK-97 commented 4 years ago

mycode


func FileListener(path string) {
    c := make(chan notify.EventInfo, 1)
    if err := notify.Watch(path, c, notify.Create, notify.InMovedFrom, notify.InModify, notify.InMovedTo, notify.Remove); err != nil {
        log.Error(err)
    }
    defer notify.Stop(c)
    moves := make(map[uint32]struct {
        From string
        To   string
    })

    for ei := range c {
        cookie := ei.Sys().(*unix.InotifyEvent).Cookie
        info := moves[cookie]
        switch ei.Event() {
        case notify.InMovedFrom:
            info.From = ei.Path()
            //log.Warn("InMovedFrom", ei.Path())
        case notify.InMovedTo:
            info.To = ei.Path()
            //log.Warn("InMovedTo", ei.Path())
        case notify.Create:
            if (ei.Path() == "/edge/synctools.zip") {
                log.Info("has detecd the sysctools package,")
                utils.Unzip("/edge/synctools.zip", "/edge/mnt")
                log.Info("has unzip the systools,")
            }
            log.Info("create", ei.Path())
        case notify.Remove:
            log.Warn("remove", ei.Path())
        case notify.InModify:
            log.Warn("modify", ei.Path())

        }
        moves[cookie] = info

        if cookie != 0 && info.From != "" && info.To != "" {
            log.Warn("File:", info.From, "was renamed to", info.To)
            delete(moves, cookie)
        }
    }
}

my watchpath is /edge/...

when i rm aa dir but the log is: INFO[0018] create/edge/mnt/aa
WARN[0020] remove/edge/mnt/aa
WARN[0020] remove/edge/mnt/aa

rjeczalik commented 4 years ago

@JK-97 What OS is that? Can you build your application with debug tag and run it again?

JK-97 commented 4 years ago

@JK-97 What OS is that? Can you build your application with debug tag and run it again?

my os is ubuntu 16.04 is that resulting in i use “rm -r xxx”? because it is recursive?

rjeczalik commented 4 years ago

@JK-97 Yes and no, if you rm -rf then you're going to receive remove events for each deleted dir and file, but you shouldn't receive duplicated events on the same channel if you registered the channel only once.

The debug output I mentioned above could shed some light what's happening.

cork commented 1 year ago

Seams to be a bug with the inotify implementation:

package main
import (
        "github.com/rjeczalik/notify"
        "github.com/davecgh/go-spew/spew"
)

func main() {
        events := make(chan notify.EventInfo, 10)
        if err := notify.Watch("/tmp/test/...", events, notify.Remove); err != nil {
                panic(err.Error())
        }

        for event := range events {
                spew.Dump(event)
        }
}

action:

/tmp/test/$ mkdir a
/tmp/test/$ rmdir a

log:

2023/01/18 10:39:11.144748 [D] dispatching notify.Create on "/tmp/test/a"
2023/01/18 10:39:12.589236 [D] dispatching notify.Remove on "/tmp/test/a"
2023/01/18 10:39:12.589256 [D] dispatching notify.Remove on "/tmp/test/a"
(*notify.event)(0xc00019e0f0)(notify.Remove: "/tmp/test/a")
(*notify.event)(0xc00019e090)(notify.Remove: "/tmp/test/a")

on:

Linux cork 6.1.6-arch1-3 #1 SMP PREEMPT_DYNAMIC Mon, 16 Jan 2023 12:51:23 +0000 x86_64 GNU/Linux

Seams to only happen for folder removal though both rm -Rf and rmdir is affected.

cork commented 1 year ago

OK so inotify gets a rouge 0x40000000 value, not sure what it means. It isn't listed in the man page...:

package main

import (
        "github.com/davecgh/go-spew/spew"
        "github.com/rjeczalik/notify"
)

func main() {
        events := make(chan notify.EventInfo, 10)
        if err := notify.Watch("/tmp/test/...", events, notify.Remove, notify.Rename); err != nil {
                panic(err.Error())
        }

        for event := range events {
                spew.Dump(event)
                spew.Dump(event.Sys())
        }
}

actions:

/tmp/test$ mkdir a
/tmp/test$ mv a b
/tmp/test$ rmdir b

log:

(*notify.event)(0xc0001ca060)(notify.Rename: "/tmp/test/a")
(*unix.InotifyEvent)(0xc0001ca060)({
 Wd: (int32) 2,
 Mask: (uint32) 2048,
 Cookie: (uint32) 0,
 Len: (uint32) 0
})
(*notify.event)(0xc0001ca000)(notify.Rename: "/tmp/test/a")
(*unix.InotifyEvent)(0xc0001ca000)({
 Wd: (int32) 1,
 Mask: (uint32) 1073741888,
 Cookie: (uint32) 7450,
 Len: (uint32) 0
})
(*notify.event)(0xc0001ca0f0)(notify.Remove: "/tmp/test/b")
(*unix.InotifyEvent)(0xc0001ca0f0)({
 Wd: (int32) 1,
 Mask: (uint32) 1073742336,
 Cookie: (uint32) 0,
 Len: (uint32) 0
})
(*notify.event)(0xc0001ca090)(notify.Remove: "/tmp/test/b")
(*unix.InotifyEvent)(0xc0001ca090)({
 Wd: (int32) 2,
 Mask: (uint32) 1024,
 Cookie: (uint32) 0,
 Len: (uint32) 0
})
cork commented 1 year ago
    name := event.Event().String()
    mask := event.Sys().(*unix.InotifyEvent).Mask
    if name == "notify.Rename" && (mask&unix.IN_MOVE_SELF) != 0 {
        continue
    } else if name == "notify.Remove" && (mask&unix.IN_DELETE_SELF) != 0 {
        continue
    }

Seams to give the correct effect. Not a fix though.