Екатерина обнови решението на 30.04.2015 11:41 (преди над 9 години)
+import re
+
+
+class FileSystemError(Exception):
+ pass
+
+
+class NodeDoesNotExistError(FileSystemError):
+ pass
+
+
+class DestinationNodeDoesNotExistError(NodeDoesNotExistError):
+ pass
+
+
+class SourceNodeDoesNotExistError(NodeDoesNotExistError):
+ pass
+
+
+class DestinationNodeExistsError(FileSystemError):
+ pass
+
+
+class DestinationNotADirectoryError(FileSystemError):
+ pass
+
+
+class NotEnoughSpaceError(FileSystemError):
+ pass
+
+
+class NonExplicitDirectoryDeletionError(FileSystemError):
+ pass
+
+
+class NonEmptyDirectoryDeletionError(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
+
+
+class FileSystem(object):
+
+ def __init__(self, size):
+ self.size = size
+ self.root = FSDirectory()
+
+ def _parse_path(self, path):
+ list_path = re.sub(r'/+', r'/', path).split('/')
+ return [node for node in list_path if node]
+
+ def _containing_directory(self, path):
+ return self.get_node('/' + '/'.join(self._parse_path(path)[:-1]))
+
+ def _get_name(self, path):
+ return self._parse_path(path)[-1]
+
+ @property
+ def available_size(self):
+ return self.size - self.root.size
+
+ def get_node(self, path):
+ if path == '' or path[0] != '/':
+ raise NodeDoesNotExistError()
+
+ list_path = self._parse_path(path)
+ current_node = self.root
+ for node_name in list_path:
+ if node_name in current_node._nodes:
+ current_node = current_node._nodes[node_name]
+ else:
+ raise NodeDoesNotExistError()
+ return current_node
+
+ def create(self, path, directory=False, content=''):
+ try:
+ containing_directory = self._containing_directory(path)
+ except NodeDoesNotExistError:
+ raise DestinationNodeDoesNotExistError()
+
+ name = self._get_name(path)
+ if name in containing_directory._nodes:
+ raise DestinationNodeExistsError()
+
+ new_node = FSDirectory() if directory else FSFile(content)
+ if new_node.size > self.available_size:
+ raise NotEnoughSpaceError()
+
+ containing_directory.add_node(name, new_node)
+
+ def remove(self, path, directory=False, force=True):
+ node = self.get_node(path)
+ if node.is_directory:
+ if directory:
+ if not((node.nodes and force) or node.nodes == []):
+ raise NonEmptyDirectoryDeletionError()
+ else:
+ raise NonExplicitDirectoryDeletionError()
+ containing_directory = self._containing_directory(path)
+ containing_directory.remove_node(self._get_name(path))
+
+ def move(self, source, destination):
+ try:
+ source_node = self.get_node(source)
+ except NodeDoesNotExistError:
+ raise SourceNodeDoesNotExistError()
+
+ try:
+ destination_node = self.get_node(destination)
+ except NodeDoesNotExistError:
+ raise DestinationNodeDoesNotExistError()
+
+ if not destination_node.is_directory:
+ raise DestinationNotADirectoryError()
+
+ source_name = self._get_name(source)
+ if source_name in destination_node._nodes:
+ raise DestinationNodeExistsError()
+
+ containing_directory = self._containing_directory(source)
+ destination_node.add_node(source_name, source_node)
+ containing_directory.remove_node(source_name)
+
+ def link(self, source, destination, symbolic=True):
+ if symbolic:
+ source_node = self.get_node(source)
+ else:
+ try:
+ source_node = self.get_node(source)
+ except NodeDoesNotExistError:
+ raise SourceNodeDoesNotExistError()
+
+ if source_node.is_directory:
+ raise DirectoryHardLinkError()
+
+ containing_directory = self._containing_directory(destination)
+ link = FSSymbolicLink(destination, source_node) if symbolic \
+ else FSHardLink(source_node)
+ containing_directory.add_node(self._get_name(destination), link)
+
+ def mount(self, file_system, path):
+ try:
+ mount_node = self.get_node(path)
+ except NodeDoesNotExistError:
+ raise MountPointDoesNotExistError()
+
+ if not mount_node.is_directory:
+ raise MountPointNotADirectoryError()
+
+ if mount_node.nodes:
+ raise MountPointNotEmptyError()
+
+ file_system.root._is_mount_point = True
+ containing_directory = self._containing_directory(path)
+ containing_directory.add_node(self._get_name(path), file_system.root)
+
+ def unmount(self, path):
+ unmount_node = self.get_node(path)
+ if not unmount_node._is_mount_point:
+ raise NotAMountpointError()
+ unmount_node._is_mount_point = False
+
+ containing_directory = self._containing_directory(path)
+ name = self._get_name(path)
+ containing_directory.remove_node(name)
+ containing_directory.add_node(name, FSDirectory())
+
+
+class FileSystemObject(object):
+
+ @property
+ def is_directory(self):
+ return isinstance(self, FSDirectory)
+
+ @property
+ def size(self):
+ return 1
+
+
+class FSFile(FileSystemObject):
+
+ def __init__(self, content=''):
+ self._content = [content]
+
+ def append(self, text):
+ self._content.append(text)
+
+ def truncate(self, text):
+ del self._content[:]
+ self._content.append(text)
+
+ @property
+ def content(self):
+ return ''.join(self._content)
+
+ @property
+ def size(self):
+ return len(self.content) + 1
+
+
+class FSDirectory(FileSystemObject):
+
+ def __init__(self):
+ self._nodes = {}
+ self._is_mount_point = False
+
+ def add_node(self, name, node):
+ self._nodes[name] = node
+
+ def remove_node(self, name):
+ del self._nodes[name]
+
+ @property
+ def nodes(self):
+ return list(self._nodes.values())
+
+ @property
+ def directories(self):
+ return [n for n in self.nodes if isinstance(n, FSDirectory) or
+ (hasattr(n, 'source') and isinstance(n.source, FSDirectory))]
+
+ @property
+ def files(self):
+ return [n for n in self.nodes if isinstance(n, FSFile) or
+ (hasattr(n, 'source') and isinstance(n.source, FSFile))]
+
+ @property
+ def size(self):
+ return sum([node.size for node in self.nodes]) + 1
+
+
+class FSSymbolicLink(FileSystemObject):
+
+ def __init__(self, path, source):
+ self.link_path = path
+ self.source = source
+
+ def __getattr__(self, attr):
+ if hasattr(self.source, attr):
+ return getattr(self.source, attr)
+ raise LinkPathError()
+
+ @property
+ def size(self):
+ return super(FSSymbolicLink, self).size
+
+
+class FSHardLink(FSFile):
+
+ def __init__(self, source):
+ self._content = source._content
+
+ @property
+ def size(self):
+ return super(FSFile, self).size