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