Александър обнови решението на 30.04.2015 16:45 (преди над 9 години)
+import re
+
+
+class FileSystem:
+
+ def __init__(self, input_size):
+ root_dir = Directory('root')
+ self.nodes = {'/': root_dir}
+ self.size = input_size
+ self.available_size = self.size - root_dir.size
+
+ def get_node(self, path):
+ try:
+ return self.nodes[path]
+ except:
+ raise NodeDoesNotExistError()
+
+ def create(self, path, directory=False, content='',
+ symbolic='', source_node=None):
+ # check if this directory or file exists
+ try:
+ self.get_node(path)
+ except:
+ pass
+ else:
+ raise DestinationNodeExistsError
+
+ path_split = path.split('/')
+ add_name = path_split[-1]
+ dir_path = '/'.join(path_split[:-1])
+ if dir_path == '':
+ dir_path = '/'
+ # check if destination exists
+ try:
+ dir_ = self.get_node(dir_path)
+ except NodeDoesNotExistError:
+ if symbolic:
+ raise LinkPathError
+ else:
+ raise
+ except:
+ raise DestinationNodeDoesNotExistError
+
+ # make new node to be added
+ if symbolic:
+ if symbolic == 'soft':
+ add_node = SoftSymbolLink(source_node)
+ else:
+ add_node = HardSymbolLink(source_node)
+ elif directory:
+ add_node = Directory(add_name)
+ else:
+ add_node = File(self, add_name, content)
+
+ if self.available_size < add_node.size:
+ raise NotEnoughSpaceError
+
+ # now add new file/directory
+ self.nodes[path] = add_node
+ dir_.nodes.append(add_node)
+
+ if add_node.is_directory:
+ dir_.directories.append(add_node)
+ else:
+ dir_.files.append(add_node)
+
+ self.available_size -= add_node.size
+
+ def _remove_keys(self, pattern):
+ nodes_items = list(self.nodes.items())
+ for dir_, node in nodes_items:
+ matched = re.match(pattern, dir_)
+ if matched:
+ self.available_size += node.size
+ del self.nodes[matched.string]
+
+ def remove(self, path, directory=False, force=True):
+ try:
+ remove_node = self.get_node(path)
+ except:
+ NodeDoesNotExistError
+
+ if remove_node.is_directory:
+ if not directory:
+ raise NonExplicitDirectoryDeletionError
+
+ if remove_node.nodes:
+ if not force:
+ raise NonEmptyDirectoryDeletionError
+ else:
+ self._remove_keys(path)
+ else:
+ self.available_size += remove_node.size
+ del self.nodes[path]
+
+ def _move_sub_nodes(self, pattern, replacement):
+ nodes_items = list(self.nodes.items())
+ pattern_obj = re.compile(pattern)
+ for old_dir, _ in nodes_items:
+ if replacement == old_dir:
+ continue
+ new_dir = pattern_obj.sub(replacement, old_dir)
+ self.nodes[new_dir] = self.nodes.pop(old_dir)
+
+ def move(self, source, destination):
+ try:
+ source_node = self.get_node(source)
+ except:
+ raise SourceNodeDoesNotExistError
+
+ try:
+ destination_node = self.get_node(destination)
+ except:
+ raise DestinationNodeDoesNotExistError
+
+ if not destination_node.is_directory:
+ raise DestinationNotADirectoryError
+
+ new_node_path = destination + '/' + source_node.name
+ try:
+ self.get_node(new_node_path)
+ except:
+ pass
+ else:
+ raise DestinationNodeExistsError
+
+ if source_node.is_directory:
+ # check if destination is subfolder of source
+ if re.match(source, destination):
+ if source == destination:
+ # return
+ raise DestinationNodeExistsError
+ else:
+ raise UnableToMoveError
+
+ self.create(new_node_path, True)
+ self.nodes[new_node_path] = source_node
+ self._move_sub_nodes(source, new_node_path)
+ else:
+ self.create(new_node_path, False, source_node.content)
+ del self.nodes[source]
+
+ def link(self, source, destination, symbolic=True):
+ if symbolic:
+ try:
+ source_node = self.get_node(source)
+ except:
+ raise NodeDoesNotExistError
+ soft_link_name = destination.split('/')[-1]
+ is_dir = source_node.is_directory
+ self.create(
+ destination, is_dir, symbolic='soft', source_node=source_node)
+ else:
+ try:
+ source_node = self.get_node(source)
+ except:
+ raise SourceNodeDoesNotExistError
+
+ if source_node.is_directory:
+ raise DirectoryHardLinkError
+
+ hard_link_name = destination.split('/')[-1]
+ is_dir = source_node.is_directory
+ self.create(destination, is_dir, symbolic='hard',
+ source_node=source_node)
+
+ def mount(self, file_system, path):
+ try:
+ path_node = self.get_node(path)
+ except:
+ raise MountPointDoesNotExistError
+
+ if not path_node.is_directory:
+ raise MountPointNotADirectoryError
+
+ if path_node.nodes:
+ raise MountPointNotEmptyError
+
+ file_system_nodes_items = list(file_system.nodes.items())
+ for file_system_node_key, file_system_val in file_system_nodes_items:
+ file_system_node_key = path + file_system_node_key
+ self.nodes[file_system_node_key] = file_system_val
+ path_node.nodes.append(file_system_val)
+
+ self.nodes[path] = file_system.get_node('/')
+ self.size += file_system.size
+ self.available_size += file_system.available_size
+
+
+class File:
+
+ def __init__(self, file_system, file_name, input_content=''):
+ self.file_system = file_system
+ self.name = file_name
+ self.content = input_content
+ self.is_directory = False
+ self.size = len(self.content) + 1
+
+ def append(self, text):
+ new_size = len(text)
+
+ if self.file_system.available_size < new_size:
+ raise NotEnoughSpaceError
+
+ self.size = new_size
+ self.content += text
+ self.file_system.available_size -= new_size
+
+ def truncate(self, text):
+ new_size = len(text) + 1
+ old_size = len(self.content) + 1
+
+ if self.file_system.available_size + old_size < new_size:
+ raise NotEnoughSpaceError
+
+ self.size = new_size
+ self.content = text
+ self.file_system.available_size += old_size
+ self.file_system.available_size -= new_size
+
+
+class Directory:
+
+ def __init__(self, directory_name):
+ self.name = directory_name
+ self.size = 1
+ self.files = []
+ self.directories = []
+ self.nodes = []
+ self.is_directory = True
+
+
+class SoftSymbolLink:
+
+ def __init__(self, link_path_):
+ self.link_path = link_path_
+ self.size = 1
+
+ @property
+ def content(self):
+ if self.is_directory:
+ raise FileSystemError
+ else:
+ return self.link_path.content
+
+ @property
+ def is_directory(self):
+ return self.link_path.is_directory
+
+ @property
+ def nodes(self):
+ if not self.is_directory:
+ raise FileSystemError
+ else:
+ return list(self.link_path.nodes)
+
+ @property
+ def files(self):
+ if not self.is_directory:
+ raise FileSystemError
+ else:
+ return self.link_path.files
+
+ @property
+ def directories(self):
+ if not self.is_directory:
+ raise FileSystemError
+ else:
+ return self.link_path.directories
+
+
+class HardSymbolLink:
+
+ def __init__(self, linked_file):
+ self.linked_file = linked_file
+ self.size = 1
+
+ @property
+ def content(self):
+ return self.linked_file.content
+
+ @property
+ def is_directory(self):
+ return self.linked_file.is_directory
+
+ @content.setter
+ def content(self, text):
+ self.linked_file.truncate(text)
+ self.size = 1
+
+ def append(self, text):
+ self.linked_file.append(text)
+ self.size = 1
+
+ def truncate(self, text):
+ self.linked_file.truncate(text)
+ self.size = 1
+
+
+# EXCEPTIONS =============================================================
+
+class LinkPathError(FileSystemError):
+
+ def __init__(self):
+ super().__init__()
+ self.message = 'Link path error !'
+
+
+class FileSystemError(Exception):
+
+ def __init__(self):
+ self.message = 'File system error !'
+
+ def __str__(self):
+ return self.message
+
+
+class NodeDoesNotExistError(FileSystemError):
+
+ def __init__(self):
+ super().__init__()
+ self.message = 'Node does not exist !'
+
+
+class SourceNodeDoesNotExistError(NodeDoesNotExistError):
+
+ def __init__(self):
+ super().__init__()
+ self.message = 'Source node does not exist !'
+
+
+class DestinationNodeDoesNotExistError(NodeDoesNotExistError):
+
+ def __init__(self):
+ super().__init__()
+ self.message = 'Destination node does not exist !'
+
+
+class DestinationNodeExistsError(FileSystemError):
+
+ def __init__(self):
+ super().__init__()
+ self.message = 'Destination node exists !'
+
+
+class FileSystemMountError(FileSystemError):
+
+ def __init__(self):
+ super().__init__()
+ self.message = 'File system mount error !'
+
+
+class MountPointDoesNotExistError(FileSystemMountError):
+
+ def __init__(self):
+ super().__init__()
+ self.message = 'Mount point does not exist !'
+
+
+class MountPointNotADirectoryError(FileSystemMountError):
+
+ def __init__(self):
+ super().__init__()
+ self.message = 'Mount point not a directory !'
+
+
+class MountPointNotEmptyError(FileSystemMountError):
+
+ def __init__(self):
+ super().__init__()
+ self.message = 'Mount point not empty !'
+
+
+class NotEnoughSpaceError(FileSystemError):
+
+ def __init__(self):
+ super().__init__()
+ self.message = 'Not enough space !'
+
+
+class NonExplicitDirectoryDeletionError(FileSystemError):
+
+ def __init__(self):
+ super().__init__()
+ self.message = 'Non explicit directory deletion error!'
+
+
+class NonEmptyDirectoryDeletionError(FileSystemError):
+
+ def __init__(self):
+ super().__init__()
+ self.message = 'Non empty directory deletion error !'
+
+
+class DestinationNotADirectoryError(FileSystemError):
+
+ def __init__(self):
+ super().__init__()
+ self.message = 'Destination not a directory error'
+
+
+class UnableToMoveError(FileSystemError):
+
+ def __init__(self):
+ super().__init__()
+ self.message = 'Unable to move error'
+
+
+class DirectoryHardLinkError(FileSystemError):
+
+ def __init__(self):
+ super().__init__()
+ self.message = 'Directory hard link error'