diff options
Diffstat (limited to 'python')
-rw-r--r-- | python/README | 21 | ||||
-rw-r--r-- | python/_fusemodule.c | 178 | ||||
-rw-r--r-- | python/fuse.py | 110 | ||||
-rwxr-xr-x | python/xmp.py | 202 |
4 files changed, 376 insertions, 135 deletions
diff --git a/python/README b/python/README index 451c56c..3b0d70f 100644 --- a/python/README +++ b/python/README @@ -1,3 +1,8 @@ +#@+leo-ver=4 +#@+node:@file README +#@@comment + + General Information =================== @@ -22,6 +27,20 @@ for some reason, fusermount <mount point> python <script name> does not seem to work. (why?) +Update +====== + +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 =========== @@ -58,3 +77,5 @@ 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/ +#@-node:@file README +#@-leo diff --git a/python/_fusemodule.c b/python/_fusemodule.c index 6956be2..557d312 100644 --- a/python/_fusemodule.c +++ b/python/_fusemodule.c @@ -1,3 +1,6 @@ +//@+leo-ver=4 +//@+node:@file _fusemodule.c +//@@language c /* Copyright (C) 2001 Jeff Epler <jepler@unpythonic.dhs.org> @@ -5,59 +8,84 @@ 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; - + *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; } +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; +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(!PyTuple_Check(v)) { goto OUT_DECREF; } - if(PyTuple_Size(v) < 10) { goto OUT_DECREF; } - for(i=0; i<10; i++) { - if (!PyInt_Check(PyTuple_GetItem(v, 0))) goto OUT_DECREF; - } +int i; +PyObject *v = PyObject_CallFunction(getattr_cb, "s", path); +PROLOGUE - st->st_mode = PyInt_AsLong(PyTuple_GetItem(v, 0)); - st->st_ino = PyInt_AsLong(PyTuple_GetItem(v, 1)); - st->st_dev = PyInt_AsLong(PyTuple_GetItem(v, 2)); - st->st_nlink= PyInt_AsLong(PyTuple_GetItem(v, 3)); - st->st_uid = PyInt_AsLong(PyTuple_GetItem(v, 4)); - st->st_gid = PyInt_AsLong(PyTuple_GetItem(v, 5)); - st->st_size = PyInt_AsLong(PyTuple_GetItem(v, 6)); - st->st_atime= PyInt_AsLong(PyTuple_GetItem(v, 7)); - st->st_mtime= PyInt_AsLong(PyTuple_GetItem(v, 8)); - st->st_ctime= PyInt_AsLong(PyTuple_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; +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; +} - ret = 0; - EPILOGUE +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); @@ -72,6 +100,8 @@ static int readlink_func(const char *path, char *link, size_t size) EPILOGUE } +//@-node:readlink_func +//@+node:getdir_add_entry static int getdir_add_entry(PyObject *w, fuse_dirh_t dh, fuse_dirfil_t df) { @@ -108,6 +138,8 @@ out_decref: 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) { @@ -130,6 +162,8 @@ static int getdir_func(const char *path, fuse_dirh_t dh, fuse_dirfil_t df) EPILOGUE } +//@-node:getdir_func +//@+node:mknod_func static int mknod_func(const char *path, mode_t m, dev_t d) { @@ -137,6 +171,8 @@ static int mknod_func(const char *path, mode_t m, dev_t d) PROLOGUE EPILOGUE } +//@-node:mknod_func +//@+node:mkdir_func static int mkdir_func(const char *path, mode_t m) { @@ -144,6 +180,8 @@ static int mkdir_func(const char *path, mode_t m) PROLOGUE EPILOGUE } +//@-node:mkdir_func +//@+node:unlink_func static int unlink_func(const char *path) { @@ -151,6 +189,8 @@ static int unlink_func(const char *path) PROLOGUE EPILOGUE } +//@-node:unlink_func +//@+node:rmdir_func static int rmdir_func(const char *path) { @@ -158,6 +198,8 @@ static int rmdir_func(const char *path) PROLOGUE EPILOGUE } +//@-node:rmdir_func +//@+node:symlink_func static int symlink_func(const char *path, const char *path1) { @@ -165,6 +207,8 @@ static int symlink_func(const char *path, const char *path1) PROLOGUE EPILOGUE } +//@-node:symlink_func +//@+node:rename_func static int rename_func(const char *path, const char *path1) { @@ -172,6 +216,8 @@ static int rename_func(const char *path, const char *path1) PROLOGUE EPILOGUE } +//@-node:rename_func +//@+node:link_func static int link_func(const char *path, const char *path1) { @@ -179,6 +225,8 @@ static int link_func(const char *path, const char *path1) PROLOGUE EPILOGUE } +//@-node:link_func +//@+node:chmod_func static int chmod_func(const char *path, mode_t m) { @@ -186,6 +234,8 @@ static int chmod_func(const char *path, mode_t m) PROLOGUE EPILOGUE } +//@-node:chmod_func +//@+node:chown_func static int chown_func(const char *path, uid_t u, gid_t g) { @@ -193,6 +243,8 @@ static int chown_func(const char *path, uid_t u, gid_t g) PROLOGUE EPILOGUE } +//@-node:chown_func +//@+node:truncate_func static int truncate_func(const char *path, off_t o) { @@ -200,6 +252,8 @@ static int truncate_func(const char *path, off_t 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); @@ -209,6 +263,8 @@ static int utime_func(const char *path, struct utimbuf *u) { PROLOGUE EPILOGUE } +//@-node:utime_func +//@+node:read_func static int read_func(const char *path, char *buf, size_t s, off_t off) { @@ -221,6 +277,8 @@ static int read_func(const char *path, char *buf, size_t s, off_t off) } EPILOGUE } +//@-node:read_func +//@+node:write_func static int write_func(const char *path, const char *buf, size_t t, off_t off) { @@ -228,13 +286,28 @@ static int write_func(const char *path, const char *buf, size_t t, off_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) { @@ -250,6 +323,8 @@ static void process_cmd(struct fuse *f, struct fuse_cmd *cmd, void *data) PyThreadState_Delete(state); PyEval_ReleaseLock(); } +//@-node:process_cmd +//@+node:pyfuse_loop_mt static void pyfuse_loop_mt(struct fuse *f) { @@ -263,6 +338,8 @@ static void pyfuse_loop_mt(struct fuse *f) /* Not yet reached: */ PyEval_RestoreThread(save); } +//@-node:pyfuse_loop_mt +//@+node:Fuse_main static PyObject * @@ -278,15 +355,15 @@ Fuse_main(PyObject *self, PyObject *args, PyObject *kw) "getattr", "readlink", "getdir", "mknod", "mkdir", "unlink", "rmdir", "symlink", "rename", "link", "chmod", "chown", "truncate", "utime", - "open", "read", "write", "flags", "multithreaded", NULL}; + "open", "read", "write", "release", "flags", "multithreaded", NULL}; memset(&op, 0, sizeof(op)); - if (!PyArg_ParseTupleAndKeywords(args, kw, "|OOOOOOOOOOOOOOOOOii", + 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, &flags, &multithreaded)) + &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; } @@ -308,6 +385,7 @@ Fuse_main(PyObject *self, PyObject *args, PyObject *kw) DO_ONE_ATTR(open); DO_ONE_ATTR(read); DO_ONE_ATTR(write); + DO_ONE_ATTR(release); fuse = fuse_new(0, flags, &op); if(multithreaded) @@ -315,11 +393,18 @@ Fuse_main(PyObject *self, PyObject *args, PyObject *kw) else fuse_loop(fuse); + //printf("Fuse_main: called\n"); + Py_INCREF(Py_None); return Py_None; } - -/* List of functions defined in the module */ +//@-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}, @@ -344,11 +429,8 @@ init_fuse(void) PyDict_SetItemString(d, "error", ErrorObject); PyDict_SetItemString(d, "DEBUG", PyInt_FromLong(FUSE_DEBUG)); } +//@-node:DL_EXPORT +//@-others - -/* - * Local Variables: - * indent-tabs-mode: t - * c-basic-offset: 8 - * End: - */ +//@-node:@file _fusemodule.c +//@-leo diff --git a/python/fuse.py b/python/fuse.py index ec1e633..ae621f3 100644 --- a/python/fuse.py +++ b/python/fuse.py @@ -1,3 +1,5 @@ +#@+leo-ver=4 +#@+node:@file fuse.py # # Copyright (C) 2001 Jeff Epler <jepler@unpythonic.dhs.org> # @@ -5,34 +7,92 @@ # 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 +import os, sys from errno import * +#@-node:imports +#@+node:class ErrnoWrapper class ErrnoWrapper: - def __init__(self, func): - self.func = func - - 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 - + #@ @+others + #@+node:__init__ + def __init__(self, func): + self.func = func + #@-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 + #@-node:__call__ + #@-others +#@-node:class ErrnoWrapper +#@+node:class Fuse class Fuse: - _attrs = ['getattr', 'readlink', 'getdir', 'mknod', 'mkdir', - 'unlink', 'rmdir', 'symlink', 'rename', 'link', 'chmod', - 'chown', 'truncate', 'utime', 'open', 'read', 'write'] - - flags = 0 - multithreaded = 0 - 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) + #@ @+others + #@+node:attribs + _attrs = ['getattr', 'readlink', 'getdir', 'mknod', 'mkdir', + 'unlink', 'rmdir', 'symlink', 'rename', 'link', 'chmod', + 'chown', 'truncate', 'utime', 'open', 'read', 'write', 'release'] + + flags = 0 + multithreaded = 0 + + #@-node:attribs + #@+node:__init__ + 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) + #@-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) + #@-node:main + #@-others +#@-node:class Fuse +#@-others +#@-node:@file fuse.py +#@-leo diff --git a/python/xmp.py b/python/xmp.py index 271e269..e85faeb 100755 --- a/python/xmp.py +++ b/python/xmp.py @@ -1,4 +1,7 @@ #!/usr/bin/env python +#@+leo-ver=4 +#@+node:@file xmp.py +#@@first #!/usr/bin/env python # # Copyright (C) 2001 Jeff Epler <jepler@unpythonic.dhs.org> # @@ -6,78 +9,153 @@ # See the file COPYING. # +#@+others +#@+node:imports + from fuse import Fuse import os from errno import * from stat import * +import thread +#@-node:imports +#@+node:class Xmp class Xmp(Fuse): - flags = 1 - - def getattr(self, path): - return os.lstat(path) - - def readlink(self, path): - return os.readlink(path) - - def getdir(self, path): - return map(lambda x: (x,0), os.listdir(path)) - - def unlink(self, path): - return os.unlink(path) - - def rmdir(self, path): - return os.rmdir(path) - - def symlink(self, path, path1): - return os.symlink(path, path1) - - def rename(self, path, path1): - return os.rename(path, path1) - - def link(self, path, path1): - return os.link(path, path1) - def chmod(self, path, mode): - return os.chmod(path, mode) - - def chown(self, path, user, group): - return os.chown(path, user, group) - - def truncate(self, path, size): - f = open(path, "w+") - return f.truncate(size) - - 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 - - def mkdir(self, path, mode): - return os.mkdir(path, mode) - - def utime(self, path, times): - return os.utime(path, times) - - def open(self, path, flags): - os.close(os.open(path, flags)) - return 0 - - def read(self, path, len, offset): - f = open(path, "r") - f.seek(offset) - return f.read(len) - - def write(self, path, buf, off): - f = open(path, "r+") - f.seek(off) - f.write(buf) - return len(buf) + #@ @+others + #@+node:__init__ + def __init__(self, *args, **kw): + + Fuse.__init__(self, *args, **kw) + + if 1: + print "mountpoint: %s" % repr(self.mountpoint) + print "unnamed mount options: %s" % self.optlist + print "named mount options: %s" % self.optdict + + # do stuff to set up your filesystem here, if you want + #thread.start_new_thread(self.mythread, ()) + pass + #@-node:__init__ + #@+node:mythread + 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" + + #@-node:mythread + #@+node:attribs + flags = 1 + + #@-node:attribs + #@+node:getattr + def getattr(self, path): + return os.lstat(path) + #@-node:getattr + #@+node:readlink + def readlink(self, path): + return os.readlink(path) + #@-node:readlink + #@+node:getdir + def getdir(self, path): + return map(lambda x: (x,0), os.listdir(path)) + #@-node:getdir + #@+node:unlink + def unlink(self, path): + return os.unlink(path) + #@-node:unlink + #@+node:rmdir + def rmdir(self, path): + return os.rmdir(path) + #@-node:rmdir + #@+node:symlink + def symlink(self, path, path1): + return os.symlink(path, path1) + #@-node:symlink + #@+node:rename + def rename(self, path, path1): + return os.rename(path, path1) + #@-node:rename + #@+node:link + def link(self, path, path1): + return os.link(path, path1) + #@-node:link + #@+node:chmod + def chmod(self, path, mode): + return os.chmod(path, mode) + #@-node:chmod + #@+node:chown + def chown(self, path, user, group): + return os.chown(path, user, group) + #@-node:chown + #@+node:truncate + def truncate(self, path, size): + f = open(path, "w+") + return f.truncate(size) + #@-node:truncate + #@+node:mknod + 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 + #@-node:mknod + #@+node:mkdir + def mkdir(self, path, mode): + return os.mkdir(path, mode) + #@-node:mkdir + #@+node:utime + def utime(self, path, times): + return os.utime(path, times) + #@-node:utime + #@+node:open + def open(self, path, flags): + #print "open: %s" % path + os.close(os.open(path, flags)) + return 0 + + #@-node:open + #@+node:read + def read(self, path, len, offset): + #print "read: %s" % path + f = open(path, "r") + f.seek(offset) + return f.read(len) + + #@-node:read + #@+node:write + def write(self, path, buf, off): + #print "write: %s" % path + f = open(path, "r+") + f.seek(off) + f.write(buf) + return len(buf) + + #@-node:write + #@+node:release + def release(self, path): + #print "release: %s" % path + return 0 + + #@-node:release + #@-others +#@-node:class Xmp +#@+node:mainline if __name__ == '__main__': + server = Xmp() server.flags = 0 server.multithreaded = 1; server.main() +#@-node:mainline +#@-others +#@-node:@file xmp.py +#@-leo |