func (fw *InotifyFileWatcher) ChangeEvents(t *tomb.Tomb, fi os.FileInfo) *FileChanges { changes := NewFileChanges() w, err := inotifyTracker.NewWatcher() if err != nil { util.Fatal("Error creating fsnotify watcher: %v", err) } err = w.Watch(fw.Filename) if err != nil { util.Fatal("Error watching %v: %v", fw.Filename, err) } fw.Size = fi.Size() go func() { defer inotifyTracker.CloseWatcher(w) defer changes.Close() for { prevSize := fw.Size var evt *fsnotify.FileEvent var ok bool select { case evt, ok = <-w.Event: if !ok { return } case <-t.Dying(): return } switch { case evt.IsDelete(): fallthrough case evt.IsRename(): changes.NotifyDeleted() return case evt.IsModify(): fi, err := os.Stat(fw.Filename) if err != nil { if os.IsNotExist(err) { changes.NotifyDeleted() return } // XXX: report this error back to the user util.Fatal("Failed to stat file %v: %v", fw.Filename, err) } fw.Size = fi.Size() if prevSize > 0 && prevSize > fw.Size { changes.NotifyTruncated() } else { changes.NotifyModified() } prevSize = fw.Size } } }() return changes }
func (fw *PollingFileWatcher) ChangeEvents(t *tomb.Tomb, origFi os.FileInfo) *FileChanges { changes := NewFileChanges() var prevModTime time.Time // XXX: use tomb.Tomb to cleanly manage these goroutines. replace // the fatal (below) with tomb's Kill. fw.Size = origFi.Size() go func() { defer changes.Close() var retry int = 0 prevSize := fw.Size for { select { case <-t.Dying(): return default: } time.Sleep(POLL_DURATION) fi, err := os.Stat(fw.Filename) if err != nil { if os.IsNotExist(err) { // File does not exist (has been deleted). changes.NotifyDeleted() return } if permissionErrorRetry(err, &retry) { continue } // XXX: report this error back to the user util.Fatal("Failed to stat file %v: %v", fw.Filename, err) } // File got moved/renamed? if !os.SameFile(origFi, fi) { changes.NotifyDeleted() return } // File got truncated? fw.Size = fi.Size() if prevSize > 0 && prevSize > fw.Size { changes.NotifyTruncated() prevSize = fw.Size continue } prevSize = fw.Size // File was appended to (changed)? modTime := fi.ModTime() if modTime != prevModTime { prevModTime = modTime changes.NotifyModified() } } }() return changes }