def save_to_block(self, block: int) -> None: """ Set the metadata space of the given block (from 0 to 38, inclusive) to this metadata. """ full_block = FileTable().read_block(block) data_section = full_block[START_OF_CONTENT:] new_bytes = self.form_bytes() + data_section write_block(block, new_bytes) FMLog.success(f"Wrote new metadata to block {block}")
def edit_file(self, first_block: int, data: bytes, offset: int) -> int: """ Returns the number of bytes written """ filetable = FileTable() (metadata, old_data) = ItemFactory(first_block).create().get_data() data_to_keep = old_data[0:offset] file_size = len(data + data_to_keep) metadata.update_all_times() metadata.SIZE = file_size if not metadata.LOCATION: FMLog.error( "Cannot edit file that does not have location in metadata") raise FuseOSError(ENOENT) to_write = metadata.form_bytes() + data_to_keep + bytearray(data) locations = filetable.write_bytes_to_block( to_write, filetable.get_file_blocks(metadata.LOCATION), ) filetable.write_to_table(locations) return len(data)
def link_file(self, file_location: int, with_name: str) -> None: """ Links an existing file to this directory """ (metadata, dir_data) = self.get_dir_data() new_dir_data = (metadata + self.clear_nulls_from_bytes(dir_data, 1) + int_to_bytes(file_location, 1)) self.save(new_dir_data) FMLog.success( f"Linked file to dirblock {self.block}, with data meta {metadata} and data {self.clear_nulls_from_bytes(dir_data,1)+bytearray(file_location)}" ) file_meta = structures.Filesystem.Filesystem().get_block_metadata( file_location) file_meta.NAME = with_name file_meta.save_to_block(file_location)
def path_resolver(self, path: str) -> int: """ Given a path, get the block index of the basename of the path. """ if path == "/": return 1 chunks = path.split(os.path.sep)[1:] last_chunk = chunks[-1] current_dir = self.get_root() found = False final_location = None is_at_end = False for chunk in chunks: possible_file = last_chunk == chunk found = False directory_files = current_dir.get_files(strip_null=True) for filename, file_location, filetype in directory_files: if filename == chunk: # found a valid name if filetype == 1 and not possible_file: # impossible FMLog.error( "Filetype indicated this is a file, but the path states this should not be a file." ) raise FuseOSError(EINVAL) final_location = file_location found = True if possible_file: is_at_end = True else: current_dir = self.dir_from_block(file_location) break if not found: return -1 if not is_at_end: raise FuseOSError(ENOENT) if not final_location: return -1 return final_location
def file_from_block(self, block_index: int): data = self.get_block_metadata(block_index) if data.TYPE == 0: FMLog.error(f"Expected file, found directory") raise FuseOSError(ENOENT) return File(block_index)
def dir_from_block(self, block_index: int): data = self.get_block_metadata(block_index) if data.TYPE == 1: FMLog.error(f"Expected directory, found file") raise FuseOSError(ENOENT) return DirFactory(block_index).construct()
block_location = fs.path_resolver(path) metadata = fs.get_block_metadata(block_location) metadata.ATIME = int(atime) metadata.MTIME = int(mtime) metadata.save_to_block(block_location) def write(self, path: str, data: bytes, offset: int, fh): fs = Filesystem() block_of_interest = fs.path_resolver(path) size = fs.edit_file(block_of_interest, data, offset) return size if __name__ == "__main__": import argparse version = platform.python_version_tuple() if not (int(version[0]) == 3 and (int(version[1]) >= 8)): FMLog.error( f"Python 3.8.5 may be required. Features are used that might not be in your detected version, Python {platform.python_version()}." ) parser = argparse.ArgumentParser() parser.add_argument("mount") args = parser.parse_args() logging.basicConfig(level=logging.DEBUG) fuse = FUSE(Small(), args.mount, foreground=True)
# ************************************************************************ import os from structures.factories.MetadataFactory import MetadataFactory from time import time from disktools import BLOCK_SIZE, NUM_BLOCKS, write_block from constants import END_OF_FILE, FREE_SPACE from stat import S_IFDIR from util.FMLog import FMLog # Filetable initial_table_block = bytearray([FREE_SPACE] * NUM_BLOCKS) initial_table_block[0] = END_OF_FILE initial_table_block[1] = END_OF_FILE FMLog.warn("✔ Created filetable in disk block 0") now = time() dir_meta = (MetadataFactory().set_with_params( LOCATION=0x01, MODE=(S_IFDIR | 0o755), ATIME=int(now), CTIME=int(now), MTIME=int(now), NLINKS=2, GID=os.getgid(), UID=os.getuid(), NAME="FMFS", TYPE=0, SIZE=64, ).construct().form_bytes())