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 }