| <?xml version="1.0" encoding="UTF-8"?> |
| <leo_file> |
| <leo_header file_format="2" tnodes="0" max_tnode_index="69" clone_windows="0"/> |
| <globals body_outline_ratio="0.2448559670781893"> |
| <global_window_position top="129" left="90" height="631" width="1124"/> |
| <global_log_window_position top="0" left="0" height="0" width="0"/> |
| </globals> |
| <preferences> |
| </preferences> |
| <find_panel_settings> |
| <find_string></find_string> |
| <change_string></change_string> |
| </find_panel_settings> |
| <vnodes> |
| <v t="davidmcnab.121303142957" a="E"><vh>fuse python bindings</vh> |
| <v t="davidmcnab.121303142957.1" a="E" tnodeList="davidmcnab.121303142957.1,davidmcnab.121303142957.2,davidmcnab.121303142957.3,davidmcnab.121303142957.4,davidmcnab.121303142957.5,davidmcnab.121303142957.6,davidmcnab.121303142957.7,davidmcnab.121303142957.8,davidmcnab.121303142957.9,davidmcnab.121303142957.10,davidmcnab.121303142957.11,davidmcnab.121303142957.12,davidmcnab.121303142957.13,davidmcnab.121303142957.14,davidmcnab.121303142957.15,davidmcnab.121303142957.16,davidmcnab.121303142957.17,davidmcnab.121303142957.18,davidmcnab.121303142957.19,davidmcnab.121303142957.20,davidmcnab.121303142957.21,davidmcnab.121303142957.22,davidmcnab.121303142957.23,davidmcnab.121303142957.24,davidmcnab.121303144441,davidmcnab.121303144441.1,davidmcnab.121303142957.25,davidmcnab.121303142957.26,davidmcnab.121303142957.27,davidmcnab.121303142957.28"><vh>@file _fusemodule.c</vh> |
| <v t="davidmcnab.121303142957.2"><vh>includes</vh></v> |
| <v t="davidmcnab.121303142957.3" a="M"><vh>globals</vh></v> |
| <v t="davidmcnab.121303142957.4"><vh>PROLOGUE</vh></v> |
| <v t="davidmcnab.121303142957.5"><vh>EPILOGUE</vh></v> |
| <v t="davidmcnab.121303142957.6"><vh>getattr_func</vh></v> |
| <v t="davidmcnab.121303142957.7"><vh>readlink_func</vh></v> |
| <v t="davidmcnab.121303142957.8"><vh>getdir_add_entry</vh></v> |
| <v t="davidmcnab.121303142957.9"><vh>getdir_func</vh></v> |
| <v t="davidmcnab.121303142957.10"><vh>mknod_func</vh></v> |
| <v t="davidmcnab.121303142957.11"><vh>mkdir_func</vh></v> |
| <v t="davidmcnab.121303142957.12"><vh>unlink_func</vh></v> |
| <v t="davidmcnab.121303142957.13"><vh>rmdir_func</vh></v> |
| <v t="davidmcnab.121303142957.14"><vh>symlink_func</vh></v> |
| <v t="davidmcnab.121303142957.15"><vh>rename_func</vh></v> |
| <v t="davidmcnab.121303142957.16"><vh>link_func</vh></v> |
| <v t="davidmcnab.121303142957.17"><vh>chmod_func</vh></v> |
| <v t="davidmcnab.121303142957.18"><vh>chown_func</vh></v> |
| <v t="davidmcnab.121303142957.19"><vh>truncate_func</vh></v> |
| <v t="davidmcnab.121303142957.20"><vh>utime_func</vh></v> |
| <v t="davidmcnab.121303142957.21"><vh>read_func</vh></v> |
| <v t="davidmcnab.121303142957.22"><vh>write_func</vh></v> |
| <v t="davidmcnab.121303142957.23"><vh>open_func</vh></v> |
| <v t="davidmcnab.121303142957.24" a="M"><vh>release_func</vh></v> |
| <v t="davidmcnab.121303144441"><vh>statfs_func</vh></v> |
| <v t="davidmcnab.121303144441.1"><vh>fsync_func</vh></v> |
| <v t="davidmcnab.121303142957.25" a="M"><vh>process_cmd</vh></v> |
| <v t="davidmcnab.121303142957.26"><vh>pyfuse_loop_mt</vh></v> |
| <v t="davidmcnab.121303142957.27" a="M"><vh>Fuse_main</vh></v> |
| <v t="davidmcnab.121303142957.28"><vh>DL_EXPORT</vh></v> |
| </v> |
| <v t="davidmcnab.121303142957.29" tnodeList="davidmcnab.121303142957.29,davidmcnab.121303142957.30,davidmcnab.121303142957.31,davidmcnab.121303142957.32,davidmcnab.121303142957.33,davidmcnab.121303142957.34,davidmcnab.121303142957.35,davidmcnab.121303142957.36,davidmcnab.121303142957.37"><vh>@file fuse.py</vh> |
| <v t="davidmcnab.121303142957.30"><vh>imports</vh></v> |
| <v t="davidmcnab.121303142957.31" a="E"><vh>class ErrnoWrapper</vh> |
| <v t="davidmcnab.121303142957.32"><vh>__init__</vh></v> |
| <v t="davidmcnab.121303142957.33"><vh>__call__</vh></v> |
| </v> |
| <v t="davidmcnab.121303142957.34" a="E"><vh>class Fuse</vh> |
| <v t="davidmcnab.121303142957.35" a="M"><vh>attribs</vh></v> |
| <v t="davidmcnab.121303142957.36"><vh>__init__</vh></v> |
| <v t="davidmcnab.121303142957.37"><vh>main</vh></v> |
| </v> |
| </v> |
| <v t="davidmcnab.121303142957.38" tnodeList="davidmcnab.121303142957.38"><vh>@file Makefile</vh></v> |
| <v t="davidmcnab.121303142957.39" a="E" tnodeList="davidmcnab.121303142957.39,davidmcnab.121303142957.40,davidmcnab.121303142957.41,davidmcnab.121303142957.42,davidmcnab.121303142957.43,davidmcnab.121303142957.44,davidmcnab.121303142957.45,davidmcnab.121303142957.46,davidmcnab.121303142957.47,davidmcnab.121303142957.48,davidmcnab.121303142957.49,davidmcnab.121303142957.50,davidmcnab.121303142957.51,davidmcnab.121303142957.52,davidmcnab.121303142957.53,davidmcnab.121303142957.54,davidmcnab.121303142957.55,davidmcnab.121303142957.56,davidmcnab.121303142957.57,davidmcnab.121303142957.58,davidmcnab.121303142957.59,davidmcnab.121303142957.60,davidmcnab.121303142957.61,davidmcnab.121303142957.62,davidmcnab.121303144134,davidmcnab.121303144134.1,davidmcnab.121303142957.63"><vh>@file xmp.py</vh> |
| <v t="davidmcnab.121303142957.40"><vh>imports</vh></v> |
| <v t="davidmcnab.121303142957.41" a="E"><vh>class Xmp</vh> |
| <v t="davidmcnab.121303142957.42"><vh>__init__</vh></v> |
| <v t="davidmcnab.121303142957.43"><vh>mythread</vh></v> |
| <v t="davidmcnab.121303142957.44"><vh>attribs</vh></v> |
| <v t="davidmcnab.121303142957.45"><vh>getattr</vh></v> |
| <v t="davidmcnab.121303142957.46"><vh>readlink</vh></v> |
| <v t="davidmcnab.121303142957.47"><vh>getdir</vh></v> |
| <v t="davidmcnab.121303142957.48"><vh>unlink</vh></v> |
| <v t="davidmcnab.121303142957.49"><vh>rmdir</vh></v> |
| <v t="davidmcnab.121303142957.50"><vh>symlink</vh></v> |
| <v t="davidmcnab.121303142957.51"><vh>rename</vh></v> |
| <v t="davidmcnab.121303142957.52"><vh>link</vh></v> |
| <v t="davidmcnab.121303142957.53"><vh>chmod</vh></v> |
| <v t="davidmcnab.121303142957.54"><vh>chown</vh></v> |
| <v t="davidmcnab.121303142957.55"><vh>truncate</vh></v> |
| <v t="davidmcnab.121303142957.56"><vh>mknod</vh></v> |
| <v t="davidmcnab.121303142957.57"><vh>mkdir</vh></v> |
| <v t="davidmcnab.121303142957.58"><vh>utime</vh></v> |
| <v t="davidmcnab.121303142957.59"><vh>open</vh></v> |
| <v t="davidmcnab.121303142957.60"><vh>read</vh></v> |
| <v t="davidmcnab.121303142957.61"><vh>write</vh></v> |
| <v t="davidmcnab.121303142957.62" a="M"><vh>release</vh></v> |
| <v t="davidmcnab.121303144134"><vh>statfs</vh></v> |
| <v t="davidmcnab.121303144134.1"><vh>fsync</vh></v> |
| </v> |
| <v t="davidmcnab.121303142957.63"><vh>mainline</vh></v> |
| </v> |
| <v t="davidmcnab.121303142957.64" tnodeList="davidmcnab.121303142957.64"><vh>@file setup.py</vh></v> |
| <v t="davidmcnab.121303142957.65" tnodeList="davidmcnab.121303142957.65"><vh>@file README</vh></v> |
| <v t="davidmcnab.121303142957.67" a="E" tnodeList="davidmcnab.121303142957.67"><vh>@file mount.fuse</vh></v> |
| <v t="davidmcnab.121403050157" a="E"><vh>@file fuse.py</vh> |
| <v t="davidmcnab.121403050157.1"><vh><< fuse declarations >></vh></v> |
| <v t="davidmcnab.121403050157.2" a="E"><vh>class ErrnoWrapper</vh> |
| <v t="davidmcnab.121403050157.3"><vh><< class ErrnoWrapper declarations >></vh></v> |
| <v t="davidmcnab.121403050157.4"><vh>__init__</vh></v> |
| <v t="davidmcnab.121403050157.5" a="V"><vh>__call__</vh></v> |
| </v> |
| <v t="davidmcnab.121403050157.6" a="E"><vh>class Fuse</vh> |
| <v t="davidmcnab.121403050157.7"><vh><< class Fuse declarations >></vh></v> |
| <v t="davidmcnab.121403050157.8"><vh>__init__</vh></v> |
| <v t="davidmcnab.121403050157.9"><vh>main</vh></v> |
| </v> |
| </v> |
| </v> |
| </vnodes> |
| <tnodes> |
| <t tx="davidmcnab.121303142957"></t> |
| <t tx="davidmcnab.121303142957.1">@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 |
| |
| </t> |
| <t tx="davidmcnab.121303142957.2">#include <Python.h> |
| #include <fuse.h> |
| #include <time.h> |
| </t> |
| <t tx="davidmcnab.121303142957.3"> |
| 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, |
| *statfs_cb=NULL, *fsync_cb=NULL |
| ; |
| </t> |
| <t tx="davidmcnab.121303142957.4">#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; } |
| |
| </t> |
| <t tx="davidmcnab.121303142957.5">#define EPILOGUE \ |
| OUT_DECREF: \ |
| Py_DECREF(v); \ |
| OUT: \ |
| return ret; |
| </t> |
| <t tx="davidmcnab.121303142957.6"> |
| /* |
| * 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 |
| } |
| |
| </t> |
| <t tx="davidmcnab.121303142957.7"> |
| 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 |
| } |
| </t> |
| <t tx="davidmcnab.121303142957.8"> |
| 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; |
| } |
| </t> |
| <t tx="davidmcnab.121303142957.9"> |
| 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 |
| } |
| </t> |
| <t tx="davidmcnab.121303142957.10"> |
| 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 |
| } |
| </t> |
| <t tx="davidmcnab.121303142957.11"> |
| static int mkdir_func(const char *path, mode_t m) |
| { |
| PyObject *v = PyObject_CallFunction(mkdir_cb, "si", path, m); |
| PROLOGUE |
| EPILOGUE |
| } |
| </t> |
| <t tx="davidmcnab.121303142957.12"> |
| static int unlink_func(const char *path) |
| { |
| PyObject *v = PyObject_CallFunction(unlink_cb, "s", path); |
| PROLOGUE |
| EPILOGUE |
| } |
| </t> |
| <t tx="davidmcnab.121303142957.13"> |
| static int rmdir_func(const char *path) |
| { |
| PyObject *v = PyObject_CallFunction(rmdir_cb, "s", path); |
| PROLOGUE |
| EPILOGUE |
| } |
| </t> |
| <t tx="davidmcnab.121303142957.14"> |
| static int symlink_func(const char *path, const char *path1) |
| { |
| PyObject *v = PyObject_CallFunction(symlink_cb, "ss", path, path1); |
| PROLOGUE |
| EPILOGUE |
| } |
| </t> |
| <t tx="davidmcnab.121303142957.15"> |
| static int rename_func(const char *path, const char *path1) |
| { |
| PyObject *v = PyObject_CallFunction(rename_cb, "ss", path, path1); |
| PROLOGUE |
| EPILOGUE |
| } |
| </t> |
| <t tx="davidmcnab.121303142957.16"> |
| static int link_func(const char *path, const char *path1) |
| { |
| PyObject *v = PyObject_CallFunction(link_cb, "ss", path, path1); |
| PROLOGUE |
| EPILOGUE |
| } |
| </t> |
| <t tx="davidmcnab.121303142957.17"> |
| static int chmod_func(const char *path, mode_t m) |
| { |
| PyObject *v = PyObject_CallFunction(chmod_cb, "si", path, m); |
| PROLOGUE |
| EPILOGUE |
| } |
| </t> |
| <t tx="davidmcnab.121303142957.18"> |
| 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 |
| } |
| </t> |
| <t tx="davidmcnab.121303142957.19"> |
| static int truncate_func(const char *path, off_t o) |
| { |
| PyObject *v = PyObject_CallFunction(truncate_cb, "si", path, o); |
| PROLOGUE |
| EPILOGUE |
| } |
| </t> |
| <t tx="davidmcnab.121303142957.20"> |
| 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 |
| } |
| </t> |
| <t tx="davidmcnab.121303142957.21"> |
| 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 |
| } |
| </t> |
| <t tx="davidmcnab.121303142957.22"> |
| 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 |
| } |
| </t> |
| <t tx="davidmcnab.121303142957.23"> |
| 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 |
| } |
| </t> |
| <t tx="davidmcnab.121303142957.24">static int release_func(const char *path, int flags) |
| { |
| PyObject *v = PyObject_CallFunction(release_cb, "si", path, flags); |
| PROLOGUE |
| //printf("release_func: path=%s flags=%d\n", path, flags); |
| EPILOGUE |
| } |
| </t> |
| <t tx="davidmcnab.121303142957.25"> |
| 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(); |
| } |
| </t> |
| <t tx="davidmcnab.121303142957.26"> |
| 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); |
| } |
| </t> |
| <t tx="davidmcnab.121303142957.27"> |
| |
| 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", "statfs", "fsync", |
| "flags", "multithreaded", NULL}; |
| |
| memset(&op, 0, sizeof(op)); |
| |
| if (!PyArg_ParseTupleAndKeywords(args, kw, "|OOOOOOOOOOOOOOOOOOOOii", |
| 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, &statfs_cb, &fsync_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); |
| DO_ONE_ATTR(statfs); |
| DO_ONE_ATTR(fsync); |
| |
| 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; |
| } |
| </t> |
| <t tx="davidmcnab.121303142957.28">@ List of functions defined in the module |
| @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)); |
| } |
| </t> |
| <t tx="davidmcnab.121303142957.29"># |
| # 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. |
| # |
| |
| |
| @language python |
| @others |
| </t> |
| <t tx="davidmcnab.121303142957.30"># suppress version mismatch warnings |
| try: |
| import warnings |
| warnings.filterwarnings('ignore', |
| 'Python C API version mismatch', |
| RuntimeWarning, |
| ) |
| except: |
| pass |
| |
| from _fuse import main, DEBUG |
| import os, sys |
| from errno import * |
| |
| </t> |
| <t tx="davidmcnab.121303142957.31">class ErrnoWrapper: |
| @others |
| </t> |
| <t tx="davidmcnab.121303142957.32">def __init__(self, func): |
| self.func = func |
| </t> |
| <t tx="davidmcnab.121303142957.33">def __call__(self, *args, **kw): |
| try: |
| return apply(self.func, args, kw) |
| except (IOError, OSError), detail: |
| # Sometimes this is an int, sometimes an instance... |
| if hasattr(detail, "errno"): detail = detail.errno |
| return -detail |
| </t> |
| <t tx="davidmcnab.121303142957.34">class Fuse: |
| |
| @others |
| </t> |
| <t tx="davidmcnab.121303142957.35">_attrs = ['getattr', 'readlink', 'getdir', 'mknod', 'mkdir', |
| 'unlink', 'rmdir', 'symlink', 'rename', 'link', 'chmod', |
| 'chown', 'truncate', 'utime', 'open', 'read', 'write', 'release', |
| 'statfs', 'fsync'] |
| |
| flags = 0 |
| multithreaded = 0 |
| |
| </t> |
| <t tx="davidmcnab.121303142957.36">def __init__(self, *args, **kw): |
| |
| # default attributes |
| self.optlist = [] |
| self.optdict = {} |
| self.mountpoint = None |
| |
| # grab arguments, if any |
| argv = sys.argv |
| argc = len(argv) |
| if argc > 1: |
| # we've been given the mountpoint |
| self.mountpoint = argv[1] |
| if argc > 2: |
| # we've received mount args |
| optstr = argv[2] |
| opts = optstr.split(",") |
| for o in opts: |
| try: |
| k, v = o.split("=", 1) |
| self.optdict[k] = v |
| except: |
| self.optlist.append(o) |
| </t> |
| <t tx="davidmcnab.121303142957.37">def main(self): |
| d = {'flags': self.flags} |
| d['multithreaded'] = self.multithreaded |
| for a in self._attrs: |
| if hasattr(self,a): |
| d[a] = ErrnoWrapper(getattr(self, a)) |
| apply(main, (), d) |
| </t> |
| <t tx="davidmcnab.121303142957.38"># Makefile now uses distutils |
| |
| _fusemodule.so: _fusemodule.c |
| #gcc -g3 -I/usr/include/python2.1 _fusemodule.c -Wl,-shared -o _fusemodule.so -Wimplicit -lfuse && python -c 'import _fuse' |
| python setup.py build_ext --inplace |
| |
| install: _fusemodule.so |
| python setup.py install |
| |
| clean: |
| rm -rf _fusemodule.so *.pyc *.pyo *~ build |
| </t> |
| <t tx="davidmcnab.121303142957.39">@first #!/usr/bin/env python |
| # |
| # 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 |
| </t> |
| <t tx="davidmcnab.121303142957.40"> |
| from fuse import Fuse |
| import os |
| from errno import * |
| from stat import * |
| |
| import thread |
| </t> |
| <t tx="davidmcnab.121303142957.41">class Xmp(Fuse): |
| |
| @others |
| </t> |
| <t tx="davidmcnab.121303142957.42">def __init__(self, *args, **kw): |
| |
| Fuse.__init__(self, *args, **kw) |
| |
| if 0: |
| print "xmp.py:Xmp:mountpoint: %s" % repr(self.mountpoint) |
| print "xmp.py:Xmp:unnamed mount options: %s" % self.optlist |
| print "xmp.py:Xmp:named mount options: %s" % self.optdict |
| |
| # do stuff to set up your filesystem here, if you want |
| #thread.start_new_thread(self.mythread, ()) |
| pass |
| </t> |
| <t tx="davidmcnab.121303142957.43">def mythread(self): |
| |
| """ |
| The beauty of the FUSE python implementation is that with the python interp |
| running in foreground, you can have threads |
| """ |
| print "mythread: started" |
| #while 1: |
| # time.sleep(120) |
| # print "mythread: ticking" |
| |
| </t> |
| <t tx="davidmcnab.121303142957.44">flags = 1 |
| |
| </t> |
| <t tx="davidmcnab.121303142957.45">def getattr(self, path): |
| return os.lstat(path) |
| </t> |
| <t tx="davidmcnab.121303142957.46">def readlink(self, path): |
| return os.readlink(path) |
| </t> |
| <t tx="davidmcnab.121303142957.47">def getdir(self, path): |
| return map(lambda x: (x,0), os.listdir(path)) |
| </t> |
| <t tx="davidmcnab.121303142957.48">def unlink(self, path): |
| return os.unlink(path) |
| </t> |
| <t tx="davidmcnab.121303142957.49">def rmdir(self, path): |
| return os.rmdir(path) |
| </t> |
| <t tx="davidmcnab.121303142957.50">def symlink(self, path, path1): |
| return os.symlink(path, path1) |
| </t> |
| <t tx="davidmcnab.121303142957.51">def rename(self, path, path1): |
| return os.rename(path, path1) |
| </t> |
| <t tx="davidmcnab.121303142957.52">def link(self, path, path1): |
| return os.link(path, path1) |
| </t> |
| <t tx="davidmcnab.121303142957.53">def chmod(self, path, mode): |
| return os.chmod(path, mode) |
| </t> |
| <t tx="davidmcnab.121303142957.54">def chown(self, path, user, group): |
| return os.chown(path, user, group) |
| </t> |
| <t tx="davidmcnab.121303142957.55">def truncate(self, path, size): |
| f = open(path, "w+") |
| return f.truncate(size) |
| </t> |
| <t tx="davidmcnab.121303142957.56">def mknod(self, path, mode, dev): |
| """ Python has no os.mknod, so we can only do some things """ |
| if S_ISREG(mode): |
| open(path, "w") |
| else: |
| return -EINVAL |
| </t> |
| <t tx="davidmcnab.121303142957.57">def mkdir(self, path, mode): |
| return os.mkdir(path, mode) |
| </t> |
| <t tx="davidmcnab.121303142957.58">def utime(self, path, times): |
| return os.utime(path, times) |
| </t> |
| <t tx="davidmcnab.121303142957.59">def open(self, path, flags): |
| #print "xmp.py:Xmp:open: %s" % path |
| os.close(os.open(path, flags)) |
| return 0 |
| |
| </t> |
| <t tx="davidmcnab.121303142957.60">def read(self, path, len, offset): |
| #print "xmp.py:Xmp:read: %s" % path |
| f = open(path, "r") |
| f.seek(offset) |
| return f.read(len) |
| |
| </t> |
| <t tx="davidmcnab.121303142957.61">def write(self, path, buf, off): |
| #print "xmp.py:Xmp:write: %s" % path |
| f = open(path, "r+") |
| f.seek(off) |
| f.write(buf) |
| return len(buf) |
| |
| </t> |
| <t tx="davidmcnab.121303142957.62">def release(self, path, flags): |
| print "xmp.py:Xmp:release: %s %s" % (path, flags) |
| return 0 |
| </t> |
| <t tx="davidmcnab.121303142957.63"> |
| if __name__ == '__main__': |
| |
| server = Xmp() |
| server.flags = 0 |
| server.multithreaded = 1; |
| server.main() |
| </t> |
| <t tx="davidmcnab.121303142957.64">""" |
| distutils script for FUSE python module |
| """ |
| |
| from distutils.core import setup, Extension |
| |
| setup(name="fuse", |
| version="0.1", |
| ext_modules=[Extension("_fusemodule", ["_fusemodule.c"], |
| library_dirs=["../lib",], |
| libraries=["fuse",], |
| ), |
| ], |
| py_modules=["fuse"], |
| ) |
| |
| </t> |
| <t tx="davidmcnab.121303142957.65">@language |
| |
| Refer to the INSTALL file for build/install instructions |
| |
| General Information |
| =================== |
| |
| This is a Python[1] interface to FUSE[2]. |
| |
| FUSE (Filesystem in USErspace) is a simple interface for userspace |
| programs to export a virtual filesystem to the linux kernel. FUSE |
| also aims to provide a secure method for non privileged users to |
| create and mount their own filesystem implementations. |
| |
| When run from the commandline, "fuse.py" simply reexports the root |
| filesystem within the mount point as example/fusexmp does in the main |
| FUSE distribution. It also offers a class, fuse.Fuse, which can be |
| subclassed to create a filesystem. fuse.Xmp is the example filesystem |
| implementation. |
| |
| In your subclass of fuse, add attributes with the expected names |
| ("getattr", "readlink", etc) and call signatures (refer to fuse.Xmp) |
| then call main(). Make it runnable as a #! script, and mount with |
| fusermount <mount point> <script name> |
| for some reason, |
| fusermount <mount point> python <script name> |
| does not seem to work. (why?) |
| |
| Update |
| ====== |
| |
| Updated 13-Dec-2003 by David McNab <david@rebirthing.co.nz> |
| |
| - changed Makefile to use Pyton distutils |
| - added setup.py for distutils |
| |
| - added 'code.leo' file for convenience of those who use the Leo |
| code editor (leo.sf.net) |
| |
| - added support for 'statfs' and 'fsync' methods (refer xmp.py) |
| |
| Updated Dec 2003 by David McNab <david@rebirthing.co.nz>: |
| |
| - added support for 'release' events (ie when file gets closed) |
| - added __init__ to base class, which picks off parameters and |
| stores them as instance attributes: |
| - self.mountpoint - the mountpoint as given in the mount command |
| - self.optlist - unnamed options (eg 'rw', 'exec' etc) |
| - self.optdict - named options (eg, '-o arg1=val1,arg2=val2...' from mount cmd) |
| - fixed incompatibility issues with recent pythons (original was broken |
| under python2.3) |
| |
| Limitations |
| =========== |
| |
| This is minimally tested, though I think I have exercised each function. |
| There's no documentation, docstrings, or tests. |
| |
| Python's lstat() does not return some fields which must be filled in |
| (st_blksize, st_blocks, st_ino), and _fusemodule assumes that the return |
| value from the lstat() method is identical to Python's lstat(). This |
| limitation should be lifted, and some standard order chosen for these |
| three values. For now, though, default values are chosen and du returns a |
| number similar to the "real" one. |
| |
| The Python Global Interpreter Lock is not handled, so using |
| fuse.MULTITHREAD will not work. Modifying the PROLOGUE and EPILOGUE |
| functions may take care of this. For now, just run without |
| fuse.MULTITHREAD in flags. |
| |
| Author |
| ====== |
| |
| I'm Jeff Epler <jepler@unpythonic.dhs.org>. I've been dabbling in |
| Python for nearly 7 years now, and interested (despite the lack of a |
| real practical use) in userspace filesystems ever since I couldn't get |
| userfs to compile way back in '93 or so. FUSE is cool, but i'm still |
| not sure what it's good for in practical terms. |
| |
| I don't know how high a level of interest I'll maintain in this project, |
| so if you want to do something with it feel free to do so. Like FUSE, |
| this software is distributed under the terms of the GNU General Public |
| License, Version 2. Future versions, if any, will be available at [3]. |
| |
| |
| [1] http://www.python.org |
| [2] http://sourceforge.net/projects/avf/ |
| [3] http://unpythonic.dhs.org/~jepler/fuse/ |
| </t> |
| <t tx="davidmcnab.121303142957.67">@first #!/usr/bin/env python |
| |
| """ |
| This utility allows FUSE filesystems to be mounted with the regular *nix |
| 'mount' command, or even be listed in /etc/fstab |
| |
| To enable this, you need to: |
| 1. set execute-permission on this script |
| 2. symlink this script into /sbin/mount.fuse |
| |
| Usage: |
| |
| You can use this in 3 ways: |
| 1. mount -t fuse /path/to/script/or/program /path/of/mount/point [options] |
| 2. mount -t fuse none /path/of/mount/point -o fs=/path/to/script/or/prog[,opt=val...] |
| 3. in /etc/fstab, add: |
| /path/to/script/or/prog /path/of/mount/point fuse noauto[,...] |
| """ |
| |
| import sys, os, time |
| |
| progname = sys.argv[0] |
| |
| def usage(ret): |
| print "Usage: %s /path/to/fuse/fs /path/of/mountpoint [-o options]" % progname |
| print "or: %s none /path/of/mountpoint [-o fs=/path/to/fuse/fs[,...]]" % progname |
| sys.exit(ret) |
| |
| def main(): |
| |
| # initial sanity check |
| argc = len(sys.argv) |
| if argc < 3 or sys.argv[3] != "-o": |
| usage(1) |
| |
| dev = sys.argv[1] |
| mountpoint = sys.argv[2] |
| |
| # grab options, if any |
| optdict = {} |
| optlist = [] |
| if argc > 4: |
| odata = sys.argv[4] |
| opts = odata.split(",") |
| #print opts |
| for o in opts: |
| try: |
| k, v = o.split("=", 1) |
| optdict[k] = v |
| except: |
| optlist.append(o) |
| else: |
| odata = "" |
| |
| #print sys.argv |
| if dev == 'none': |
| if not optdict.has_key("fs"): |
| print "%s: Must specify python file with 'fs' option\n" % progname |
| usage(1) |
| pyfile = optdict['fs'] |
| else: |
| pyfile = dev |
| |
| if not os.path.isfile(pyfile): |
| print "%s: file %s doesn't exist, or is not a file" % (progname, pyfile) |
| sys.exit(1) |
| pypath = os.path.abspath(pyfile) |
| |
| #print optdict, optlist |
| |
| # all seems ok - run our fuse fs as a child |
| if os.fork() == 0: |
| os.system("fusermount -c -x %s %s %s %s" % (mountpoint, pypath, mountpoint, odata)) |
| else: |
| #print "parent exiting..." |
| pass |
| |
| if __name__ == '__main__': |
| main() |
| |
| </t> |
| <t tx="davidmcnab.121303144134">def statfs(self): |
| """ |
| Should return a tuple with the following 6 elements: |
| - blocksize - size of file blocks, in bytes |
| - totalblocks - total number of blocks in the filesystem |
| - freeblocks - number of free blocks |
| - totalfiles - total number of file inodes |
| - freefiles - nunber of free file inodes |
| |
| Feel free to set any of the above values to 0, which tells |
| the kernel that the info is not available. |
| """ |
| print "xmp.py:Xmp:statfs: returning fictitious values" |
| blocks_size = 1024 |
| blocks = 100000 |
| blocks_free = 25000 |
| files = 100000 |
| files_free = 60000 |
| namelen = 80 |
| return (blocks_size, blocks, blocks_free, files, files_free, namelen) |
| </t> |
| <t tx="davidmcnab.121303144134.1">def fsync(self, path, isfsyncfile): |
| print "xmp.py:Xmp:fsync: path=%s, isfsyncfile=%s" % (path, isfsyncfile) |
| return 0 |
| |
| </t> |
| <t tx="davidmcnab.121303144441">static int statfs_func(struct fuse_statfs *fst) |
| { |
| int i; |
| long retvalues[6]; |
| PyObject *v = PyObject_CallFunction(statfs_cb, ""); |
| PROLOGUE |
| |
| if (!PySequence_Check(v)) |
| { goto OUT_DECREF; } |
| if (PySequence_Size(v) < 6) |
| { goto OUT_DECREF; } |
| for(i=0; i<6; i++) |
| { |
| PyObject *tmp = PySequence_GetItem(v, i); |
| retvalues[i] = PyInt_Check(tmp) |
| ? PyInt_AsLong(tmp) |
| : (PyLong_Check(tmp) |
| ? PyLong_AsLong(tmp) |
| : 0); |
| } |
| |
| fst->block_size = retvalues[0]; |
| fst->blocks = retvalues[1]; |
| fst->blocks_free = retvalues[2]; |
| fst->files = retvalues[3]; |
| fst->files_free = retvalues[4]; |
| fst->namelen = retvalues[5]; |
| ret = 0; |
| |
| #ifdef IGNORE_THIS |
| printf("block_size=%ld, blocks=%ld, blocks_free=%ld, files=%ld, files_free=%ld, namelen=%ld\n", |
| retvalues[0], retvalues[1], retvalues[2], retvalues[3], retvalues[4], retvalues[5]); |
| #endif |
| |
| EPILOGUE |
| |
| } |
| |
| </t> |
| <t tx="davidmcnab.121303144441.1">static int fsync_func(const char *path, int isfsyncfile) |
| { |
| PyObject *v = PyObject_CallFunction(fsync_cb, "si", path, isfsyncfile); |
| PROLOGUE |
| EPILOGUE |
| } |
| |
| </t> |
| <t tx="davidmcnab.121403050157">@ignore |
| @language python |
| << fuse declarations >> |
| @others |
| #@-node:main |
| #@-others |
| #@-node:class Fuse |
| #@-others |
| #@-node:@file fuse.py |
| #@-leo |
| </t> |
| <t tx="davidmcnab.121403050157.1">#@+leo-ver=4 |
| #@+node:@file fuse.py |
| # |
| # 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. |
| # |
| |
| |
| #@@language python |
| #@+others |
| #@+node:imports |
| # suppress version mismatch warnings |
| try: |
| import warnings |
| warnings.filterwarnings('ignore', |
| 'Python C API version mismatch', |
| RuntimeWarning, |
| ) |
| except: |
| pass |
| |
| from _fuse import main, DEBUG |
| import os, sys |
| from errno import * |
| |
| #@-node:imports |
| #@+node:class ErrnoWrapper |
| </t> |
| <t tx="davidmcnab.121403050157.2">class ErrnoWrapper: |
| << class ErrnoWrapper declarations >> |
| @others |
| </t> |
| <t tx="davidmcnab.121403050157.3"> #@ @+others |
| #@+node:__init__ |
| </t> |
| <t tx="davidmcnab.121403050157.4">def __init__(self, func): |
| self.func = func |
| </t> |
| <t tx="davidmcnab.121403050157.5">#@-node:__init__ |
| #@+node:__call__ |
| def __call__(self, *args, **kw): |
| try: |
| return apply(self.func, args, kw) |
| except (IOError, OSError), detail: |
| # Sometimes this is an int, sometimes an instance... |
| if hasattr(detail, "errno"): detail = detail.errno |
| return -detail |
| </t> |
| <t tx="davidmcnab.121403050157.6"> #@-node:__call__ |
| #@-others |
| #@-node:class ErrnoWrapper |
| #@+node:class Fuse |
| class Fuse: |
| << class Fuse declarations >> |
| @others |
| </t> |
| <t tx="davidmcnab.121403050157.7">#@ @+others |
| #@+node:attribs |
| _attrs = ['getattr', 'readlink', 'getdir', 'mknod', 'mkdir', |
| 'unlink', 'rmdir', 'symlink', 'rename', 'link', 'chmod', |
| 'chown', 'truncate', 'utime', 'open', 'read', 'write', 'release', |
| 'statfs', 'fsync'] |
| |
| flags = 0 |
| multithreaded = 0 |
| |
| #@-node:attribs |
| #@+node:__init__ |
| </t> |
| <t tx="davidmcnab.121403050157.8">def __init__(self, *args, **kw): |
| |
| # default attributes |
| self.optlist = [] |
| self.optdict = {} |
| self.mountpoint = None |
| |
| # grab arguments, if any |
| argv = sys.argv |
| argc = len(argv) |
| if argc > 1: |
| # we've been given the mountpoint |
| self.mountpoint = argv[1] |
| if argc > 2: |
| # we've received mount args |
| optstr = argv[2] |
| opts = optstr.split(",") |
| for o in opts: |
| try: |
| k, v = o.split("=", 1) |
| self.optdict[k] = v |
| except: |
| self.optlist.append(o) |
| </t> |
| <t tx="davidmcnab.121403050157.9">#@-node:__init__ |
| #@+node:main |
| def main(self): |
| d = {'flags': self.flags} |
| d['multithreaded'] = self.multithreaded |
| for a in self._attrs: |
| if hasattr(self,a): |
| d[a] = ErrnoWrapper(getattr(self, a)) |
| apply(main, (), d) |
| </t> |
| </tnodes> |
| </leo_file> |