rm dir actions triggered two remove event
JK-97 opened this issue · comments
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
@JK-97 What OS is that? Can you build your application with debug tag and run it again?
@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?
@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.
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.
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
})
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.