1 /*******************************************************************************
2 
3     Linux File System event file descriptor.
4     See http://man7.org/linux/man-pages/man7/inotify.7.html
5 
6     Copyright:
7         Copyright (c) 2009-2016 dunnhumby Germany GmbH.
8         All rights reserved.
9 
10     License:
11         Boost Software License Version 1.0. See LICENSE_BOOST.txt for details.
12         Alternatively, this file may be distributed under the terms of the Tango
13         3-Clause BSD License (see LICENSE_BSD.txt for details).
14 
15 *******************************************************************************/
16 
17 module ocean.sys.Inotify;
18 
19 import ocean.text.util.StringC;
20 import ocean.sys.ErrnoException;
21 
22 import core.sys.linux.sys.inotify;
23 
24 import ocean.io.model.IConduit: ISelectable;
25 
26 import ocean.stdc.posix.sys.types: ssize_t;
27 import core.sys.posix.unistd: read, close;
28 import core.stdc.errno: EAGAIN, EWOULDBLOCK, errno;
29 
30 
31 
32 /*******************************************************************************
33 
34     Inotify fd class
35 
36 *******************************************************************************/
37 
38 public class Inotify : ISelectable
39 {
40     import ocean.sys.CloseOnExec;
41 
42     /***************************************************************************
43 
44         Exception class, thrown on errors with inotify functions
45 
46     ***************************************************************************/
47 
48     static public class InotifyException : ErrnoException { }
49 
50 
51     /***************************************************************************
52 
53         Inotify exception instance.
54 
55     ***************************************************************************/
56 
57     private InotifyException e;
58 
59 
60     /***************************************************************************
61 
62         Integer file descriptor provided by the operating system and used to
63         manage the Inotify instance.
64 
65     ***************************************************************************/
66 
67     private int fd;
68 
69 
70     /***************************************************************************
71 
72         Struct that enables the reading of events from iterator.
73 
74     ***************************************************************************/
75 
76     private static struct EventsIterator
77     {
78         /***********************************************************************
79 
80             The inotify instance which the events will be fetched
81 
82         ***********************************************************************/
83 
84         private Inotify outer;
85 
86 
87         /***********************************************************************
88 
89             Iterator Operator overload - Iterates per inotify event fetched from
90             the inotify instance of this struct.
91 
92             Returns:
93                 Result of each iteration
94 
95             Throws:
96                 upon failure to read inotify events
97 
98         ***********************************************************************/
99 
100         public int opApply ( scope int delegate ( ref inotify_event* ) dg )
101         {
102             //255 is the default max filename length in linux)
103             char[inotify_event.sizeof + 255 + 1] buffer_temp;
104             void[] buffer = buffer_temp;
105 
106             int result = 0;
107 
108             ssize_t read_bytes;
109             read_loop: while ( (read_bytes = read((&this).outer.fd, buffer.ptr, buffer.length)) > 0 )
110             {
111                 inotify_event *i_event;
112 
113                 for ( uint i; i < read_bytes; i += inotify_event.sizeof + i_event.len  )
114                 {
115                     i_event = cast(inotify_event*) &buffer[i];
116                     result = dg(i_event);
117 
118                     if (result)
119                     {
120                         break read_loop;
121                     }
122                 }
123             }
124 
125             return result;
126         }
127     }
128 
129 
130     /***************************************************************************
131 
132         Constructor.
133 
134         Throws:
135             upon failure to create a inotify instance (fd)
136 
137     ***************************************************************************/
138 
139     public this ( )
140     {
141         this(new InotifyException);
142     }
143 
144 
145     /***************************************************************************
146 
147         Constructor. Creates a Inotify file descriptor.
148 
149         Params:
150             e = inotify exception instance to be used internally
151 
152         Throws:
153             upon failure to create a inotify instance (fd)
154 
155     ***************************************************************************/
156 
157     public this ( InotifyException e )
158     {
159         this.e = e;
160 
161         this.fd = this.e.enforceRet!(inotify_init1)(&verify)
162             .call(setCloExec(IN_NONBLOCK, IN_CLOEXEC));
163     }
164 
165 
166     /***************************************************************************
167 
168         Required by ISelectable interface.
169 
170         Returns:
171             file descriptor used to manage inotify event
172 
173     ***************************************************************************/
174 
175     public Handle fileHandle ( )
176     {
177         return cast(Handle)this.fd;
178     }
179 
180 
181     /***************************************************************************
182 
183         Manipulates  the  "watch  list"  associated  with an inotify instance.
184         Each item ("watch") in the watch list specifies the pathname of a file
185         or directory, along with some set of events that the kernel should
186         monitor for the file referred to by that pathname. Either creates a new
187         watch item, or modifies an existing watch. Each watch has a unique
188         "watch descriptor", which is returned by this function.
189 
190         params:
191             path   = File path to watch (directories are also supported)
192             events = Inotify events that will be watched (bit mask)
193 
194         return:
195              Unique "watch descriptor"
196 
197         Throws:
198             upon failure to add the "watch descriptor"
199 
200     ***************************************************************************/
201 
202     public uint addWatch ( char[] path, uint events )
203     {
204         return cast(uint) this.e.enforceRet!(.inotify_add_watch)(&verify)
205                       .call(this.fd, StringC.toCString(path), events);
206     }
207 
208 
209     /***************************************************************************
210 
211         Removes the provided item from the inotify instance.
212 
213         Returns:
214             wd = "watch descriptor" that was removed (is no longer watched)
215 
216         Throws:
217             upon failure to unwatch the "watch descriptor"
218 
219     ***************************************************************************/
220 
221     public uint rmWatch ( int wd )
222     {
223         return cast(uint) this.e.enforceRet!(.inotify_rm_watch)(&verify).call(this.fd, wd);
224     }
225 
226 
227     /***************************************************************************
228 
229         Reads the events associated to the inotify file descriptor, and return
230         in the form of iterator
231 
232         Returns:
233             EventsIterator containing all inotify events
234 
235         Throws:
236             upon failure to read inotify events
237 
238     ***************************************************************************/
239 
240     public EventsIterator readEvents ( )
241     {
242         EventsIterator it;
243         it.outer = this;
244 
245         return it;
246     }
247 
248 
249     /***************************************************************************
250 
251         Handy function to verify the success of system calls
252 
253         Params:
254             fd = returned code by the system call
255 
256         Returns:
257             True in case of success. False, otherwise.
258 
259     ***************************************************************************/
260 
261     private static bool verify ( int fd )
262     {
263         return fd >= 0;
264     }
265 
266 
267     /***************************************************************************
268 
269         Destructor. Destroys the inotify file descriptor.
270 
271     ***************************************************************************/
272 
273     ~this ( )
274     {
275         close(this.fd);
276     }
277 }