1 /*
2 * gamin.c: glue to the gamin library for access from Python
3 *
4 * See Copyright for the status of this software.
5 *
6 * veillard@redhat.com
7 */
8
9 #include <Python.h>
10 #include <fam.h>
11 #include "config.h"
12
13 #ifdef GAMIN_DEBUG_API
14 int FAMDebug(FAMConnection *fc, const char *filename, FAMRequest * fr,
15 void *userData);
16 #endif
17
18 void init_gamin(void);
19
20 static FAMConnection **connections = NULL;
21 static int nb_connections = 0;
22 static int max_connections = 0;
23
24 static FAMRequest **requests = NULL;
25 static int nb_requests = 0;
26 static int max_requests = 0;
27
28 static int
get_connection(void)29 get_connection(void) {
30 int i;
31
32 if (connections == NULL) {
33 max_connections = 10;
34 connections = (FAMConnection **) malloc(max_connections *
35 sizeof(FAMConnection *));
36 if (connections == NULL) {
37 max_connections = 0;
38 return(-1);
39 }
40 memset(connections, 0, max_connections * sizeof(FAMConnection *));
41 }
42 for (i = 0;i < max_connections;i++)
43 if (connections[i] == NULL)
44 break;
45 if (i >= max_connections) {
46 FAMConnection **tmp;
47
48 tmp = (FAMConnection **) realloc(connections, max_connections * 2 *
49 sizeof(FAMConnection *));
50 if (tmp == NULL)
51 return(-1);
52 memset(&tmp[max_connections], 0,
53 max_connections * sizeof(FAMConnection *));
54 max_connections *= 2;
55 connections = tmp;
56 }
57 connections[i] = (FAMConnection *) malloc(sizeof(FAMConnection));
58 if (connections[i] == NULL)
59 return(-1);
60 nb_connections++;
61 return(i);
62 }
63
64 static int
release_connection(int no)65 release_connection(int no) {
66 if ((no < 0) || (no >= max_connections))
67 return(-1);
68 if (connections[no] == NULL)
69 return(-1);
70 free(connections[no]);
71 connections[no] = NULL;
72 nb_connections--;
73 return(0);
74 }
75
76 static FAMConnection *
check_connection(int no)77 check_connection(int no) {
78 if ((no < 0) || (no >= max_connections))
79 return(NULL);
80 return(connections[no]);
81 }
82
83 static int
get_request(void)84 get_request(void) {
85 int i;
86
87 if (requests == NULL) {
88 max_requests = 10;
89 requests = (FAMRequest **) malloc(max_requests *
90 sizeof(FAMRequest *));
91 if (requests == NULL) {
92 max_requests = 0;
93 return(-1);
94 }
95 memset(requests, 0, max_requests * sizeof(FAMRequest *));
96 }
97 for (i = 0;i < max_requests;i++)
98 if (requests[i] == NULL)
99 break;
100 if (i >= max_requests) {
101 FAMRequest **tmp;
102
103 tmp = (FAMRequest **) realloc(requests, max_requests * 2 *
104 sizeof(FAMRequest *));
105 if (tmp == NULL)
106 return(-1);
107 memset(&tmp[max_requests], 0,
108 max_requests * sizeof(FAMRequest *));
109 max_requests *= 2;
110 requests = tmp;
111 }
112 requests[i] = (FAMRequest *) malloc(sizeof(FAMRequest));
113 if (requests[i] == NULL)
114 return(-1);
115 nb_requests++;
116 return(i);
117 }
118
119 static int
release_request(int no)120 release_request(int no) {
121 if ((no < 0) || (no >= max_requests))
122 return(-1);
123 if (requests[no] == NULL)
124 return(-1);
125 free(requests[no]);
126 requests[no] = NULL;
127 nb_requests--;
128 return(0);
129 }
130
131 static FAMRequest *
check_request(int no)132 check_request(int no) {
133 if ((no < 0) || (no >= max_requests))
134 return(NULL);
135 return(requests[no]);
136 }
137
fam_connect(void)138 static int fam_connect(void) {
139 int ret;
140 int no = get_connection();
141 FAMConnection *conn;
142
143 if (no < 0)
144 return(-1);
145 conn = connections[no];
146 if (conn == NULL)
147 return(-1);
148 ret = FAMOpen2(conn, "gamin-python");
149 if (ret < 0) {
150 release_connection(no);
151 return(ret);
152 }
153 return(no);
154 }
155
156 static int
call_internal_callback(PyObject * self,const char * filename,FAMCodes event)157 call_internal_callback(PyObject *self, const char *filename, FAMCodes event) {
158 PyObject *ret;
159
160 if ((self == NULL) || (filename == NULL))
161 return(-1);
162 /* fprintf(stderr, "call_internal_callback(%p)\n", self); */
163 ret = PyEval_CallMethod(self, (char *) "_internal_callback",
164 (char *) "(zi)", filename, (int) event);
165 if (ret != NULL) {
166 Py_DECREF(ret);
167 #if 0
168 } else {
169 fprintf(stderr, "call_internal_callback() failed\n");
170 #endif
171 }
172 return(0);
173 }
174
175 static PyObject *
gamin_Errno(PyObject * self,PyObject * args)176 gamin_Errno(PyObject *self, PyObject * args) {
177 return(PyInt_FromLong(FAMErrno));
178 }
179
180 static PyObject *
gamin_MonitorConnect(PyObject * self,PyObject * args)181 gamin_MonitorConnect(PyObject *self, PyObject * args) {
182 int ret;
183
184 ret = fam_connect();
185 if (ret < 0) {
186 return(PyInt_FromLong(-1));
187 }
188 return(PyInt_FromLong(ret));
189 }
190
191 static PyObject *
gamin_GetFd(PyObject * self,PyObject * args)192 gamin_GetFd(PyObject *self, PyObject * args) {
193 int no;
194 FAMConnection *conn;
195
196 if (!PyArg_ParseTuple(args, (char *)"i:GetFd", &no))
197 return(NULL);
198
199 conn = check_connection(no);
200 if (conn == NULL) {
201 return(PyInt_FromLong(-1));
202 }
203 return(PyInt_FromLong(FAMCONNECTION_GETFD(conn)));
204 }
205
206 static PyObject *
gamin_MonitorClose(PyObject * self,PyObject * args)207 gamin_MonitorClose(PyObject *self, PyObject * args) {
208 int no;
209 int ret;
210
211 if (!PyArg_ParseTuple(args, (char *)"i:MonitorClose", &no))
212 return(NULL);
213
214 ret = release_connection(no);
215 return(PyInt_FromLong(ret));
216 }
217
218 static PyObject *
gamin_ProcessOneEvent(PyObject * self,PyObject * args)219 gamin_ProcessOneEvent(PyObject *self, PyObject * args) {
220 int ret;
221 FAMEvent fe;
222 int no;
223 FAMConnection *conn;
224
225 if (!PyArg_ParseTuple(args, (char *)"i:ProcessOneEvent", &no))
226 return(NULL);
227
228 conn = check_connection(no);
229 if (conn == NULL) {
230 return(PyInt_FromLong(-1));
231 }
232
233 ret = FAMNextEvent(conn, &fe);
234 if (ret < 0) {
235 return(PyInt_FromLong(-1));
236 }
237 call_internal_callback(fe.userdata, &fe.filename[0], fe.code);
238
239 return(PyInt_FromLong(ret));
240 }
241
242 static PyObject *
gamin_ProcessEvents(PyObject * self,PyObject * args)243 gamin_ProcessEvents(PyObject *self, PyObject * args) {
244 int ret;
245 int nb = 0;
246 FAMEvent fe;
247 int no;
248 FAMConnection *conn;
249
250 if (!PyArg_ParseTuple(args, (char *)"i:ProcessOneEvent", &no))
251 return(NULL);
252
253 conn = check_connection(no);
254 if (conn == NULL) {
255 return(PyInt_FromLong(-1));
256 }
257
258 do {
259 ret = FAMPending(conn);
260 if (ret < 0)
261 return(PyInt_FromLong(-1));
262 if (ret == 0)
263 break;
264 ret = FAMNextEvent(conn, &fe);
265 if (ret < 0)
266 return(PyInt_FromLong(-1));
267 call_internal_callback(fe.userdata, &fe.filename[0], fe.code);
268 nb++;
269 } while (ret >= 0);
270
271 return(PyInt_FromLong(nb));
272 }
273
274 static PyObject *
gamin_EventPending(PyObject * self,PyObject * args)275 gamin_EventPending(PyObject *self, PyObject * args) {
276 int no;
277 FAMConnection *conn;
278
279 if (!PyArg_ParseTuple(args, (char *)"i:ProcessOneEvent", &no))
280 return(NULL);
281
282 conn = check_connection(no);
283 if (conn == NULL) {
284 return(PyInt_FromLong(-1));
285 }
286 return(PyInt_FromLong(FAMPending(conn)));
287 }
288
289 static PyObject *
gamin_MonitorNoExists(PyObject * self,PyObject * args)290 gamin_MonitorNoExists(PyObject *self, PyObject * args) {
291 int no;
292 FAMConnection *conn;
293
294 if (!PyArg_ParseTuple(args, (char *)"i:MonitorNoExists", &no))
295 return(NULL);
296
297 conn = check_connection(no);
298 if (conn == NULL) {
299 return(PyInt_FromLong(-1));
300 }
301 return(PyInt_FromLong(FAMNoExists(conn)));
302 }
303
304 static PyObject *
gamin_MonitorDirectory(PyObject * self,PyObject * args)305 gamin_MonitorDirectory(PyObject *self, PyObject * args) {
306 PyObject *userdata;
307 char * filename;
308 int ret;
309 int noreq;
310 int no;
311 FAMConnection *conn;
312 FAMRequest *request;
313
314 if (!PyArg_ParseTuple(args, (char *)"izO:MonitorDirectory",
315 &no, &filename, &userdata))
316 return(NULL);
317
318 conn = check_connection(no);
319 if (conn == NULL) {
320 return(PyInt_FromLong(-1));
321 }
322 noreq = get_request();
323 if (noreq < 0) {
324 return(PyInt_FromLong(-1));
325 }
326 request = check_request(noreq);
327
328 ret = FAMMonitorDirectory(conn, filename, request, userdata);
329 if (ret < 0) {
330 release_request(noreq);
331 return(PyInt_FromLong(-1));
332 }
333 return(PyInt_FromLong(noreq));
334 }
335
336 static PyObject *
gamin_MonitorFile(PyObject * self,PyObject * args)337 gamin_MonitorFile(PyObject *self, PyObject * args) {
338 PyObject *userdata;
339 char * filename;
340 int ret;
341 int noreq;
342 int no;
343 FAMConnection *conn;
344 FAMRequest *request;
345
346 if (!PyArg_ParseTuple(args, (char *)"izO:MonitorFile",
347 &no, &filename, &userdata))
348 return(NULL);
349
350 conn = check_connection(no);
351 if (conn == NULL) {
352 return(PyInt_FromLong(-1));
353 }
354 noreq = get_request();
355 if (noreq < 0) {
356 return(PyInt_FromLong(-1));
357 }
358 request = check_request(noreq);
359
360 ret = FAMMonitorFile(conn, filename, request, userdata);
361 if (ret < 0) {
362 release_request(noreq);
363 return(PyInt_FromLong(-1));
364 }
365 return(PyInt_FromLong(noreq));
366 }
367
368 static PyObject *
gamin_MonitorCancel(PyObject * self,PyObject * args)369 gamin_MonitorCancel(PyObject *self, PyObject * args) {
370 int ret;
371 int noreq;
372 int no;
373 FAMConnection *conn;
374 FAMRequest *request;
375
376 if (!PyArg_ParseTuple(args, (char *)"ii:MonitorCancel",
377 &no, &noreq))
378 return(NULL);
379
380 conn = check_connection(no);
381 if (conn == NULL) {
382 return(PyInt_FromLong(-1));
383 }
384 request = check_request(noreq);
385 if (request == NULL) {
386 return(PyInt_FromLong(-1));
387 }
388
389 ret = FAMCancelMonitor(conn, request);
390 if (ret < 0) {
391 release_request(noreq);
392 return(PyInt_FromLong(-1));
393 }
394 return(PyInt_FromLong(ret));
395 }
396
397 #ifdef GAMIN_DEBUG_API
398 static PyObject *
gamin_MonitorDebug(PyObject * self,PyObject * args)399 gamin_MonitorDebug(PyObject *self, PyObject * args) {
400 PyObject *userdata;
401 char * filename;
402 int ret;
403 int noreq;
404 int no;
405 FAMConnection *conn;
406 FAMRequest *request;
407
408 if (!PyArg_ParseTuple(args, (char *)"izO:MonitorDebug",
409 &no, &filename, &userdata))
410 return(NULL);
411
412 conn = check_connection(no);
413 if (conn == NULL) {
414 return(PyInt_FromLong(-1));
415 }
416 noreq = get_request();
417 if (noreq < 0) {
418 return(PyInt_FromLong(-1));
419 }
420 request = check_request(noreq);
421
422 ret = FAMDebug(conn, filename, request, userdata);
423 if (ret < 0) {
424 release_request(noreq);
425 return(PyInt_FromLong(-1));
426 }
427 return(PyInt_FromLong(noreq));
428 }
429 #endif
430
431 static PyMethodDef gaminMethods[] = {
432 {(char *)"MonitorConnect", gamin_MonitorConnect, METH_VARARGS, NULL},
433 {(char *)"MonitorDirectory", gamin_MonitorDirectory, METH_VARARGS, NULL},
434 {(char *)"MonitorFile", gamin_MonitorFile, METH_VARARGS, NULL},
435 {(char *)"MonitorCancel", gamin_MonitorCancel, METH_VARARGS, NULL},
436 {(char *)"MonitorNoExists", gamin_MonitorNoExists, METH_VARARGS, NULL},
437 {(char *)"EventPending", gamin_EventPending, METH_VARARGS, NULL},
438 {(char *)"ProcessOneEvent", gamin_ProcessOneEvent, METH_VARARGS, NULL},
439 {(char *)"ProcessEvents", gamin_ProcessEvents, METH_VARARGS, NULL},
440 {(char *)"MonitorClose", gamin_MonitorClose, METH_VARARGS, NULL},
441 {(char *)"GetFd", gamin_GetFd, METH_VARARGS, NULL},
442 {(char *)"Errno", gamin_Errno, METH_VARARGS, NULL},
443 #ifdef GAMIN_DEBUG_API
444 {(char *)"MonitorDebug", gamin_MonitorDebug, METH_VARARGS, NULL},
445 #endif
446 {NULL, NULL, 0, NULL}
447 };
448
449 void
init_gamin(void)450 init_gamin(void)
451 {
452 static int initialized = 0;
453
454 if (initialized != 0)
455 return;
456
457 /* intialize the python extension module */
458 Py_InitModule((char *) "_gamin", gaminMethods);
459
460 initialized = 1;
461 }
462
463