def parse_dir_entries_in_address( self, address: int = 0, max_address: int = 0, tmp_lfn_entry: FATLongDirectoryEntry = FATLongDirectoryEntry()): """Parses directory entries in address range.""" dir_hdr_size = FATDirectoryEntry.FAT_DIRECTORY_HEADER_SIZE if max_address == 0: max_address = FATDirectoryEntry.FAT_DIRECTORY_HEADER_SIZE dir_entries = [] for hdr_addr in range(address, max_address, dir_hdr_size): # Parse each entry dir_hdr = self.__parse_dir_entry(hdr_addr) dir_sn = EightDotThree(encoding=self.encoding) try: dir_sn.set_byte_name(dir_hdr["DIR_Name"]) except NotAFatEntryException as ex: # Not a directory of any kind, invalidate temporary LFN entries tmp_lfn_entry = FATLongDirectoryEntry() if ex.free_type == ex.FREE_ENTRY: # Empty directory entry, continue elif ex.free_type == ex.LAST_ENTRY: # Last directory entry, do not parse any further break else: dir_hdr["DIR_Name"] = dir_sn # Long File Names if FATLongDirectoryEntry.is_lfn_entry(dir_hdr["DIR_Name"], dir_hdr["DIR_Attr"]): self.parse_lfn_entry(tmp_lfn_entry, hdr_addr) continue # Normal directory entries if not tmp_lfn_entry.is_lfn_entry_complete(): # Ignore incomplete LFN entries altogether tmp_lfn_entry = None dir_entry = FATDirectoryEntry(encoding=self.encoding, lfn_entry=tmp_lfn_entry, **dir_hdr) dir_entries += [dir_entry] if dir_entry.is_directory() and not dir_entry.is_special(): # Iterate all subdirectories except for dot and dotdot subdirs = self.parse_dir_entries_in_cluster_chain( dir_entry.get_cluster()) for d in subdirs: dir_entry.add_subdirectory(d) # Reset temporary LFN entry tmp_lfn_entry = FATLongDirectoryEntry() return dir_entries, tmp_lfn_entry
def test_bytename_set_not_a_directory_free_entry(): """Test that 0x00 is detect as the last entry of the directory cluster.""" sfn = EightDotThree() with pytest.raises(NotADirectoryError) as ex: sfn.set_byte_name(b'\xE5 ') assert ex.free_type == ex.FREE_ENTRY
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_bytename_set_invalid_length(): """Test that a byte name can only be set with the correct length.""" sfn = EightDotThree() for n in [b'', b'1234567890', b'123456789011']: with pytest.raises(ValueError): sfn.set_byte_name(n)