author Alain Leufroy <alain.leufroy@logilab.fr>
Tue, 02 Apr 2013 12:21:13 +0200
changeset 14 f4791bdd245a
parent 0 03d0140deb6c
child 2 3164ba33cbc3
permissions -rw-r--r--
refactorization - separate fs specific code to hdf5 specific codes - user better names - use generators instead of list - move functions to class method as they should be overwriten for future implementations

#!/usr/bin/env python

# Copyright (C) 2012  Alain Leufroy <alain.leufroy@logilab.fr>
# This program can be distributed under the terms of the GNU LGPL.
# See the file COPYING.

HDF5 filesystem implementation.

import os
import os.path as osp
import stat
import errno
from itertools import imap, chain
from functools import partial

import h5py

import fuse
fuse.fuse_python_api = (0, 2)

__version__ = (0, 0, 1)

class H5IOError(IOError):
    """Raised when a bad hdf5 entry was given"""
    # OSError and IOError are converted to errno by fuse.ErrnoWrapper

class Stat(fuse.FuseStruct): # pylint: disable-msg=R0903
    "Fill up stat attributes with user acces"
    st_mode  = None
    st_ino   = 0
    st_dev   = 0
    st_nlink = None
    st_uid   = os.getuid()
    st_gid   = os.getgid()
    st_size  = 0
    st_atime = 0
    st_mtime = 0
    st_ctime = 0

class GroupStat(Stat): # pylint: disable-msg=R0903
    "Fill up stat attributes with user acces for Groups"
    st_mode = stat.S_IFDIR | stat.S_IREAD | stat.S_IEXEC
    st_nlink = 1

class DatasetStat(Stat): # pylint: disable-msg=R0903
    "Fill up stat attributes with user acces for Groups"
    st_mode = stat.S_IFREG | stat.S_IREAD
    st_nlink = 1

# TODO: h5file.id.get_comment() ...
class FsMixin(object):
    '''Implement the HDF5 filesytem interface'''

    h5file = None

    def get_entry(self, path):
        '''Return the entry recorded at ``path`` or raise H5IOError'''
            h5entry = self.h5file[path]
        except KeyError:
            raise H5IOError(errno.ENOENT, 'No such Dataset or Group', path)
        return h5entry

    def get_stat(h5entry):
        '''Return the entry stat information (an instance of Stat)'''
        if isinstance(h5entry, h5py.highlevel.Group):
            return GroupStat()
        if isinstance(h5entry, h5py.highlevel.Dataset):
            return DatasetStat()
        raise H5IOError(errno.ENOENT, 'Unknown entry type', h5entry.name)

    def get_name(h5entry):
        '''Return the entry file name as string'''
        # XXX unicode seems not to be allowed
        return str(osp.basename(h5entry.name))

    def list_group(self, group, specs=('.', '..')):
        '''A fonction generator that yields name of the entries in the group.
        The list is in arbritary order with specials entries ``specs``.'''
        return chain(iter(specs), imap(self.get_name, group.itervalues()))

    def readdir(self, path, offset):
        '''Return a generator that yields entries from the given Group path'''
        convert = partial(fuse.Direntry, offset=offset)
        return imap(convert, self.list_group(self.get_entry(path)))

    def getattr(self, path):
        '''Return the stat attributes of the given ``path``'''
        return self.get_stat(self.get_entry(path))

def __main__():
    '''Main entry point that start the HDF5 filesystem server'''
    usage = "\nUserspace HDF5 file explorer.\n\n%prog sourcefile mountpoint"
    class H5FS(FsMixin, fuse.Fuse):
        '''merge Fuse + HDF5 interface'''
    server = H5FS(version="%proog " + fuse.__version__,
    _opts, ags = server.cmdline
    h5file = h5py.File(ags.pop(), 'r')
        server.h5file = h5file

if __name__ == '__main__':