Димитър обнови решението на 30.04.2015 16:26 (преди над 9 години)
+class Dir:
+ def __init__(self, name):
+ self.name = name
+ self._nodes = {}
+ self.is_directory = True
+
+ def __contains__(self, node):
+ return node in self._nodes.values()
+
+ def is_filesystem(self):
+ return False
+
+ @property
+ def directories(self):
+ nodes = list(filter(lambda x: not x.is_filesystem(),
+ self._nodes.values()))
+ return [node for node in nodes if node.is_directory]
+
+ @property
+ def files(self):
+ nodes = list(filter(lambda x: not x.is_filesystem(),
+ self._nodes.values()))
+ return [node for node in nodes
+ if not node.is_directory]
+
+ @property
+ def nodes(self):
+ return list(self._nodes.values())
+
+ @property
+ def size(self):
+ return (1 + sum([node.size for node in self.directories]) +
+ sum([node.real_size for node in self.files]))
+
+ def contains_path(self, path):
+ return path in self._nodes
+
+
+class File():
+ def __init__(self, name, content, fs):
+ self.name = name
+ self.encoding = "utf-8"
+ self._content = bytearray(content, self.encoding)
+ self.hard_links_count = 1
+ self.is_directory = False
+ self.fs = fs
+
+ @property
+ def size(self):
+ return len(self._content) + 1
+
+ @property
+ def real_size(self):
+ return len(self._content)/self.hard_links_count + 1
+
+ @property
+ def content(self):
+ return self._content.decode(self.encoding)
+
+ def is_filesystem(self):
+ return False
+
+ def append(self, text):
+ if self.fs.available_size + len(text) > self.fs.size:
+ raise NotEnoughSpaceError()
+ self._content.extend(bytearray(text, self.encoding))
+
+ def truncate(self, text):
+ if self.fs.available_size - self.size + len(text) + 1 > self.fs.size:
+ raise NotEnoughSpaceError()
+ self._content.clear()
+ self._content.extend(bytearray(text, self.encoding))
+
+
+class Symlink:
+ def __init__(self, link, fs):
+ self.link_path = link
+ self.size = 1
+ self.fs = fs
+ self.is_directory = fs.get_node(link).is_directory
+
+ def is_filesystem(self):
+ return False
+
+ @property
+ def real_size(self):
+ return self.size
+
+ def __getattr__(self, name):
+ try:
+ node = self.fs.get_node(self.link_path)
+ except NodeDoesNotExistError:
+ raise LinkPathError
+
+ return getattr(node, name)
+
+
+class FileSystem:
+ def __init__(self, size, dir_separator='/'):
+ if size <= 0:
+ raise NotEnoughSpaceError()
+
+ self.size = size
+ self.dir_separator = dir_separator
+ self.root = Dir(self.dir_separator)
+
+ @property
+ def available_size(self):
+ return int(self.size - self.root.size)
+
+ def is_filesystem(self):
+ return True
+
+ def split_path(self, path):
+ return [segment for segment in path.split(self.dir_separator)
+ if segment != '']
+
+ def get_basepath_and_path(self, path_):
+ split_path = self.split_path(path_)
+ path = split_path[-1]
+ base_path = self.dir_separator.join(split_path[:-1])
+ if len(base_path.strip()) == 0:
+ base_path = self.dir_separator
+ return (base_path, path)
+
+ def get_node(self, path):
+ if len(path.strip()) == 0:
+ raise NodeDoesNotExistError
+
+ if len(path.strip().replace(self.dir_separator, "")) == 0:
+ return self.root
+
+ current = self.root
+ segments = self.split_path(path)
+
+ for segment in segments:
+ if current.contains_path(segment):
+ current = current._nodes[segment]
+ if current.is_filesystem():
+ current = current.root
+ else:
+ raise NodeDoesNotExistError('"{}" does not exist'.format(path))
+
+ return current
+
+ def create(self, path, directory=False, content=''):
+ node = None
+ parent, name = self.get_basepath_and_path(path)
+ node = Dir(name) if directory else File(name, content, self)
+
+ if self.available_size - node.size < 0:
+ raise NotEnoughSpaceError()
+
+ try:
+ destination = self.get_node(parent)
+ except NodeDoesNotExistError:
+ raise DestinationNodeDoesNotExistError()
+
+ if destination.contains_path(name):
+ raise DestinationNodeExistsError()
+
+ destination._nodes[name] = node
+
+ def remove(self, path, directory=False, force=True):
+ node = self.get_node(path)
+ if node.is_directory and not directory:
+ raise NonExplicitDirectoryDeletionError()
+
+ if node.is_directory and not force and len(node.nodes) != 0:
+ raise NonEmptyDirectoryDeletionError()
+
+ parent, name = self.get_basepath_and_path(path)
+ parent_dir = self.get_node(parent)
+ del parent_dir._nodes[name]
+
+ def move(self, source, destination):
+ try:
+ destination_node = self.get_node(destination)
+ except NodeDoesNotExistError:
+ raise DestinationNodeDoesNotExistError()
+
+ try:
+ source_node = self.get_node(source)
+ except NodeDoesNotExistError:
+ raise SourceNodeDoesNotExistError()
+
+ if not destination_node.is_directory:
+ raise DestinationNotADirectoryError()
+
+ parent, name = self.get_basepath_and_path(source)
+ if destination_node.contains_path(name):
+ raise DestinationNodeExistsError()
+
+ destination_node._nodes[name] = source_node
+ parent_source = self.get_node(parent)
+ del parent_source._nodes[name]
+
+ def link(self, source, destination, symbolic=True):
+ try:
+ source_node = self.get_node(source)
+ except NodeDoesNotExistError:
+ if symbolic:
+ raise
+ else:
+ raise SourceNodeDoesNotExistError()
+
+ if source_node.is_directory and not symbolic:
+ raise DirectoryHardLinkError()
+
+ if symbolic:
+ node = Symlink(source, self)
+ else:
+ node = File(destination, "", self)
+ node._content = source_node._content
+ source_node.hard_links_count += 1
+ node.hard_links_count = source_node.hard_links_count
+
+ parent, name = self.get_basepath_and_path(destination)
+ parent_node = self.get_node(parent)
+ parent_node._nodes[name] = node
+
+ def mount(self, file_system, path):
+ try:
+ destination = self.get_node(path)
+ except NodeDoesNotExistError:
+ raise MountPointDoesNotExistError
+
+ if not destination.is_directory:
+ raise MountPointNotADirectoryError()
+
+ if len(destination.nodes) > 0:
+ raise MountPointNotEmptyError()
+
+ parent, name = self.get_basepath_and_path(path)
+ parent_node = self.get_node(parent)
+ parent_node._nodes[name] = file_system
+
+ def unmount(self, path):
+ self.get_node(path)
+ parent, name = self.get_basepath_and_path(path)
+ parent_node = self.get_node(parent)
+ if not parent_node._nodes[name].is_filesystem():
+ raise NotAMountpointError()
+
+ del parent_node._nodes[name]
+ parent_node._nodes[name] = Dir("mnt")
+
+
+class FileSystemError(Exception):
+ pass
+
+
+class NodeDoesNotExistError(FileSystemError):
+ pass
+
+
+class DestinationNodeDoesNotExistError(NodeDoesNotExistError):
+ pass
+
+
+class SourceNodeDoesNotExistError(NodeDoesNotExistError):
+ pass
+
+
+class NotEnoughSpaceError(FileSystemError):
+ pass
+
+
+class DestinationNodeExistsError(FileSystemError):
+ pass
+
+
+class NonExplicitDirectoryDeletionError(FileSystemError):
+ pass
+
+
+class NonEmptyDirectoryDeletionError(FileSystemError):
+ pass
+
+
+class DestinationNotADirectoryError(FileSystemError):
+ pass
+
+
+class LinkPathError(FileSystemError):
+ pass
+
+
+class DirectoryHardLinkError(FileSystemError):
+ pass
+
+
+class FileSystemMountError(FileSystemError):
+ pass
+
+
+class MountPointNotEmptyError(FileSystemMountError):
+ pass
+
+
+class MountPointNotADirectoryError(FileSystemMountError):
+ pass
+
+
+class MountPointDoesNotExistError(FileSystemMountError):
+ pass
+
+
+class NotAMountpointError(FileSystemMountError):
+ pass