Пример #1
0
    def __init__(self, root, mount_point):
        self.root = root
        self.mount_point = mount_point

        db_path = self.root + '/.store.db'

        st_dict = self._get_st_dict(os.lstat(self.root))
        self.gid = st_dict['st_gid']
        self.uid = st_dict['st_uid']

        stv = self._get_st_dict(os.lstat(self.root))

        self.store = HandleStore(db_path, stv)

        handle = self._get_handle_path('/')
        if handle is None:
            handle = (hash_path('/'), '/', None, 1, stv, None)
            self.store.put(hash_path('/'), handle)
Пример #2
0
class FlatFS(Operations):
    def __init__(self, root, mount_point):
        self.root = root
        self.mount_point = mount_point

        db_path = self.root + '/.store.db'

        st_dict = self._get_st_dict(os.lstat(self.root))
        self.gid = st_dict['st_gid']
        self.uid = st_dict['st_uid']

        stv = self._get_st_dict(os.lstat(self.root))

        self.store = HandleStore(db_path, stv)

        handle = self._get_handle_path('/')
        if handle is None:
            handle = (hash_path('/'), '/', None, 1, stv, None)
            self.store.put(hash_path('/'), handle)

    def init(self, path):
        super(FlatFS, self).init(path)

    def __del__(self):
        del self.store

    # Helpers
    # =======
    def _full_path(self, partial):
        path = self._get_full_path_hash(hash_path(partial))
        return path

    def _full_path_handle(self, handle):
        return os.path.join(self.root, handle[0])

    def _get_full_path_hash(self, _hash_path):
        path = os.path.join(self.root, _hash_path)
        return path

    def _is_dir(self, path):
        handle = self._get_handle_path(path)
        return self._is_dir_handle(handle)

    def _is_dir_handle(self, handle):
        return handle is not None and handle[3]

    def _get_handle_path(self, path):
        return self._get_handle_hash(hash_path(path))

    def _get_handle_hash(self, path_hash):
        return self.store.get(path_hash)

    def _list_dir(self, path):
        return self.store.get("l_" + hash_path(path))

    def _copy_handle(self, handle, key=None, name=None, stv=None):
        if key is None:
            key = handle[0]
        if name is None:
            name = handle[1]
        if stv is None:
            stv = handle[4]
        return key, name, handle[2], handle[3], stv, handle[5]

    def _create_handle(self, path, is_dir, dir_stv=None, link_path=None):
        dir_flag = 0
        if is_dir:
            dir_flag = 1

        parent, name = _split_path(path)

        handle = (hash_path(path), name, parent, dir_flag, dir_stv, link_path)

        self.store.put(handle[0], handle)
        if is_dir:
            self.store.put("l_" + handle[0], [])

        parent_dir_key = "l_" + hash_path("/" + handle[2])
        _dir = self.store.get(parent_dir_key)
        _dir.append(handle[1])

        self.store.put(parent_dir_key, _dir)

        return handle

    def _rename_handle(self, old, new):
        parent, name = _split_path(new)

        self._remove_handle(new)

        parent, old_name = os.path.split(old)

        parent_hash = hash_path(parent)
        parent_l = self.store.get("l_" + parent_hash)
        parent_l.remove(old_name)
        parent_l.append(name)
        self.store.put("l_" + parent_hash, parent_l)

        handle = self._remove_handle(old)
        handle = self._copy_handle(handle, key=hash_path(new), name=name)

        self.store.put(handle[0], handle)

    def _update_dir_stv(self, handle, new_stv):
        handle = self._copy_handle(handle, stv=new_stv)
        self.store.put(handle[0], handle)

    def _remove_handle(self, path):
        _hash_path = hash_path(path)

        handle = self.store.remove(_hash_path)
        if handle is not None:
            parent, name = os.path.split(path)

            if handle[3] == 1:
                self.store.remove('l_' + _hash_path)

            parent_hash = hash_path(parent)
            parent_l = self.store.get("l_" + parent_hash)
            if name in parent_l:
                parent_l.remove(name)
                self.store.put("l_" + parent_hash, parent_l)

        return handle

    def _get_dir_stv(self, handle):
        return handle[4]

    def _create_new_dir_st(self, mode):
        return dict(st_mode=(S_IFDIR | mode), st_nlink=2, st_size=0, st_ctime=time(), st_mtime=time(), st_atime=time(),
                    st_gid=self.gid, st_uid=self.uid)

    def _get_st_dict(self, st):
        return dict((key, getattr(st, key)) for key in
                    ('st_atime', 'st_ctime', 'st_gid', 'st_mode', 'st_mtime', 'st_nlink', 'st_size', 'st_uid'))

    # Filesystem methods
    # ==================

    def access(self, path, mode):
        if not os.access(self.root, mode):
            raise FuseOSError(errno.EACCES)

    def chmod(self, path, mode):
        handle = self._get_handle_path(path)
        if self._is_dir_handle(handle):
            stv = self._get_dir_stv(handle)
            stv['st_mode'] &= 0770000
            stv['st_mode'] |= mode
            self._update_dir_stv(handle, stv)
            return 0
        full_path = self._full_path(path)
        return os.chmod(full_path, mode)

    def chown(self, path, uid, gid):
        handle = self._get_handle_path(path)
        if self._is_dir_handle(handle):
            stv = self._get_dir_stv(handle)
            stv['st_uid'] = uid
            stv['st_gid'] = gid
            self._update_dir_stv(handle, stv)
            return 0
        full_path = self._full_path(path)
        return os.chown(full_path, uid, gid)

    def getattr(self, path, fh=None):
        handle = self._get_handle_path(path)
        if self._is_dir_handle(handle):
            return self._get_dir_stv(handle)
        else:
            st = os.lstat(self._full_path(path))
            return self._get_st_dict(st)

    def readdir(self, path, fh):
        dirents = ['.', '..']
        dirents.extend(self._list_dir(path))
        for r in dirents:
            yield r

    def readlink(self, path):
        return os.readlink(self._full_path(path))

    def mknod(self, path, mode, dev):
        return os.mknod(self._full_path(path), mode, dev)

    def rmdir(self, path):
        list_dir = self._list_dir(path)
        if len(list_dir) > 0:
            raise FuseOSError(errno.ENOANO)
        self._remove_handle(path)

    def mkdir(self, path, mode):
        handle = self._get_handle_path(path)
        if handle is not None:
            raise FuseOSError(errno.ENOANO)
        self._create_handle(path, True, dir_stv=self._create_new_dir_st(mode))
        return

    def statfs(self, path):
        handle = self._get_handle_path(path)
        if self._is_dir_handle(handle):
            stv = os.statvfs(self.root)
        else:
            full_path = self._full_path(path)
            stv = os.statvfs(full_path)

        return dict((key, getattr(stv, key)) for key in ('f_bavail', 'f_bfree',
                                                         'f_blocks', 'f_bsize', 'f_favail', 'f_ffree', 'f_files',
                                                         'f_flag',
                                                         'f_frsize', 'f_namemax'))

    def unlink(self, path):
        res = os.unlink(self._full_path(path))
        self._remove_handle(path)
        return res

    def symlink(self, name, target):
        handle = self._get_handle_path(name)
        if handle is not None:
            raise FuseOSError(errno.ENOANO)

        path = os.path.abspath(os.path.join(self.mount_point, "." + os.path.split(name)[0], target))

        if path.startswith(self.mount_point):
            fuse_path = path[len(self.mount_point):]
            res = os.symlink(hash_path(fuse_path), self._full_path(name))
        else:
            res = os.symlink(path, self._full_path(name))

        self._create_handle(name, False, link_path=target)

        return res

    def rename(self, old, new):
        handle = self._get_handle_path(old)
        if handle is None:
            raise FuseOSError(errno.ENOANO)
        res = os.rename(self._full_path(old), self._full_path(new))
        self._rename_handle(old, new)
        return res

    def link(self, target, name):
        return os.link(self._full_path(target), self._full_path(name))

    def utimens(self, path, times=None):
        handle = self._get_handle_path(path)
        if self._is_dir_handle(handle):
            stv = self._get_dir_stv(handle)
            atime, mtime = times if times else (time(), time())
            stv['st_atime'] = atime
            stv['st_mtime'] = mtime
            self._update_dir_stv(handle, stv)
            return
        elif handle[5] is not None:
            return

        return os.utime(self._full_path(path), times)

    # File methods
    # ============

    def open(self, path, flags):
        full_path = self._full_path(path)
        return os.open(full_path, flags)

    def create(self, path, mode, fi=None):
        handle = self._get_handle_path(path)
        if handle is not None:
            raise FuseOSError(errno.ENOANO)
        res = os.open(self._full_path(path), os.O_WRONLY | os.O_CREAT, mode)
        self._create_handle(path, False)
        return res

    def read(self, path, length, offset, fh):
        os.lseek(fh, offset, os.SEEK_SET)
        return os.read(fh, length)

    def write(self, path, buf, offset, fh):
        os.lseek(fh, offset, os.SEEK_SET)
        return os.write(fh, buf)

    def truncate(self, path, length, fh=None):
        full_path = self._full_path(path)
        with open(full_path, 'r+') as f:
            f.truncate(length)

    def flush(self, path, fh):
        return os.fsync(fh)

    def release(self, path, fh):
        return os.close(fh)

    def fsync(self, path, fdatasync, fh):
        return self.flush(path, fh)