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
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),
if fileEvent.IsRename() {
w.removeWatch(fileEvent.Name)
+ delete(w.fileExists, fileEvent.Name)
+ }
+ if fileEvent.IsDelete() {
+ delete(w.fileExists, fileEvent.Name)
}
}
}
// 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
// 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)
fileEvent.create = true
w.internalEvent <- fileEvent
}
+ w.fileExists[filePath] = true
}
w.watchDirectoryFiles(dirPath)
}
}
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 {
// 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)
}
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