88from littlefs import LittleFS , __version__
99from littlefs .errors import LittleFSError
1010from littlefs .repl import LittleFSRepl
11- from littlefs .context import UserContextFile
11+ from littlefs .context import UserContextFile , UserContext
1212
1313# Dictionary mapping suffixes to their size in bytes
1414_suffix_map = {
1818}
1919
2020
21- def _fs_from_args (args : argparse .Namespace , mount = True ) -> LittleFS :
21+ def _fs_from_args (args : argparse .Namespace , block_count = None , mount = True , context : UserContext = None ) -> LittleFS :
22+ block_count = block_count if block_count is not None else getattr (args , "block_count" , 0 )
2223 return LittleFS (
24+ context = context ,
2325 block_size = args .block_size ,
24- block_count = getattr ( args , " block_count" , 0 ) ,
26+ block_count = block_count ,
2527 name_max = args .name_max ,
2628 mount = mount ,
2729 )
@@ -105,11 +107,7 @@ def create(parser: argparse.ArgumentParser, args: argparse.Namespace) -> int:
105107 if args .compact :
106108 if args .verbose :
107109 print (f"Compacting... { fs .used_block_count } / { args .block_count } " )
108- compact_fs = LittleFS (
109- block_size = args .block_size ,
110- block_count = fs .used_block_count ,
111- name_max = args .name_max ,
112- )
110+ compact_fs = _fs_from_args (args , block_count = fs .used_block_count )
113111 for root , dirs , files in fs .walk ("/" ):
114112 if not root .endswith ("/" ):
115113 root += "/"
@@ -131,21 +129,37 @@ def create(parser: argparse.ArgumentParser, args: argparse.Namespace) -> int:
131129 return 0
132130
133131
134- def _list (parser : argparse .ArgumentParser , args : argparse .Namespace ) -> int :
135- """List LittleFS image contents."""
136- fs = _fs_from_args (args , mount = False )
137- fs .context .buffer = bytearray (args .source .read_bytes ())
132+ def _mount_from_context (parser : argparse .ArgumentParser , args : argparse .Namespace , context : UserContext ) -> LittleFS :
133+ # Block count is 0 because we don't know the size of the real image yet, the source file may be compacted (with the create --compact option).
134+ fs = _fs_from_args (args , block_count = 0 , mount = False , context = context )
138135 fs .mount ()
139136
140137 if args .verbose :
141- fs_size = len (fs .context .buffer )
138+ input_image_size = context .in_size
139+ actual_image_size = fs .block_count * args .block_size
142140 print ("LittleFS Configuration:" )
143141 print (f" Block Size: { args .block_size :9d} / 0x{ args .block_size :X} " )
144- print (f" Image Size: { fs_size :9d} / 0x{ fs_size :X} " )
142+ if input_image_size != actual_image_size :
143+ print (f" Image Size: { actual_image_size :9d} / 0x{ actual_image_size :X} " )
144+ print (f" Input Image Size (compacted): { input_image_size :9d} / 0x{ input_image_size :X} " )
145+ else :
146+ print (f" Image Size: { input_image_size :9d} / 0x{ input_image_size :X} " )
145147 print (f" Block Count: { fs .block_count :9d} " )
146148 print (f" Name Max: { args .name_max :9d} " )
147149 print (f" Image: { args .source } " )
148150
151+ return fs
152+
153+
154+ def _list (parser : argparse .ArgumentParser , args : argparse .Namespace ) -> int :
155+ """List LittleFS image contents."""
156+ source : Path = args .source
157+ if not source .is_file ():
158+ parser .error (f"Source image '{ source } ' does not exist." )
159+ context = UserContext (buffer = bytearray (source .read_bytes ()))
160+
161+ fs = _mount_from_context (parser , args , context )
162+
149163 for root , dirs , files in fs .walk ("/" ):
150164 if not root .endswith ("/" ):
151165 root += "/"
@@ -158,18 +172,12 @@ def _list(parser: argparse.ArgumentParser, args: argparse.Namespace) -> int:
158172
159173def extract (parser : argparse .ArgumentParser , args : argparse .Namespace ) -> int :
160174 """Extract LittleFS image contents to a directory."""
161- fs = _fs_from_args (args , mount = False )
162- fs .context .buffer = bytearray (args .source .read_bytes ())
163- fs .mount ()
175+ source : Path = args .source
176+ if not source .is_file ():
177+ parser .error (f"Source image '{ source } ' does not exist." )
178+ context = UserContext (buffer = bytearray (source .read_bytes ()))
164179
165- if args .verbose :
166- fs_size = len (fs .context .buffer )
167- print ("LittleFS Configuration:" )
168- print (f" Block Size: { args .block_size :9d} / 0x{ args .block_size :X} " )
169- print (f" Image Size: { fs_size :9d} / 0x{ fs_size :X} " )
170- print (f" Block Count: { fs .block_count :9d} " )
171- print (f" Name Max: { args .name_max :9d} " )
172- print (f" Image: { args .source } " )
180+ fs = _mount_from_context (parser , args , context )
173181
174182 root_dest = args .destination .absolute ()
175183 if not root_dest .exists ():
@@ -202,36 +210,19 @@ def extract(parser: argparse.ArgumentParser, args: argparse.Namespace) -> int:
202210
203211def repl (parser : argparse .ArgumentParser , args : argparse .Namespace ) -> int :
204212 """Inspect an existing LittleFS image through an interactive shell."""
205-
206213 source : Path = args .source
207214 if not source .is_file ():
208215 parser .error (f"Source image '{ source } ' does not exist." )
216+ context = UserContextFile (str (source )) # In repl we want context to be the file itself, so commands will change it
209217
210- image_size = source .stat ().st_size
211- if not image_size or image_size % args .block_size :
212- parser .error (
213- f"Image size ({ image_size } bytes) is not a multiple of the supplied block size ({ args .block_size } )."
214- )
215-
216- block_count = image_size // args .block_size
217- if block_count == 0 :
218- parser .error ("Image is smaller than a single block; cannot mount." )
219-
220- context = UserContextFile (str (source ))
221- fs = LittleFS (
222- context = context ,
223- block_size = args .block_size ,
224- block_count = block_count ,
225- name_max = args .name_max ,
226- mount = False ,
227- )
228-
229- shell = LittleFSRepl (fs )
230218 try :
231219 try :
232- shell . do_mount ( )
220+ fs = _mount_from_context ( parser , args , context )
233221 except LittleFSError as exc :
234222 parser .error (f"Failed to mount '{ source } ': { exc } " )
223+
224+ shell = LittleFSRepl (fs )
225+
235226 shell .cmdloop ()
236227 finally :
237228 if shell ._mounted :
@@ -367,6 +358,7 @@ def add_command(handler, name="", help=""):
367358
368359 return parser
369360
361+
370362# Getting argv optionally from the caller to enable call from python (generally for testing, but could be used for other purposes)
371363def main (argv = None ):
372364 if argv is None :
@@ -379,4 +371,3 @@ def main(argv=None):
379371
380372if __name__ == "__main__" :
381373 sys .exit (main ())
382-
0 commit comments