Files
gvisor-tap-vsock/pkg/utils/filewatcher.go
Fata Nugraha c56ed7ab4a Use poll based file watcher
fsnotify/fsnotify can't watch a folder that contains a symlink into
a socket or named pipe.

Use poll-based mechanism to watch the file for the time being until
we find a better way or fix the issue in the upstream.

Signed-off-by: Fata Nugraha <fatanugraha@outlook.com>
2025-01-22 21:59:37 +08:00

64 lines
1.2 KiB
Go

package utils
import (
"os"
"time"
)
// FileWatcher is an utility that
type FileWatcher struct {
path string
closeCh chan struct{}
pollInterval time.Duration
}
func NewFileWatcher(path string) *FileWatcher {
return &FileWatcher{
path: path,
pollInterval: 5 * time.Second, // 5s is the default inode cache timeout in linux for most systems.
closeCh: make(chan struct{}),
}
}
func (fw *FileWatcher) Start(changeHandler func()) {
prevModTime := fw.fileModTime(fw.path)
// use polling-based approach to detect file changes
// we can't use fsnotify/fsnotify due to issues with symlink+socket. see #462.
go func() {
for {
select {
case _, ok := <-fw.closeCh:
if !ok {
return // watcher is closed.
}
case <-time.After(fw.pollInterval):
}
modTime := fw.fileModTime(fw.path)
if modTime.IsZero() {
continue // file does not exists
}
if !prevModTime.Equal(modTime) {
changeHandler()
prevModTime = modTime
}
}
}()
}
func (fw *FileWatcher) fileModTime(path string) time.Time {
info, err := os.Stat(path)
if err != nil {
return time.Time{}
}
return info.ModTime()
}
func (fw *FileWatcher) Stop() {
close(fw.closeCh)
}