Repository: syncthing/syncthing (language: go)

Issue:
notify: File mode change events not emitted on MacOS/FSEvents watcher
Technically an issue in `syncthing/notify`. It seems like it doesn't generate events when changing file mode, which means permissions don't get synced after running `chmod` until the next scan.

I've done a tiny bit of digging and it looks like those events should be generated by FSEvents. The`fsnotify` package, which uses `kqueue` instead of `FSEvents`, does seem to emit `chmod` events.

Version: Syncthing v1.18.1-1 macos
OS: macOS BigSur x64 11.5.2

Repro:

* Have a synced folder
* Create a file
* Change file permissions using `chmod`

Result:

* File permissions are not synced until next scan or until file is modified e.g by `touch`ing it

Expected:

* File permissions will be synced after `fsWatchDelay`



notify: File mode change events not emitted on MacOS/FSEvents watcher
Technically an issue in `syncthing/notify`. It seems like it doesn't generate events when changing file mode, which means permissions don't get synced after running `chmod` until the next scan.

I've done a tiny bit of digging and it looks like those events should be generated by FSEvents. The`fsnotify` package, which uses `kqueue` instead of `FSEvents`, does seem to emit `chmod` events.

Version: Syncthing v1.18.1-1 macos
OS: macOS BigSur x64 11.5.2

Repro:

* Have a synced folder
* Create a file
* Change file permissions using `chmod`

Result:

* File permissions are not synced until next scan or until file is modified e.g by `touch`ing it

Expected:

* File permissions will be synced after `fsWatchDelay`





Discussion / hints:
Does this issue reproduce for anyone else?
That might be an issue on our side: We don't choose any FSEvents specific event types for detecting permission changes. None of the availabe ones look like permission change to me, except for those about owner and xattr, but we don't care about either of those. If anyone knows which events get triggered on a "normal" permission change, please let me know

```
	FSEventsMustScanSubDirs Event = 0x00001
	FSEventsUserDropped           = 0x00002
	FSEventsKernelDropped         = 0x00004
	FSEventsEventIdsWrapped       = 0x00008
	FSEventsHistoryDone           = 0x00010
	FSEventsRootChanged           = 0x00020
	FSEventsMount                 = 0x00040
	FSEventsUnmount               = 0x00080
	FSEventsCreated               = 0x00100
	FSEventsRemoved               = 0x00200
	FSEventsInodeMetaMod          = 0x00400
	FSEventsRenamed               = 0x00800
	FSEventsModified              = 0x01000
	FSEventsFinderInfoMod         = 0x02000
	FSEventsChangeOwner           = 0x04000
	FSEventsXattrMod              = 0x08000
	FSEventsIsFile                = 0x10000
	FSEventsIsDir                 = 0x20000
	FSEventsIsSymlink             = 0x40000
```
I would guess perhaps FSEventsInodeMetaMod but I can test it later
We do listen for that as a regular event already. regular as in not exclusive to permissions, i.e. we also listen to it if ignore permissions is set.
If I listen to `notify.All` I don't get events for touch or chmod; ~~if I specifically listen for just `notify.FSEventsInodeMetaMod` then I get that event for touch and chmod.~~ that was wrong.

The event that gets generated when I chmod is `notify.FSEventsChangeOwner`. (Owner was not changed.)
Thanks @calmh, this seems to fix the issue on my end:

```diff
diff --git a/lib/fs/basicfs_watch_eventtypes_darwin.go b/lib/fs/basicfs_watch_eventtypes_darwin.go
index 8968c50db..9e5a733c4 100644
--- a/lib/fs/basicfs_watch_eventtypes_darwin.go
+++ b/lib/fs/basicfs_watch_eventtypes_darwin.go
@@ -13,6 +13,6 @@ import "github.com/syncthing/notify"
 
 const (
 	subEventMask  = notify.Create | notify.Remove | notify.Write | notify.Rename | notify.FSEventsInodeMetaMod
-	permEventMask = 0
+	permEventMask = notify.FSEventsChangeOwner
 	rmEventMask   = notify.Remove | notify.Rename
 )

```

Is this reasonable, should I open a PR?
Does this issue reproduce for anyone else?
That might be an issue on our side: We don't choose any FSEvents specific event types for detecting permission changes. None of the availabe ones look like permission change to me, except for those about owner and xattr, but we don't care about either of those. If anyone knows which events get triggered on a "normal" permission change, please let me know

```
	FSEventsMustScanSubDirs Event = 0x00001
	FSEventsUserDropped           = 0x00002
	FSEventsKernelDropped         = 0x00004
	FSEventsEventIdsWrapped       = 0x00008
	FSEventsHistoryDone           = 0x00010
	FSEventsRootChanged           = 0x00020
	FSEventsMount                 = 0x00040
	FSEventsUnmount               = 0x00080
	FSEventsCreated               = 0x00100
	FSEventsRemoved               = 0x00200
	FSEventsInodeMetaMod          = 0x00400
	FSEventsRenamed               = 0x00800
	FSEventsModified              = 0x01000
	FSEventsFinderInfoMod         = 0x02000
	FSEventsChangeOwner           = 0x04000
	FSEventsXattrMod              = 0x08000
	FSEventsIsFile                = 0x10000
	FSEventsIsDir                 = 0x20000
	FSEventsIsSymlink             = 0x40000
```
I would guess perhaps FSEventsInodeMetaMod but I can test it later
We do listen for that as a regular event already. regular as in not exclusive to permissions, i.e. we also listen to it if ignore permissions is set.
If I listen to `notify.All` I don't get events for touch or chmod; ~~if I specifically listen for just `notify.FSEventsInodeMetaMod` then I get that event for touch and chmod.~~ that was wrong.

The event that gets generated when I chmod is `notify.FSEventsChangeOwner`. (Owner was not changed.)
Thanks @calmh, this seems to fix the issue on my end:

```diff
diff --git a/lib/fs/basicfs_watch_eventtypes_darwin.go b/lib/fs/basicfs_watch_eventtypes_darwin.go
index 8968c50db..9e5a733c4 100644
--- a/lib/fs/basicfs_watch_eventtypes_darwin.go
+++ b/lib/fs/basicfs_watch_eventtypes_darwin.go
@@ -13,6 +13,6 @@ import "github.com/syncthing/notify"
 
 const (
 	subEventMask  = notify.Create | notify.Remove | notify.Write | notify.Rename | notify.FSEventsInodeMetaMod
-	permEventMask = 0
+	permEventMask = notify.FSEventsChangeOwner
 	rmEventMask   = notify.Remove | notify.Rename
 )

```

Is this reasonable, should I open a PR?

Fix patch:
diff --git a/lib/fs/basicfs_watch_eventtypes_darwin.go b/lib/fs/basicfs_watch_eventtypes_darwin.go
index 8968c50db13..1b68f1d1746 100644
--- a/lib/fs/basicfs_watch_eventtypes_darwin.go
+++ b/lib/fs/basicfs_watch_eventtypes_darwin.go
@@ -12,7 +12,8 @@ package fs
 import "github.com/syncthing/notify"
 
 const (
-	subEventMask  = notify.Create | notify.Remove | notify.Write | notify.Rename | notify.FSEventsInodeMetaMod
-	permEventMask = 0
+	subEventMask = notify.Create | notify.Remove | notify.Write | notify.Rename | notify.FSEventsInodeMetaMod
+	// FSEventsChangeOwner fires on permission change
+	permEventMask = notify.FSEventsChangeOwner
 	rmEventMask   = notify.Remove | notify.Rename
 )


Test patch: