Example #1
0
def test_deletion():
	meta1 = "apple"
	meta2 = "microsoft"
	meta3 = "linux"
	T = BlobTree(strdict())
	T.create_subtree("/sub", meta1)
	T.create_subtree("/sub/sub", meta2)
	T.create_data("/sub/data", meta3)
	T.set_data("/sub/data", "some data")
	assert "sub" in T.list_dir("/")
	T.unlink("/sub")
	assert not "sub" in T.list_dir("/")
Example #2
0
def test_deletion():
    meta1 = "apple"
    meta2 = "microsoft"
    meta3 = "linux"
    T = BlobTree(strdict())
    T.create_subtree("/sub", meta1)
    T.create_subtree("/sub/sub", meta2)
    T.create_data("/sub/data", meta3)
    T.set_data("/sub/data", "some data")
    assert "sub" in T.list_dir("/")
    T.unlink("/sub")
    assert not "sub" in T.list_dir("/")
Example #3
0
class KVFS:
    """A Key-Value-File-System
	This class is initialized with a key value store
	and implements a file system on top of it,
	providing methods like mkdir, create, read, write, ...
	
	In a failure case IOError gets raised.
	
	Some features like permissions or hardlinks are not yet supported."""
    def __init__(self, kv_store):
        self._bt = BlobTree(kv_store)
        m = _MetaData()
        m['st_mode'] = m['st_mode'] | stat.S_IFDIR
        self.root_meta = m

    def getattr(self, path):
        """returns the attributes of the object at `path`."""
        if path == "/":
            return self.root_meta
        try:
            return _MetaData(self._bt.get_meta_data(path))
        except KeyError:
            _raise_io(errno.ENOENT, path)

    def setattr(self, path, attr):
        """sets the attributes of the object at `path`."""
        if path == "/":
            _raise_io(errno.EPERM, path)
        try:
            self._bt.set_meta_data(path, attr)
        except (KeyError, IndexError):
            _raise_io(errno.ENOENT, path)

    def create(self, path):
        """create a file"""
        if self._bt.exists(path):
            _raise_io(errno.EEXIST, path)
        m = _MetaData()
        m['st_mode'] = m['st_mode'] | stat.S_IFREG
        m['st_size'] = 0
        self._bt.create_data(path, str(m))

    def mkdir(self, path):
        """creates a directory"""
        if self._bt.exists(path):
            _raise_io(errno.EEXIST, path)
        m = _MetaData()
        m['st_mode'] = m['st_mode'] | stat.S_IFDIR
        self._bt.create_subtree(path, str(m))

    def readdir(self, path):
        """read contents of a directory"""
        try:
            files = self._bt.list_dir(path)
        except KeyError:
            _raise_io(errno.ENOENT, path)
        yield '.'
        yield '..'
        for f in files:
            yield f

    def readlink(self, path):
        """resolves a symbolic link"""
        # TODO recursive?
        meta = self.getattr(path)
        try:
            return meta['symlink']
        except KeyError:
            _raise_io(errno.ENOLINK, path)

    def symlink(self, target, name):
        """create a symbolic link target->name"""
        if self._bt.exists(target):
            _raise_io(errno.EEXIST, target)
        m = _MetaData()
        # use attributes to save target and link property
        m['symlink'] = name
        m['st_mode'] = m['st_mode'] | stat.S_IFLNK
        self._bt.create_data(target, str(m))

    def remove(self, path):
        """removes a file or directory"""
        try:
            self._bt.unlink(path)
        except KeyError:
            _raise_io(errno.ENOENT, path)

    def rename(self, old, new):
        """rename a file (note that directories may change)"""
        try:
            self._bt.rename(old, new)
        except KeyError:
            _raise_io(errno.ENOENT, old)

    def link(self, target, name):
        """create a hardlink"""
        self._bt.create_data(target, self.getattr(name))
        self._bt.set_data(target, self._bt.get_data(name))
        # FIXME this is a copy, not a hardlink!
        # Subsequent changes won't be applied.
        # A transparent link blob type would be needed,
        # but that should rather be called a symlink.

    def _get_data(self, path):
        """get data from path or raise IOERROR"""
        try:
            return self._bt.get_data(path)
        except KeyError:
            _raise_io(errno.ENOENT, path)
        except TypeError:
            _raise_io(errno.EISDIR, path)

    def read(self, path, length=2000000000, offset=0):
        """read data from a file"""
        data = self._get_data(path)
        return data[offset:offset + length]

    def write(self, path, buf, offset=0):
        """write data to a file"""
        meta = self.getattr(path)
        if offset == 0 and len(buf) >= meta['st_size']:
            data = buf
        else:
            data = self._get_data(path)
            data = data[:offset] + buf + data[offset + len(buf):]
        meta['st_mtime'] = time.time()
        meta['st_size'] = len(data)
        self._bt.set_data(path, data, str(meta))

    def flush(self, path="/"):
        """clear all buffers, finish all pending operations"""
        self._bt.flush()

    def truncate(self, path, length):
        """truncate file to given length"""
        data = self._get_data(path)
        self._bt.set_data(path, data[:length])
Example #4
0
class KVFS:
	"""A Key-Value-File-System
	This class is initialized with a key value store
	and implements a file system on top of it,
	providing methods like mkdir, create, read, write, ...
	
	In a failure case IOError gets raised.
	
	Some features like permissions or hardlinks are not yet supported."""
	def __init__(self, kv_store):
		self._bt = BlobTree(kv_store)
		m = _MetaData()
		m['st_mode'] = m['st_mode'] | stat.S_IFDIR
		self.root_meta = m

	def getattr(self, path):
		"""returns the attributes of the object at `path`."""
		if path == "/":
			return self.root_meta
		try:
			return _MetaData(self._bt.get_meta_data(path))
		except KeyError:
			_raise_io(errno.ENOENT, path)
			
	def setattr(self, path, attr):
		"""sets the attributes of the object at `path`."""
		if path == "/":
			_raise_io(errno.EPERM, path)
		try:
			self._bt.set_meta_data(path, attr)
		except (KeyError, IndexError):
			_raise_io(errno.ENOENT, path)

	def create(self, path):
		"""create a file"""
		if self._bt.exists(path):
			_raise_io(errno.EEXIST, path)
		m = _MetaData()
		m['st_mode'] = m['st_mode'] | stat.S_IFREG
		m['st_size'] = 0
		self._bt.create_data(path, str(m))

	def mkdir(self, path):
		"""creates a directory"""
		if self._bt.exists(path):
			_raise_io(errno.EEXIST, path)
		m = _MetaData()
		m['st_mode'] = m['st_mode'] | stat.S_IFDIR
		self._bt.create_subtree(path, str(m))

	def readdir(self, path):
		"""read contents of a directory"""
		try:
			files = self._bt.list_dir(path)
		except KeyError:
			_raise_io(errno.ENOENT, path)
		yield '.'
		yield '..'
		for f in files:
			yield f

	def readlink(self, path):
		"""resolves a symbolic link"""
		# TODO recursive?
		meta = self.getattr(path)
		try:
			return meta['symlink']
		except KeyError:
			_raise_io(errno.ENOLINK, path)

	def symlink(self, target, name):
		"""create a symbolic link target->name"""
		if self._bt.exists(target):
			_raise_io(errno.EEXIST, target)
		m = _MetaData()
		# use attributes to save target and link property
		m['symlink'] = name
		m['st_mode'] = m['st_mode'] | stat.S_IFLNK
		self._bt.create_data(target, str(m))
		
	def remove(self, path):
		"""removes a file or directory"""
		try:
			self._bt.unlink(path)
		except KeyError:
			_raise_io(errno.ENOENT, path)

	def rename(self, old, new):
		"""rename a file (note that directories may change)"""
		try:
			self._bt.rename(old, new)
		except KeyError:
			_raise_io(errno.ENOENT, old)

	def link(self, target, name):
		"""create a hardlink"""
		self._bt.create_data(target, self.getattr(name))
		self._bt.set_data(target, self._bt.get_data(name))
		# FIXME this is a copy, not a hardlink!
		# Subsequent changes won't be applied.
		# A transparent link blob type would be needed,
		# but that should rather be called a symlink.

	def _get_data(self, path):
		"""get data from path or raise IOERROR"""
		try:
			return self._bt.get_data(path)
		except KeyError:
			_raise_io(errno.ENOENT, path)
		except TypeError:
			_raise_io(errno.EISDIR, path)

	def read(self, path, length=2000000000, offset=0):
		"""read data from a file"""
		data = self._get_data(path)
		return data[offset:offset+length]

	def write(self, path, buf, offset=0):
		"""write data to a file"""
		meta = self.getattr(path)
		if offset==0 and len(buf) >= meta['st_size']:
			data = buf
		else:
			data = self._get_data(path)
			data = data[:offset] + buf + data[offset+len(buf):]
		meta['st_mtime'] = time.time()
		meta['st_size'] = len(data)
		self._bt.set_data(path, data, str(meta))

	def flush(self, path="/"):
		"""clear all buffers, finish all pending operations"""
		self._bt.flush()

	def truncate(self, path, length):
		"""truncate file to given length"""
		data = self._get_data(path)
		self._bt.set_data(path, data[:length])