1 |
//@+leo-ver=4 |
2 |
//@+node:@file _fusemodule.c |
3 |
//@@language c |
4 |
/* |
5 |
Copyright (C) 2001 Jeff Epler <jepler@unpythonic.dhs.org> |
6 |
|
7 |
This program can be distributed under the terms of the GNU GPL. |
8 |
See the file COPYING. |
9 |
*/ |
10 |
|
11 |
//@+others |
12 |
//@+node:includes |
13 |
#include <Python.h> |
14 |
#include "fuse.h" |
15 |
#include <time.h> |
16 |
//@-node:includes |
17 |
//@+node:globals |
18 |
|
19 |
static PyObject *getattr_cb=NULL, *readlink_cb=NULL, *getdir_cb=NULL, |
20 |
*mknod_cb=NULL, *mkdir_cb=NULL, *unlink_cb=NULL, *rmdir_cb=NULL, |
21 |
*symlink_cb=NULL, *rename_cb=NULL, *link_cb=NULL, *chmod_cb=NULL, |
22 |
*chown_cb=NULL, *truncate_cb=NULL, *utime_cb=NULL, |
23 |
*open_cb=NULL, *read_cb=NULL, *write_cb=NULL, *release_cb=NULL, |
24 |
*statfs_cb=NULL, *fsync_cb=NULL |
25 |
; |
26 |
//@-node:globals |
27 |
//@+node:PROLOGUE |
28 |
#define PROLOGUE \ |
29 |
int ret = -EINVAL; \ |
30 |
if (!v) { PyErr_Print(); goto OUT; } \ |
31 |
if(v == Py_None) { ret = 0; goto OUT_DECREF; } \ |
32 |
if(PyInt_Check(v)) { ret = PyInt_AsLong(v); goto OUT_DECREF; } |
33 |
|
34 |
//@-node:PROLOGUE |
35 |
//@+node:EPILOGUE |
36 |
#define EPILOGUE \ |
37 |
OUT_DECREF: \ |
38 |
Py_DECREF(v); \ |
39 |
OUT: \ |
40 |
return ret; |
41 |
//@-node:EPILOGUE |
42 |
//@+node:getattr_func |
43 |
|
44 |
/* |
45 |
* Local Variables: |
46 |
* indent-tabs-mode: t |
47 |
* c-basic-offset: 8 |
48 |
* End: |
49 |
* Changed by David McNab (david@rebirthing.co.nz) to work with recent pythons. |
50 |
* Namely, replacing PyTuple_* with PySequence_*, and checking numerical values |
51 |
* with both PyInt_Check and PyLong_Check. |
52 |
*/ |
53 |
|
54 |
static int getattr_func(const char *path, struct stat *st) |
55 |
{ |
56 |
int i; |
57 |
PyObject *v = PyObject_CallFunction(getattr_cb, "s", path); |
58 |
PROLOGUE |
59 |
|
60 |
if(!PySequence_Check(v)) { goto OUT_DECREF; } |
61 |
if(PySequence_Size(v) < 10) { goto OUT_DECREF; } |
62 |
for(i=0; i<10; i++) |
63 |
{ |
64 |
PyObject *tmp = PySequence_GetItem(v, i); |
65 |
if (!(PyInt_Check(tmp) || PyLong_Check(tmp))) goto OUT_DECREF; |
66 |
} |
67 |
|
68 |
st->st_mode = PyInt_AsLong(PySequence_GetItem(v, 0)); |
69 |
st->st_ino = PyInt_AsLong(PySequence_GetItem(v, 1)); |
70 |
st->st_dev = PyInt_AsLong(PySequence_GetItem(v, 2)); |
71 |
st->st_nlink= PyInt_AsLong(PySequence_GetItem(v, 3)); |
72 |
st->st_uid = PyInt_AsLong(PySequence_GetItem(v, 4)); |
73 |
st->st_gid = PyInt_AsLong(PySequence_GetItem(v, 5)); |
74 |
st->st_size = PyInt_AsLong(PySequence_GetItem(v, 6)); |
75 |
st->st_atime= PyInt_AsLong(PySequence_GetItem(v, 7)); |
76 |
st->st_mtime= PyInt_AsLong(PySequence_GetItem(v, 8)); |
77 |
st->st_ctime= PyInt_AsLong(PySequence_GetItem(v, 9)); |
78 |
|
79 |
/* Fill in fields not provided by Python lstat() */ |
80 |
st->st_blksize= 4096; |
81 |
st->st_blocks= (st->st_size + 511)/512; |
82 |
st->st_ino = 0; |
83 |
|
84 |
ret = 0; |
85 |
EPILOGUE |
86 |
} |
87 |
|
88 |
//@-node:getattr_func |
89 |
//@+node:readlink_func |
90 |
|
91 |
static int readlink_func(const char *path, char *link, size_t size) |
92 |
{ |
93 |
PyObject *v = PyObject_CallFunction(readlink_cb, "s", path); |
94 |
char *s; |
95 |
PROLOGUE |
96 |
|
97 |
if(!PyString_Check(v)) { ret = -EINVAL; goto OUT_DECREF; } |
98 |
s = PyString_AsString(v); |
99 |
strncpy(link, s, size); |
100 |
link[size-1] = '\0'; |
101 |
ret = 0; |
102 |
|
103 |
EPILOGUE |
104 |
} |
105 |
//@-node:readlink_func |
106 |
//@+node:getdir_add_entry |
107 |
|
108 |
static int getdir_add_entry(PyObject *w, fuse_dirh_t dh, fuse_dirfil_t df) |
109 |
{ |
110 |
PyObject *o0; |
111 |
PyObject *o1; |
112 |
int ret = -EINVAL; |
113 |
|
114 |
if(!PySequence_Check(w)) { |
115 |
printf("getdir item not sequence\n"); |
116 |
goto out; |
117 |
} |
118 |
if(PySequence_Length(w) != 2) { |
119 |
printf("getdir item not len 2\n"); |
120 |
goto out; |
121 |
} |
122 |
o0 = PySequence_GetItem(w, 0); |
123 |
o1 = PySequence_GetItem(w, 1); |
124 |
|
125 |
if(!PyString_Check(o0)) { |
126 |
printf("getdir item[0] not string\n"); |
127 |
goto out_decref; |
128 |
} |
129 |
if(!PyInt_Check(o1)) { |
130 |
printf("getdir item[1] not int\n"); |
131 |
goto out_decref; |
132 |
} |
133 |
|
134 |
ret = df(dh, PyString_AsString(o0), PyInt_AsLong(o1)); |
135 |
|
136 |
out_decref: |
137 |
Py_DECREF(o0); |
138 |
Py_DECREF(o1); |
139 |
|
140 |
out: |
141 |
return ret; |
142 |
} |
143 |
//@-node:getdir_add_entry |
144 |
//@+node:getdir_func |
145 |
|
146 |
static int getdir_func(const char *path, fuse_dirh_t dh, fuse_dirfil_t df) |
147 |
{ |
148 |
PyObject *v = PyObject_CallFunction(getdir_cb, "s", path); |
149 |
int i; |
150 |
PROLOGUE |
151 |
|
152 |
if(!PySequence_Check(v)) { |
153 |
printf("getdir_func not sequence\n"); |
154 |
goto OUT_DECREF; |
155 |
} |
156 |
for(i=0; i < PySequence_Length(v); i++) { |
157 |
PyObject *w = PySequence_GetItem(v, i); |
158 |
ret = getdir_add_entry(w, dh, df); |
159 |
Py_DECREF(w); |
160 |
if(ret != 0) |
161 |
goto OUT_DECREF; |
162 |
} |
163 |
ret = 0; |
164 |
|
165 |
EPILOGUE |
166 |
} |
167 |
//@-node:getdir_func |
168 |
//@+node:mknod_func |
169 |
|
170 |
static int mknod_func(const char *path, mode_t m, dev_t d) |
171 |
{ |
172 |
PyObject *v = PyObject_CallFunction(mknod_cb, "sii", path, m, d); |
173 |
PROLOGUE |
174 |
EPILOGUE |
175 |
} |
176 |
//@-node:mknod_func |
177 |
//@+node:mkdir_func |
178 |
|
179 |
static int mkdir_func(const char *path, mode_t m) |
180 |
{ |
181 |
PyObject *v = PyObject_CallFunction(mkdir_cb, "si", path, m); |
182 |
PROLOGUE |
183 |
EPILOGUE |
184 |
} |
185 |
//@-node:mkdir_func |
186 |
//@+node:unlink_func |
187 |
|
188 |
static int unlink_func(const char *path) |
189 |
{ |
190 |
PyObject *v = PyObject_CallFunction(unlink_cb, "s", path); |
191 |
PROLOGUE |
192 |
EPILOGUE |
193 |
} |
194 |
//@-node:unlink_func |
195 |
//@+node:rmdir_func |
196 |
|
197 |
static int rmdir_func(const char *path) |
198 |
{ |
199 |
PyObject *v = PyObject_CallFunction(rmdir_cb, "s", path); |
200 |
PROLOGUE |
201 |
EPILOGUE |
202 |
} |
203 |
//@-node:rmdir_func |
204 |
//@+node:symlink_func |
205 |
|
206 |
static int symlink_func(const char *path, const char *path1) |
207 |
{ |
208 |
PyObject *v = PyObject_CallFunction(symlink_cb, "ss", path, path1); |
209 |
PROLOGUE |
210 |
EPILOGUE |
211 |
} |
212 |
//@-node:symlink_func |
213 |
//@+node:rename_func |
214 |
|
215 |
static int rename_func(const char *path, const char *path1) |
216 |
{ |
217 |
PyObject *v = PyObject_CallFunction(rename_cb, "ss", path, path1); |
218 |
PROLOGUE |
219 |
EPILOGUE |
220 |
} |
221 |
//@-node:rename_func |
222 |
//@+node:link_func |
223 |
|
224 |
static int link_func(const char *path, const char *path1) |
225 |
{ |
226 |
PyObject *v = PyObject_CallFunction(link_cb, "ss", path, path1); |
227 |
PROLOGUE |
228 |
EPILOGUE |
229 |
} |
230 |
//@-node:link_func |
231 |
//@+node:chmod_func |
232 |
|
233 |
static int chmod_func(const char *path, mode_t m) |
234 |
{ |
235 |
PyObject *v = PyObject_CallFunction(chmod_cb, "si", path, m); |
236 |
PROLOGUE |
237 |
EPILOGUE |
238 |
} |
239 |
//@-node:chmod_func |
240 |
//@+node:chown_func |
241 |
|
242 |
static int chown_func(const char *path, uid_t u, gid_t g) |
243 |
{ |
244 |
PyObject *v = PyObject_CallFunction(chown_cb, "sii", path, u, g); |
245 |
PROLOGUE |
246 |
EPILOGUE |
247 |
} |
248 |
//@-node:chown_func |
249 |
//@+node:truncate_func |
250 |
|
251 |
static int truncate_func(const char *path, off_t o) |
252 |
{ |
253 |
PyObject *v = PyObject_CallFunction(truncate_cb, "si", path, o); |
254 |
PROLOGUE |
255 |
EPILOGUE |
256 |
} |
257 |
//@-node:truncate_func |
258 |
//@+node:utime_func |
259 |
|
260 |
static int utime_func(const char *path, struct utimbuf *u) { |
261 |
int actime = u ? u->actime : time(NULL); |
262 |
int modtime = u ? u->modtime : actime; |
263 |
PyObject *v = PyObject_CallFunction(utime_cb, "s(ii)", |
264 |
path, actime, modtime); |
265 |
PROLOGUE |
266 |
EPILOGUE |
267 |
} |
268 |
//@-node:utime_func |
269 |
//@+node:read_func |
270 |
|
271 |
static int read_func(const char *path, char *buf, size_t s, off_t off) |
272 |
{ |
273 |
PyObject *v = PyObject_CallFunction(read_cb, "sii", path, s, off); |
274 |
PROLOGUE |
275 |
if(PyString_Check(v)) { |
276 |
if(PyString_Size(v) > s) goto OUT_DECREF; |
277 |
memcpy(buf, PyString_AsString(v), PyString_Size(v)); |
278 |
ret = PyString_Size(v); |
279 |
} |
280 |
EPILOGUE |
281 |
} |
282 |
//@-node:read_func |
283 |
//@+node:write_func |
284 |
|
285 |
static int write_func(const char *path, const char *buf, size_t t, off_t off) |
286 |
{ |
287 |
PyObject *v = PyObject_CallFunction(write_cb,"ss#i", path, buf, t, off); |
288 |
PROLOGUE |
289 |
EPILOGUE |
290 |
} |
291 |
//@-node:write_func |
292 |
//@+node:open_func |
293 |
|
294 |
static int open_func(const char *path, int mode) |
295 |
{ |
296 |
PyObject *v = PyObject_CallFunction(open_cb, "si", path, mode); |
297 |
PROLOGUE |
298 |
printf("open_func: path=%s\n", path); |
299 |
EPILOGUE |
300 |
} |
301 |
//@-node:open_func |
302 |
//@+node:release_func |
303 |
static int release_func(const char *path, int flags) |
304 |
{ |
305 |
PyObject *v = PyObject_CallFunction(release_cb, "si", path, flags); |
306 |
PROLOGUE |
307 |
//printf("release_func: path=%s flags=%d\n", path, flags); |
308 |
EPILOGUE |
309 |
} |
310 |
//@-node:release_func |
311 |
//@+node:statfs_func |
312 |
static int statfs_func(struct fuse_statfs *fst) |
313 |
{ |
314 |
int i; |
315 |
long retvalues[6]; |
316 |
PyObject *v = PyObject_CallFunction(statfs_cb, ""); |
317 |
PROLOGUE |
318 |
|
319 |
if (!PySequence_Check(v)) |
320 |
{ goto OUT_DECREF; } |
321 |
if (PySequence_Size(v) < 6) |
322 |
{ goto OUT_DECREF; } |
323 |
for(i=0; i<6; i++) |
324 |
{ |
325 |
PyObject *tmp = PySequence_GetItem(v, i); |
326 |
retvalues[i] = PyInt_Check(tmp) |
327 |
? PyInt_AsLong(tmp) |
328 |
: (PyLong_Check(tmp) |
329 |
? PyLong_AsLong(tmp) |
330 |
: 0); |
331 |
} |
332 |
|
333 |
fst->block_size = retvalues[0]; |
334 |
fst->blocks = retvalues[1]; |
335 |
fst->blocks_free = retvalues[2]; |
336 |
fst->files = retvalues[3]; |
337 |
fst->files_free = retvalues[4]; |
338 |
fst->namelen = retvalues[5]; |
339 |
ret = 0; |
340 |
|
341 |
#ifdef IGNORE_THIS |
342 |
printf("block_size=%ld, blocks=%ld, blocks_free=%ld, files=%ld, files_free=%ld, namelen=%ld\n", |
343 |
retvalues[0], retvalues[1], retvalues[2], retvalues[3], retvalues[4], retvalues[5]); |
344 |
#endif |
345 |
|
346 |
EPILOGUE |
347 |
|
348 |
} |
349 |
|
350 |
//@-node:statfs_func |
351 |
//@+node:fsync_func |
352 |
static int fsync_func(const char *path, int isfsyncfile) |
353 |
{ |
354 |
PyObject *v = PyObject_CallFunction(fsync_cb, "si", path, isfsyncfile); |
355 |
PROLOGUE |
356 |
EPILOGUE |
357 |
} |
358 |
|
359 |
//@-node:fsync_func |
360 |
//@+node:process_cmd |
361 |
|
362 |
static void process_cmd(struct fuse *f, struct fuse_cmd *cmd, void *data) |
363 |
{ |
364 |
PyInterpreterState *interp = (PyInterpreterState *) data; |
365 |
PyThreadState *state; |
366 |
|
367 |
PyEval_AcquireLock(); |
368 |
state = PyThreadState_New(interp); |
369 |
PyThreadState_Swap(state); |
370 |
__fuse_process_cmd(f, cmd); |
371 |
PyThreadState_Clear(state); |
372 |
PyThreadState_Swap(NULL); |
373 |
PyThreadState_Delete(state); |
374 |
PyEval_ReleaseLock(); |
375 |
} |
376 |
//@-node:process_cmd |
377 |
//@+node:pyfuse_loop_mt |
378 |
|
379 |
static void pyfuse_loop_mt(struct fuse *f) |
380 |
{ |
381 |
PyInterpreterState *interp; |
382 |
PyThreadState *save; |
383 |
|
384 |
PyEval_InitThreads(); |
385 |
interp = PyThreadState_Get()->interp; |
386 |
save = PyEval_SaveThread(); |
387 |
__fuse_loop_mt(f, process_cmd, interp); |
388 |
/* Not yet reached: */ |
389 |
PyEval_RestoreThread(save); |
390 |
} |
391 |
//@-node:pyfuse_loop_mt |
392 |
//@+node:Fuse_main |
393 |
|
394 |
|
395 |
static PyObject * |
396 |
Fuse_main(PyObject *self, PyObject *args, PyObject *kw) |
397 |
{ |
398 |
int flags=0; |
399 |
int multithreaded=0; |
400 |
static struct fuse *fuse=NULL; |
401 |
|
402 |
struct fuse_operations op; |
403 |
|
404 |
static char *kwlist[] = { |
405 |
"getattr", "readlink", "getdir", "mknod", |
406 |
"mkdir", "unlink", "rmdir", "symlink", "rename", |
407 |
"link", "chmod", "chown", "truncate", "utime", |
408 |
"open", "read", "write", "release", "statfs", "fsync", |
409 |
"flags", "multithreaded", NULL}; |
410 |
|
411 |
memset(&op, 0, sizeof(op)); |
412 |
|
413 |
if (!PyArg_ParseTupleAndKeywords(args, kw, "|OOOOOOOOOOOOOOOOOOOOii", |
414 |
kwlist, &getattr_cb, &readlink_cb, &getdir_cb, &mknod_cb, |
415 |
&mkdir_cb, &unlink_cb, &rmdir_cb, &symlink_cb, &rename_cb, |
416 |
&link_cb, &chmod_cb, &chown_cb, &truncate_cb, &utime_cb, |
417 |
&open_cb, &read_cb, &write_cb, &release_cb, &statfs_cb, &fsync_cb, |
418 |
&flags, &multithreaded)) |
419 |
return NULL; |
420 |
|
421 |
#define DO_ONE_ATTR(name) if(name ## _cb) { Py_INCREF(name ## _cb); op.name = name ## _func; } else { op.name = NULL; } |
422 |
|
423 |
DO_ONE_ATTR(getattr); |
424 |
DO_ONE_ATTR(readlink); |
425 |
DO_ONE_ATTR(getdir); |
426 |
DO_ONE_ATTR(mknod); |
427 |
DO_ONE_ATTR(mkdir); |
428 |
DO_ONE_ATTR(unlink); |
429 |
DO_ONE_ATTR(rmdir); |
430 |
DO_ONE_ATTR(symlink); |
431 |
DO_ONE_ATTR(rename); |
432 |
DO_ONE_ATTR(link); |
433 |
DO_ONE_ATTR(chmod); |
434 |
DO_ONE_ATTR(chown); |
435 |
DO_ONE_ATTR(truncate); |
436 |
DO_ONE_ATTR(utime); |
437 |
DO_ONE_ATTR(open); |
438 |
DO_ONE_ATTR(read); |
439 |
DO_ONE_ATTR(write); |
440 |
DO_ONE_ATTR(release); |
441 |
DO_ONE_ATTR(statfs); |
442 |
DO_ONE_ATTR(fsync); |
443 |
|
444 |
fuse = fuse_new(0, flags, &op); |
445 |
if(multithreaded) |
446 |
pyfuse_loop_mt(fuse); |
447 |
else |
448 |
fuse_loop(fuse); |
449 |
|
450 |
//printf("Fuse_main: called\n"); |
451 |
|
452 |
Py_INCREF(Py_None); |
453 |
return Py_None; |
454 |
} |
455 |
//@-node:Fuse_main |
456 |
//@+node:DL_EXPORT |
457 |
//@+at |
458 |
//@nonl |
459 |
// List of functions defined in the module |
460 |
//@-at |
461 |
//@@c |
462 |
|
463 |
static PyMethodDef Fuse_methods[] = { |
464 |
{"main", (PyCFunction)Fuse_main, METH_VARARGS|METH_KEYWORDS}, |
465 |
{NULL, NULL} /* sentinel */ |
466 |
}; |
467 |
|
468 |
|
469 |
/* Initialization function for the module (*must* be called init_fuse) */ |
470 |
|
471 |
DL_EXPORT(void) |
472 |
init_fuse(void) |
473 |
{ |
474 |
PyObject *m, *d; |
475 |
static PyObject *ErrorObject; |
476 |
|
477 |
/* Create the module and add the functions */ |
478 |
m = Py_InitModule("_fuse", Fuse_methods); |
479 |
|
480 |
/* Add some symbolic constants to the module */ |
481 |
d = PyModule_GetDict(m); |
482 |
ErrorObject = PyErr_NewException("fuse.error", NULL, NULL); |
483 |
PyDict_SetItemString(d, "error", ErrorObject); |
484 |
PyDict_SetItemString(d, "DEBUG", PyInt_FromLong(FUSE_DEBUG)); |
485 |
} |
486 |
//@-node:DL_EXPORT |
487 |
//@-others |
488 |
|
489 |
//@-node:@file _fusemodule.c |
490 |
//@-leo |