lib/fs: Add bitmasks for Darwin to handle change to empty files (fixes #7731) (#7756)

This commit is contained in:
Anur 2021-06-09 18:57:06 +08:00 committed by GitHub
parent 18a608a6ff
commit e7f8538e4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 83 additions and 2 deletions

View File

@ -0,0 +1,17 @@
// Copyright (C) 2021 The Syncthing Authors.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
// +build darwin,!kqueue,cgo
package fs
import "github.com/syncthing/notify"
const (
subEventMask = notify.Create | notify.Remove | notify.Write | notify.Rename | notify.FSEventsInodeMetaMod
permEventMask = 0
rmEventMask = notify.Remove | notify.Rename
)

View File

@ -4,8 +4,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file, // License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/. // You can obtain one at http://mozilla.org/MPL/2.0/.
// +build !linux,!windows,!dragonfly,!freebsd,!netbsd,!openbsd,!solaris // +build !linux,!windows,!dragonfly,!freebsd,!netbsd,!openbsd,!solaris,!darwin,!cgo
// +build !darwin darwin,cgo
// Catch all platforms that are not specifically handled to use the generic // Catch all platforms that are not specifically handled to use the generic
// event types. // event types.

View File

@ -12,6 +12,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
@ -445,6 +446,61 @@ func TestWatchModTime(t *testing.T) {
} }
} }
testScenario(t, name, testCase, expectedEvents, allowedEvents, fakeMatcher{}, false)
}
func TestModifyFile(t *testing.T) {
name := "modify"
old := createTestFile(name, "file")
modifyTestFile(name, old, "syncthing")
testCase := func() {
modifyTestFile(name, old, "modified")
}
expectedEvents := []Event{
{old, NonRemove},
}
allowedEvents := []Event{
{name, NonRemove},
}
sleepMs(1000)
testScenario(t, name, testCase, expectedEvents, allowedEvents, fakeMatcher{}, false)
}
func TestTruncateFileOnly(t *testing.T) {
name := "truncate"
file := createTestFile(name, "file")
modifyTestFile(name, file, "syncthing")
// modified the content to empty use os.WriteFile will first truncate the file
// (/os/file.go:696) then write nothing. This logic is also used in many editors,
// such as when emptying a file in VSCode or JetBrain
//
// darwin will only modified the inode's metadata, such us mtime, file size, etc.
// but would not modified the file directly, so FSEvent 'FSEventsModified' will not
// be received
//
// we should watch the FSEvent 'FSEventsInodeMetaMod' to watch the Inode metadata,
// and that should be considered as an NonRemove Event
//
// notify also considered FSEventsInodeMetaMod as Write Event
// /watcher_fsevents.go:89
testCase := func() {
modifyTestFile(name, file, "")
}
expectedEvents := []Event{
{file, NonRemove},
}
allowedEvents := []Event{
{file, NonRemove},
}
sleepMs(1000)
testScenario(t, name, testCase, expectedEvents, allowedEvents, fakeMatcher{}, true) testScenario(t, name, testCase, expectedEvents, allowedEvents, fakeMatcher{}, true)
} }
@ -470,6 +526,15 @@ func renameTestFile(name string, old string, new string) {
} }
} }
func modifyTestFile(name string, file string, content string) {
joined := filepath.Join(testDirAbs, name, file)
err := ioutil.WriteFile(joined, []byte(content), 0755)
if err != nil {
panic(fmt.Sprintf("Failed to modify test file %s: %s", joined, err))
}
}
func sleepMs(ms int) { func sleepMs(ms int) {
time.Sleep(time.Duration(ms) * time.Millisecond) time.Sleep(time.Duration(ms) * time.Millisecond)
} }