summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@sbcglobal.net>2016-12-18 15:51:39 -0500
committerLuke Shumaker <lukeshu@sbcglobal.net>2016-12-18 15:51:39 -0500
commitfc5d64a5fc886e0b8519e8c19d311ebfb0df59db (patch)
tree2fd417f1d24bd9d7956b705212037f1aad9854c5
parent09db31c7264e370fbbafab81a0c30b1ac1b80514 (diff)
add inotify.NewInotify
-rw-r--r--inotify/inotify.go26
-rw-r--r--inotify/syscall.go21
2 files changed, 47 insertions, 0 deletions
diff --git a/inotify/inotify.go b/inotify/inotify.go
index 2db414c..1c0c3c6 100644
--- a/inotify/inotify.go
+++ b/inotify/inotify.go
@@ -96,6 +96,32 @@ func newInotify(fd inFd, blocking bool) *Inotify {
return in
}
+// NewInotify creates an Inotify object that wraps an inotify instance
+// on an already open file descriptor, much like net.FileListener.
+//
+// Closing file does not affect the Inotify, and closing Inotify does
+// not affect file.
+func NewInotify(file *os.File) (*Inotify, error) {
+ dup, err := sys_dupfd_cloexec(inFd(file.Fd()))
+ if err != nil {
+ return nil, err
+ }
+
+ nonblock, err := sys_getnonblock(dup)
+ if err != nil {
+ sys_close(dup)
+ return nil, err
+ }
+
+ err = sys_setnonblock(dup, false)
+ if err != nil {
+ sys_close(dup)
+ return nil, err
+ }
+
+ return newInotify(dup, !nonblock), nil
+}
+
// InotifyInit creates an inotify instance. The variant
// InotifyInit1() allows flags to access extra functionality.
func InotifyInit() (*Inotify, error) {
diff --git a/inotify/syscall.go b/inotify/syscall.go
index 0a0c2f0..33a10e2 100644
--- a/inotify/syscall.go
+++ b/inotify/syscall.go
@@ -73,3 +73,24 @@ func sys_read(fd inFd, p []byte) (int, error) {
n, err := syscall.Read(int(fd), p)
return n, os.NewSyscallError("read", err)
}
+
+func sys_dupfd_cloexec(fd inFd) (inFd, error) {
+ n, _, errno := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), syscall.F_DUPFD_CLOEXEC, 0)
+ if errno != 0 {
+ return -1, os.NewSyscallError("dupfd_cloexec", errno)
+ }
+ return inFd(n), nil
+}
+
+func sys_setnonblock(fd inFd, nonblocking bool) error {
+ err := syscall.SetNonblock(int(fd), nonblocking)
+ return os.NewSyscallError("setnonblock", err)
+}
+
+func sys_getnonblock(fd inFd) (bool, error) {
+ flag, _, errno := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), syscall.F_GETFL, 0)
+ if errno != 0 {
+ return false, os.NewSyscallError("getnonblock", errno)
+ }
+ return flag & syscall.O_NONBLOCK != 0, nil
+}