def test_make_8dot3_name(): """Test that make_8dot3_filename generates valid 8dot3 filenames.""" fde = mock.MagicMock() fde.get_entries.return_value = ([], [], []) sfn = EightDotThree() n = sfn.make_8dot3_name("This is a long filename.txt", fde) sfn.set_str_name(n) assert "THISIS.TXT" == n assert sfn.is_8dot3_conform(sfn.get_unpadded_filename())
def test_checksum_calculation_referenceimpl_random(): """Test that the checksum calculation works, following reference impl.""" base = ''.join(random.choices(string.ascii_letters + string.digits, k=8)).upper() ext = ''.join(random.choices(string.ascii_letters + string.digits, k=3)).upper() sfn = EightDotThree() sfn.set_str_name(f"{base}.{ext}") assert sfn.checksum() == calculate_checksum_referenceimpl(sfn.name)
def parse_root_dir(self): """Parses root directory entry.""" root_dir_sfn = EightDotThree() root_dir_sfn.set_str_name("ROOTDIR") self.root_dir = FATDirectoryEntry( DIR_Name=root_dir_sfn, DIR_Attr=FATDirectoryEntry.ATTR_DIRECTORY, DIR_NTRes=0, DIR_CrtTimeTenth=0, DIR_CrtDateTenth=0, DIR_LstAccessDate=0, DIR_FstClusHI=0, DIR_WrtTime=0, DIR_WrtDate=0, DIR_FstClusLO=0, DIR_FileSize=0, encoding=self.encoding) if self.fat_type in [self.FAT_TYPE_FAT12, self.FAT_TYPE_FAT16]: self._fat12_parse_root_dir() else: self._fat32_parse_root_dir()
def makedir(self, path: str, permissions: Permissions = None, recreate: bool = False): """Create directory on filesystem. :param path: Path of new directory on filesystem :param permissions: Currently not implemented :param recreate: Ignore if directory already exists """ base = "/".join(path.split("/")[:-1]) dirname = path.split("/")[-1] # Plausability checks try: base = self.opendir(base) except DirectoryExpected: raise ResourceNotFound(path) try: self._get_dir_entry(path) except ResourceNotFound: pass else: # TODO: Implement recreate param raise DirectoryExists(path) parent_is_root = base == self.fs.root_dir # Determine 8DOT3 file name + LFN short_name = EightDotThree() n = short_name.make_8dot3_name(dirname, base) short_name.set_str_name(n) newdir = FATDirectoryEntry(DIR_Name=short_name, DIR_Attr=FATDirectoryEntry.ATTR_DIRECTORY, DIR_NTRes=0, DIR_CrtTimeTenth=0, DIR_CrtDateTenth=0, DIR_LstAccessDate=0, DIR_FstClusHI=0x00, DIR_WrtTime=0, DIR_WrtDate=0, DIR_FstClusLO=0x00, DIR_FileSize=0, encoding=self.fs.encoding) # Create LFN entry if required if short_name.get_unpadded_filename() != dirname: lfn_entry = make_lfn_entry(dirname, short_name) newdir.set_lfn_entry(lfn_entry) # Create . and .. directory entries first_cluster = self.fs.allocate_bytes( FATDirectoryEntry.FAT_DIRECTORY_HEADER_SIZE * 2, erase=True)[0] newdir.set_cluster(first_cluster) dot_sn = EightDotThree() dot_sn.set_byte_name(b". ") dot = FATDirectoryEntry(DIR_Name=dot_sn, DIR_Attr=FATDirectoryEntry.ATTR_DIRECTORY, DIR_NTRes=newdir.ntres, DIR_CrtTimeTenth=newdir.crttimetenth, DIR_CrtDateTenth=newdir.crtdatetenth, DIR_LstAccessDate=newdir.lstaccessdate, DIR_FstClusHI=newdir.fstclushi, DIR_WrtTime=newdir.wrttime, DIR_WrtDate=newdir.wrtdate, DIR_FstClusLO=newdir.fstcluslo, DIR_FileSize=newdir.filesize, encoding=self.fs.encoding) dotdot_sn = EightDotThree() dotdot_sn.set_byte_name(b".. ") base_fstclushi = base.fstclushi if not parent_is_root else 0x0 base_fstcluslo = base.fstcluslo if not parent_is_root else 0x0 dotdot = FATDirectoryEntry(DIR_Name=dotdot_sn, DIR_Attr=FATDirectoryEntry.ATTR_DIRECTORY, DIR_NTRes=base.ntres, DIR_CrtTimeTenth=base.crttimetenth, DIR_CrtDateTenth=base.crtdatetenth, DIR_LstAccessDate=base.lstaccessdate, DIR_FstClusHI=base_fstclushi, DIR_WrtTime=base.wrttime, DIR_WrtDate=base.wrtdate, DIR_FstClusLO=base_fstcluslo, DIR_FileSize=base.filesize, encoding=self.fs.encoding) newdir.add_subdirectory(dot) newdir.add_subdirectory(dotdot) # Write new directory contents self.fs.update_directory_entry(newdir) # Write parent directory base.add_subdirectory(newdir) self.fs.update_directory_entry(base) # Flush FAT(s) to disk self.fs.flush_fat()
def test_checksum_calculation_referenceimpl(): """Test that the checksum calculation works, following reference impl.""" sfn = EightDotThree() sfn.set_str_name("FILENAME.TXT") assert sfn.checksum() == calculate_checksum_referenceimpl(sfn.name)
def test_checksum_calculation_precalculated(): """Test that the checksum calculation works, with a precalculated value.""" sfn = EightDotThree() sfn.set_str_name("FILENAME.TXT") assert sfn.checksum() == 58
def create(self, path: str, wipe: bool = False) -> bool: """Create a new file. :param path: Path of new file on filesystem :param wipe: Overwrite existing file contents """ basename = "/".join(path.split("/")[:-1]) dirname = path.split("/")[-1] # Plausability checks try: base = self.opendir(basename) except DirectoryExpected: raise ResourceNotFound(path) try: dentry = self._get_dir_entry(path) except ResourceNotFound: pass else: if not wipe: return False else: # Clean up existing file contents # TODO: touch {a,m}time old_cluster = dentry.get_cluster() dentry.set_cluster(0) self.fs.free_cluster_chain(old_cluster) return True # Determine 8DOT3 file name + LFN short_name = EightDotThree() n = short_name.make_8dot3_name(dirname, base) short_name.set_str_name(n) dt = DosDateTime.now(tz=self.tz) newdir = FATDirectoryEntry(DIR_Name=short_name, DIR_Attr=0, DIR_NTRes=0, DIR_CrtTimeTenth=0, DIR_CrtTime=dt.serialize_time(), DIR_CrtDate=dt.serialize_date(), DIR_LstAccessDate=dt.serialize_date(), DIR_FstClusHI=0x00, DIR_WrtTime=dt.serialize_time(), DIR_WrtDate=dt.serialize_date(), DIR_FstClusLO=0x00, DIR_FileSize=0, encoding=self.fs.encoding) # Create LFN entry if required _sfn = short_name.get_unpadded_filename() if _sfn != dirname.upper() or (_sfn != dirname and self.preserve_case): lfn_entry = make_lfn_entry(dirname, short_name) newdir.set_lfn_entry(lfn_entry) # Write reference to parent directory base.add_subdirectory(newdir) self.fs.update_directory_entry(base) # Flush FAT(s) to disk self.fs.flush_fat() return True