From a640626b76e7b548c2a523196c7f718a29b6498a Mon Sep 17 00:00:00 2001 From: "radek.tandler" Date: Thu, 2 Nov 2023 11:33:47 +0100 Subject: [PATCH] fix(fatfs): Fixed fatfsparse.py parsing of FAT boot sector The fatfsparse.py script was too strict in parsing the FAT boot sector, causing it to fail in certain cases. This commit fixes the issue by making the parsing less strict and allowing for more flexibility in the boot sector format. This change improves the reliability and compatibility of the fatfsparse.py script, ensuring that it can correctly parse a wider range of FAT boot sectors. Docs updated --- components/fatfs/fatfs_utils/boot_sector.py | 17 ++++++++--------- components/fatfs/fatfsparse.py | 11 +++++++++-- docs/en/api-reference/storage/fatfs.rst | 3 ++- docs/zh_CN/api-reference/storage/fatfs.rst | 3 ++- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/components/fatfs/fatfs_utils/boot_sector.py b/components/fatfs/fatfs_utils/boot_sector.py index 615dd06511..389d27c7a2 100644 --- a/components/fatfs/fatfs_utils/boot_sector.py +++ b/components/fatfs/fatfs_utils/boot_sector.py @@ -1,9 +1,9 @@ -# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2021-2023 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 from inspect import getmembers, isroutine from typing import Optional -from construct import Const, Int8ul, Int16ul, Int32ul, PaddedString, Struct, core +from construct import Bytes, Const, Int8ul, Int16ul, Int32ul, PaddedString, Padding, Struct, core from .exceptions import InconsistentFATAttributes, NotInitialized from .fatfs_state import BootSectorState @@ -29,8 +29,7 @@ class BootSector: BOOT_HEADER_SIZE = 512 BOOT_SECTOR_HEADER = Struct( - # this value reflects BS_jmpBoot used for ESP32 boot sector (any other accepted) - 'BS_jmpBoot' / Const(b'\xeb\xfe\x90'), + 'BS_jmpBoot' / Bytes(3), 'BS_OEMName' / PaddedString(MAX_OEM_NAME_SIZE, SHORT_NAMES_ENCODING), 'BPB_BytsPerSec' / Int16ul, 'BPB_SecPerClus' / Int8ul, @@ -45,12 +44,12 @@ class BootSector: 'BPB_HiddSec' / Int32ul, 'BPB_TotSec32' / Int32ul, # zero if the FAT type is 12/16, otherwise number of sectors 'BS_DrvNum' / Const(b'\x80'), - 'BS_Reserved1' / Const(EMPTY_BYTE), + 'BS_Reserved1' / Padding(1), 'BS_BootSig' / Const(b'\x29'), 'BS_VolID' / Int32ul, 'BS_VolLab' / PaddedString(MAX_VOL_LAB_SIZE, SHORT_NAMES_ENCODING), 'BS_FilSysType' / PaddedString(MAX_FS_TYPE_SIZE, SHORT_NAMES_ENCODING), - 'BS_EMPTY' / Const(448 * EMPTY_BYTE), + 'BS_EMPTY' / Padding(448), 'Signature_word' / Const(FATDefaults.SIGNATURE_WORD) ) assert BOOT_SECTOR_HEADER.sizeof() == BOOT_HEADER_SIZE @@ -73,7 +72,8 @@ class BootSector: * EMPTY_BYTE) self.boot_sector_state.binary_image = ( BootSector.BOOT_SECTOR_HEADER.build( - dict(BS_OEMName=pad_string(boot_sector_state.oem_name, size=BootSector.MAX_OEM_NAME_SIZE), + dict(BS_jmpBoot=(b'\xeb\xfe\x90'), + BS_OEMName=pad_string(boot_sector_state.oem_name, size=BootSector.MAX_OEM_NAME_SIZE), BPB_BytsPerSec=boot_sector_state.sector_size, BPB_SecPerClus=boot_sector_state.sectors_per_cluster, BPB_RsvdSecCnt=boot_sector_state.reserved_sectors_cnt, @@ -91,8 +91,7 @@ class BootSector: BS_VolLab=pad_string(boot_sector_state.volume_label, size=BootSector.MAX_VOL_LAB_SIZE), BS_FilSysType=pad_string(boot_sector_state.file_sys_type, - size=BootSector.MAX_FS_TYPE_SIZE) - ) + size=BootSector.MAX_FS_TYPE_SIZE)) ) + pad_header + fat_tables_content + root_dir_content + data_content ) diff --git a/components/fatfs/fatfsparse.py b/components/fatfs/fatfsparse.py index c5d3716c56..25f0ec302a 100755 --- a/components/fatfs/fatfsparse.py +++ b/components/fatfs/fatfsparse.py @@ -1,5 +1,5 @@ #!/usr/bin/env python -# SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: Apache-2.0 import argparse import os @@ -100,7 +100,7 @@ def remove_wear_levelling_if_exists(fs_: bytes) -> bytes: boot_sector__.parse_boot_sector(fs_) if boot_sector__.boot_sector_state.size == len(fs_): return fs_ - except construct.core.ConstError: + except UnicodeDecodeError: pass plain_fs: bytes = remove_wl(fs_) return plain_fs @@ -124,6 +124,9 @@ if __name__ == '__main__': default=None, help="If detection doesn't work correctly, " 'you can force analyzer to or not to assume WL.') + argument_parser.add_argument('--verbose', + action='store_true', + help='Prints details about FAT image.') args = argument_parser.parse_args() @@ -157,6 +160,10 @@ if __name__ == '__main__': boot_sector_ = BootSector() boot_sector_.parse_boot_sector(fs) + + if args.verbose: + print(str(boot_sector_)) + fat = FAT(boot_sector_.boot_sector_state, init_=False) boot_dir_start_ = boot_sector_.boot_sector_state.root_directory_start diff --git a/docs/en/api-reference/storage/fatfs.rst b/docs/en/api-reference/storage/fatfs.rst index ae7721dcbe..98ddd976e0 100644 --- a/docs/en/api-reference/storage/fatfs.rst +++ b/docs/en/api-reference/storage/fatfs.rst @@ -136,8 +136,9 @@ It is a reverse tool of (:component_file:`fatfsgen.py `), i.e Usage:: - ./fatfsparse.py [-h] [--wl-layer {detect,enabled,disabled}] fatfs_image.img + ./fatfsparse.py [-h] [--wl-layer {detect,enabled,disabled}] [--verbose] fatfs_image.img +Parameter --verbose prints detailed information from boot sector of the FatFs image to the terminal before folder structure is generated. High-level API Reference ------------------------ diff --git a/docs/zh_CN/api-reference/storage/fatfs.rst b/docs/zh_CN/api-reference/storage/fatfs.rst index c16d8e6518..e153139b5d 100644 --- a/docs/zh_CN/api-reference/storage/fatfs.rst +++ b/docs/zh_CN/api-reference/storage/fatfs.rst @@ -136,8 +136,9 @@ FatFs 分区分析器 可以使用:: - ./fatfsparse.py [-h] [--wl-layer {detect,enabled,disabled}] fatfs_image.img + ./fatfsparse.py [-h] [--wl-layer {detect,enabled,disabled}] [--verbose] fatfs_image.img +生成文件夹结构之前,参数 --verbose 将根据 FatFs 镜像的引导扇区在终端打印详细信息。 高级 API 参考 ------------------------