blob: 557d312bce33f37926bdfc0dba26f290c5651fe9 [file] [log] [blame]
//@+leo-ver=4
//@+node:@file _fusemodule.c
//@@language c
/*
Copyright (C) 2001 Jeff Epler <jepler@unpythonic.dhs.org>
This program can be distributed under the terms of the GNU GPL.
See the file COPYING.
*/
//@+others
//@+node:includes
#include <Python.h>
#include <fuse.h>
#include <time.h>
//@-node:includes
//@+node:globals
static PyObject *getattr_cb=NULL, *readlink_cb=NULL, *getdir_cb=NULL,
*mknod_cb=NULL, *mkdir_cb=NULL, *unlink_cb=NULL, *rmdir_cb=NULL,
*symlink_cb=NULL, *rename_cb=NULL, *link_cb=NULL, *chmod_cb=NULL,
*chown_cb=NULL, *truncate_cb=NULL, *utime_cb=NULL,
*open_cb=NULL, *read_cb=NULL, *write_cb=NULL, *release_cb=NULL;
//@-node:globals
//@+node:PROLOGUE
#define PROLOGUE \
int ret = -EINVAL; \
if (!v) { PyErr_Print(); goto OUT; } \
if(v == Py_None) { ret = 0; goto OUT_DECREF; } \
if(PyInt_Check(v)) { ret = PyInt_AsLong(v); goto OUT_DECREF; }
//@-node:PROLOGUE
//@+node:EPILOGUE
#define EPILOGUE \
OUT_DECREF: \
Py_DECREF(v); \
OUT: \
return ret;
//@-node:EPILOGUE
//@+node:getattr_func
/*
* Local Variables:
* indent-tabs-mode: t
* c-basic-offset: 8
* End:
* Changed by David McNab (david@rebirthing.co.nz) to work with recent pythons.
* Namely, replacing PyTuple_* with PySequence_*, and checking numerical values
* with both PyInt_Check and PyLong_Check.
*/
static int getattr_func(const char *path, struct stat *st)
{
int i;
PyObject *v = PyObject_CallFunction(getattr_cb, "s", path);
PROLOGUE
if(!PySequence_Check(v)) { goto OUT_DECREF; }
if(PySequence_Size(v) < 10) { goto OUT_DECREF; }
for(i=0; i<10; i++)
{
PyObject *tmp = PySequence_GetItem(v, i);
if (!(PyInt_Check(tmp) || PyLong_Check(tmp))) goto OUT_DECREF;
}
st->st_mode = PyInt_AsLong(PySequence_GetItem(v, 0));
st->st_ino = PyInt_AsLong(PySequence_GetItem(v, 1));
st->st_dev = PyInt_AsLong(PySequence_GetItem(v, 2));
st->st_nlink= PyInt_AsLong(PySequence_GetItem(v, 3));
st->st_uid = PyInt_AsLong(PySequence_GetItem(v, 4));
st->st_gid = PyInt_AsLong(PySequence_GetItem(v, 5));
st->st_size = PyInt_AsLong(PySequence_GetItem(v, 6));
st->st_atime= PyInt_AsLong(PySequence_GetItem(v, 7));
st->st_mtime= PyInt_AsLong(PySequence_GetItem(v, 8));
st->st_ctime= PyInt_AsLong(PySequence_GetItem(v, 9));
/* Fill in fields not provided by Python lstat() */
st->st_blksize= 4096;
st->st_blocks= (st->st_size + 511)/512;
st->st_ino = 0;
ret = 0;
EPILOGUE
}
//@-node:getattr_func
//@+node:readlink_func
static int readlink_func(const char *path, char *link, size_t size)
{
PyObject *v = PyObject_CallFunction(readlink_cb, "s", path);
char *s;
PROLOGUE
if(!PyString_Check(v)) { ret = -EINVAL; goto OUT_DECREF; }
s = PyString_AsString(v);
strncpy(link, s, size);
link[size-1] = '\0';
ret = 0;
EPILOGUE
}
//@-node:readlink_func
//@+node:getdir_add_entry
static int getdir_add_entry(PyObject *w, fuse_dirh_t dh, fuse_dirfil_t df)
{
PyObject *o0;
PyObject *o1;
int ret = -EINVAL;
if(!PySequence_Check(w)) {
printf("getdir item not sequence\n");
goto out;
}
if(PySequence_Length(w) != 2) {
printf("getdir item not len 2\n");
goto out;
}
o0 = PySequence_GetItem(w, 0);
o1 = PySequence_GetItem(w, 1);
if(!PyString_Check(o0)) {
printf("getdir item[0] not string\n");
goto out_decref;
}
if(!PyInt_Check(o1)) {
printf("getdir item[1] not int\n");
goto out_decref;
}
ret = df(dh, PyString_AsString(o0), PyInt_AsLong(o1));
out_decref:
Py_DECREF(o0);
Py_DECREF(o1);
out:
return ret;
}
//@-node:getdir_add_entry
//@+node:getdir_func
static int getdir_func(const char *path, fuse_dirh_t dh, fuse_dirfil_t df)
{
PyObject *v = PyObject_CallFunction(getdir_cb, "s", path);
int i;
PROLOGUE
if(!PySequence_Check(v)) {
printf("getdir_func not sequence\n");
goto OUT_DECREF;
}
for(i=0; i < PySequence_Length(v); i++) {
PyObject *w = PySequence_GetItem(v, i);
ret = getdir_add_entry(w, dh, df);
Py_DECREF(w);
if(ret != 0)
goto OUT_DECREF;
}
ret = 0;
EPILOGUE
}
//@-node:getdir_func
//@+node:mknod_func
static int mknod_func(const char *path, mode_t m, dev_t d)
{
PyObject *v = PyObject_CallFunction(mknod_cb, "sii", path, m, d);
PROLOGUE
EPILOGUE
}
//@-node:mknod_func
//@+node:mkdir_func
static int mkdir_func(const char *path, mode_t m)
{
PyObject *v = PyObject_CallFunction(mkdir_cb, "si", path, m);
PROLOGUE
EPILOGUE
}
//@-node:mkdir_func
//@+node:unlink_func
static int unlink_func(const char *path)
{
PyObject *v = PyObject_CallFunction(unlink_cb, "s", path);
PROLOGUE
EPILOGUE
}
//@-node:unlink_func
//@+node:rmdir_func
static int rmdir_func(const char *path)
{
PyObject *v = PyObject_CallFunction(rmdir_cb, "s", path);
PROLOGUE
EPILOGUE
}
//@-node:rmdir_func
//@+node:symlink_func
static int symlink_func(const char *path, const char *path1)
{
PyObject *v = PyObject_CallFunction(symlink_cb, "ss", path, path1);
PROLOGUE
EPILOGUE
}
//@-node:symlink_func
//@+node:rename_func
static int rename_func(const char *path, const char *path1)
{
PyObject *v = PyObject_CallFunction(rename_cb, "ss", path, path1);
PROLOGUE
EPILOGUE
}
//@-node:rename_func
//@+node:link_func
static int link_func(const char *path, const char *path1)
{
PyObject *v = PyObject_CallFunction(link_cb, "ss", path, path1);
PROLOGUE
EPILOGUE
}
//@-node:link_func
//@+node:chmod_func
static int chmod_func(const char *path, mode_t m)
{
PyObject *v = PyObject_CallFunction(chmod_cb, "si", path, m);
PROLOGUE
EPILOGUE
}
//@-node:chmod_func
//@+node:chown_func
static int chown_func(const char *path, uid_t u, gid_t g)
{
PyObject *v = PyObject_CallFunction(chown_cb, "sii", path, u, g);
PROLOGUE
EPILOGUE
}
//@-node:chown_func
//@+node:truncate_func
static int truncate_func(const char *path, off_t o)
{
PyObject *v = PyObject_CallFunction(truncate_cb, "si", path, o);
PROLOGUE
EPILOGUE
}
//@-node:truncate_func
//@+node:utime_func
static int utime_func(const char *path, struct utimbuf *u) {
int actime = u ? u->actime : time(NULL);
int modtime = u ? u->modtime : actime;
PyObject *v = PyObject_CallFunction(utime_cb, "s(ii)",
path, actime, modtime);
PROLOGUE
EPILOGUE
}
//@-node:utime_func
//@+node:read_func
static int read_func(const char *path, char *buf, size_t s, off_t off)
{
PyObject *v = PyObject_CallFunction(read_cb, "sii", path, s, off);
PROLOGUE
if(PyString_Check(v)) {
if(PyString_Size(v) > s) goto OUT_DECREF;
memcpy(buf, PyString_AsString(v), PyString_Size(v));
ret = PyString_Size(v);
}
EPILOGUE
}
//@-node:read_func
//@+node:write_func
static int write_func(const char *path, const char *buf, size_t t, off_t off)
{
PyObject *v = PyObject_CallFunction(write_cb,"ss#i", path, buf, t, off);
PROLOGUE
EPILOGUE
}
//@-node:write_func
//@+node:open_func
static int open_func(const char *path, int mode)
{
PyObject *v = PyObject_CallFunction(open_cb, "si", path, mode);
PROLOGUE
printf("open_func: path=%s\n", path);
EPILOGUE
}
//@-node:open_func
//@+node:release_func
static int release_func(const char *path)
{
PyObject *v = PyObject_CallFunction(release_cb, "s", path);
PROLOGUE
printf("release_func: path=%s\n", path);
EPILOGUE
}
//@-node:release_func
//@+node:process_cmd
static void process_cmd(struct fuse *f, struct fuse_cmd *cmd, void *data)
{
PyInterpreterState *interp = (PyInterpreterState *) data;
PyThreadState *state;
PyEval_AcquireLock();
state = PyThreadState_New(interp);
PyThreadState_Swap(state);
__fuse_process_cmd(f, cmd);
PyThreadState_Clear(state);
PyThreadState_Swap(NULL);
PyThreadState_Delete(state);
PyEval_ReleaseLock();
}
//@-node:process_cmd
//@+node:pyfuse_loop_mt
static void pyfuse_loop_mt(struct fuse *f)
{
PyInterpreterState *interp;
PyThreadState *save;
PyEval_InitThreads();
interp = PyThreadState_Get()->interp;
save = PyEval_SaveThread();
__fuse_loop_mt(f, process_cmd, interp);
/* Not yet reached: */
PyEval_RestoreThread(save);
}
//@-node:pyfuse_loop_mt
//@+node:Fuse_main
static PyObject *
Fuse_main(PyObject *self, PyObject *args, PyObject *kw)
{
int flags=0;
int multithreaded=0;
static struct fuse *fuse=NULL;
struct fuse_operations op;
static char *kwlist[] = {
"getattr", "readlink", "getdir", "mknod",
"mkdir", "unlink", "rmdir", "symlink", "rename",
"link", "chmod", "chown", "truncate", "utime",
"open", "read", "write", "release", "flags", "multithreaded", NULL};
memset(&op, 0, sizeof(op));
if (!PyArg_ParseTupleAndKeywords(args, kw, "|OOOOOOOOOOOOOOOOOOii",
kwlist, &getattr_cb, &readlink_cb, &getdir_cb, &mknod_cb,
&mkdir_cb, &unlink_cb, &rmdir_cb, &symlink_cb, &rename_cb,
&link_cb, &chmod_cb, &chown_cb, &truncate_cb, &utime_cb,
&open_cb, &read_cb, &write_cb, &release_cb, &flags, &multithreaded))
return NULL;
#define DO_ONE_ATTR(name) if(name ## _cb) { Py_INCREF(name ## _cb); op.name = name ## _func; } else { op.name = NULL; }
DO_ONE_ATTR(getattr);
DO_ONE_ATTR(readlink);
DO_ONE_ATTR(getdir);
DO_ONE_ATTR(mknod);
DO_ONE_ATTR(mkdir);
DO_ONE_ATTR(unlink);
DO_ONE_ATTR(rmdir);
DO_ONE_ATTR(symlink);
DO_ONE_ATTR(rename);
DO_ONE_ATTR(link);
DO_ONE_ATTR(chmod);
DO_ONE_ATTR(chown);
DO_ONE_ATTR(truncate);
DO_ONE_ATTR(utime);
DO_ONE_ATTR(open);
DO_ONE_ATTR(read);
DO_ONE_ATTR(write);
DO_ONE_ATTR(release);
fuse = fuse_new(0, flags, &op);
if(multithreaded)
pyfuse_loop_mt(fuse);
else
fuse_loop(fuse);
//printf("Fuse_main: called\n");
Py_INCREF(Py_None);
return Py_None;
}
//@-node:Fuse_main
//@+node:DL_EXPORT
//@+at
//@nonl
// List of functions defined in the module
//@-at
//@@c
static PyMethodDef Fuse_methods[] = {
{"main", (PyCFunction)Fuse_main, METH_VARARGS|METH_KEYWORDS},
{NULL, NULL} /* sentinel */
};
/* Initialization function for the module (*must* be called init_fuse) */
DL_EXPORT(void)
init_fuse(void)
{
PyObject *m, *d;
static PyObject *ErrorObject;
/* Create the module and add the functions */
m = Py_InitModule("_fuse", Fuse_methods);
/* Add some symbolic constants to the module */
d = PyModule_GetDict(m);
ErrorObject = PyErr_NewException("fuse.error", NULL, NULL);
PyDict_SetItemString(d, "error", ErrorObject);
PyDict_SetItemString(d, "DEBUG", PyInt_FromLong(FUSE_DEBUG));
}
//@-node:DL_EXPORT
//@-others
//@-node:@file _fusemodule.c
//@-leo