Skip to content

Commit

Permalink
Merge branch 'feature/fatfs-support-detection-minimal-partition-size'…
Browse files Browse the repository at this point in the history
… into 'master'

fatfsgen.py: Support for detection of minimal partition size

Closes IDF-4122

See merge request espressif/esp-idf!20178
  • Loading branch information
dobairoland committed Oct 12, 2022
2 parents 1bbd524 + 2140869 commit 95c4749
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 3 deletions.
7 changes: 6 additions & 1 deletion components/fatfs/fatfs_utils/utils.py
Expand Up @@ -14,6 +14,7 @@
# the regex pattern defines symbols that are allowed by long file names but not by short file names
INVALID_SFN_CHARS_PATTERN = re.compile(r'[.+,;=\[\]]')

FATFS_MIN_ALLOC_UNIT: int = 128
FAT12_MAX_CLUSTERS: int = 4085
FAT16_MAX_CLUSTERS: int = 65525
RESERVED_CLUSTERS_COUNT: int = 2
Expand Down Expand Up @@ -174,7 +175,9 @@ def get_args_for_partition_generator(desc: str, wl: bool) -> argparse.Namespace:
help='Filename of the generated fatfs image')
parser.add_argument('--partition_size',
default=FATDefaults.SIZE,
help='Size of the partition in bytes')
help='Size of the partition in bytes.' +
('' if wl else ' Use `--partition_size detect` for detecting the minimal partition size.')
)
parser.add_argument('--sector_size',
default=FATDefaults.SECTOR_SIZE,
type=int,
Expand Down Expand Up @@ -207,6 +210,8 @@ def get_args_for_partition_generator(desc: str, wl: bool) -> argparse.Namespace:
args = parser.parse_args()
if args.fat_type == 0:
args.fat_type = None
if args.partition_size == 'detect' and not wl:
args.partition_size = -1
args.partition_size = int(str(args.partition_size), 0)
if not os.path.isdir(args.input_directory):
raise NotADirectoryError(f'The target directory `{args.input_directory}` does not exist!')
Expand Down
47 changes: 45 additions & 2 deletions components/fatfs/fatfsgen.py
Expand Up @@ -7,11 +7,15 @@
from typing import Any, List, Optional

from fatfs_utils.boot_sector import BootSector
from fatfs_utils.exceptions import NoFreeClusterException
from fatfs_utils.fat import FAT
from fatfs_utils.fatfs_state import FATFSState
from fatfs_utils.fs_object import Directory
from fatfs_utils.utils import (BYTES_PER_DIRECTORY_ENTRY, FATFS_INCEPTION, FATDefaults,
get_args_for_partition_generator, read_filesystem)
from fatfs_utils.long_filename_utils import get_required_lfn_entries_count
from fatfs_utils.utils import (BYTES_PER_DIRECTORY_ENTRY, FATFS_INCEPTION, FATFS_MIN_ALLOC_UNIT,
RESERVED_CLUSTERS_COUNT, FATDefaults, get_args_for_partition_generator,
get_fat_sectors_count, get_non_data_sectors_cnt, read_filesystem,
required_clusters_count)


class FATFS:
Expand Down Expand Up @@ -184,8 +188,47 @@ def generate(self, input_directory: str) -> None:
self._generate_partition_from_folder(folder_name, folder_path=path_to_folder, is_dir=True)


def calculate_min_space(path: List[str],
fs_entity: str,
sector_size: int = 0x1000,
long_file_names: bool = False,
is_root: bool = False) -> int:
if os.path.isfile(os.path.join(*path, fs_entity)):
with open(os.path.join(*path, fs_entity), 'rb') as file_:
content = file_.read()
res: int = required_clusters_count(sector_size, content)
return res
buff: int = 0
dir_size = 2 * FATDefaults.ENTRY_SIZE # record for symlinks "." and ".."
for file in sorted(os.listdir(os.path.join(*path, fs_entity))):
if long_file_names and True:
# LFN entries + one short entry
dir_size += (get_required_lfn_entries_count(fs_entity) + 1) * FATDefaults.ENTRY_SIZE
else:
dir_size += FATDefaults.ENTRY_SIZE
buff += calculate_min_space(path + [fs_entity], file, sector_size, long_file_names, is_root=False)
if is_root and dir_size // FATDefaults.ENTRY_SIZE > FATDefaults.ROOT_ENTRIES_COUNT:
raise NoFreeClusterException('Not enough space in root!')

# roundup sectors, at least one is required
buff += (dir_size + sector_size - 1) // sector_size
return buff


def main() -> None:
args = get_args_for_partition_generator('Create a FAT filesystem and populate it with directory content', wl=False)

if args.partition_size == -1:
clusters = calculate_min_space([], args.input_directory, args.sector_size, long_file_names=True, is_root=True)
fats = get_fat_sectors_count(clusters, args.sector_size)
root_dir_sectors = (FATDefaults.ROOT_ENTRIES_COUNT * FATDefaults.ENTRY_SIZE) // args.sector_size
args.partition_size = max(FATFS_MIN_ALLOC_UNIT * args.sector_size,
(clusters + fats + get_non_data_sectors_cnt(RESERVED_CLUSTERS_COUNT,
fats,
root_dir_sectors)
) * args.sector_size
)

fatfs = FATFS(sector_size=args.sector_size,
sectors_per_cluster=args.sectors_per_cluster,
size=args.partition_size,
Expand Down

0 comments on commit 95c4749

Please sign in to comment.