fatfsparse.py 3.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. # SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
  2. # SPDX-License-Identifier: Apache-2.0
  3. import os
  4. import sys
  5. from typing import Tuple
  6. from fatfs_utils.boot_sector import BootSector
  7. from fatfs_utils.cluster import Cluster
  8. from fatfs_utils.entry import Entry
  9. from fatfs_utils.fat import FAT
  10. from fatfs_utils.fatfs_state import BootSectorState
  11. from fatfs_utils.utils import PAD_CHAR, FATDefaults, read_filesystem
  12. def get_chained_full_content(cluster_id_: int,
  13. fat_: FAT,
  14. state_: BootSectorState,
  15. binary_array_: bytearray) -> bytearray:
  16. if fat_.is_cluster_last(cluster_id_):
  17. data_address_ = Cluster.compute_cluster_data_address(state_, cluster_id_)
  18. content_: bytearray = binary_array_[data_address_: data_address_ + state_.sector_size]
  19. return content_
  20. fat_value_: int = fat_.get_cluster_value(cluster_id_)
  21. data_address_ = Cluster.compute_cluster_data_address(state_, cluster_id_)
  22. content_ = binary_array_[data_address_: data_address_ + state_.sector_size]
  23. while not fat_.is_cluster_last(cluster_id_):
  24. cluster_id_ = fat_value_
  25. fat_value_ = fat_.get_cluster_value(cluster_id_)
  26. data_address_ = Cluster.compute_cluster_data_address(state_, cluster_id_)
  27. content_ += binary_array_[data_address_: data_address_ + state_.sector_size]
  28. return content_
  29. def get_name_and_id(obj_: dict) -> Tuple[str, int]:
  30. cluster_id_ = obj_['DIR_FstClusLO']
  31. obj_ext_ = obj_['DIR_Name_ext'].rstrip(chr(PAD_CHAR))
  32. ext_ = f'.{obj_ext_}' if len(obj_ext_) > 0 else ''
  33. obj_name_ = obj_['DIR_Name'].rstrip(chr(PAD_CHAR)) + ext_
  34. return obj_name_, cluster_id_
  35. def traverse_folder_tree(directory_bytes_: bytes,
  36. name: str,
  37. state_: BootSectorState, fat_: FAT,
  38. binary_array_: bytearray) -> None:
  39. if name not in ('.', '..'):
  40. os.makedirs(name)
  41. for i in range(len(directory_bytes_) // FATDefaults.ENTRY_SIZE):
  42. obj_address_ = FATDefaults.ENTRY_SIZE * i
  43. obj_ = Entry.ENTRY_FORMAT_SHORT_NAME.parse(
  44. directory_bytes_[obj_address_: obj_address_ + FATDefaults.ENTRY_SIZE])
  45. if obj_['DIR_Attr'] == Entry.ATTR_ARCHIVE:
  46. obj_name_, cluster_id_ = get_name_and_id(obj_)
  47. content_ = get_chained_full_content(
  48. cluster_id_=cluster_id_,
  49. fat_=fat_,
  50. state_=state_,
  51. binary_array_=binary_array_
  52. ).rstrip(chr(0x00).encode())
  53. with open(os.path.join(name, obj_name_), 'wb') as new_file:
  54. new_file.write(content_)
  55. elif obj_['DIR_Attr'] == Entry.ATTR_DIRECTORY:
  56. obj_name_, cluster_id_ = get_name_and_id(obj_)
  57. if obj_name_ in ('.', '..'):
  58. continue
  59. child_directory_bytes_ = get_chained_full_content(
  60. cluster_id_=obj_['DIR_FstClusLO'],
  61. fat_=fat_,
  62. state_=state_,
  63. binary_array_=binary_array_
  64. )
  65. traverse_folder_tree(directory_bytes_=child_directory_bytes_,
  66. name=os.path.join(name, obj_name_),
  67. state_=state_,
  68. fat_=fat_,
  69. binary_array_=binary_array_)
  70. if __name__ == '__main__':
  71. fs = read_filesystem(sys.argv[1])
  72. parser = BootSector()
  73. parser.parse_boot_sector(fs)
  74. fat = FAT(parser.boot_sector_state, init_=False)
  75. boot_dir_start_ = parser.boot_sector_state.root_directory_start
  76. boot_dir_sectors = parser.boot_sector_state.root_dir_sectors_cnt
  77. full_ = fs[boot_dir_start_: boot_dir_start_ + boot_dir_sectors * parser.boot_sector_state.sector_size]
  78. traverse_folder_tree(full_,
  79. parser.boot_sector_state.volume_label.rstrip(chr(PAD_CHAR)),
  80. parser.boot_sector_state, fat, fs)