aboutsummaryrefslogtreecommitdiffstats
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/README21
-rw-r--r--python/_fusemodule.c178
-rw-r--r--python/fuse.py110
-rwxr-xr-xpython/xmp.py202
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