427ff7329ea4e8b2192100e17a77ff0e7561c736
[cl-inotify.git] / inotify.lisp
1 (in-package #:cl-notify)
2
3 (defbitfield (inotify-flags :uint32)
4   (:in-access #.in-access)
5   (:in-modify #.in-modify)
6   (:in-attrib #.in-attrib)
7   (:in-close-write #.in-close-write)
8   (:in-close-nowrite #.in-close-nowrite)
9   (:in-close #.in-close)
10   (:in-open #.in-open)
11   (:in-moved-from #.in-moved-from)
12   (:in-moved-to #.in-moved-to)
13   (:in-move #.in-move)
14   (:in-create #.in-create)
15   (:in-delete #.in-delete)
16   (:in-delete-self #.in-delete-self)
17   (:in-move-self #.in-move-self)
18   (:in-unmount #.in-unmount)
19   (:in-q-overflow #.in-q-overflow)
20   (:in-ignored #.in-ignored)
21   (:in-onlydir #.in-onlydir)
22   (:in-dont-follow #.in-dont-follow)
23   (:in-mask-add #.in-mask-add)
24   (:in-isdir #.in-isdir)
25   (:in-oneshot #.in-oneshot)
26   (:in-all-events #.in-all-events))
27
28 (defcfun "inotify_init" :int)
29
30 (defcfun "inotify_add_watch" :int
31   (fd :int)
32   (pathname :string)
33   (mask inotify-flags))
34
35 (defcfun "inotify_rm_watch" :int
36   (fd :int)
37   (wd :int))
38
39 (binary-types:define-signed int #.(cffi:foreign-type-size :int))
40
41 (binary-types:define-binary-struct inotify-event ()
42   (wd 0 :binary-type int)
43   (mask 0 :binary-type binary-types:u32)
44   (cookie 0 :binary-type binary-types:u32)
45   (name NIL))
46
47 (defstruct (inotify-instance (:constructor make-inotify-instance (fd stream)))
48   fd
49   stream)
50
51 (defun init-endian ()
52   (setf binary-types:*endian*
53         #+little-endian :little-endian
54         #+big-endian :big-endian
55         #-(or little-endian big-endian) (error "unknown endianess")))
56
57 (init-endian)
58
59 (defun inotify-read-raw-event (stream)
60   (let* ((event (binary-types:read-binary 'inotify-event stream))
61          (len (binary-types:read-binary 'binary-types:u32 stream)))
62     (when (> len 0)
63       (with-slots (name) event
64         (setf name
65               (binary-types:read-binary-string stream :size len :terminators '(0)))))
66     event))
67
68 (defun inotify-read-event (stream)
69   (let ((event (inotify-read-raw-event stream)))
70     (with-slots (mask) event
71       (setf mask (foreign-bitfield-symbols 'inotify-flags mask)))
72     event))
73
74 (defun make-notify ()
75   (let* ((fd (inotify-init)))
76     (when (< fd 0)
77       (error "inotify_init failed: ~A" fd))
78     ;; file descriptor is collected with auto-close
79     (make-inotify-instance
80      fd
81      (sb-sys:make-fd-stream fd
82                             :input T
83                             :element-type '(unsigned-byte 8)
84                             :name (format NIL "inotify event queue ~A" fd)
85                             :auto-close T))))
86
87 (defun close-notify (notify)
88   (close (inotify-instance-stream notify))
89   (values))
90
91 (defun watch (notify pathname flags)
92   (let ((path (princ-to-string pathname))
93         result)
94     (setf result
95           (inotify-add-watch (inotify-instance-fd notify)
96                              path
97                              (if (listp flags)
98                                  (foreign-bitfield-value 'inotify-flags flags)
99                                  flags)))
100     (when (< result 0)
101       (error "inotify_add_watch failed: ~A" result))
102     result))
103
104 (defun unwatch (notify handle)
105   (let ((result (inotify-rm-watch (inotify-instance-fd notify) handle)))
106     (when (< result 0)
107       (error "inotify_rm_watch failed: ~A" result))
108     (values)))