#1962: separating file system into more managable files
This commit is contained in:
@@ -2,11 +2,8 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import math
|
|
||||||
import os.path
|
import os.path
|
||||||
import shutil
|
import shutil
|
||||||
from abc import abstractmethod
|
|
||||||
from enum import Enum
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Dict, Optional
|
from typing import Dict, Optional
|
||||||
|
|
||||||
@@ -14,152 +11,13 @@ from prettytable import MARKDOWN, PrettyTable
|
|||||||
|
|
||||||
from primaite import getLogger
|
from primaite import getLogger
|
||||||
from primaite.simulator.core import RequestManager, RequestType, SimComponent
|
from primaite.simulator.core import RequestManager, RequestType, SimComponent
|
||||||
|
from primaite.simulator.file_system.file_system_item_abc import FileSystemItemABC, FileSystemItemHealthStatus
|
||||||
from primaite.simulator.file_system.file_type import FileType, get_file_type_from_extension
|
from primaite.simulator.file_system.file_type import FileType, get_file_type_from_extension
|
||||||
from primaite.simulator.system.core.sys_log import SysLog
|
from primaite.simulator.system.core.sys_log import SysLog
|
||||||
|
|
||||||
_LOGGER = getLogger(__name__)
|
_LOGGER = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def convert_size(size_bytes: int) -> str:
|
|
||||||
"""
|
|
||||||
Convert a file size from bytes to a string with a more human-readable format.
|
|
||||||
|
|
||||||
This function takes the size of a file in bytes and converts it to a string representation with appropriate size
|
|
||||||
units (B, KB, MB, GB, etc.).
|
|
||||||
|
|
||||||
:param size_bytes: The size of the file in bytes.
|
|
||||||
:return: The human-readable string representation of the file size.
|
|
||||||
"""
|
|
||||||
if size_bytes == 0:
|
|
||||||
return "0 B"
|
|
||||||
|
|
||||||
# Tuple of size units starting from Bytes up to Yottabytes
|
|
||||||
size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
|
|
||||||
|
|
||||||
# Calculate the index (i) that will be used to select the appropriate size unit from size_name
|
|
||||||
i = int(math.floor(math.log(size_bytes, 1024)))
|
|
||||||
|
|
||||||
# Calculate the adjusted size value (s) in terms of the new size unit
|
|
||||||
p = math.pow(1024, i)
|
|
||||||
s = round(size_bytes / p, 2)
|
|
||||||
|
|
||||||
return f"{s} {size_name[i]}"
|
|
||||||
|
|
||||||
|
|
||||||
class FileSystemItemHealthStatus(Enum):
|
|
||||||
"""Status of the FileSystemItem."""
|
|
||||||
|
|
||||||
GOOD = 0
|
|
||||||
"""File/Folder is OK."""
|
|
||||||
|
|
||||||
COMPROMISED = 1
|
|
||||||
"""File/Folder is quarantined."""
|
|
||||||
|
|
||||||
CORRUPT = 2
|
|
||||||
"""File/Folder is corrupted."""
|
|
||||||
|
|
||||||
RESTORING = 3
|
|
||||||
"""File/Folder is in the process of being restored."""
|
|
||||||
|
|
||||||
REPAIRING = 3
|
|
||||||
"""File/Folder is in the process of being repaired."""
|
|
||||||
|
|
||||||
|
|
||||||
class FileSystemItemABC(SimComponent):
|
|
||||||
"""
|
|
||||||
Abstract base class for file system items used in the file system simulation.
|
|
||||||
|
|
||||||
:ivar name: The name of the FileSystemItemABC.
|
|
||||||
"""
|
|
||||||
|
|
||||||
name: str
|
|
||||||
"The name of the FileSystemItemABC."
|
|
||||||
|
|
||||||
health_status: FileSystemItemHealthStatus = FileSystemItemHealthStatus.GOOD
|
|
||||||
"Actual status of the current FileSystemItem"
|
|
||||||
|
|
||||||
visible_health_status: FileSystemItemHealthStatus = FileSystemItemHealthStatus.GOOD
|
|
||||||
"Visible status of the current FileSystemItem"
|
|
||||||
|
|
||||||
previous_hash: Optional[str] = None
|
|
||||||
"Hash of the file contents or the description state"
|
|
||||||
|
|
||||||
revealed_to_red: bool = False
|
|
||||||
"If true, the folder/file has been revealed to the red agent."
|
|
||||||
|
|
||||||
def describe_state(self) -> Dict:
|
|
||||||
"""
|
|
||||||
Produce a dictionary describing the current state of this object.
|
|
||||||
|
|
||||||
:return: Current state of this object and child objects.
|
|
||||||
"""
|
|
||||||
state = super().describe_state()
|
|
||||||
state["name"] = self.name
|
|
||||||
state["status"] = self.health_status.name
|
|
||||||
state["visible_status"] = self.visible_health_status.name
|
|
||||||
state["previous_hash"] = self.previous_hash
|
|
||||||
state["revealed_to_red"] = self.revealed_to_red
|
|
||||||
return state
|
|
||||||
|
|
||||||
def _init_request_manager(self) -> RequestManager:
|
|
||||||
rm = super()._init_request_manager()
|
|
||||||
|
|
||||||
rm.add_request(name="scan", request_type=RequestType(func=lambda request, context: self.scan()))
|
|
||||||
rm.add_request(name="checkhash", request_type=RequestType(func=lambda request, context: self.check_hash()))
|
|
||||||
rm.add_request(name="repair", request_type=RequestType(func=lambda request, context: self.repair()))
|
|
||||||
rm.add_request(name="restore", request_type=RequestType(func=lambda request, context: self.restore()))
|
|
||||||
|
|
||||||
rm.add_request(name="corrupt", request_type=RequestType(func=lambda request, context: self.corrupt()))
|
|
||||||
|
|
||||||
return rm
|
|
||||||
|
|
||||||
@property
|
|
||||||
def size_str(self) -> str:
|
|
||||||
"""
|
|
||||||
Get the file size in a human-readable string format.
|
|
||||||
|
|
||||||
This property makes use of the :func:`convert_size` function to convert the `self.size` attribute to a string
|
|
||||||
that is easier to read and understand.
|
|
||||||
|
|
||||||
:return: The human-readable string representation of the file size.
|
|
||||||
"""
|
|
||||||
return convert_size(self.size)
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def check_hash(self) -> bool:
|
|
||||||
"""
|
|
||||||
Checks the has of the file to detect any changes.
|
|
||||||
|
|
||||||
For current implementation, any change in file hash means it is compromised.
|
|
||||||
|
|
||||||
Return False if corruption is detected, otherwise True
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def repair(self) -> bool:
|
|
||||||
"""
|
|
||||||
Repair the FileSystemItem.
|
|
||||||
|
|
||||||
True if successfully repaired. False otherwise.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def corrupt(self) -> bool:
|
|
||||||
"""
|
|
||||||
Corrupt the FileSystemItem.
|
|
||||||
|
|
||||||
True if successfully corrupted. False otherwise.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def restore(self) -> bool:
|
|
||||||
"""Restore the file/folder to the state before it got ruined."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class FileSystem(SimComponent):
|
class FileSystem(SimComponent):
|
||||||
"""Class that contains all the simulation File System."""
|
"""Class that contains all the simulation File System."""
|
||||||
|
|
||||||
|
|||||||
151
src/primaite/simulator/file_system/file_system_item_abc.py
Normal file
151
src/primaite/simulator/file_system/file_system_item_abc.py
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import math
|
||||||
|
from abc import abstractmethod
|
||||||
|
from enum import Enum
|
||||||
|
from typing import Dict, Optional
|
||||||
|
|
||||||
|
from primaite import getLogger
|
||||||
|
from primaite.simulator.core import RequestManager, RequestType, SimComponent
|
||||||
|
|
||||||
|
_LOGGER = getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def convert_size(size_bytes: int) -> str:
|
||||||
|
"""
|
||||||
|
Convert a file size from bytes to a string with a more human-readable format.
|
||||||
|
|
||||||
|
This function takes the size of a file in bytes and converts it to a string representation with appropriate size
|
||||||
|
units (B, KB, MB, GB, etc.).
|
||||||
|
|
||||||
|
:param size_bytes: The size of the file in bytes.
|
||||||
|
:return: The human-readable string representation of the file size.
|
||||||
|
"""
|
||||||
|
if size_bytes == 0:
|
||||||
|
return "0 B"
|
||||||
|
|
||||||
|
# Tuple of size units starting from Bytes up to Yottabytes
|
||||||
|
size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
|
||||||
|
|
||||||
|
# Calculate the index (i) that will be used to select the appropriate size unit from size_name
|
||||||
|
i = int(math.floor(math.log(size_bytes, 1024)))
|
||||||
|
|
||||||
|
# Calculate the adjusted size value (s) in terms of the new size unit
|
||||||
|
p = math.pow(1024, i)
|
||||||
|
s = round(size_bytes / p, 2)
|
||||||
|
|
||||||
|
return f"{s} {size_name[i]}"
|
||||||
|
|
||||||
|
|
||||||
|
class FileSystemItemHealthStatus(Enum):
|
||||||
|
"""Status of the FileSystemItem."""
|
||||||
|
|
||||||
|
GOOD = 0
|
||||||
|
"""File/Folder is OK."""
|
||||||
|
|
||||||
|
COMPROMISED = 1
|
||||||
|
"""File/Folder is quarantined."""
|
||||||
|
|
||||||
|
CORRUPT = 2
|
||||||
|
"""File/Folder is corrupted."""
|
||||||
|
|
||||||
|
RESTORING = 3
|
||||||
|
"""File/Folder is in the process of being restored."""
|
||||||
|
|
||||||
|
REPAIRING = 3
|
||||||
|
"""File/Folder is in the process of being repaired."""
|
||||||
|
|
||||||
|
|
||||||
|
class FileSystemItemABC(SimComponent):
|
||||||
|
"""
|
||||||
|
Abstract base class for file system items used in the file system simulation.
|
||||||
|
|
||||||
|
:ivar name: The name of the FileSystemItemABC.
|
||||||
|
"""
|
||||||
|
|
||||||
|
name: str
|
||||||
|
"The name of the FileSystemItemABC."
|
||||||
|
|
||||||
|
health_status: FileSystemItemHealthStatus = FileSystemItemHealthStatus.GOOD
|
||||||
|
"Actual status of the current FileSystemItem"
|
||||||
|
|
||||||
|
visible_health_status: FileSystemItemHealthStatus = FileSystemItemHealthStatus.GOOD
|
||||||
|
"Visible status of the current FileSystemItem"
|
||||||
|
|
||||||
|
previous_hash: Optional[str] = None
|
||||||
|
"Hash of the file contents or the description state"
|
||||||
|
|
||||||
|
revealed_to_red: bool = False
|
||||||
|
"If true, the folder/file has been revealed to the red agent."
|
||||||
|
|
||||||
|
def describe_state(self) -> Dict:
|
||||||
|
"""
|
||||||
|
Produce a dictionary describing the current state of this object.
|
||||||
|
|
||||||
|
:return: Current state of this object and child objects.
|
||||||
|
"""
|
||||||
|
state = super().describe_state()
|
||||||
|
state["name"] = self.name
|
||||||
|
state["status"] = self.health_status.name
|
||||||
|
state["visible_status"] = self.visible_health_status.name
|
||||||
|
state["previous_hash"] = self.previous_hash
|
||||||
|
state["revealed_to_red"] = self.revealed_to_red
|
||||||
|
return state
|
||||||
|
|
||||||
|
def _init_request_manager(self) -> RequestManager:
|
||||||
|
rm = super()._init_request_manager()
|
||||||
|
|
||||||
|
rm.add_request(name="scan", request_type=RequestType(func=lambda request, context: self.scan()))
|
||||||
|
rm.add_request(name="checkhash", request_type=RequestType(func=lambda request, context: self.check_hash()))
|
||||||
|
rm.add_request(name="repair", request_type=RequestType(func=lambda request, context: self.repair()))
|
||||||
|
rm.add_request(name="restore", request_type=RequestType(func=lambda request, context: self.restore()))
|
||||||
|
|
||||||
|
rm.add_request(name="corrupt", request_type=RequestType(func=lambda request, context: self.corrupt()))
|
||||||
|
|
||||||
|
return rm
|
||||||
|
|
||||||
|
@property
|
||||||
|
def size_str(self) -> str:
|
||||||
|
"""
|
||||||
|
Get the file size in a human-readable string format.
|
||||||
|
|
||||||
|
This property makes use of the :func:`convert_size` function to convert the `self.size` attribute to a string
|
||||||
|
that is easier to read and understand.
|
||||||
|
|
||||||
|
:return: The human-readable string representation of the file size.
|
||||||
|
"""
|
||||||
|
return convert_size(self.size)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def check_hash(self) -> bool:
|
||||||
|
"""
|
||||||
|
Checks the has of the file to detect any changes.
|
||||||
|
|
||||||
|
For current implementation, any change in file hash means it is compromised.
|
||||||
|
|
||||||
|
Return False if corruption is detected, otherwise True
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def repair(self) -> bool:
|
||||||
|
"""
|
||||||
|
Repair the FileSystemItem.
|
||||||
|
|
||||||
|
True if successfully repaired. False otherwise.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def corrupt(self) -> bool:
|
||||||
|
"""
|
||||||
|
Corrupt the FileSystemItem.
|
||||||
|
|
||||||
|
True if successfully corrupted. False otherwise.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def restore(self) -> bool:
|
||||||
|
"""Restore the file/folder to the state before it got ruined."""
|
||||||
|
pass
|
||||||
Reference in New Issue
Block a user