@@ -73,12 +73,47 @@ def chromeos_offset(self):
73
73
74
74
return offset
75
75
76
- def find_file (self , filename , path_to_file = ( "opt" , "google" , "chrome" , "WidevineCdm" , "_platform_specific" , "cros_arm" ) ):
76
+ def _find_file_naive (self , filename ):
77
77
"""
78
- Finds a file at a given path, or search upwards if not found.
78
+ Finds a file by basically searching for the filename as bytes in the bytestream.
79
+ Searches through the whole image only once, making it fast, but may be unreliable at times.
80
+
79
81
Returns a directory entry.
82
+ """
83
+
84
+ bin_filename = filename .encode ('ascii' )
85
+ chunksize = 4 * 1024 ** 2
86
+ chunk1 = self .read_stream (chunksize )
87
+ while True :
88
+ chunk2 = self .read_stream (chunksize )
89
+ if not chunk2 :
90
+ raise ChromeOSError ('File {filename} not found in the ChromeOS image' .format (filename = filename ))
91
+
92
+ chunk = chunk1 + chunk2
93
+ if bin_filename in chunk :
94
+ i_index_pos = chunk .index (bin_filename ) - 8
95
+ file_entry = self .dir_entry (chunk [i_index_pos :i_index_pos + len (filename ) + 8 ])
96
+ if file_entry ['inode' ] < self .sb_dict ['s_inodes_count' ] and file_entry ['name_len' ] == len (filename ):
97
+ break
98
+
99
+ log (0 , 'Found filename, but checks did not pass:' )
100
+ log (0 , 'inode number: {inode} < {count}, name_len: {name_len} == {len_filename}' .format (inode = file_entry ['inode' ],
101
+ count = self .sb_dict ['s_inodes_count' ],
102
+ name_len = file_entry ['name_len' ],
103
+ len_filename = len (filename )))
104
+
105
+ chunk1 = chunk2
106
+
107
+ return file_entry
108
+
109
+ def _find_file_properly (self , filename , path_to_file = ("opt" , "google" , "chrome" , "WidevineCdm" , "_platform_specific" , "cros_arm" )):
110
+ """
111
+ Finds a file at a given path, or searches upwards if not found.
80
112
81
113
Assumes the path is roughly correct, else it might take long.
114
+ It also might take long for ZIP files, since it might have to jump back and forth while traversing down the given path.
115
+
116
+ Returns a directory entry.
82
117
"""
83
118
root_inode_pos = self ._calc_inode_pos (2 )
84
119
root_inode_dict = self ._inode_table (root_inode_pos )
@@ -107,10 +142,9 @@ def find_file(self, filename, path_to_file=("opt", "google", "chrome", "Widevine
107
142
def _find_file_in_dir (self , filename , dentries ):
108
143
"""
109
144
Finds a file in a directory or recursively in its subdirectories.
110
- Returns a directory entry.
111
-
112
145
Can take long for deep searches.
113
- Returns the first result.
146
+
147
+ Returns the first result as a directory entry.
114
148
"""
115
149
try :
116
150
return dentries [filename ]
@@ -128,6 +162,23 @@ def _find_file_in_dir(self, filename, dentries):
128
162
129
163
return None
130
164
165
+ def find_file (self , filename , path_to_file = None ):
166
+ """
167
+ Finds a file. Supplying a path could take longer for ZIP files!
168
+
169
+ Returns a directory entry.
170
+ """
171
+
172
+ if path_to_file :
173
+ return self ._find_file_properly (filename , path_to_file )
174
+
175
+ try :
176
+ return self ._find_file_naive (filename )
177
+ except ChromeOSError :
178
+ if self .progress :
179
+ self .progress .update (5 , localize (30071 )) # Could not find file, doing proper search
180
+ return self ._find_file_properly (filename )
181
+
131
182
def _calc_inode_pos (self , inode_num ):
132
183
"""Calculate the byte position of an inode from its index"""
133
184
blk_group_num = (inode_num - 1 ) // self .sb_dict ['s_inodes_per_group' ]
@@ -223,10 +274,10 @@ def dir_entry(chunk):
223
274
dir_names = ('inode' , 'rec_len' , 'name_len' , 'file_type' , 'name' )
224
275
dir_fmt = '<IHBB' + str (len (chunk ) - 8 ) + 's'
225
276
226
- dir_dict = dict (list (zip (dir_names , unpack (dir_fmt , chunk ))))
227
- dir_dict ["name" ] = dir_dict ["name" ][:dir_dict ["name_len" ]]
277
+ entry = dict (list (zip (dir_names , unpack (dir_fmt , chunk ))))
278
+ entry ["name" ] = entry ["name" ][:entry ["name_len" ]]
228
279
229
- return dir_dict
280
+ return entry
230
281
231
282
def dir_entries (self , dir_file ):
232
283
"""Returns all directory entries of a directory file as dict of dicts with name as key"""
@@ -371,11 +422,11 @@ def extract_file(self, filename, extract_path):
371
422
try :
372
423
if self .progress :
373
424
self .progress .update (5 , localize (30061 ))
374
- dir_dict = self .find_file (filename )
425
+ file_entry = self .find_file (filename )
375
426
376
427
if self .progress :
377
428
self .progress .update (32 , localize (30062 ))
378
- inode_pos = self ._calc_inode_pos (dir_dict ["inode" ])
429
+ inode_pos = self ._calc_inode_pos (file_entry ["inode" ])
379
430
inode_dict = self ._inode_table (inode_pos )
380
431
381
432
self .write_file (inode_dict , os .path .join (extract_path , filename ))
0 commit comments