]> go.fuhry.dev Git - fsnotify.git/commitdiff
BSD - fix to not longer get duplicate CREATE events
authorChris Howey <chris@howey.me>
Wed, 26 Sep 2012 00:57:52 +0000 (19:57 -0500)
committerChris Howey <chris@howey.me>
Wed, 26 Sep 2012 00:57:52 +0000 (19:57 -0500)
needed to add DELETE watch for directories that are created in
watched directory

Also added a test for this behaviour

fsnotify_bsd.go
fsnotify_test.go

index 5ddf57841dc33410d515fe240493032e0e4c9164..015648b7168e7aa10a665ae6894935f56ad5bd92 100644 (file)
@@ -42,6 +42,7 @@ type Watcher struct {
        fsnFlags      map[string]uint32   // Map of watched files to flags used for filter
        paths         map[int]string      // Map of watched paths (key: watch descriptor)
        finfo         map[int]os.FileInfo // Map of file information (isDir, isReg; key: watch descriptor)
+       fileExists    map[string]bool     // Keep track of if we know this file exists (to stop duplicate create events)
        Error         chan error          // Errors are sent on this channel
        internalEvent chan *FileEvent     // Events are queued on this channel
        Event         chan *FileEvent     // Events are returned on this channel
@@ -62,6 +63,7 @@ func NewWatcher() (*Watcher, error) {
                fsnFlags:      make(map[string]uint32),
                paths:         make(map[int]string),
                finfo:         make(map[int]os.FileInfo),
+               fileExists:    make(map[string]bool),
                internalEvent: make(chan *FileEvent),
                Event:         make(chan *FileEvent),
                Error:         make(chan error),
@@ -249,6 +251,10 @@ func (w *Watcher) readEvents() {
 
                        if fileEvent.IsRename() {
                                w.removeWatch(fileEvent.Name)
+                               delete(w.fileExists, fileEvent.Name)
+                       }
+                       if fileEvent.IsDelete() {
+                               delete(w.fileExists, fileEvent.Name)
                        }
                }
        }
@@ -263,15 +269,22 @@ func (w *Watcher) watchDirectoryFiles(dirPath string) error {
 
        // Search for new files
        for _, fileInfo := range files {
+               filePath := filepath.Join(dirPath, fileInfo.Name())
                if fileInfo.IsDir() == false {
-                       filePath := filepath.Join(dirPath, fileInfo.Name())
                        // Watch file to mimic linux fsnotify
                        e := w.addWatch(filePath, NOTE_DELETE|NOTE_WRITE|NOTE_RENAME)
                        w.fsnFlags[filePath] = FSN_ALL
                        if e != nil {
                                return e
                        }
+               } else {
+                       // Linux gives deletes if not explicitly watching
+                       e := w.addWatch(filePath, NOTE_DELETE)
+                       if e != nil {
+                               return e
+                       }
                }
+               w.fileExists[filePath] = true
        }
 
        return nil
@@ -291,8 +304,8 @@ func (w *Watcher) sendDirectoryChangeEvents(dirPath string) {
        // Search for new files
        for _, fileInfo := range files {
                filePath := filepath.Join(dirPath, fileInfo.Name())
-               _, watchFound := w.watches[filePath]
-               if watchFound == false {
+               _, doesExist := w.fileExists[filePath]
+               if doesExist == false {
                        w.fsnFlags[filePath] = FSN_ALL
                        // Send create event
                        fileEvent := new(FileEvent)
@@ -300,6 +313,7 @@ func (w *Watcher) sendDirectoryChangeEvents(dirPath string) {
                        fileEvent.create = true
                        w.internalEvent <- fileEvent
                }
+               w.fileExists[filePath] = true
        }
        w.watchDirectoryFiles(dirPath)
 }
index f586165a1307ecbbb8c5b412ad38572bb6e8ae61..1df2fdbbb23afdde1b62f7683e640352ccc75244 100644 (file)
@@ -265,7 +265,9 @@ func TestFsnotifySubDir(t *testing.T) {
        }
 
        const testDir string = "_test"
+       const testFile1 string = "_test/TestFsnotifyFile1.testfile"
        const testSubDir string = "_test/sub"
+       const testSubDirFile string = "_test/sub/TestFsnotifyFile1.testfile"
 
        // Create directory to watch
        if os.Mkdir(testDir, 0777) != nil {
@@ -283,15 +285,19 @@ func TestFsnotifySubDir(t *testing.T) {
        // Receive events on the event channel on a separate goroutine
        eventstream := watcher.Event
        var createReceived = 0
+       var deleteReceived = 0
        done := make(chan bool)
        go func() {
                for event := range eventstream {
                        // Only count relevant events
-                       if event.Name == testDir || event.Name == testSubDir {
+                       if event.Name == testDir || event.Name == testSubDir || event.Name == testFile1 {
                                t.Logf("event received: %s", event)
                                if event.IsCreate() {
                                        createReceived++
                                }
+                               if event.IsDelete() {
+                                       deleteReceived++
+                               }
                        } else {
                                t.Logf("unexpected event received: %s", event)
                        }
@@ -310,10 +316,35 @@ func TestFsnotifySubDir(t *testing.T) {
                t.Fatalf("Failed to create test sub-directory: %s", err)
        }
 
+       // Create a file
+       var f *os.File
+       f, err = os.OpenFile(testFile1, os.O_WRONLY|os.O_CREATE, 0666)
+       if err != nil {
+               t.Fatalf("creating test file failed: %s", err)
+       }
+       f.Sync()
+       f.Close()
+
+       // Create a file (Should not see this! we are not watching subdir)
+       var fs *os.File
+       fs, err = os.OpenFile(testSubDirFile, os.O_WRONLY|os.O_CREATE, 0666)
+       if err != nil {
+               t.Fatalf("creating test file failed: %s", err)
+       }
+       fs.Sync()
+       fs.Close()
+
+       // Make sure receive deletes for both file and sub-directory
+       os.RemoveAll(testSubDir)
+       os.Remove(testFile1)
+
        // We expect this event to be received almost immediately, but let's wait 500 ms to be sure
        time.Sleep(500 * time.Millisecond)
-       if createReceived != 1 {
-               t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", createReceived, 1)
+       if createReceived != 2 {
+               t.Fatalf("incorrect number of create events received after 500 ms (%d vs %d)", createReceived, 2)
+       }
+       if deleteReceived != 2 {
+               t.Fatalf("incorrect number of delete events received after 500 ms (%d vs %d)", deleteReceived, 2)
        }
 
        // Try closing the fsnotify instance