Антоан обнови решението на 30.04.2015 04:06 (преди над 9 години)
+class FileSystem:
+
+ def __init__(self, size):
+ self.root = Directory("/", None, "/", self)
+ self.size = size
+ self.available_size = size
+
+ def get_node(self, path):
+
+ if path == "/":
+ return self.root
+
+ segments = path.split("/")[1:]
+ num_segments = len(segments)
+ node = self.root
+ for index, segment in enumerate(segments):
+ if node.is_directory():
+ node = node.get_node(segment)
+
+ if not node:
+ raise NodeDoesNotExistError()
+ else:
+ if not index == num_segments - 1 or not node.name == segment:
+ raise NodeDoesNotExistError()
+
+ return node
+
+ def create(self, path, directory=False, content=''):
+ parent_dir = "/".join(path.split("/")[:-1])
+ name = path.split("/")[-1]
+
+ try:
+ parent = self.get_node(parent_dir)
+
+ if not parent.is_directory():
+ raise DestinationNodeDoesNotExistError()
+
+ if parent.get_node(name):
+ raise DestinationNodeExistsError()
+
+ if directory and parent.is_directory():
+ new_node = Directory(path, parent, name, self)
+ elif not directory:
+ new_node = File(path, content, parent, name, self)
+
+ if self.available_size - new_node.size < 0:
+ raise NotEnoughSpaceError()
+
+ parent.add_node(new_node)
+
+ except NodeDoesNotExistError:
+ raise DestinationNodeDoesNotExistError()
+
+ def remove(self, path, directory=False, force=True):
+ try:
+ del_node = self.get_node(path)
+ if del_node.is_directory():
+ if not directory:
+ raise NonExplicitDirectoryDeletionError()
+ elif not del_node.nodes and not force:
+ raise NonEmptyDirectoryDeletionError()
+
+ del_node.parent.remove_node(del_node)
+
+ except NodeDoesNotExistError:
+ raise
+
+ def move(self, source, destination):
+ try:
+ source_node = self.get_node(source)
+ except NodeDoesNotExistError:
+ raise SourceNodeDoesNotExistError()
+
+ try:
+ destination_node = self.get_node(destination)
+ if not destination_node.is_directory():
+ raise DestinationNotADirectoryError()
+ except NodeDoesNotExistError:
+ raise DestinationNodeDoesNotExistError()
+
+ source_node.parent.remove_node(source_node)
+ destination_node.add_node(source_node)
+
+ def link(self, source, destination, symbolic=True):
+ try:
+ source_node = self.get_node(source)
+ if source_node.is_directory() and not symbolic:
+ raise DirectoryHardLinkError()
+ except NodeDoesNotExistError:
+ if symbolic:
+ raise
+ else:
+ raise SourceNodeDoesNotExistError()
+
+ self.create(destination)
+ link = self.get_node(destination)
+
+ if symbolic:
+ link.link_path = source
+ else:
+ link.make_hardlink(source_node)
+
+ def mount(self, file_system, path):
+ try:
+ source_node = self.get_node(path)
+ if source_node.is_directory() and source_node.nodes:
+ raise MountPointNotEmptyError()
+
+ if not source_node.is_directory():
+ raise MountPointNotADirectoryError()
+
+ source_node.mount = file_system
+
+ except NodeDoesNotExistError:
+ raise MountPointDoesNotExistError()
+
+ def unmount(self, path):
+ try:
+ source_node = self.get_node(path)
+ except NodeDoesNotExistError:
+ raise
+
+ if not source_node.is_directory() or not source_node.mount:
+ raise NotAMountpointError()
+
+ source_node.mount = None
+
+
+class Node:
+
+ def __init__(self, path, is_dir, parent, name, file_system):
+ self.path = self
+ self.parent = parent
+ self.name = name
+ self.file_system = file_system
+
+
+class RawContent:
+
+ def __init__(self, content):
+ self.content = content
+ self.refs = 0
+
+
+class File(Node):
+
+ def __init__(self, path, content, parent, name, file_system):
+ Node.__init__(self, path, False, parent, name, file_system)
+ self.__raw_content__ = RawContent(content)
+ self.link_path = None
+ self.is_hardlink = False
+
+ @property
+ def size(self):
+ return len(self.__raw_content__.content) + 1
+
+ @property
+ def content(self):
+ return self.__raw_content__.content
+
+ def decrease_refs(self):
+ self.__raw_content__.refs -= 1
+ return self.__raw_content__.refs
+
+ def make_hardlink(self, source):
+ self.__raw_content__ = source.__raw_content__
+ self.__raw_content__.refs += 1
+ self.is_hardlink = True
+
+ def append(self, text):
+
+ length = len(text)
+ if self.file_system.available_size - length < 0:
+ raise NotEnoughSpaceError()
+
+ self.__raw_content__.content += text
+ self.file_system.available_size -= length
+
+ def truncate(self, text):
+
+ length = len(text)
+ if self.file_system.available_size + self.size - length < 0:
+ raise NotEnoughSpaceError()
+
+ self.file_system.available_size += self.size - length
+ self.__raw_content__.content = text
+
+ def is_directory(self):
+ return False
+
+ def __getattribute__(self, name):
+ file_attrs = {"content"}
+ dir_attrs = {"files", "directories", "nodes"}
+ if name in file_attrs or name in dir_attrs:
+
+ if not self.link_path:
+ return object.__getattribute__(self, name)
+
+ try:
+ node = self.file_system.get_node(self.link_path)
+ except NodeDoesNotExistError:
+ raise LinkPathError()
+
+ is_dir = node.is_directory()
+ if (is_dir and name in dir_attrs) or \
+ (not is_dir and name in file_attrs):
+ return node.__getattribute__(name)
+
+ return object.__getattribute__(self, name)
+
+
+class Directory(Node):
+
+ def __init__(self, path, parent, name, file_system):
+ Node.__init__(self, path, True, parent, name, file_system)
+ self.directories = []
+ self.files = []
+ self.nodes = []
+ self.mount = None
+
+ def add_node(self, node):
+ if node.is_directory():
+ self.directories.append(node)
+ else:
+ self.files.append(node)
+
+ self.nodes.append(node)
+ node.parent = self
+ self.file_system.available_size -= node.size
+
+ def remove_node(self, node):
+
+ size = node.size
+
+ if node.is_directory():
+ self.directories.remove(node)
+ else:
+ self.files.remove(node)
+ if node.is_hardlink and node.decrease_refs():
+ size = 1
+
+ self.nodes.remove(node)
+ node.parent = None
+ self.file_system.available_size += size
+
+ def get_node(self, node_name):
+
+ if not self.nodes and self.mount:
+ return self.mount.get_node("/" + node_name)
+
+ for node in self.nodes:
+ if node.name == node_name:
+ if node.mount:
+ return node.mount.root
+ return node
+ return None
+
+ @property
+ def size(self):
+ return 1
+
+ def is_directory(self):
+ return True
+
+
+class FileSystemError(Exception):
+
+ def __init__(self):
+ pass
+
+
+class FileSystemMountError(FileSystemError):
+
+ def __init__(self):
+ pass
+
+
+class MountPointNotEmptyError(FileSystemMountError):
+
+ def __init__(self):
+ pass
+
+
+class MountPointNotADirectoryError(FileSystemMountError):
+
+ def __init__(self):
+ pass
+
+
+class MountPointDoesNotExistError(FileSystemMountError):
+
+ def __init__(self):
+ pass
+
+
+class NodeDoesNotExistError(FileSystemError):
+
+ def __init__(self):
+ pass
+
+
+class DestinationNodeExistsError(FileSystemError):
+
+ def __init__(self):
+ pass
+
+
+class DestinationNodeDoesNotExistError(FileSystemError):
+
+ def __init__(self):
+ pass
+
+
+class NotEnoughSpaceError(FileSystemError):
+
+ def __init__(self):
+ pass
+
+
+class NonExplicitDirectoryDeletionError(FileSystemError):
+
+ def __init__(self):
+ pass
+
+
+class NonEmptyDirectoryDeletionError(FileSystemError):
+
+ def __init__(self):
+ pass
+
+
+class SourceNodeDoesNotExistError(FileSystemError):
+
+ def __init__(self):
+ pass
+
+
+class DestinationNotADirectoryError(FileSystemError):
+
+ def __init__(self):
+ pass
+
+
+class DirectoryHardLinkError(FileSystemError):
+
+ def __init__(self):
+ pass
+
+
+class NotAMountpointError(FileSystemError):
+
+ def __init__(self):
+ pass
+
+
+class LinkPathError(FileSystemError):
+
+ def __init__(self):
+ pass