@@ -130,42 +130,83 @@ def fs_printfile(self, src, chunk_size=256):
130130 except TransportExecError as e :
131131 raise _convert_filesystem_error (e , src ) from None
132132
133- def fs_readfile (self , src , chunk_size = 256 , progress_callback = None ):
133+ def fs_readfile (self , src , chunk_size = 256 , progress_callback = None , verify_hash = False ):
134134 if progress_callback :
135135 src_size = self .fs_stat (src ).st_size
136136
137137 contents = bytearray ()
138138
139139 try :
140- self .exec ("f=open('%s','rb')\n r=f.read" % src )
140+ if verify_hash :
141+ # Initialize hash on device along with file read
142+ self .exec (
143+ "import hashlib\n h=hashlib.sha256()\n f=open('%s','rb')\n r=f.read\n u=h.update"
144+ % src
145+ )
146+ else :
147+ self .exec ("f=open('%s','rb')\n r=f.read" % src )
148+
141149 while True :
142150 chunk = self .eval ("r({})" .format (chunk_size ))
143151 if not chunk :
144152 break
153+ if verify_hash :
154+ # Update hash with chunk
155+ self .exec ("u(" + repr (chunk ) + ")" )
145156 contents .extend (chunk )
146157 if progress_callback :
147158 progress_callback (len (contents ), src_size )
148159 self .exec ("f.close()" )
160+
161+ if verify_hash :
162+ # Get final hash from device
163+ remote_hash = self .eval ("h.digest()" )
164+ # Calculate local hash
165+ local_hash = hashlib .sha256 (contents ).digest ()
166+ if remote_hash != local_hash :
167+ raise TransportError ("file transfer verification failed for '%s'" % src )
149168 except TransportExecError as e :
150169 raise _convert_filesystem_error (e , src ) from None
151170
152171 return contents
153172
154- def fs_writefile (self , dest , data , chunk_size = 256 , progress_callback = None ):
173+ def fs_writefile (self , dest , data , chunk_size = 256 , progress_callback = None , verify_hash = False ):
155174 if progress_callback :
156175 src_size = len (data )
157176 written = 0
158177
159178 try :
160- self .exec ("f=open('%s','wb')\n w=f.write" % dest )
161- while data :
162- chunk = data [:chunk_size ]
163- self .exec ("w(" + repr (chunk ) + ")" )
164- data = data [len (chunk ) :]
179+ if verify_hash :
180+ # Calculate source hash
181+ source_hash = hashlib .sha256 (data ).digest ()
182+ # Initialize hash on device along with file write
183+ self .exec (
184+ "import hashlib\n h=hashlib.sha256()\n f=open('%s','wb')\n w=f.write\n u=h.update"
185+ % dest
186+ )
187+ else :
188+ self .exec ("f=open('%s','wb')\n w=f.write" % dest )
189+
190+ data_remaining = data
191+ while data_remaining :
192+ chunk = data_remaining [:chunk_size ]
193+ if verify_hash :
194+ # Write chunk and update hash in one call
195+ self .exec ("d=" + repr (chunk ) + "\n w(d)\n u(d)" )
196+ else :
197+ self .exec ("w(" + repr (chunk ) + ")" )
198+ data_remaining = data_remaining [len (chunk ) :]
165199 if progress_callback :
166200 written += len (chunk )
167201 progress_callback (written , src_size )
202+
168203 self .exec ("f.close()" )
204+
205+ if verify_hash :
206+ # Get final hash from device
207+ remote_hash = self .eval ("h.digest()" )
208+ if remote_hash != source_hash :
209+ raise TransportError ("file transfer verification failed for '%s'" % dest )
169210 except TransportExecError as e :
170211 raise _convert_filesystem_error (e , dest ) from None
171212
0 commit comments