| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | #!/usr/bin/env python | 
					
						
							|  |  |  | # | 
					
						
							|  |  |  | # spiffsgen is a tool used to generate a spiffs image from a directory | 
					
						
							|  |  |  | # | 
					
						
							| 
									
										
										
										
											2022-02-22 00:09:24 +03:00
										 |  |  | # SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD | 
					
						
							|  |  |  | # SPDX-License-Identifier: Apache-2.0 | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-04 23:32:40 +01:00
										 |  |  | from __future__ import division, print_function | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | import argparse | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | import io | 
					
						
							|  |  |  | import math | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | import struct | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  | try: | 
					
						
							|  |  |  |     import typing | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     TSP = typing.TypeVar('TSP', bound='SpiffsObjPageWithIdx') | 
					
						
							|  |  |  |     ObjIdsItem = typing.Tuple[int, typing.Type[TSP]] | 
					
						
							|  |  |  | except ImportError: | 
					
						
							|  |  |  |     pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | SPIFFS_PH_FLAG_USED_FINAL_INDEX = 0xF8 | 
					
						
							|  |  |  | SPIFFS_PH_FLAG_USED_FINAL = 0xFC | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | SPIFFS_PH_FLAG_LEN = 1 | 
					
						
							|  |  |  | SPIFFS_PH_IX_SIZE_LEN = 4 | 
					
						
							|  |  |  | SPIFFS_PH_IX_OBJ_TYPE_LEN = 1 | 
					
						
							|  |  |  | SPIFFS_TYPE_FILE = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # Based on typedefs under spiffs_config.h | 
					
						
							|  |  |  | SPIFFS_OBJ_ID_LEN = 2  # spiffs_obj_id | 
					
						
							|  |  |  | SPIFFS_SPAN_IX_LEN = 2  # spiffs_span_ix | 
					
						
							|  |  |  | SPIFFS_PAGE_IX_LEN = 2  # spiffs_page_ix | 
					
						
							|  |  |  | SPIFFS_BLOCK_IX_LEN = 2  # spiffs_block_ix | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-30 18:37:15 +02:00
										 |  |  | class SpiffsBuildConfig(object): | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |     def __init__(self, | 
					
						
							|  |  |  |                  page_size,  # type: int | 
					
						
							|  |  |  |                  page_ix_len,  # type: int | 
					
						
							|  |  |  |                  block_size,  # type: int | 
					
						
							|  |  |  |                  block_ix_len,  # type: int | 
					
						
							|  |  |  |                  meta_len,  # type: int | 
					
						
							|  |  |  |                  obj_name_len,  # type: int | 
					
						
							|  |  |  |                  obj_id_len,  # type: int | 
					
						
							|  |  |  |                  span_ix_len,  # type: int | 
					
						
							|  |  |  |                  packed,  # type: bool | 
					
						
							|  |  |  |                  aligned,  # type: bool | 
					
						
							|  |  |  |                  endianness,  # type: str | 
					
						
							|  |  |  |                  use_magic,  # type: bool | 
					
						
							|  |  |  |                  use_magic_len,  # type: bool | 
					
						
							|  |  |  |                  aligned_obj_ix_tables  # type: bool | 
					
						
							|  |  |  |                  ): | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         if block_size % page_size != 0: | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |             raise RuntimeError('block size should be a multiple of page size') | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.page_size = page_size | 
					
						
							|  |  |  |         self.block_size = block_size | 
					
						
							|  |  |  |         self.obj_id_len = obj_id_len | 
					
						
							|  |  |  |         self.span_ix_len = span_ix_len | 
					
						
							|  |  |  |         self.packed = packed | 
					
						
							|  |  |  |         self.aligned = aligned | 
					
						
							|  |  |  |         self.obj_name_len = obj_name_len | 
					
						
							|  |  |  |         self.meta_len = meta_len | 
					
						
							|  |  |  |         self.page_ix_len = page_ix_len | 
					
						
							|  |  |  |         self.block_ix_len = block_ix_len | 
					
						
							|  |  |  |         self.endianness = endianness | 
					
						
							|  |  |  |         self.use_magic = use_magic | 
					
						
							|  |  |  |         self.use_magic_len = use_magic_len | 
					
						
							| 
									
										
										
										
											2021-03-22 21:05:22 +01:00
										 |  |  |         self.aligned_obj_ix_tables = aligned_obj_ix_tables | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.PAGES_PER_BLOCK = self.block_size // self.page_size | 
					
						
							|  |  |  |         self.OBJ_LU_PAGES_PER_BLOCK = int(math.ceil(self.block_size / self.page_size * self.obj_id_len / self.page_size)) | 
					
						
							|  |  |  |         self.OBJ_USABLE_PAGES_PER_BLOCK = self.PAGES_PER_BLOCK - self.OBJ_LU_PAGES_PER_BLOCK | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.OBJ_LU_PAGES_OBJ_IDS_LIM = self.page_size // self.obj_id_len | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.OBJ_DATA_PAGE_HEADER_LEN = self.obj_id_len + self.span_ix_len + SPIFFS_PH_FLAG_LEN | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         pad = 4 - (4 if self.OBJ_DATA_PAGE_HEADER_LEN % 4 == 0 else self.OBJ_DATA_PAGE_HEADER_LEN % 4) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED = self.OBJ_DATA_PAGE_HEADER_LEN + pad | 
					
						
							|  |  |  |         self.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED_PAD = pad | 
					
						
							|  |  |  |         self.OBJ_DATA_PAGE_CONTENT_LEN = self.page_size - self.OBJ_DATA_PAGE_HEADER_LEN | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.OBJ_INDEX_PAGES_HEADER_LEN = (self.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED + SPIFFS_PH_IX_SIZE_LEN + | 
					
						
							|  |  |  |                                            SPIFFS_PH_IX_OBJ_TYPE_LEN + self.obj_name_len + self.meta_len) | 
					
						
							| 
									
										
										
										
											2021-03-22 21:05:22 +01:00
										 |  |  |         if aligned_obj_ix_tables: | 
					
						
							|  |  |  |             self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED = (self.OBJ_INDEX_PAGES_HEADER_LEN + SPIFFS_PAGE_IX_LEN - 1) & ~(SPIFFS_PAGE_IX_LEN - 1) | 
					
						
							|  |  |  |             self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED_PAD = self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED - self.OBJ_INDEX_PAGES_HEADER_LEN | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED = self.OBJ_INDEX_PAGES_HEADER_LEN | 
					
						
							|  |  |  |             self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED_PAD = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.OBJ_INDEX_PAGES_OBJ_IDS_HEAD_LIM = (self.page_size - self.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED) // self.block_ix_len | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |         self.OBJ_INDEX_PAGES_OBJ_IDS_LIM = (self.page_size - self.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED) // self.block_ix_len | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class SpiffsFullError(RuntimeError): | 
					
						
							| 
									
										
										
										
											2021-04-14 18:43:26 +02:00
										 |  |  |     pass | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-30 18:37:15 +02:00
										 |  |  | class SpiffsPage(object): | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |     _endianness_dict = { | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |         'little': '<', | 
					
						
							|  |  |  |         'big': '>' | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     _len_dict = { | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |         1: 'B', | 
					
						
							|  |  |  |         2: 'H', | 
					
						
							|  |  |  |         4: 'I', | 
					
						
							|  |  |  |         8: 'Q' | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |     def __init__(self, bix, build_config):  # type: (int, SpiffsBuildConfig) -> None | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         self.build_config = build_config | 
					
						
							|  |  |  |         self.bix = bix | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |     def to_binary(self):  # type: () -> bytes | 
					
						
							|  |  |  |         raise NotImplementedError() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class SpiffsObjPageWithIdx(SpiffsPage): | 
					
						
							|  |  |  |     def __init__(self, obj_id, build_config):  # type: (int, SpiffsBuildConfig) -> None | 
					
						
							|  |  |  |         super(SpiffsObjPageWithIdx, self).__init__(0, build_config) | 
					
						
							|  |  |  |         self.obj_id = obj_id | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-14 18:43:26 +02:00
										 |  |  |     def to_binary(self):  # type: () -> bytes | 
					
						
							|  |  |  |         raise NotImplementedError() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | class SpiffsObjLuPage(SpiffsPage): | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |     def __init__(self, bix, build_config):  # type: (int, SpiffsBuildConfig) -> None | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         SpiffsPage.__init__(self, bix, build_config) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.obj_ids_limit = self.build_config.OBJ_LU_PAGES_OBJ_IDS_LIM | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |         self.obj_ids = list()  # type: typing.List[ObjIdsItem] | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |     def _calc_magic(self, blocks_lim):  # type: (int) -> int | 
					
						
							| 
									
										
										
										
											2021-04-14 18:43:26 +02:00
										 |  |  |         # Calculate the magic value mirroring computation done by the macro SPIFFS_MAGIC defined in | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         # spiffs_nucleus.h | 
					
						
							|  |  |  |         magic = 0x20140529 ^ self.build_config.page_size | 
					
						
							|  |  |  |         if self.build_config.use_magic_len: | 
					
						
							|  |  |  |             magic = magic ^ (blocks_lim - self.bix) | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |         # narrow the result to build_config.obj_id_len bytes | 
					
						
							|  |  |  |         mask = (2 << (8 * self.build_config.obj_id_len)) - 1 | 
					
						
							|  |  |  |         return magic & mask | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |     def register_page(self, page):  # type: (TSP) -> None | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         if not self.obj_ids_limit > 0: | 
					
						
							|  |  |  |             raise SpiffsFullError() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         obj_id = (page.obj_id, page.__class__) | 
					
						
							|  |  |  |         self.obj_ids.append(obj_id) | 
					
						
							|  |  |  |         self.obj_ids_limit -= 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |     def to_binary(self):  # type: () -> bytes | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |         img = b'' | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         for (obj_id, page_type) in self.obj_ids: | 
					
						
							|  |  |  |             if page_type == SpiffsObjIndexPage: | 
					
						
							|  |  |  |                 obj_id ^= (1 << ((self.build_config.obj_id_len * 8) - 1)) | 
					
						
							|  |  |  |             img += struct.pack(SpiffsPage._endianness_dict[self.build_config.endianness] + | 
					
						
							|  |  |  |                                SpiffsPage._len_dict[self.build_config.obj_id_len], obj_id) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-10 09:01:57 +02:00
										 |  |  |         assert len(img) <= self.build_config.page_size | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |         img += b'\xFF' * (self.build_config.page_size - len(img)) | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return img | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |     def magicfy(self, blocks_lim):  # type: (int) -> None | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         # Only use magic value if no valid obj id has been written to the spot, which is the | 
					
						
							|  |  |  |         # spot taken up by the last obj id on last lookup page. The parent is responsible | 
					
						
							|  |  |  |         # for determining which is the last lookup page and calling this function. | 
					
						
							|  |  |  |         remaining = self.obj_ids_limit | 
					
						
							|  |  |  |         empty_obj_id_dict = { | 
					
						
							|  |  |  |             1: 0xFF, | 
					
						
							|  |  |  |             2: 0xFFFF, | 
					
						
							|  |  |  |             4: 0xFFFFFFFF, | 
					
						
							|  |  |  |             8: 0xFFFFFFFFFFFFFFFF | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |         if remaining >= 2: | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |             for i in range(remaining): | 
					
						
							|  |  |  |                 if i == remaining - 2: | 
					
						
							|  |  |  |                     self.obj_ids.append((self._calc_magic(blocks_lim), SpiffsObjDataPage)) | 
					
						
							|  |  |  |                     break | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     self.obj_ids.append((empty_obj_id_dict[self.build_config.obj_id_len], SpiffsObjDataPage)) | 
					
						
							|  |  |  |                 self.obj_ids_limit -= 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  | class SpiffsObjIndexPage(SpiffsObjPageWithIdx): | 
					
						
							|  |  |  |     def __init__(self, obj_id, span_ix, size, name, build_config | 
					
						
							|  |  |  |                  ):  # type: (int, int, int, str, SpiffsBuildConfig) -> None | 
					
						
							|  |  |  |         super(SpiffsObjIndexPage, self).__init__(obj_id, build_config) | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         self.span_ix = span_ix | 
					
						
							|  |  |  |         self.name = name | 
					
						
							|  |  |  |         self.size = size | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if self.span_ix == 0: | 
					
						
							|  |  |  |             self.pages_lim = self.build_config.OBJ_INDEX_PAGES_OBJ_IDS_HEAD_LIM | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             self.pages_lim = self.build_config.OBJ_INDEX_PAGES_OBJ_IDS_LIM | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |         self.pages = list()  # type: typing.List[int] | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |     def register_page(self, page):  # type: (SpiffsObjDataPage) -> None | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         if not self.pages_lim > 0: | 
					
						
							|  |  |  |             raise SpiffsFullError | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.pages.append(page.offset) | 
					
						
							|  |  |  |         self.pages_lim -= 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |     def to_binary(self):  # type: () -> bytes | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         obj_id = self.obj_id ^ (1 << ((self.build_config.obj_id_len * 8) - 1)) | 
					
						
							|  |  |  |         img = struct.pack(SpiffsPage._endianness_dict[self.build_config.endianness] + | 
					
						
							|  |  |  |                           SpiffsPage._len_dict[self.build_config.obj_id_len] + | 
					
						
							|  |  |  |                           SpiffsPage._len_dict[self.build_config.span_ix_len] + | 
					
						
							|  |  |  |                           SpiffsPage._len_dict[SPIFFS_PH_FLAG_LEN], | 
					
						
							|  |  |  |                           obj_id, | 
					
						
							|  |  |  |                           self.span_ix, | 
					
						
							|  |  |  |                           SPIFFS_PH_FLAG_USED_FINAL_INDEX) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Add padding before the object index page specific information | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |         img += b'\xFF' * self.build_config.OBJ_DATA_PAGE_HEADER_LEN_ALIGNED_PAD | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # If this is the first object index page for the object, add filname, type | 
					
						
							|  |  |  |         # and size information | 
					
						
							|  |  |  |         if self.span_ix == 0: | 
					
						
							|  |  |  |             img += struct.pack(SpiffsPage._endianness_dict[self.build_config.endianness] + | 
					
						
							|  |  |  |                                SpiffsPage._len_dict[SPIFFS_PH_IX_SIZE_LEN]  + | 
					
						
							|  |  |  |                                SpiffsPage._len_dict[SPIFFS_PH_FLAG_LEN], | 
					
						
							|  |  |  |                                self.size, | 
					
						
							|  |  |  |                                SPIFFS_TYPE_FILE) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 21:05:22 +01:00
										 |  |  |             img += self.name.encode() + (b'\x00' * ( | 
					
						
							|  |  |  |                 (self.build_config.obj_name_len - len(self.name)) | 
					
						
							|  |  |  |                 + self.build_config.meta_len | 
					
						
							|  |  |  |                 + self.build_config.OBJ_INDEX_PAGES_HEADER_LEN_ALIGNED_PAD)) | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # Finally, add the page index of daa pages | 
					
						
							|  |  |  |         for page in self.pages: | 
					
						
							|  |  |  |             page = page >> int(math.log(self.build_config.page_size, 2)) | 
					
						
							|  |  |  |             img += struct.pack(SpiffsPage._endianness_dict[self.build_config.endianness] + | 
					
						
							|  |  |  |                                SpiffsPage._len_dict[self.build_config.page_ix_len], page) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-10 09:01:57 +02:00
										 |  |  |         assert len(img) <= self.build_config.page_size | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |         img += b'\xFF' * (self.build_config.page_size - len(img)) | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return img | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  | class SpiffsObjDataPage(SpiffsObjPageWithIdx): | 
					
						
							|  |  |  |     def __init__(self, offset, obj_id, span_ix, contents, build_config | 
					
						
							|  |  |  |                  ):  # type: (int, int, int, bytes, SpiffsBuildConfig) -> None | 
					
						
							|  |  |  |         super(SpiffsObjDataPage, self).__init__(obj_id, build_config) | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         self.span_ix = span_ix | 
					
						
							|  |  |  |         self.contents = contents | 
					
						
							|  |  |  |         self.offset = offset | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |     def to_binary(self):  # type: () -> bytes | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         img = struct.pack(SpiffsPage._endianness_dict[self.build_config.endianness] + | 
					
						
							|  |  |  |                           SpiffsPage._len_dict[self.build_config.obj_id_len] + | 
					
						
							|  |  |  |                           SpiffsPage._len_dict[self.build_config.span_ix_len] + | 
					
						
							|  |  |  |                           SpiffsPage._len_dict[SPIFFS_PH_FLAG_LEN], | 
					
						
							|  |  |  |                           self.obj_id, | 
					
						
							|  |  |  |                           self.span_ix, | 
					
						
							|  |  |  |                           SPIFFS_PH_FLAG_USED_FINAL) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         img += self.contents | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-10 09:01:57 +02:00
										 |  |  |         assert len(img) <= self.build_config.page_size | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |         img += b'\xFF' * (self.build_config.page_size - len(img)) | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         return img | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-30 18:37:15 +02:00
										 |  |  | class SpiffsBlock(object): | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |     def _reset(self):  # type: () -> None | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         self.cur_obj_index_span_ix = 0 | 
					
						
							|  |  |  |         self.cur_obj_data_span_ix = 0 | 
					
						
							|  |  |  |         self.cur_obj_id = 0 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |         self.cur_obj_idx_page = None  # type: typing.Optional[SpiffsObjIndexPage] | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-14 18:43:26 +02:00
										 |  |  |     def __init__(self, bix, build_config):  # type: (int, SpiffsBuildConfig) -> None | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         self.build_config = build_config | 
					
						
							|  |  |  |         self.offset = bix * self.build_config.block_size | 
					
						
							|  |  |  |         self.remaining_pages = self.build_config.OBJ_USABLE_PAGES_PER_BLOCK | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |         self.pages = list()  # type: typing.List[SpiffsPage] | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         self.bix = bix | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         lu_pages = list() | 
					
						
							|  |  |  |         for i in range(self.build_config.OBJ_LU_PAGES_PER_BLOCK): | 
					
						
							|  |  |  |             page = SpiffsObjLuPage(self.bix, self.build_config) | 
					
						
							|  |  |  |             lu_pages.append(page) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.pages.extend(lu_pages) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.lu_page_iter = iter(lu_pages) | 
					
						
							|  |  |  |         self.lu_page = next(self.lu_page_iter) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self._reset() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |     def _register_page(self, page):  # type: (TSP) -> None | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         if isinstance(page, SpiffsObjDataPage): | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |             assert self.cur_obj_idx_page is not None | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |             self.cur_obj_idx_page.register_page(page)  # can raise SpiffsFullError | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             self.lu_page.register_page(page) | 
					
						
							|  |  |  |         except SpiffsFullError: | 
					
						
							|  |  |  |             self.lu_page = next(self.lu_page_iter) | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 self.lu_page.register_page(page) | 
					
						
							|  |  |  |             except AttributeError:  # no next lookup page | 
					
						
							|  |  |  |                 # Since the amount of lookup pages is pre-computed at every block instance, | 
					
						
							|  |  |  |                 # this should never occur | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |                 raise RuntimeError('invalid attempt to add page to a block when there is no more space in lookup') | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.pages.append(page) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |     def begin_obj(self, obj_id, size, name, obj_index_span_ix=0, obj_data_span_ix=0 | 
					
						
							|  |  |  |                   ):  # type: (int, int, str, int, int) -> None | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         if not self.remaining_pages > 0: | 
					
						
							|  |  |  |             raise SpiffsFullError() | 
					
						
							|  |  |  |         self._reset() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.cur_obj_id = obj_id | 
					
						
							|  |  |  |         self.cur_obj_index_span_ix = obj_index_span_ix | 
					
						
							|  |  |  |         self.cur_obj_data_span_ix = obj_data_span_ix | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         page = SpiffsObjIndexPage(obj_id, self.cur_obj_index_span_ix, size, name, self.build_config) | 
					
						
							|  |  |  |         self._register_page(page) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.cur_obj_idx_page = page | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.remaining_pages -= 1 | 
					
						
							|  |  |  |         self.cur_obj_index_span_ix += 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |     def update_obj(self, contents):  # type: (bytes) -> None | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         if not self.remaining_pages > 0: | 
					
						
							|  |  |  |             raise SpiffsFullError() | 
					
						
							|  |  |  |         page = SpiffsObjDataPage(self.offset + (len(self.pages) * self.build_config.page_size), | 
					
						
							|  |  |  |                                  self.cur_obj_id, self.cur_obj_data_span_ix, contents, self.build_config) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self._register_page(page) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.cur_obj_data_span_ix += 1 | 
					
						
							|  |  |  |         self.remaining_pages -= 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |     def end_obj(self):  # type: () -> None | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         self._reset() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |     def is_full(self):  # type: () -> bool | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         return self.remaining_pages <= 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |     def to_binary(self, blocks_lim):  # type: (int) -> bytes | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |         img = b'' | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if self.build_config.use_magic: | 
					
						
							|  |  |  |             for (idx, page) in enumerate(self.pages): | 
					
						
							|  |  |  |                 if idx == self.build_config.OBJ_LU_PAGES_PER_BLOCK - 1: | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |                     assert isinstance(page, SpiffsObjLuPage) | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |                     page.magicfy(blocks_lim) | 
					
						
							|  |  |  |                 img += page.to_binary() | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             for page in self.pages: | 
					
						
							|  |  |  |                 img += page.to_binary() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-10 09:01:57 +02:00
										 |  |  |         assert len(img) <= self.build_config.block_size | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |         img += b'\xFF' * (self.build_config.block_size - len(img)) | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         return img | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-30 18:37:15 +02:00
										 |  |  | class SpiffsFS(object): | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |     def __init__(self, img_size, build_config):  # type: (int, SpiffsBuildConfig) -> None | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         if img_size % build_config.block_size != 0: | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |             raise RuntimeError('image size should be a multiple of block size') | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         self.img_size = img_size | 
					
						
							|  |  |  |         self.build_config = build_config | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |         self.blocks = list()  # type: typing.List[SpiffsBlock] | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         self.blocks_lim = self.img_size // self.build_config.block_size | 
					
						
							|  |  |  |         self.remaining_blocks = self.blocks_lim | 
					
						
							|  |  |  |         self.cur_obj_id = 1  # starting object id | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |     def _create_block(self):  # type: () -> SpiffsBlock | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         if self.is_full(): | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |             raise SpiffsFullError('the image size has been exceeded') | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-14 18:43:26 +02:00
										 |  |  |         block = SpiffsBlock(len(self.blocks), self.build_config) | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         self.blocks.append(block) | 
					
						
							|  |  |  |         self.remaining_blocks -= 1 | 
					
						
							|  |  |  |         return block | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |     def is_full(self):  # type: () -> bool | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         return self.remaining_blocks <= 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |     def create_file(self, img_path, file_path):  # type: (str, str) -> None | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         if len(img_path) > self.build_config.obj_name_len: | 
					
						
							|  |  |  |             raise RuntimeError("object name '%s' too long" % img_path) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         name = img_path | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |         with open(file_path, 'rb') as obj: | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |             contents = obj.read() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         stream = io.BytesIO(contents) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             block = self.blocks[-1] | 
					
						
							|  |  |  |             block.begin_obj(self.cur_obj_id, len(contents), name) | 
					
						
							|  |  |  |         except (IndexError, SpiffsFullError): | 
					
						
							|  |  |  |             block = self._create_block() | 
					
						
							|  |  |  |             block.begin_obj(self.cur_obj_id, len(contents), name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         contents_chunk = stream.read(self.build_config.OBJ_DATA_PAGE_CONTENT_LEN) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         while contents_chunk: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 block = self.blocks[-1] | 
					
						
							|  |  |  |                 try: | 
					
						
							|  |  |  |                     # This can fail because either (1) all the pages in block have been | 
					
						
							|  |  |  |                     # used or (2) object index has been exhausted. | 
					
						
							|  |  |  |                     block.update_obj(contents_chunk) | 
					
						
							|  |  |  |                 except SpiffsFullError: | 
					
						
							|  |  |  |                     # If its (1), use the outer exception handler | 
					
						
							|  |  |  |                     if block.is_full(): | 
					
						
							|  |  |  |                         raise SpiffsFullError | 
					
						
							|  |  |  |                     # If its (2), write another object index page | 
					
						
							|  |  |  |                     block.begin_obj(self.cur_obj_id, len(contents), name, | 
					
						
							|  |  |  |                                     obj_index_span_ix=block.cur_obj_index_span_ix, | 
					
						
							|  |  |  |                                     obj_data_span_ix=block.cur_obj_data_span_ix) | 
					
						
							|  |  |  |                     continue | 
					
						
							|  |  |  |             except (IndexError, SpiffsFullError): | 
					
						
							|  |  |  |                 # All pages in the block have been exhausted. Create a new block, copying | 
					
						
							|  |  |  |                 # the previous state of the block to a new one for the continuation of the | 
					
						
							|  |  |  |                 # current object | 
					
						
							|  |  |  |                 prev_block = block | 
					
						
							|  |  |  |                 block = self._create_block() | 
					
						
							|  |  |  |                 block.cur_obj_id = prev_block.cur_obj_id | 
					
						
							|  |  |  |                 block.cur_obj_idx_page = prev_block.cur_obj_idx_page | 
					
						
							|  |  |  |                 block.cur_obj_data_span_ix = prev_block.cur_obj_data_span_ix | 
					
						
							|  |  |  |                 block.cur_obj_index_span_ix = prev_block.cur_obj_index_span_ix | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             contents_chunk = stream.read(self.build_config.OBJ_DATA_PAGE_CONTENT_LEN) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         block.end_obj() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.cur_obj_id += 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  |     def to_binary(self):  # type: () -> bytes | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |         img = b'' | 
					
						
							| 
									
										
										
										
											2021-03-22 21:11:36 +01:00
										 |  |  |         all_blocks = [] | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         for block in self.blocks: | 
					
						
							| 
									
										
										
										
											2021-03-22 21:11:36 +01:00
										 |  |  |             all_blocks.append(block.to_binary(self.blocks_lim)) | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         bix = len(self.blocks) | 
					
						
							|  |  |  |         if self.build_config.use_magic: | 
					
						
							|  |  |  |             # Create empty blocks with magic numbers | 
					
						
							|  |  |  |             while self.remaining_blocks > 0: | 
					
						
							| 
									
										
										
										
											2021-04-14 18:43:26 +02:00
										 |  |  |                 block = SpiffsBlock(bix, self.build_config) | 
					
						
							| 
									
										
										
										
											2021-03-22 21:11:36 +01:00
										 |  |  |                 all_blocks.append(block.to_binary(self.blocks_lim)) | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |                 self.remaining_blocks -= 1 | 
					
						
							|  |  |  |                 bix += 1 | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             # Just fill remaining spaces FF's | 
					
						
							| 
									
										
										
										
											2021-04-30 18:37:15 +02:00
										 |  |  |             all_blocks.append(b'\xFF' * (self.img_size - len(all_blocks) * self.build_config.block_size)) | 
					
						
							| 
									
										
										
										
											2021-03-22 21:11:36 +01:00
										 |  |  |         img += b''.join([blk for blk in all_blocks]) | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         return img | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-14 18:42:56 +02:00
										 |  |  | class CustomHelpFormatter(argparse.HelpFormatter): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     Similar to argparse.ArgumentDefaultsHelpFormatter, except it | 
					
						
							|  |  |  |     doesn't add the default value if "(default:" is already present. | 
					
						
							|  |  |  |     This helps in the case of options with action="store_false", like | 
					
						
							|  |  |  |     --no-magic or --no-magic-len. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     def _get_help_string(self, action):  # type: (argparse.Action) -> str | 
					
						
							|  |  |  |         if action.help is None: | 
					
						
							|  |  |  |             return '' | 
					
						
							|  |  |  |         if '%(default)' not in action.help and '(default:' not in action.help: | 
					
						
							|  |  |  |             if action.default is not argparse.SUPPRESS: | 
					
						
							|  |  |  |                 defaulting_nargs = [argparse.OPTIONAL, argparse.ZERO_OR_MORE] | 
					
						
							|  |  |  |                 if action.option_strings or action.nargs in defaulting_nargs: | 
					
						
							|  |  |  |                     return action.help + ' (default: %(default)s)' | 
					
						
							|  |  |  |         return action.help | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 22:06:01 +01:00
										 |  |  | def main():  # type: () -> None | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     parser = argparse.ArgumentParser(description='SPIFFS Image Generator', | 
					
						
							| 
									
										
										
										
											2021-04-14 18:42:56 +02:00
										 |  |  |                                      formatter_class=CustomHelpFormatter) | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     parser.add_argument('image_size', | 
					
						
							|  |  |  |                         help='Size of the created image') | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     parser.add_argument('base_dir', | 
					
						
							|  |  |  |                         help='Path to directory from which the image will be created') | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     parser.add_argument('output_file', | 
					
						
							|  |  |  |                         help='Created image output file path') | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     parser.add_argument('--page-size', | 
					
						
							|  |  |  |                         help='Logical page size. Set to value same as CONFIG_SPIFFS_PAGE_SIZE.', | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |                         type=int, | 
					
						
							|  |  |  |                         default=256) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     parser.add_argument('--block-size', | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |                         help="Logical block size. Set to the same value as the flash chip's sector size (g_rom_flashchip.sector_size).", | 
					
						
							|  |  |  |                         type=int, | 
					
						
							|  |  |  |                         default=4096) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     parser.add_argument('--obj-name-len', | 
					
						
							|  |  |  |                         help='File full path maximum length. Set to value same as CONFIG_SPIFFS_OBJ_NAME_LEN.', | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |                         type=int, | 
					
						
							|  |  |  |                         default=32) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     parser.add_argument('--meta-len', | 
					
						
							|  |  |  |                         help='File metadata length. Set to value same as CONFIG_SPIFFS_META_LENGTH.', | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |                         type=int, | 
					
						
							|  |  |  |                         default=4) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     parser.add_argument('--use-magic', | 
					
						
							| 
									
										
										
										
											2021-03-22 21:05:22 +01:00
										 |  |  |                         dest='use_magic', | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |                         help='Use magic number to create an identifiable SPIFFS image. Specify if CONFIG_SPIFFS_USE_MAGIC.', | 
					
						
							| 
									
										
										
										
											2021-03-22 21:05:22 +01:00
										 |  |  |                         action='store_true') | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-22 21:05:22 +01:00
										 |  |  |     parser.add_argument('--no-magic', | 
					
						
							|  |  |  |                         dest='use_magic', | 
					
						
							| 
									
										
										
										
											2021-04-14 18:42:56 +02:00
										 |  |  |                         help='Inverse of --use-magic (default: --use-magic is enabled)', | 
					
						
							| 
									
										
										
										
											2021-03-22 21:05:22 +01:00
										 |  |  |                         action='store_false') | 
					
						
							| 
									
										
										
										
											2019-07-14 16:45:35 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     parser.add_argument('--use-magic-len', | 
					
						
							| 
									
										
										
										
											2021-03-22 21:05:22 +01:00
										 |  |  |                         dest='use_magic_len', | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |                         help='Use position in memory to create different magic numbers for each block. Specify if CONFIG_SPIFFS_USE_MAGIC_LENGTH.', | 
					
						
							| 
									
										
										
										
											2021-03-22 21:05:22 +01:00
										 |  |  |                         action='store_true') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parser.add_argument('--no-magic-len', | 
					
						
							|  |  |  |                         dest='use_magic_len', | 
					
						
							| 
									
										
										
										
											2021-04-14 18:42:56 +02:00
										 |  |  |                         help='Inverse of --use-magic-len (default: --use-magic-len is enabled)', | 
					
						
							| 
									
										
										
										
											2021-03-22 21:05:22 +01:00
										 |  |  |                         action='store_false') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parser.add_argument('--follow-symlinks', | 
					
						
							|  |  |  |                         help='Take into account symbolic links during partition image creation.', | 
					
						
							|  |  |  |                         action='store_true') | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     parser.add_argument('--big-endian', | 
					
						
							|  |  |  |                         help='Specify if the target architecture is big-endian. If not specified, little-endian is assumed.', | 
					
						
							| 
									
										
										
										
											2021-03-22 21:05:22 +01:00
										 |  |  |                         action='store_true') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parser.add_argument('--aligned-obj-ix-tables', | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |                         action='store_true', | 
					
						
							| 
									
										
										
										
											2021-03-22 21:05:22 +01:00
										 |  |  |                         help='Use aligned object index tables. Specify if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES is set.') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     parser.set_defaults(use_magic=True, use_magic_len=True) | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     args = parser.parse_args() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if not os.path.exists(args.base_dir): | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |         raise RuntimeError('given base directory %s does not exist' % args.base_dir) | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |     with open(args.output_file, 'wb') as image_file: | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |         image_size = int(args.image_size, 0) | 
					
						
							|  |  |  |         spiffs_build_default = SpiffsBuildConfig(args.page_size, SPIFFS_PAGE_IX_LEN, | 
					
						
							|  |  |  |                                                  args.block_size, SPIFFS_BLOCK_IX_LEN, args.meta_len, | 
					
						
							|  |  |  |                                                  args.obj_name_len, SPIFFS_OBJ_ID_LEN, SPIFFS_SPAN_IX_LEN, | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |                                                  True, True, 'big' if args.big_endian else 'little', | 
					
						
							| 
									
										
										
										
											2021-03-22 21:05:22 +01:00
										 |  |  |                                                  args.use_magic, args.use_magic_len, args.aligned_obj_ix_tables) | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         spiffs = SpiffsFS(image_size, spiffs_build_default) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-14 16:45:35 +02:00
										 |  |  |         for root, dirs, files in os.walk(args.base_dir, followlinks=args.follow_symlinks): | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |             for f in files: | 
					
						
							|  |  |  |                 full_path = os.path.join(root, f) | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  |                 spiffs.create_file('/' + os.path.relpath(full_path, args.base_dir).replace('\\', '/'), full_path) | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         image = spiffs.to_binary() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         image_file.write(image) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-26 10:49:01 +08:00
										 |  |  | if __name__ == '__main__': | 
					
						
							| 
									
										
										
										
											2019-01-09 23:36:44 +08:00
										 |  |  |     main() |