Станислав обнови решението на 29.04.2015 16:53 (преди над 9 години)
+class FileSystemError(Exception):
+ pass
+
+
+class NotEnoughSpaceError(FileSystemError):
+ pass
+
+
+class NodeDoesNotExistError(FileSystemError):
+ pass
+
+
+class DestinationNodeExistsError(FileSystemError):
+ pass
+
+
+class NonExplicitDirectoryDeletionError(FileSystemError):
+ pass
+
+
+class SourceNodeDoesNotExistError(NodeDoesNotExistError):
+ pass
+
+
+class DestinationNodeDoesNotExistError(NodeDoesNotExistError):
+ pass
+
+
+class FileSystemMountError(FileSystemError):
+ pass
+
+
+class MountPointDoesNotExistError(FileSystemMountError):
+ pass
+
+
+class MountPointNotADirectoryError(FileSystemMountError):
+ pass
+
+
+class NotAMountpointError(FileSystemMountError):
+ pass
+
+
+class MountPointNotEmptyError(FileSystemMountError):
+ pass
+
+
+class DirectoryHardLinkError(FileSystemError):
+ pass
+
+
+class NonEmptyDirectoryDeletionError(FileSystemError):
+ pass
+
+
+class DestinationNotADirectoryError(FileSystemError):
+ pass
+
+
+class LinkPathError(FileSystemError):
+ pass
+
+
+class Node(object):
+
+ def __init__(self, parent, name, item, mounted=False):
+ self.parent = parent
+ self._name = name
+ self._item = item
+ self._mounted = mounted
+
+ @property
+ def name(self):
+ return self._name
+
+ @property
+ def item(self):
+ return self._item
+
+ @property
+ def mounted(self):
+ return self._mounted
+
+ def remove(self, directory, force):
+ if self.item.is_directory and not directory:
+ raise NonExplicitDirectoryDeletionError
+ if self.item.is_directory and len(self.item.nodes) > 0 and not force:
+ raise NonEmptyDirectoryDeletionError
+ self.parent.item.remove_child(self.name)
+
+
+class File(object):
+
+ def __init__(self, content):
+ self._content = content
+
+ @property
+ def is_directory(self):
+ return False
+
+ @property
+ def size(self):
+ return 1 + len(self.content)
+
+ @property
+ def content(self):
+ return self._content
+
+ @property
+ def is_file_system(self):
+ return False
+
+ def append(self, text):
+ self._content += text
+
+ def truncate(self, text):
+ self._content = text
+
+
+class Directory(object):
+
+ def __init__(self):
+ self.children = {}
+
+ @property
+ def is_directory(self):
+ return True
+
+ @property
+ def size(self):
+ return 1 + sum(map(lambda child: child.item.size,
+ self.children.values()))
+
+ @property
+ def directories(self):
+ return [child.item for child in self.children.values()
+ if child.item.is_directory]
+
+ @property
+ def files(self):
+ return [child.item for child in self.children.values()
+ if not child.item.is_directory]
+
+ @property
+ def nodes(self):
+ return [child.item for child in self.children.values()]
+
+ @property
+ def is_file_system(self):
+ return False
+
+ def get_child(self, components):
+ if len(components) == 0:
+ raise NodeDoesNotExistError
+
+ child = self.children.get(components[0], None)
+ if child is None:
+ raise NodeDoesNotExistError
+
+ if len(components) == 1:
+ return child
+ else:
+ return child.item.get_child(components[1:])
+
+ def add_child(self, name, node):
+ if name in self.children:
+ raise DestinationNodeExistsError
+ self.children[name] = node
+
+ def remove_child(self, name):
+ del self.children[name]
+
+
+class SymbolicLink(object):
+
+ def __init__(self, link):
+ self._link = link
+
+ @property
+ def link_path(self):
+ return self._link
+
+ @property
+ def size(self):
+ return 1
+
+ @property
+ def is_file_system(self):
+ return False
+
+ def __getattr__(self, name):
+ try:
+ return getattr(self._link, name)
+ except Exception:
+ raise LinkPathError
+
+
+class FileSystem(object):
+
+ def __init__(self, size):
+ self.total_size = size
+ self._root = Node(None, None, Directory())
+
+ @property
+ def root(self):
+ return self._root.item
+
+ @property
+ def is_file_system(self):
+ return True
+
+ @property
+ def size(self):
+ return self.total_size
+
+ @property
+ def available_size(self):
+ return self.total_size - self._root.item.size
+
+ def get_node(self, path):
+ return self._get_node_internal(path).item
+
+ def get_child(self, components):
+ if len(components) == 0:
+ return self._root
+ return self._root.item.get_child(components)
+
+ def create(self, path, directory=False, content=''):
+ _, *components, name = path.split('/')
+ try:
+ parent = self.get_child(components)
+ except NodeDoesNotExistError:
+ raise DestinationNodeDoesNotExistError
+ if directory:
+ self._create(parent, name, Directory())
+ else:
+ self._create(parent, name, File(content))
+
+ def remove(self, path, directory=False, force=True):
+ node = self._get_node_internal(path)
+ node.remove(directory, force)
+
+ def mount(self, file_system, path):
+ try:
+ dir = self._get_node_internal(path)
+ except NodeDoesNotExistError:
+ raise MountPointDoesNotExistError
+ if not dir.item.is_directory:
+ raise MountPointNotADirectoryError
+ if len(dir.item.nodes) > 0:
+ raise MountPointNotEmptyError
+ self.remove(path, True, True)
+ mounted_node = Node(dir.parent, dir.name,
+ file_system.get_node('/'), mounted=True)
+ dir.parent.item.add_child(dir.name, mounted_node)
+
+ def unmount(self, path):
+ node = self._get_node_internal(path)
+ if not node.mounted:
+ raise NotAMountpointError
+ node.parent.item.remove_child(node.name)
+ empty_dir = Node(node.parent, node.name, Directory())
+ node.parent.item.add_child(node.name, empty_dir)
+
+ def link(self, source, destination, symbolic=True):
+ try:
+ node = self.get_node(source)
+ except NodeDoesNotExistError:
+ if symbolic:
+ raise NodeDoesNotExistError
+ else:
+ raise SourceNodeDoesNotExistError
+ if node.is_directory and not symbolic:
+ raise DirectoryHardLinkError
+ _, *components, name = destination.split('/')
+ parent = self.get_child(components)
+ self._create(parent, name, SymbolicLink(node))
+
+ def move(self, source, destination):
+ try:
+ node = self._get_node_internal(source)
+ except NodeDoesNotExistError:
+ raise SourceNodeDoesNotExistError
+ try:
+ dest = self.get_node(destination)
+ except NodeDoesNotExistError:
+ raise DestinationNodeDoesNotExistError
+ if not dest.is_directory:
+ raise DestinationNotADirectoryError
+ self.remove(source, node.item.is_directory, True)
+ dest.add_child(node.name, Node(dest, node.name, node.item))
+
+ def _create(self, parent, name, entry):
+ if self.available_size < entry.size:
+ raise NotEnoughSpaceError
+ parent.item.add_child(name, Node(parent, name, entry))
+
+ def _get_node_internal(self, path):
+ if not path:
+ raise NodeDoesNotExistError
+ if path == '/':
+ return self._root
+ components = path.split('/')
+ return self.get_child(components[1:])