Skip to content

Instantly share code, notes, and snippets.

@barezina
Last active March 13, 2021 05:30
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save barezina/a7d11d9c7a8b0ef8c435758406743347 to your computer and use it in GitHub Desktop.
Save barezina/a7d11d9c7a8b0ef8c435758406743347 to your computer and use it in GitHub Desktop.
ios backup extractor - restores an iTunes backup to it's original files
import sqlite3
import os
import uuid
import shutil
import re
print('ios backup python script for linux (ubuntu)')
# this function helps traverse the returned results from the db
def dict_factory(cursor, row):
d = {}
for idx, col in enumerate(cursor.description):
d[col[0]] = row[idx]
return d
# set this to the path of your itunes backup
backuppath = '/media/bob/Crucial M2 NVME 1TB/Users/bob/Apple/MobileSync/Backup/00008030-000C70E03688802E/'
extractedFilePath = '/media/bob/Crucial M2 SATA 1TB/'
# read the manifest file to figure out what to map the files/names to
conn = sqlite3.connect(backuppath + 'Manifest.db')
conn.row_factory = dict_factory
c = conn.cursor()
c.execute("""
select substr(fileId, 0, 3) as folder, fileID, relativePath
from Files
""")
results = c.fetchall()
# make folders to categorise the files
if not os.path.isdir(extractedFilePath + '000_extracted_files/'):
os.makedirs(extractedFilePath + '000_extracted_files/')
if not os.path.isdir(extractedFilePath + '000_extracted_files/photos/'):
os.makedirs(extractedFilePath + '000_extracted_files/photos')
if not os.path.isdir(extractedFilePath + '000_extracted_files/videos/'):
os.makedirs(extractedFilePath + '000_extracted_files/videos')
if not os.path.isdir(extractedFilePath + '000_extracted_files/png/'):
os.makedirs(extractedFilePath + '000_extracted_files/png')
if not os.path.isdir(extractedFilePath + '000_extracted_files/databases/'):
os.makedirs(extractedFilePath + '000_extracted_files/databases')
if not os.path.isdir(extractedFilePath + '000_extracted_files/other/'):
os.makedirs(extractedFilePath + '000_extracted_files/other')
if not os.path.isdir(extractedFilePath + '000_extracted_files/raws/'):
os.makedirs(extractedFilePath + '000_extracted_files/raws')
# for every file in the database, map it's hashed name to its real name and
# copy to a folder that makes sense
for row in results:
# Get the information for this file out of the database row
folder = row['folder']
fileID = row['fileID']
relativePath = row['relativePath']
# make the whole path lowercase (and shorter, and replace out spaces and problem characters)
relativePath = relativePath.lower()
relativePath = re.sub('[^a-z0-9./\-_]', '-', relativePath)
# split the path into segments (folder, filename, extension)
# add the first eight characters from the hash so we can refer back to the db later if need be.
fileName = relativePath.split('/').pop()
prefix = str(fileID)[:8]
pathElements = relativePath.split('/')
pathElements.pop()
pathOnly = '/'.join(pathElements)
fileNameElements = fileName.split('.')
fileNameOnly = fileNameElements.pop(0)
fileNameOnly = fileNameOnly[:26]
extension = '.'.join(fileNameElements)
if len(extension) < 1:
# if the file doesnt have an extension, just skip it
continue
newFolder = ''
# figure out which folder this file belongs in
if extension == 'jpg' or extension == 'jpeg' or extension == 'elif':
newFolder = 'photos/'
elif extension == 'cr2':
newFolder = 'raws/'
elif extension == 'png':
newFolder = 'png/'
elif extension == 'mp4' or extension == 'mov' or extension == 'avi':
newFolder = 'videos/'
elif extension == 'db' or extension == 'sqlite':
newFolder = 'databases/'
else:
newFolder = 'other/'
extension = '.' + extension
newExtension = extension
if newExtension == '.jpeg':
newExtension = '.jpg'
oldApplePath = backuppath + folder + '/' + fileID
newBackupPath = extractedFilePath + '000_extracted_files/' + newFolder + fileNameOnly + '_' + prefix + newExtension
if os.path.exists(oldApplePath):
# If the old file exists, copy it to the new destination with the proper name
print(oldApplePath + ' -> ' + newBackupPath)
shutil.copyfile(oldApplePath, newBackupPath)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment