@@ -56,17 +56,6 @@ async def download(url):
5656 return await resp .read () if resp .status == 200 else resp .status
5757
5858
59- def extract_fs (pak : PAK ):
60- """Return the fs.bin, app.bin or rootfs.bin file as bytes."""
61- sections = {s .name : s for s in pak .sections if s .name in FS_SECTIONS }
62- if len (sections ) == 2 :
63- return pak .extract_section (sections ["app" ])
64- elif len (sections ) == 1 :
65- return pak .extract_section (sections .popitem ()[1 ])
66- else :
67- return "No section found"
68-
69-
7059def extract_paks (zip ) -> list [tuple [str , PAK ]]:
7160 """Return a list of tuples, one for each PAK file found in the ZIP.
7261
@@ -94,12 +83,12 @@ def get_info_from_files(files):
9483 return info
9584
9685
97- def get_files_from_squashfs (binbytes ):
86+ def get_files_from_squashfs (fd , offset = 0 , closefd = True ):
9887 # Firmwares using squashfs have either one or two file system
9988 # sections. When there is only one, the app directory is located at
10089 # /mnt/app. Otherwise it's the same as with cramfs and ubifs.
10190 files = dict .fromkeys (FILES )
102- with SquashFsImage . from_bytes ( binbytes ) as image :
91+ with SquashFsImage ( fd , offset , closefd ) as image :
10392 for name in files :
10493 path2 = posixpath .join ("/mnt/app" , name )
10594 if (file := (image .select (name ) or image .select (path2 ))) is not None :
@@ -120,22 +109,22 @@ def get_files_from_ubifs(binbytes):
120109 return files
121110
122111
123- def get_files_from_ubi (binbytes ):
124- fsbytes = get_fs_from_ubi (binbytes )
112+ def get_files_from_ubi (fd , size , offset = 0 ):
113+ fsbytes = get_fs_from_ubi (fd , size , offset )
125114 fs = FileSystem .from_magic (fsbytes [:4 ])
126115 if fs == FileSystem .UBIFS :
127116 return get_files_from_ubifs (fsbytes )
128117 elif fs == FileSystem .SQUASHFS :
129- return get_files_from_squashfs (fsbytes )
118+ return get_files_from_squashfs (io . BytesIO ( fsbytes ) )
130119 raise Exception ("Unknown file system in UBI" )
131120
132121
133- def get_files_from_cramfs (binbytes ):
122+ def get_files_from_cramfs (fd , offset = 0 , closefd = True ):
134123 # For now all firmwares using cramfs have two file system sections.
135124 # The interesting files are in the root directory of the "app" one.
136125 # Using select() with a relative path is enough.
137126 files = dict .fromkeys (FILES )
138- with Cramfs .from_bytes ( binbytes ) as cramfs :
127+ with Cramfs .from_fd ( fd , offset , closefd ) as cramfs :
139128 for name in files :
140129 if (file := cramfs .select (name )) is not None :
141130 files [name ] = file .read_bytes ()
@@ -152,17 +141,18 @@ def is_local_file(string):
152141
153142async def get_info_from_pak (pak : PAK ):
154143 ha = await asyncio .to_thread (sha256_pak , pak )
155- binbytes = await asyncio .to_thread (extract_fs , pak )
156- if isinstance (binbytes , str ):
157- return {"error" : binbytes , "sha256" : ha }
158- func = {
159- FileSystem .CRAMFS : get_files_from_cramfs ,
160- FileSystem .UBI : get_files_from_ubi ,
161- FileSystem .SQUASHFS : get_files_from_squashfs ,
162- }.get (FileSystem .from_magic (binbytes [:4 ]))
163- if func is None :
144+ fs_sections = [s for s in pak .sections if s .name in FS_SECTIONS ]
145+ app = fs_sections [- 1 ]
146+ pak ._fd .seek (app .start )
147+ fs = FileSystem .from_magic (pak ._fd .read (4 ))
148+ if fs == FileSystem .CRAMFS :
149+ files = await asyncio .to_thread (get_files_from_cramfs , pak ._fd , app .start , False )
150+ elif fs == FileSystem .UBI :
151+ files = await asyncio .to_thread (get_files_from_ubi , pak ._fd , app .len , app .start )
152+ elif fs == FileSystem .SQUASHFS :
153+ files = await asyncio .to_thread (get_files_from_squashfs , pak ._fd , app .start , False )
154+ else :
164155 return {"error" : "Unrecognized image type" , "sha256" : ha }
165- files = await asyncio .to_thread (func , binbytes )
166156 info = get_info_from_files (files )
167157 return {** info , "sha256" : ha }
168158
0 commit comments