Fix chunking in libimobiledevice and remove obsolete logging code

This commit is contained in:
Kovid Goyal 2013-09-02 08:43:53 +05:30
parent 54a56df2f2
commit 55b40e7e65

View file

@ -182,9 +182,8 @@ class libiMobileDevice():
# iDevice udid string
UDID_SIZE = 40
def __init__(self, log=debug_print, verbose=False):
self.log = log
self.verbose = verbose
def __init__(self, **kwargs):
self.verbose = kwargs.get('verbose', False)
self._log_location()
self.afc = None
@ -218,7 +217,7 @@ def connect_idevice(self):
self.device_connected = True
except libiMobileDeviceException as e:
self.log(e.value)
self._log(e.value)
self.disconnect_idevice()
return self.device_connected
@ -240,12 +239,10 @@ def copy_to_idevice(self, src, dst):
handle = self._afc_file_open(str(dst), mode=mode)
if handle is not None:
success = self._afc_file_write(handle, content, mode=mode)
if self.verbose:
self.log(" success: %s" % success)
self._log(" success: %s" % success)
self._afc_file_close(handle)
else:
if self.verbose:
self.log(" could not create copy")
self._log(" could not create copy")
def copy_from_idevice(self, src, dst):
'''
@ -255,13 +252,42 @@ def copy_from_idevice(self, src, dst):
dst: file object on local filesystem
'''
self._log_location("src='%s', dst='%s'" % (src, dst.name))
data = self.read(src, mode='rb')
dst.write(data)
dst.close()
BUFFER_SIZE = 10 * 1024 * 1024
data = None
mode = 'rb'
handle = self._afc_file_open(src, mode)
if handle is not None:
file_stats = self._afc_get_file_info(src)
file_size = int(file_stats['st_size'])
self._log("file_size: {:,} bytes".format(file_size))
if file_size > BUFFER_SIZE:
bytes_remaining = file_size
while bytes_remaining:
if bytes_remaining > BUFFER_SIZE:
self._log("copying {:,} byte chunk".format(BUFFER_SIZE))
data = self._afc_file_read(handle, BUFFER_SIZE, mode)
dst.write(data)
bytes_remaining -= BUFFER_SIZE
else:
self._log("copying final {:,} bytes".format(bytes_remaining))
data = self._afc_file_read(handle, bytes_remaining, mode)
dst.write(data)
bytes_remaining = 0
else:
self._log("copying %d {:,} bytes".format(file_size))
data = self._afc_file_read(handle, file_size, mode)
dst.write(data)
# Update timestamps to match
file_stats = self._afc_get_file_info(src)
os.utime(dst.name, (file_stats['st_mtime'], file_stats['st_mtime']))
self._afc_file_close(handle)
dst.close()
# Update timestamps to match
file_stats = self._afc_get_file_info(src)
os.utime(dst.name, (file_stats['st_mtime'], file_stats['st_mtime']))
else:
self._log(" could not open file")
raise libiMobileDeviceIOException("could not open file %s for reading" % repr(src))
def disconnect_idevice(self):
'''
@ -275,8 +301,7 @@ def disconnect_idevice(self):
self._idevice_free()
self.device_mounted = False
else:
if self.verbose:
self.log(" device already disconnected")
self._log(" device already disconnected")
def dismount_ios_media_folder(self):
self._afc_client_free()
@ -412,8 +437,8 @@ def load_library(self):
self.plist_lib = cdll.LoadLibrary('libplist.dll')
self._log_location(env)
self.log(" libimobiledevice loaded from '%s'" % self.lib._name)
self.log(" libplist loaded from '%s'" % self.plist_lib._name)
self._log(" libimobiledevice loaded from '%s'" % self.lib._name)
self._log(" libplist loaded from '%s'" % self.plist_lib._name)
if False:
self._idevice_set_debug_level(DEBUG)
@ -455,7 +480,7 @@ def mount_ios_app(self, app_name=None, app_id=None):
self._instproxy_client_free()
if not app_name in self.installed_apps:
self.log(" '%s' not installed on this iDevice" % app_name)
self._log(" '%s' not installed on this iDevice" % app_name)
self.disconnect_idevice()
else:
# Mount the app's Container
@ -470,7 +495,7 @@ def mount_ios_app(self, app_name=None, app_id=None):
self.device_mounted = True
except libiMobileDeviceException as e:
self.log(e.value)
self._log(e.value)
self.disconnect_idevice()
elif app_id:
@ -487,7 +512,7 @@ def mount_ios_app(self, app_name=None, app_id=None):
self.device_mounted = True
except libiMobileDeviceException as e:
self.log(e.value)
self._log(e.value)
self.disconnect_idevice()
if self.device_mounted:
@ -524,12 +549,14 @@ def mount_ios_media_folder(self):
self.device_mounted = True
except libiMobileDeviceException as e:
self.log(e.value)
self._log(e.value)
self.dismount_ios_media_folder()
def read(self, path, mode='r'):
'''
Convenience method to read from path on iDevice
Convenience method to read from path on iDevice to memory buffer.
Use for small files.
For larger files copied to local file, use copy_from_idevice()
'''
self._log_location("'%s', mode='%s'" % (path, mode))
@ -540,8 +567,7 @@ def read(self, path, mode='r'):
data = self._afc_file_read(handle, int(file_stats['st_size']), mode)
self._afc_file_close(handle)
else:
if self.verbose:
self.log(" could not open file")
self._log(" could not open file")
raise libiMobileDeviceIOException("could not open file %s for reading" % repr(path))
return data
@ -559,8 +585,8 @@ def rename(self, from_name, to_name):
error = self.lib.afc_rename_path(byref(self.afc),
str(from_name),
str(to_name))
if error and self.verbose:
self.log(" ERROR: %s" % self.afc_error(error))
if error:
self._log(" ERROR: %s" % self.afc_error(error))
def remove(self, path):
'''
@ -573,8 +599,8 @@ def remove(self, path):
error = self.lib.afc_remove_path(byref(self.afc), str(path))
if error and self.verbose:
self.log(" ERROR: %s" % self.afc_error(error))
if error:
self._log(" ERROR: %s" % self.afc_error(error))
def stat(self, path):
'''
@ -600,12 +626,10 @@ def write(self, content, destination, mode='w'):
handle = self._afc_file_open(destination, mode=mode)
if handle is not None:
success = self._afc_file_write(handle, content, mode=mode)
if self.verbose:
self.log(" success: %s" % success)
self._log(" success: %s" % success)
self._afc_file_close(handle)
else:
if self.verbose:
self.log(" could not open file for writing")
self._log(" could not open file for writing")
raise libiMobileDeviceIOException("could not open file for writing")
# ~~~ AFC functions ~~~
@ -624,8 +648,8 @@ def _afc_client_free(self):
self._log_location()
error = self.lib.afc_client_free(byref(self.afc)) & 0xFFFF
if error and self.verbose:
self.log(" ERROR: %s" % self.afc_error(error))
if error:
self._log(" ERROR: %s" % self.afc_error(error))
def _afc_client_new(self):
'''
@ -784,8 +808,8 @@ def _afc_file_close(self, handle):
error = self.lib.afc_file_close(byref(self.afc),
handle) & 0xFFFF
if error and self.verbose:
self.log(" ERROR: %s" % self._afc_error(error))
if error:
self._log(" ERROR: %s" % self._afc_error(error))
def _afc_file_open(self, filename, mode='r'):
'''
@ -825,8 +849,7 @@ def _afc_file_open(self, filename, mode='r'):
byref(handle)) & 0xFFFF
if error:
if self.verbose:
self.log(" ERROR: %s" % self._afc_error(error))
self._log(" ERROR: %s" % self._afc_error(error))
return None
else:
return handle
@ -863,15 +886,13 @@ def _afc_file_read(self, handle, size, mode):
size,
byref(bytes_read)) & 0xFFFF
if error:
if self.verbose:
self.log(" ERROR: %s" % self._afc_error(error))
self._log(" ERROR: %s" % self._afc_error(error))
return data
else:
data = create_string_buffer(size)
error = self.lib.afc_file_read(byref(self.afc), handle, byref(data), size, byref(bytes_read))
if error:
if self.verbose:
self.log(" ERROR: %s" % self._afc_error(error))
self._log(" ERROR: %s" % self._afc_error(error))
return data.value
def _afc_file_write(self, handle, content, mode='w'):
@ -911,8 +932,7 @@ def _afc_file_write(self, handle, content, mode='w'):
len(content),
byref(bytes_written)) & 0xFFFF
if error:
if self.verbose:
self.log(" ERROR: %s" % self._afc_error(error))
self._log(" ERROR: %s" % self._afc_error(error))
return False
return True
@ -953,13 +973,11 @@ def _afc_get_device_info(self):
device_info[item_list[i]] = item_list[i+1]
if self.verbose:
for key in device_info.keys():
self.log("{0:>16}: {1}".format(key, device_info[key]))
self._log("{0:>16}: {1}".format(key, device_info[key]))
else:
if self.verbose:
self.log(" ERROR: %s" % self._afc_error(error))
self._log(" ERROR: %s" % self._afc_error(error))
else:
if self.verbose:
self.log(" ERROR: AFC not initialized, can't get device info")
self._log(" ERROR: AFC not initialized, can't get device info")
return device_info
def _afc_get_file_info(self, path):
@ -993,8 +1011,7 @@ def _afc_get_file_info(self, path):
byref(infolist)) & 0xFFFF
file_stats = {}
if error:
if self.verbose:
self.log(" ERROR: %s" % self._afc_error(error))
self._log(" ERROR: %s" % self._afc_error(error))
else:
num_items = 0
item_list = []
@ -1012,7 +1029,7 @@ def _afc_get_file_info(self, path):
if False and self.verbose:
for key in file_stats.keys():
self.log(" %s: %s" % (key, file_stats[key]))
self._log(" %s: %s" % (key, file_stats[key]))
return file_stats
def _afc_make_directory(self, path):
@ -1031,8 +1048,7 @@ def _afc_make_directory(self, path):
error = self.lib.afc_make_directory(byref(self.afc),
str(path)) & 0xFFFF
if error:
if self.verbose:
self.log(" ERROR: %s" % self._afc_error(error))
self._log(" ERROR: %s" % self._afc_error(error))
return error
@ -1061,8 +1077,7 @@ def _afc_read_directory(self, directory=''):
str(directory),
byref(dirs)) & 0xFFFF
if error:
if self.verbose:
self.log(" ERROR: %s" % self._afc_error(error))
self._log(" ERROR: %s" % self._afc_error(error))
else:
num_dirs = 0
dir_list = []
@ -1110,8 +1125,7 @@ def _house_arrest_client_free(self):
error = self.lib.house_arrest_client_free(byref(self.house_arrest)) & 0xFFFF
if error:
error = error - 0x10000
if self.verbose:
self.log(" ERROR: %s" % self._house_arrest_error(error))
self._log(" ERROR: %s" % self._house_arrest_error(error))
def _house_arrest_client_new(self):
'''
@ -1144,12 +1158,11 @@ def _house_arrest_client_new(self):
raise libiMobileDeviceException(error_description)
else:
if not house_arrest_client_t:
if self.verbose:
self.log(" Could not start document sharing service")
self.log(" 1: Bad command")
self.log(" 2: Bad device")
self.log(" 3. Connection refused")
self.log(" 6. Bad version")
self._log(" Could not start document sharing service")
self._log(" 1: Bad command")
self._log(" 2: Bad device")
self._log(" 3. Connection refused")
self._log(" 6. Bad version")
return None
else:
return house_arrest_client_t.contents
@ -1204,11 +1217,9 @@ def _house_arrest_get_result(self):
# To determine success, we need to inspect the returned plist
if 'Status' in result:
if self.verbose:
self.log(" STATUS: %s" % result['Status'])
self._log(" STATUS: %s" % result['Status'])
elif 'Error' in result:
if self.verbose:
self.log(" ERROR: %s" % result['Error'])
self._log(" ERROR: %s" % result['Error'])
raise libiMobileDeviceException(result['Error'])
def _house_arrest_send_command(self, command=None, appid=None):
@ -1237,8 +1248,7 @@ def _house_arrest_send_command(self, command=None, appid=None):
commands = ['VendContainer', 'VendDocuments']
if command not in commands:
if self.verbose:
self.log(" ERROR: available commands: %s" % ', '.join(commands))
self._log(" ERROR: available commands: %s" % ', '.join(commands))
return
_command = create_string_buffer(command)
@ -1291,8 +1301,7 @@ def _idevice_free(self):
if error:
error = error - 0x10000
if self.verbose:
self.log(" ERROR: %s" % self._idevice_error(error))
self._log(" ERROR: %s" % self._idevice_error(error))
def _idevice_get_device_list(self):
'''
@ -1313,12 +1322,10 @@ def _idevice_get_device_list(self):
if error:
error = error - 0x10000
if error == -3:
if self.verbose:
self.log(" no connected devices")
self._log(" no connected devices")
else:
device_list = None
if self.verbose:
self.log(" ERROR: %s" % self._idevice_error(error))
self._log(" ERROR: %s" % self._idevice_error(error))
else:
index = 0
while devices[index]:
@ -1326,8 +1333,7 @@ def _idevice_get_device_list(self):
if devices[index].contents.value not in device_list:
device_list.append(devices[index].contents.value)
index += 1
if self.verbose:
self.log(" %s" % repr(device_list))
self._log(" %s" % repr(device_list))
#self.lib.idevice_device_list_free()
return device_list
@ -1358,12 +1364,11 @@ def _idevice_new(self):
desc=self._idevice_error(error))
raise libiMobileDeviceException(error_description)
else:
if self.verbose:
if idevice_t.contents.conn_type == 1:
self.log(" conn_type: CONNECTION_USBMUXD")
else:
self.log(" conn_type: Unknown (%d)" % idevice_t.contents.conn_type)
self.log(" udid: %s" % idevice_t.contents.udid)
if idevice_t.contents.conn_type == 1:
self._log(" conn_type: CONNECTION_USBMUXD")
else:
self._log(" conn_type: Unknown (%d)" % idevice_t.contents.conn_type)
self._log(" udid: %s" % idevice_t.contents.udid)
return idevice_t.contents
def _idevice_set_debug_level(self, debug):
@ -1400,7 +1405,7 @@ def _instproxy_browse(self, applist=[]):
else:
# Get the number of apps
#app_count = self.lib.plist_array_get_size(apps)
#self.log(" app_count: %d" % app_count)
#self._log(" app_count: %d" % app_count)
# Convert the app plist to xml
xml = POINTER(c_void_p)()
@ -1416,9 +1421,9 @@ def _instproxy_browse(self, applist=[]):
elif 'CFBundleExecutable' in app:
app_name = app['CFBundleExecutable']
else:
self.log(" unable to find app name in bundle:")
self._log(" unable to find app name in bundle:")
for key in sorted(app.keys()):
self.log(" %s %s" % (repr(key), repr(app[key])))
self._log(" %s %s" % (repr(key), repr(app[key])))
continue
if not applist:
@ -1434,7 +1439,7 @@ def _instproxy_browse(self, applist=[]):
if self.verbose:
for app in sorted(installed_apps, key=lambda s: s.lower()):
attrs = {'app_name': app, 'app_id': installed_apps[app]['app_id'], 'app_version': installed_apps[app]['app_version']}
self.log(" {app_name:<30} {app_id:<40} {app_version}".format(**attrs))
self._log(" {app_name:<30} {app_id:<40} {app_version}".format(**attrs))
self.plist_lib.plist_free(apps)
return installed_apps
@ -1657,8 +1662,7 @@ def _lockdown_get_device_name(self):
raise libiMobileDeviceException(error_description)
else:
device_name = device_name_p.contents.value
if self.verbose:
self.log(" device_name: %s" % device_name)
self._log(" device_name: %s" % device_name)
return device_name
def _lockdown_get_value(self, requested_items=[]):
@ -1806,11 +1810,9 @@ def _lockdown_goodbye(self):
if self.control:
error = self.lib.lockdownd_goodbye(byref(self.control)) & 0xFFFF
error = error - 0x10000
if self.verbose:
self.log(" ERROR: %s" % self.error_lockdown(error))
self._log(" ERROR: %s" % self.error_lockdown(error))
else:
if self.verbose:
self.log(" connection already closed")
self._log(" connection already closed")
def _lockdown_start_service(self, service_name):
'''
@ -1869,5 +1871,5 @@ def _log_location(self, *args):
if len(args) > 1:
arg2 = args[1]
self.log(self.LOCATION_TEMPLATE.format(cls=self.__class__.__name__,
func=sys._getframe(1).f_code.co_name, arg1=arg1, arg2=arg2))
debug_print(self.LOCATION_TEMPLATE.format(cls=self.__class__.__name__,
func=sys._getframe(1).f_code.co_name, arg1=arg1, arg2=arg2))