summaryrefslogtreecommitdiff
path: root/vendor/github.com/nxadm/tail/watch/inotify.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/nxadm/tail/watch/inotify.go')
-rw-r--r--vendor/github.com/nxadm/tail/watch/inotify.go135
1 files changed, 135 insertions, 0 deletions
diff --git a/vendor/github.com/nxadm/tail/watch/inotify.go b/vendor/github.com/nxadm/tail/watch/inotify.go
new file mode 100644
index 000000000..439921810
--- /dev/null
+++ b/vendor/github.com/nxadm/tail/watch/inotify.go
@@ -0,0 +1,135 @@
+// Copyright (c) 2015 HPE Software Inc. All rights reserved.
+// Copyright (c) 2013 ActiveState Software Inc. All rights reserved.
+
+package watch
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+
+ "github.com/nxadm/tail/util"
+
+ "github.com/fsnotify/fsnotify"
+ "gopkg.in/tomb.v1"
+)
+
+// InotifyFileWatcher uses inotify to monitor file changes.
+type InotifyFileWatcher struct {
+ Filename string
+ Size int64
+}
+
+func NewInotifyFileWatcher(filename string) *InotifyFileWatcher {
+ fw := &InotifyFileWatcher{filepath.Clean(filename), 0}
+ return fw
+}
+
+func (fw *InotifyFileWatcher) BlockUntilExists(t *tomb.Tomb) error {
+ err := WatchCreate(fw.Filename)
+ if err != nil {
+ return err
+ }
+ defer RemoveWatchCreate(fw.Filename)
+
+ // Do a real check now as the file might have been created before
+ // calling `WatchFlags` above.
+ if _, err = os.Stat(fw.Filename); !os.IsNotExist(err) {
+ // file exists, or stat returned an error.
+ return err
+ }
+
+ events := Events(fw.Filename)
+
+ for {
+ select {
+ case evt, ok := <-events:
+ if !ok {
+ return fmt.Errorf("inotify watcher has been closed")
+ }
+ evtName, err := filepath.Abs(evt.Name)
+ if err != nil {
+ return err
+ }
+ fwFilename, err := filepath.Abs(fw.Filename)
+ if err != nil {
+ return err
+ }
+ if evtName == fwFilename {
+ return nil
+ }
+ case <-t.Dying():
+ return tomb.ErrDying
+ }
+ }
+ panic("unreachable")
+}
+
+func (fw *InotifyFileWatcher) ChangeEvents(t *tomb.Tomb, pos int64) (*FileChanges, error) {
+ err := Watch(fw.Filename)
+ if err != nil {
+ return nil, err
+ }
+
+ changes := NewFileChanges()
+ fw.Size = pos
+
+ go func() {
+
+ events := Events(fw.Filename)
+
+ for {
+ prevSize := fw.Size
+
+ var evt fsnotify.Event
+ var ok bool
+
+ select {
+ case evt, ok = <-events:
+ if !ok {
+ RemoveWatch(fw.Filename)
+ return
+ }
+ case <-t.Dying():
+ RemoveWatch(fw.Filename)
+ return
+ }
+
+ switch {
+ case evt.Op&fsnotify.Remove == fsnotify.Remove:
+ fallthrough
+
+ case evt.Op&fsnotify.Rename == fsnotify.Rename:
+ RemoveWatch(fw.Filename)
+ changes.NotifyDeleted()
+ return
+
+ //With an open fd, unlink(fd) - inotify returns IN_ATTRIB (==fsnotify.Chmod)
+ case evt.Op&fsnotify.Chmod == fsnotify.Chmod:
+ fallthrough
+
+ case evt.Op&fsnotify.Write == fsnotify.Write:
+ fi, err := os.Stat(fw.Filename)
+ if err != nil {
+ if os.IsNotExist(err) {
+ RemoveWatch(fw.Filename)
+ 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, nil
+}