fix
authorMiklos Szeredi <miklos@szeredi.hu>
Thu, 11 Dec 2003 14:27:57 +0000 (14:27 +0000)
committerMiklos Szeredi <miklos@szeredi.hu>
Thu, 11 Dec 2003 14:27:57 +0000 (14:27 +0000)
ChangeLog
python/README
python/_fusemodule.c
python/fuse.py
python/xmp.py
util/fusermount.c
util/mount.fuse [new file with mode: 0644]

index ada91667104b74f0214bc388aa2156ab6e183dbc..438e74f556945a07198d85aed9d61b5151fee9f9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
+2003-12-11  Miklos Szeredi <mszeredi@inf.bme.hu>
+
+       * Add file locking for mount/unmount (based on patch by Valient
+       Gough)
+
+2003-12-11  David McNab <david@rebirthing.co.nz>
+
+       * Python filesystem - was broken with python2.3, now fixed:
+          - changed PyTuple_* calls to PySequence_*, because os.lstat
+            is no longer returning a pure tuple
+          - changed PyInt_Check() calls to also call PyLong_Check,
+            to cover for cases (eg os.lstat) where longs are returned
+          - Added support for file 'release' handling, which IMO is
+            essential since this signals to a FS that writes to a file
+            are complete (and therefore the file can now be disposed of
+            meaningfully at the python filesystem's discretion)
+          - Added '__init__' handler to base Fuse class, which allows
+            your Python class to know the mountpoint and mount args,
+            as attributes myfs.mountpoint, myfs.optlist, myfs.optdict
+       
+       * General:
+          - added 'mount.fuse' script (in util/ dir), which is meant to be
+            symlinked from /sbin, and which allows FUSE filesystems to
+            be mounted with the 'mount' command, and listed in fstab;
+            also, mount arguments get passed to your filesystem
+
+
 2003-11-04  Miklos Szeredi <mszeredi@inf.bme.hu>
 
        * Fix kernel version detection (again).  Bugreport by Peter Levart
index 451c56c82a13c0cfec0a9290bb6d12a843ee0926..3b0d70fe217410109466b39b47627bf300eb93a3 100644 (file)
@@ -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
index 6956be2f8e233f7a67e4e5b015efbfb42c35fcc3..557d312bce33f37926bdfc0dba26f290c5651fe9 100644 (file)
@@ -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
index ec1e6330efd25ec4000cb2aca7634f59a6680dbf..ae621f31bb384198c1b7300d355ef8c619e041a5 100644 (file)
@@ -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
index 271e2696c263bee4407aa6ec0fac01c32c4d02a9..e85faeb006fdc37faa4892183ee8e8c6743304a3 100755 (executable)
@@ -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>
 #
 #    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
index f223c5f5668b217064ec2357ccbb645e99a55362..c451c41b3d46257b98c2da18e971474ee353f501 100644 (file)
@@ -59,6 +59,33 @@ static const char *get_user_name()
     }
 }
 
+/* use a lock file so that multiple fusermount processes don't try and
+   modify the mtab file at once! */
+static int lock_mtab()
+{
+    const char *mtab_lock = _PATH_MOUNTED ".fuselock";
+    int mtablock;
+    int res;
+
+    mtablock = open(mtab_lock, O_RDWR | O_CREAT, 0600);
+    if(mtablock >= 0) {
+        res = lockf(mtablock, F_LOCK, 0);
+        if(res < 0)
+            perror("error getting lock: %s");
+    } else
+        fprintf(stderr, "unable to open fuse lock file, continuing anyway\n");
+
+    return mtablock;
+}
+
+static void unlock_mtab(int mtablock)
+{
+    if(mtablock >= 0) {
+       lockf(mtablock, F_ULOCK, 0);
+       close(mtablock);
+    }
+}
+
 static int add_mount(const char *dev, const char *mnt, const char *type)
 {
     int res;
@@ -343,6 +370,7 @@ static int mount_fuse(const char *mnt, int flags)
     const char *dev = FUSE_DEV;
     const char *type = "fuse";
     struct stat stbuf;
+    int mtablock;
 
     res = check_perm(mnt, &stbuf);
     if(res == -1)
@@ -371,8 +399,10 @@ static int mount_fuse(const char *mnt, int flags)
     res = do_mount(dev, mnt, type, stbuf.st_mode & S_IFMT, fd, flags);
     if(res == -1)
         return -1;
-
+    
+    mtablock = lock_mtab();
     res = add_mount(dev, mnt, type);
+    unlock_mtab(mtablock);
     if(res == -1) {
         umount(mnt);
         return -1;
@@ -530,7 +560,9 @@ int main(int argc, char *argv[])
         restore_privs();
     
     if(unmount) {
+        int mtablock = lock_mtab();
         res = remove_mount(mnt);
+        unlock_mtab(mtablock);
         if(res == -1)
             exit(1);
         
diff --git a/util/mount.fuse b/util/mount.fuse
new file mode 100644 (file)
index 0000000..4ec1409
--- /dev/null
@@ -0,0 +1,85 @@
+#!/usr/bin/env python
+#@+leo-ver=4
+#@+node:@file mount.fuse
+#@@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()
+
+#@-node:@file mount.fuse
+#@-leo