Fixed "database disk image is malformed" error when sending a large number of books to idevices.

Fixed _afc_file_read to continuing reading bytes until all bytes are
read up to the requested file length; the first read only returns the
first 0x400000 bytes, so any files larger than that were not being fully
read. The missing bytes were initialised to null in the target file,
resulting in a corrupt file (the local copy of the Marvin sqlite
database).
This commit is contained in:
Polyfun 2014-11-13 08:19:30 +00:00
parent 77ebeb6eea
commit 2792dbc37c

View File

@ -284,22 +284,22 @@ class libiMobileDevice():
if handle is not None: if handle is not None:
file_stats = self._afc_get_file_info(src) file_stats = self._afc_get_file_info(src)
file_size = int(file_stats['st_size']) file_size = int(file_stats['st_size'])
self._log("file_size: {:,} bytes".format(file_size)) self._log("file {0} file_size: {1:,} bytes".format(repr(src), file_size))
if file_size > BUFFER_SIZE: if file_size > BUFFER_SIZE:
bytes_remaining = file_size bytes_remaining = file_size
while bytes_remaining: while bytes_remaining:
if bytes_remaining > BUFFER_SIZE: if bytes_remaining > BUFFER_SIZE:
self._log("copying {:,} byte chunk".format(BUFFER_SIZE)) self._log("copying file {0} to {1}, {2:,} byte chunk".format(repr(src), dst.name, BUFFER_SIZE))
data = self._afc_file_read(handle, BUFFER_SIZE, mode) data = self._afc_file_read(handle, BUFFER_SIZE, mode)
dst.write(data) dst.write(data)
bytes_remaining -= BUFFER_SIZE bytes_remaining -= BUFFER_SIZE
else: else:
self._log("copying final {:,} bytes".format(bytes_remaining)) self._log("copying file {0} to {1}, final {2:,} bytes".format(repr(src), dst.name, bytes_remaining))
data = self._afc_file_read(handle, bytes_remaining, mode) data = self._afc_file_read(handle, bytes_remaining, mode)
dst.write(data) dst.write(data)
bytes_remaining = 0 bytes_remaining = 0
else: else:
self._log("copying {:,} bytes".format(file_size)) self._log("copying file {0} to {1}, {2:,} bytes".format(repr(src), dst.name, file_size))
data = self._afc_file_read(handle, file_size, mode) data = self._afc_file_read(handle, file_size, mode)
dst.write(data) dst.write(data)
@ -308,6 +308,7 @@ class libiMobileDevice():
# Update timestamps to match # Update timestamps to match
file_stats = self._afc_get_file_info(src) file_stats = self._afc_get_file_info(src)
self._log("copied file {0} ({1:,} bytes) to file '{2}' ({3:,} bytes)".format(repr(src), file_size, dst.name, os.path.getsize(dst.name)))
os.utime(dst.name, (file_stats['st_mtime'], file_stats['st_mtime'])) os.utime(dst.name, (file_stats['st_mtime'], file_stats['st_mtime']))
else: else:
@ -903,22 +904,28 @@ class libiMobileDevice():
bytes_read = c_uint(0) bytes_read = c_uint(0)
bytes_remaining = size
if 'b' in mode: if 'b' in mode:
data = bytearray(size) data = bytearray(size)
datatype = c_char * size datatype = c_char * size
error = self.lib.afc_file_read(byref(self.afc), while bytes_remaining > 0:
handle, error = self.lib.afc_file_read(byref(self.afc),
byref(datatype.from_buffer(data)), handle,
size, byref(datatype.from_buffer(data), size - bytes_remaining),
byref(bytes_read)) & 0xFFFF bytes_remaining,
if error: byref(bytes_read)) & 0xFFFF
self._log_error(" ERROR: {0} handle:{1}".format(self._afc_error(error), handle)) if error:
self._log_error(" ERROR: {0} handle:{1}".format(self._afc_error(error), handle))
bytes_remaining -= bytes_read.value
bytes_read = c_uint(0)
return data return data
else: else:
data = create_string_buffer(size) data = create_string_buffer(size)
error = self.lib.afc_file_read(byref(self.afc), handle, byref(data), size, byref(bytes_read)) while bytes_remaining > 0:
if error: error = self.lib.afc_file_read(byref(self.afc), handle, byref(data, size - bytes_remaining), bytes_remaining, byref(bytes_read))
self._log_error(" ERROR: {0} handle:{1}".format(self._afc_error(error), handle)) if error:
self._log_error(" ERROR: {0} handle:{1}".format(self._afc_error(error), handle))
bytes_remaining -= bytes_read.value
return data.value return data.value
def _afc_file_write(self, handle, content, mode='w'): def _afc_file_write(self, handle, content, mode='w'):
@ -1914,3 +1921,4 @@ class libiMobileDevice():
def __null(self, *args, **kwargs): def __null(self, *args, **kwargs):
pass pass