Красимир обнови решението на 30.04.2015 09:19 (преди над 9 години)
+class FileSystemError(Exception):
+ pass
+
+
+class FileSystemMountError(FileSystemError):
+ pass
+
+
+class NodeDoesNotExistError(FileSystemError):
+ pass
+
+
+class DestinationNodeExistsError(FileSystemError):
+ pass
+
+
+class SourceNodeDoesNotExistError(NodeDoesNotExistError):
+ pass
+
+
+class DestinationNodeDoesNotExistError(NodeDoesNotExistError):
+ pass
+
+
+class MountPointDoesNotExistError(FileSystemMountError):
+ pass
+
+
+class MountPointNotADirectoryError(FileSystemMountError):
+ pass
+
+
+class MountPointNotEmptyError(FileSystemMountError):
+ pass
+
+
+class NotEnoughSpaceError(FileSystemError):
+ pass
+
+
+class NonEmptyDirectoryDeletionError(FileSystemError):
+ pass
+
+
+class NonExplicitDirectoryDeletionError(FileSystemError):
+ pass
+
+
+class DestinationNotADirectoryError(FileSystemError):
+ pass
+
+
+class DirectoryHardLinkError(FileSystemError):
+ pass
+
+
+class LinkPathError(FileSystemError):
+ pass
+
+
+class FileSystem:
+ def __init__(self, size):
+ self.__size = size
+ self.__available_size = size - 1
+ if self.__available_size < 0:
+ raise NotEnoughSpaceError
+ self.directory_obj = Directory('/')
+ self.file_obj = File()
+ self.all_nodes = {'/': self.directory_obj}
+
+ @property
+ def size(self):
+ return self.__size
+
+ @property
+ def available_size(self):
+ return self.__available_size
+
+ def get_node(self, path):
+ try:
+ if type(self.all_nodes[path]) is dict:
+ return self.all_nodes[path]['data']
+ return self.all_nodes[path]
+ except KeyError:
+ raise NodeDoesNotExistError
+
+ def create(self, path, directory=False, content=''):
+ if directory:
+ self.__check_errors_for_directory(path)
+ old_path = path
+ path = FileSystem.format_path(path)
+ directory = self.directory_obj.create(path)
+ self.all_nodes[old_path] = directory
+ self.__available_size -= 1
+ else:
+ file_size = len(content)
+ self.__check_errors_for_file(path, file_size + 1)
+ file_details = File(path, content, self)
+ self.all_nodes[path] = file_details
+ self.__available_size -= file_size + 1
+
+ def remove(self, path, directory=False, force=True):
+ pd = FileSystem.format_path_to_parent_directory(path)
+ parent_directory = pd[0]
+ try:
+ if type(self.all_nodes[path]) is Directory:
+ if directory:
+ self.all_nodes[parent_directory].remove(path, force)
+ for_remove = FileSystem.slice_dict(self.all_nodes, path)
+ sizes = self.get_all_size_for_free(for_remove)
+ self.__remove_tree(for_remove)
+ self.__available_size += sizes
+ else:
+ raise NonExplicitDirectoryDeletionError
+ else:
+ self.all_nodes[path].remove(path)
+ self.__available_size += self.all_nodes[path].size
+ del self.all_nodes[path]
+ except KeyError:
+ raise NodeDoesNotExistError
+
+ def move(self, source, destination):
+ self.__check_errors_for_move(source, destination)
+ path = FileSystem.format_path_to_parent_directory(source)
+ parent_source = self.get_node(path[0])
+ source_item = self.get_node(source)
+ destination_item = self.get_node(destination)
+ destination_item.move(source_item)
+ parent_source.remove(source_item.path, force=True)
+ if type(source_item) is Directory:
+ for_rename = self.slice_dict(self.all_nodes, source + '/')
+ for_rename[source] = self.all_nodes[source]
+ self.__remove_tree(for_rename)
+ names = self.__get_new_names(for_rename, path[0], destination)
+ self.all_nodes.update(names)
+ else:
+ new_key = destination + '/' + path[1]
+ self.all_nodes[new_key] = self.all_nodes.pop(source)
+ self.all_nodes[new_key].path = new_key
+
+ # TODO: Implement
+ def link(self, source, destination, symbolic=True):
+ self.__check_errors_for_link(source, symbolic)
+ if symbolic:
+ self.all_nodes[destination] = {
+ 'data': self.all_nodes[source],
+ 'source': source,
+ }
+ self.__available_size -= 1
+
+ def mount(self, file_system, path):
+ self.__cehck_exception_for_mount(path)
+ self.all_nodes[path] = file_system
+ self.__available_size -= 1
+
+ @staticmethod
+ def get_all_size_for_free(for_remove):
+ size = 0
+ for value in for_remove.values():
+ size += value.size
+ return size
+
+ @staticmethod
+ def check_available_size(available_size, size_decrement):
+ if (available_size - size_decrement) < 0:
+ raise NotEnoughSpaceError
+
+ @staticmethod
+ def format_path(path):
+ new_path = path.split('/')
+ new_path[0] = '/'
+ return new_path
+
+ @staticmethod
+ def format_path_to_parent_directory(path):
+ new_path = path.rsplit('/', 1)
+ if new_path[0] == '':
+ new_path[0] = '/'
+ return new_path
+
+ def format_path_to_rename_key(self, path, split_word):
+ new_path = path.split(split_word, 1)
+ return new_path
+
+ @staticmethod
+ def slice_dict(d, s):
+ return {k: v for k, v in d.items() if k.startswith(s)}
+
+ def __check_errors_for_file(self, path, size):
+ self.__check_general_errors(path)
+ FileSystem.check_available_size(self.__available_size, size)
+
+ def __check_errors_for_directory(self, path):
+ self.__check_general_errors(path)
+ FileSystem.check_available_size(self.__available_size, 1)
+
+ def __check_errors_for_move(self, source, destination):
+ if source not in self.all_nodes.keys():
+ raise SourceNodeDoesNotExistError
+ if destination not in self.all_nodes.keys():
+ raise DestinationNodeDoesNotExistError
+ if type(self.all_nodes[destination]) is not Directory:
+ raise DestinationNotADirectoryError
+ path = FileSystem.format_path_to_parent_directory(source)
+ if destination == '/':
+ destination = destination + path[1]
+ else:
+ destination = destination + '/' + path[1]
+ if destination in self.all_nodes.keys():
+ raise DestinationNodeExistsError
+
+ def __check_errors_for_link(self, source, symbolic):
+ if source not in self.all_nodes.keys() and symbolic:
+ raise NodeDoesNotExistError
+ if not symbolic:
+ try:
+ self.all_nodes[source]
+ except KeyError:
+ raise SourceNodeDoesNotExistError
+ if not symbolic and type(self.all_nodes[source]) is Directory:
+ raise DirectoryHardLinkError
+
+ def __check_general_errors(self, path):
+ if path in self.all_nodes.keys():
+ raise DestinationNodeExistsError
+ path = FileSystem.format_path_to_parent_directory(path)
+ if path[0] not in self.all_nodes.keys():
+ raise DestinationNodeDoesNotExistError
+
+ def __get_new_names(self, old_nodes, parent_path, destination):
+ new_nodes = {}
+ for key, value in old_nodes.items():
+ continue_name = self.format_path_to_rename_key(key, parent_path)
+ new_path = destination + continue_name[1]
+ new_nodes[new_path] = value
+ new_nodes[new_path].path = new_path
+ return new_nodes
+
+ def __cehck_exception_for_mount(self, path):
+ if path not in self.all_nodes.keys():
+ raise MountPointDoesNotExistError
+ if type(self.all_nodes[path]) is File:
+ raise MountPointNotADirectoryError
+ if not self.all_nodes[path].is_empty():
+ raise MountPointNotEmptyError
+
+ def __remove_tree(self, for_remove):
+ for key in for_remove.keys():
+ del self.all_nodes[key]
+
+
+class Directory:
+
+ def __init__(self, path):
+ self.__is_directory = True
+ self.__sub_directory = []
+ self.__sub_files = []
+ self.__path = path
+
+ @property
+ def path(self):
+ return self.__path
+
+ @property
+ def is_directory(self):
+ return self.__is_directory
+
+ @property
+ def directories(self):
+ return self.__sub_directory
+
+ @property
+ def files(self):
+ return self.__sub_files
+
+ @property
+ def nodes(self):
+ return self.__sub_directory + self.__sub_files
+
+ @property
+ def size(self):
+ return 1
+
+ @files.setter
+ def files(self, file):
+ self.__sub_files.append(file)
+
+ @path.setter
+ def path(self, path):
+ self.__path = path
+
+ def is_empty(self):
+ if len(self.__sub_files) == 0 and len(self.__sub_directory) == 0:
+ return True
+ return False
+
+ def create(self, path):
+ parent_directory = self.__destination_folder(path)
+ directory_path = Directory.get_correct_directory_path(path)
+ new_directory = Directory(directory_path)
+ parent_directory.__sub_directory.append(new_directory)
+ return new_directory
+
+ def remove(self, path, force=False):
+ child_directory = None
+
+ for counter, directory in enumerate(self.__sub_directory):
+ if directory.path == path:
+ child_directory = self.__sub_directory[counter]
+ break
+ if force is False and\
+ (len(child_directory.__sub_files) != 0 or
+ len(child_directory.__sub_directory) != 0):
+ raise NonEmptyDirectoryDeletionError
+ self.__sub_directory.remove(child_directory)
+
+ def remove_file(self, file):
+ self.__sub_files.remove(file)
+
+ def move(self, sources):
+ if type(sources) is Directory:
+ self.__sub_directory.append(sources)
+ elif type(sources) is File:
+ self.__sub_files.append(sources)
+
+ def __destination_folder(self, path):
+ if len(path) == 1:
+ return self
+ directory_path = Directory.construct_path(path)
+ for directory in self.__sub_directory:
+ if directory_path == directory.path:
+ path[0] = Directory.construct_path(path)
+ del path[1]
+ return directory.__destination_folder(path)
+ return self
+
+ @staticmethod
+ def get_correct_directory_path(path):
+ if path[0] == '/':
+ directory_path = '/' + '/'.join(path[1:])
+ else:
+ directory_path = '/'.join(path)
+ return directory_path
+
+ @staticmethod
+ def construct_path(path):
+ if path[0] == '/':
+ return path[0] + path[1]
+ return path[0] + '/' + path[1]
+
+
+class File:
+ def __init__(self, path=None, content=None, file_system=None):
+ self.__content = content
+ self.__path = path
+ self.__fs = file_system
+ self.__insert_in_correct_directory(path)
+ self.__is_directory = False
+
+ @property
+ def is_directory(self):
+ return self.__is_directory
+
+ @property
+ def content(self):
+ return self.__content
+
+ @property
+ def size(self):
+ return len(self.__content) + 1
+
+ @property
+ def path(self):
+ return self.__path
+
+ @path.setter
+ def path(self, path):
+ self.__path = path
+
+ def append(self, content):
+ self.__content += content
+
+ def truncate(self, content):
+ self.__content = content
+
+ def remove(self, path):
+ new_path = FileSystem.format_path_to_parent_directory(path)
+ node = self.__fs.get_node(new_path[0])
+ node.remove_file(self)
+
+ def __insert_in_correct_directory(self, path=None):
+ if path is not None:
+ path = FileSystem.format_path_to_parent_directory(path)
+ node = self.__fs.get_node(path[0])
+ node.files = self