+class RouteMeta(type):
+ """
+ Metaclass to calculate controller methods
+
+ Routes needs to be pre-seeded with a list of "controllers". For
+ all descendents of RouteFS, the list of controllers is defined to
+ be any non-private methods of the class that were not in the
+ RouteFS class.
+ """
+ def __init__(cls, classname, bases, dict_):
+ super(RouteMeta, cls).__init__(classname, bases, dict_)
+ if bases != (fuse.Fuse,):
+ new_funcs = set(dict_.keys()).difference(dir(RouteFS))
+ cls.controllers([func for func in new_funcs \
+ if not func.startswith('_')])
+
+class RouteFS(fuse.Fuse):
+ """
+ RouteFS: Web 2.0 for filesystems
+ """
+ __metaclass__ = RouteMeta
+ def __init__(self, *args, **kwargs):
+ super(RouteFS, self).__init__(*args, **kwargs)
+
+ self.map = self.make_map()
+ self.map.create_regs(self.controller_list)
+
+ def make_map(self):
+ """
+ This method should be overridden by descendents of RouteFS to
+ define the routing for the filesystem
+ """
+ m = routes.Mapper()
+
+ m.connect(':controller')
+
+ return m
+
+ @classmethod
+ def controllers(cls, lst):
+ cls.controller_list = lst
+
+ def _get_file(self, path):
+ """
+ Find the filesystem entry object for a given path
+ """
+ match = self.map.match(path)
+ if match is None:
+ return
+ controller = match.pop('controller')
+ result = getattr(self, controller)(**match)
+ return result
+
+ def readdir(self, path, offset):
+ """
+ If the path referred to is a directory, return the elements of
+ that diectory
+ """
+ obj = self._get_file(path)
+ if type(obj) is not Directory:
+ return
+ else:
+ for member in ['.', '..'] + obj:
+ yield fuse.Direntry(str(member))
+
+ def getattr(self, path):
+ """
+ Return the stat information for a path
+
+ The stat information for a directory, symlink, or file is
+ predetermined based on which it is.
+ """
+ obj = self._get_file(path)
+ if obj is None:
+ return -errno.ENOENT
+
+ st = RouteStat()
+ if type(obj) is Directory:
+ st.st_mode = stat.S_IFDIR | 0755
+ st.st_nlink = 2
+ elif type(obj) is Symlink:
+ st.st_mode = stat.S_IFLNK | 0777
+ st.st_nlink = 1
+ st.st_size = len(obj)
+ else:
+ st.st_mode = stat.S_IFREG | 0444
+ st.st_nlink = 1
+ st.st_size = len(obj)
+
+ return st
+
+ def read(self, path, length, offset):
+ """
+ If the path specified is a file, return the requested portion
+ of the file
+ """
+ obj = self._get_file(path)
+ if obj is None:
+ return -errno.ENOENT
+ elif type(obj) in (Directory, Symlink):
+ return -errno.EINVAL
+ else:
+ return obj[offset:offset + length]
+
+ def readlink(self, path):
+ """
+ If the path specified is a symlink, return the target
+ """
+ obj = self._get_file(path)
+ if type(obj) is not Symlink:
+ return -errno.EINVAL
+ else:
+ return obj
+
+class Directory(list):
+ """
+ A dummy class representing a filesystem entry that should be a
+ directory
+ """