2008-05-21 18:01:39 +04:00
# include <stdlib.h>
# include <sys/types.h>
# include <string.h>
# include "common.h"
2008-07-23 21:27:35 +04:00
# include <xpwn/libxpwn.h>
2008-05-21 19:11:09 +04:00
# include <xpwn/nor_files.h>
# include <dmg/dmg.h>
# include <dmg/filevault.h>
# include <xpwn/ibootim.h>
# include <xpwn/plist.h>
# include <xpwn/outputstate.h>
# include <hfs/hfslib.h>
# include <dmg/dmglib.h>
# include <xpwn/pwnutil.h>
2008-07-23 22:30:19 +04:00
# include <stdio.h>
# ifdef WIN32
# include <windows.h>
# endif
2008-05-21 18:01:39 +04:00
char endianness ;
2008-07-23 22:30:19 +04:00
static char * tmpFile = NULL ;
static AbstractFile * openRoot ( void * * buffer , size_t * rootSize ) {
static char tmpFileBuffer [ 512 ] ;
if ( ( * buffer ) ! = NULL ) {
return createAbstractFileFromMemoryFile ( buffer , rootSize ) ;
} else {
if ( tmpFile = = NULL ) {
# ifdef WIN32
char tmpFilePath [ 512 ] ;
GetTempPath ( 512 , tmpFilePath ) ;
2008-07-25 01:09:13 +04:00
GetTempFileName ( tmpFilePath , " root " , 0 , tmpFileBuffer ) ;
2008-07-23 22:30:19 +04:00
# else
strcpy ( tmpFileBuffer , " /tmp/rootfs " ) ;
# endif
tmpFile = tmpFileBuffer ;
2008-07-25 01:09:13 +04:00
FILE * tFile = fopen ( tmpFile , " wb " ) ;
2008-07-23 22:30:19 +04:00
fclose ( tFile ) ;
}
2008-07-25 01:09:13 +04:00
return createAbstractFileFromFile ( fopen ( tmpFile , " r+b " ) ) ;
2008-07-23 22:30:19 +04:00
}
}
void closeRoot ( void * buffer ) {
if ( buffer ! = NULL ) {
free ( buffer ) ;
}
if ( tmpFile ! = NULL ) {
unlink ( tmpFile ) ;
}
}
2008-05-21 18:01:39 +04:00
int main ( int argc , char * argv [ ] ) {
2008-07-23 21:27:35 +04:00
init_libxpwn ( ) ;
2008-05-21 18:01:39 +04:00
Dictionary * info ;
Dictionary * firmwarePatches ;
Dictionary * patchDict ;
ArrayValue * patchArray ;
void * buffer ;
StringValue * actionValue ;
StringValue * pathValue ;
StringValue * fileValue ;
StringValue * patchValue ;
char * patchPath ;
char * rootFSPathInIPSW ;
io_func * rootFS ;
Volume * rootVolume ;
size_t rootSize ;
2008-07-25 01:09:13 +04:00
size_t preferredRootSize = 0 ;
2008-07-25 09:39:34 +04:00
size_t minimumRootSize = 0 ;
2008-05-21 18:01:39 +04:00
char * ramdiskFSPathInIPSW ;
2008-07-21 06:15:03 +04:00
unsigned int ramdiskKey [ 16 ] ;
unsigned int ramdiskIV [ 16 ] ;
unsigned int * pRamdiskKey = NULL ;
unsigned int * pRamdiskIV = NULL ;
2008-05-21 18:01:39 +04:00
io_func * ramdiskFS ;
Volume * ramdiskVolume ;
int i ;
OutputState * outputState ;
char * bundlePath ;
char * bundleRoot = " FirmwareBundles/ " ;
int mergePaths ;
char * outputIPSW ;
void * imageBuffer ;
size_t imageSize ;
2008-07-21 06:15:03 +04:00
AbstractFile * bootloader39 = NULL ;
AbstractFile * bootloader46 = NULL ;
AbstractFile * applelogo = NULL ;
AbstractFile * recoverymode = NULL ;
char noWipe = FALSE ;
2008-05-21 18:01:39 +04:00
2008-07-21 06:15:03 +04:00
char unlockBaseband = FALSE ;
char selfDestruct = FALSE ;
char use39 = FALSE ;
char use46 = FALSE ;
char doBootNeuter = FALSE ;
2008-07-22 05:30:24 +04:00
char updateBB = TRUE ;
2008-07-25 01:09:13 +04:00
char useMemory = FALSE ;
2008-07-21 06:15:03 +04:00
unsigned int key [ 16 ] ;
unsigned int iv [ 16 ] ;
unsigned int * pKey = NULL ;
unsigned int * pIV = NULL ;
2008-05-21 18:01:39 +04:00
if ( argc < 3 ) {
2008-07-25 01:09:13 +04:00
XLOG ( 0 , " usage %s <input.ipsw> <target.ipsw> [-b <bootimage.png>] [-r <recoveryimage.png>] [-s <system partition size>] [-memory] [-nobbupdate] [-nowipe] [-e \" <action to exclude> \" ] [[-unlock] [-use39] [-use46] [-cleanup] -3 <bootloader 3.9 file> -4 <bootloader 4.6 file>] <package1.tar> <package2.tar>... \n " , argv [ 0 ] ) ;
2008-05-21 18:01:39 +04:00
return 0 ;
}
outputIPSW = argv [ 2 ] ;
info = parseIPSW ( argv [ 1 ] , bundleRoot , & bundlePath , & outputState ) ;
if ( info = = NULL ) {
2008-07-23 21:27:35 +04:00
XLOG ( 0 , " error: Could not load IPSW \n " ) ;
2008-05-21 18:01:39 +04:00
exit ( 1 ) ;
}
firmwarePatches = ( Dictionary * ) getValueByKey ( info , " FilesystemPatches " ) ;
for ( i = 3 ; i < argc ; i + + ) {
if ( argv [ i ] [ 0 ] ! = ' - ' ) {
break ;
}
2008-07-25 01:09:13 +04:00
if ( strcmp ( argv [ i ] , " -memory " ) = = 0 ) {
useMemory = TRUE ;
continue ;
}
if ( strcmp ( argv [ i ] , " -s " ) = = 0 ) {
2008-07-25 09:39:34 +04:00
int size ;
sscanf ( argv [ i + 1 ] , " %d " , & size ) ;
preferredRootSize = size ;
2008-07-25 01:09:13 +04:00
i + + ;
continue ;
}
2008-07-21 06:15:03 +04:00
if ( strcmp ( argv [ i ] , " -nowipe " ) = = 0 ) {
noWipe = TRUE ;
2008-07-25 01:09:13 +04:00
continue ;
2008-07-21 06:15:03 +04:00
}
2008-07-22 05:30:24 +04:00
if ( strcmp ( argv [ i ] , " -nobbupdate " ) = = 0 ) {
updateBB = FALSE ;
2008-07-25 01:09:13 +04:00
continue ;
2008-07-22 05:30:24 +04:00
}
2008-05-21 18:01:39 +04:00
if ( strcmp ( argv [ i ] , " -e " ) = = 0 ) {
removeKey ( firmwarePatches , argv [ i + 1 ] ) ;
i + + ;
continue ;
}
if ( strcmp ( argv [ i ] , " -unlock " ) = = 0 ) {
unlockBaseband = TRUE ;
continue ;
}
if ( strcmp ( argv [ i ] , " -cleanup " ) = = 0 ) {
selfDestruct = TRUE ;
continue ;
}
if ( strcmp ( argv [ i ] , " -use39 " ) = = 0 ) {
if ( use46 ) {
2008-07-23 21:27:35 +04:00
XLOG ( 0 , " error: select only one of -use39 and -use46 \n " ) ;
2008-05-21 18:01:39 +04:00
exit ( 1 ) ;
}
use39 = TRUE ;
continue ;
}
if ( strcmp ( argv [ i ] , " -use46 " ) = = 0 ) {
if ( use39 ) {
2008-07-23 21:27:35 +04:00
XLOG ( 0 , " error: select only one of -use39 and -use46 \n " ) ;
2008-05-21 18:01:39 +04:00
exit ( 1 ) ;
}
use46 = TRUE ;
continue ;
}
if ( strcmp ( argv [ i ] , " -b " ) = = 0 ) {
applelogo = createAbstractFileFromFile ( fopen ( argv [ i + 1 ] , " rb " ) ) ;
if ( ! applelogo ) {
2008-07-23 21:27:35 +04:00
XLOG ( 0 , " cannot open %s \n " , argv [ i + 1 ] ) ;
2008-05-21 18:01:39 +04:00
exit ( 1 ) ;
}
i + + ;
continue ;
}
if ( strcmp ( argv [ i ] , " -r " ) = = 0 ) {
recoverymode = createAbstractFileFromFile ( fopen ( argv [ i + 1 ] , " rb " ) ) ;
if ( ! recoverymode ) {
2008-07-23 21:27:35 +04:00
XLOG ( 0 , " cannot open %s \n " , argv [ i + 1 ] ) ;
2008-05-21 18:01:39 +04:00
exit ( 1 ) ;
}
i + + ;
continue ;
}
if ( strcmp ( argv [ i ] , " -3 " ) = = 0 ) {
bootloader39 = createAbstractFileFromFile ( fopen ( argv [ i + 1 ] , " rb " ) ) ;
if ( ! bootloader39 ) {
2008-07-23 21:27:35 +04:00
XLOG ( 0 , " cannot open %s \n " , argv [ i + 1 ] ) ;
2008-05-21 18:01:39 +04:00
exit ( 1 ) ;
}
i + + ;
continue ;
}
if ( strcmp ( argv [ i ] , " -4 " ) = = 0 ) {
bootloader46 = createAbstractFileFromFile ( fopen ( argv [ i + 1 ] , " rb " ) ) ;
if ( ! bootloader46 ) {
2008-07-23 21:27:35 +04:00
XLOG ( 0 , " cannot open %s \n " , argv [ i + 1 ] ) ;
2008-05-21 18:01:39 +04:00
exit ( 1 ) ;
}
i + + ;
continue ;
}
}
if ( use39 | | use46 | | unlockBaseband | | selfDestruct | | bootloader39 | | bootloader46 ) {
2008-07-20 12:49:39 +04:00
if ( ! ( bootloader39 ) | | ! ( bootloader46 ) ) {
2008-07-23 21:27:35 +04:00
XLOG ( 0 , " error: you must specify both bootloader files. \n " ) ;
2008-05-21 18:01:39 +04:00
exit ( 1 ) ;
} else {
2008-07-20 12:49:39 +04:00
doBootNeuter = TRUE ;
2008-05-21 18:01:39 +04:00
}
}
mergePaths = i ;
firmwarePatches = ( Dictionary * ) getValueByKey ( info , " FirmwarePatches " ) ;
patchDict = ( Dictionary * ) firmwarePatches - > values ;
while ( patchDict ! = NULL ) {
fileValue = ( StringValue * ) getValueByKey ( patchDict , " File " ) ;
2008-07-20 10:38:12 +04:00
StringValue * keyValue = ( StringValue * ) getValueByKey ( patchDict , " Key " ) ;
StringValue * ivValue = ( StringValue * ) getValueByKey ( patchDict , " IV " ) ;
2008-07-21 06:15:03 +04:00
pKey = NULL ;
pIV = NULL ;
2008-07-20 10:38:12 +04:00
if ( keyValue ) {
2008-07-21 06:15:03 +04:00
sscanf ( keyValue - > value , " %2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x " ,
2008-07-20 10:38:12 +04:00
& key [ 0 ] , & key [ 1 ] , & key [ 2 ] , & key [ 3 ] , & key [ 4 ] , & key [ 5 ] , & key [ 6 ] , & key [ 7 ] , & key [ 8 ] ,
& key [ 9 ] , & key [ 10 ] , & key [ 11 ] , & key [ 12 ] , & key [ 13 ] , & key [ 14 ] , & key [ 15 ] ) ;
2008-07-21 06:15:03 +04:00
2008-07-20 10:38:12 +04:00
pKey = key ;
}
if ( ivValue ) {
2008-07-21 06:15:03 +04:00
sscanf ( ivValue - > value , " %2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x " ,
2008-07-20 10:38:12 +04:00
& iv [ 0 ] , & iv [ 1 ] , & iv [ 2 ] , & iv [ 3 ] , & iv [ 4 ] , & iv [ 5 ] , & iv [ 6 ] , & iv [ 7 ] , & iv [ 8 ] ,
& iv [ 9 ] , & iv [ 10 ] , & iv [ 11 ] , & iv [ 12 ] , & iv [ 13 ] , & iv [ 14 ] , & iv [ 15 ] ) ;
pIV = iv ;
}
2008-07-21 06:15:03 +04:00
if ( strcmp ( patchDict - > dValue . key , " Restore Ramdisk " ) = = 0 ) {
ramdiskFSPathInIPSW = fileValue - > value ;
if ( pKey ) {
memcpy ( ramdiskKey , key , sizeof ( key ) ) ;
memcpy ( ramdiskIV , iv , sizeof ( iv ) ) ;
pRamdiskKey = ramdiskKey ;
pRamdiskIV = ramdiskIV ;
} else {
pRamdiskKey = NULL ;
pRamdiskIV = NULL ;
}
}
2008-05-21 18:01:39 +04:00
patchValue = ( StringValue * ) getValueByKey ( patchDict , " Patch2 " ) ;
if ( patchValue ) {
2008-07-21 06:15:03 +04:00
if ( noWipe ) {
2008-07-23 21:27:35 +04:00
XLOG ( 0 , " %s: " , patchDict - > dValue . key ) ; fflush ( stdout ) ;
2008-07-20 10:38:12 +04:00
doPatch ( patchValue , fileValue , bundlePath , & outputState , pKey , pIV ) ;
2008-05-21 18:01:39 +04:00
patchDict = ( Dictionary * ) patchDict - > dValue . next ;
continue ; /* skip over the normal Patch */
}
}
patchValue = ( StringValue * ) getValueByKey ( patchDict , " Patch " ) ;
if ( patchValue ) {
2008-07-23 21:27:35 +04:00
XLOG ( 0 , " %s: " , patchDict - > dValue . key ) ; fflush ( stdout ) ;
2008-07-20 10:38:12 +04:00
doPatch ( patchValue , fileValue , bundlePath , & outputState , pKey , pIV ) ;
2008-05-21 18:01:39 +04:00
}
if ( strcmp ( patchDict - > dValue . key , " AppleLogo " ) = = 0 & & applelogo ) {
2008-07-23 21:27:35 +04:00
XLOG ( 0 , " replacing %s \n " , fileValue - > value ) ; fflush ( stdout ) ;
2008-07-21 06:15:03 +04:00
ASSERT ( ( imageBuffer = replaceBootImage ( getFileFromOutputState ( & outputState , fileValue - > value ) , pKey , pIV , applelogo , & imageSize ) ) ! = NULL , " failed to use new image " ) ;
2008-05-21 18:01:39 +04:00
addToOutput ( & outputState , fileValue - > value , imageBuffer , imageSize ) ;
}
if ( strcmp ( patchDict - > dValue . key , " RecoveryMode " ) = = 0 & & recoverymode ) {
2008-07-23 21:27:35 +04:00
XLOG ( 0 , " replacing %s \n " , fileValue - > value ) ; fflush ( stdout ) ;
2008-07-21 06:15:03 +04:00
ASSERT ( ( imageBuffer = replaceBootImage ( getFileFromOutputState ( & outputState , fileValue - > value ) , pKey , pIV , recoverymode , & imageSize ) ) ! = NULL , " failed to use new image " ) ;
2008-05-21 18:01:39 +04:00
addToOutput ( & outputState , fileValue - > value , imageBuffer , imageSize ) ;
}
patchDict = ( Dictionary * ) patchDict - > dValue . next ;
}
2008-07-23 09:41:35 +04:00
2008-05-21 18:01:39 +04:00
fileValue = ( StringValue * ) getValueByKey ( info , " RootFilesystem " ) ;
rootFSPathInIPSW = fileValue - > value ;
2008-07-25 09:39:34 +04:00
2008-07-29 21:48:01 +04:00
size_t defaultRootSize = ( ( IntegerValue * ) getValueByKey ( info , " RootFilesystemSize " ) ) - > value ;
minimumRootSize = defaultRootSize * 1000 * 1000 ;
2008-07-25 09:39:34 +04:00
minimumRootSize - = minimumRootSize % 512 ;
2008-07-25 01:09:13 +04:00
if ( preferredRootSize = = 0 ) {
2008-07-29 21:48:01 +04:00
preferredRootSize = defaultRootSize ;
2008-07-25 01:09:13 +04:00
}
2008-07-29 21:48:01 +04:00
rootSize = preferredRootSize * 1000 * 1000 ;
rootSize - = rootSize % 512 ;
2008-07-25 01:09:13 +04:00
if ( useMemory ) {
buffer = malloc ( rootSize ) ;
} else {
buffer = NULL ;
}
2008-05-21 18:01:39 +04:00
2008-07-23 09:41:35 +04:00
if ( buffer = = NULL ) {
2008-07-25 01:09:13 +04:00
XLOG ( 2 , " using filesystem backed temporary storage \n " ) ;
2008-07-23 09:41:35 +04:00
}
2008-05-21 18:01:39 +04:00
extractDmg (
createAbstractFileFromFileVault ( getFileFromOutputState ( & outputState , rootFSPathInIPSW ) , ( ( StringValue * ) getValueByKey ( info , " RootFilesystemKey " ) ) - > value ) ,
2008-07-23 22:30:19 +04:00
openRoot ( ( void * * ) & buffer , & rootSize ) , - 1 ) ;
2008-05-21 18:01:39 +04:00
2008-07-23 22:30:19 +04:00
rootFS = IOFuncFromAbstractFile ( openRoot ( ( void * * ) & buffer , & rootSize ) ) ;
2008-05-21 18:01:39 +04:00
rootVolume = openVolume ( rootFS ) ;
2008-07-25 09:39:34 +04:00
XLOG ( 0 , " Growing root to minimum: %ld \n " , ( long ) minimumRootSize ) ; fflush ( stdout ) ;
grow_hfs ( rootVolume , minimumRootSize ) ;
if ( rootSize > minimumRootSize ) {
XLOG ( 0 , " Growing root: %ld \n " , ( long ) rootSize ) ; fflush ( stdout ) ;
grow_hfs ( rootVolume , rootSize ) ;
}
2008-05-21 18:01:39 +04:00
firmwarePatches = ( Dictionary * ) getValueByKey ( info , " FilesystemPatches " ) ;
patchArray = ( ArrayValue * ) firmwarePatches - > values ;
while ( patchArray ! = NULL ) {
for ( i = 0 ; i < patchArray - > size ; i + + ) {
patchDict = ( Dictionary * ) patchArray - > values [ i ] ;
fileValue = ( StringValue * ) getValueByKey ( patchDict , " File " ) ;
actionValue = ( StringValue * ) getValueByKey ( patchDict , " Action " ) ;
if ( strcmp ( actionValue - > value , " ReplaceKernel " ) = = 0 ) {
pathValue = ( StringValue * ) getValueByKey ( patchDict , " Path " ) ;
2008-07-23 21:27:35 +04:00
XLOG ( 0 , " replacing kernel... %s -> %s \n " , fileValue - > value , pathValue - > value ) ; fflush ( stdout ) ;
2008-05-21 18:01:39 +04:00
add_hfs ( rootVolume , getFileFromOutputState ( & outputState , fileValue - > value ) , pathValue - > value ) ;
} if ( strcmp ( actionValue - > value , " Patch " ) = = 0 ) {
patchValue = ( StringValue * ) getValueByKey ( patchDict , " Patch " ) ;
2008-05-24 03:49:26 +04:00
patchPath = ( char * ) malloc ( sizeof ( char ) * ( strlen ( bundlePath ) + strlen ( patchValue - > value ) + 2 ) ) ;
2008-05-21 18:01:39 +04:00
strcpy ( patchPath , bundlePath ) ;
strcat ( patchPath , " / " ) ;
strcat ( patchPath , patchValue - > value ) ;
2008-07-23 21:27:35 +04:00
XLOG ( 0 , " patching %s (%s)... " , fileValue - > value , patchPath ) ;
2008-05-21 18:01:39 +04:00
doPatchInPlace ( rootVolume , fileValue - > value , patchPath ) ;
free ( patchPath ) ;
}
}
patchArray = ( ArrayValue * ) patchArray - > dValue . next ;
}
2008-06-08 23:42:53 +04:00
for ( ; mergePaths < argc ; mergePaths + + ) {
2008-07-23 21:27:35 +04:00
XLOG ( 0 , " merging %s \n " , argv [ mergePaths ] ) ;
2008-07-20 10:38:12 +04:00
AbstractFile * tarFile = createAbstractFileFromFile ( fopen ( argv [ mergePaths ] , " rb " ) ) ;
hfs_untar ( rootVolume , tarFile ) ;
tarFile - > close ( tarFile ) ;
2008-05-21 18:01:39 +04:00
}
2008-07-22 05:30:24 +04:00
if ( pRamdiskKey ) {
2008-07-22 06:32:41 +04:00
ramdiskFS = IOFuncFromAbstractFile ( openAbstractFile2 ( getFileFromOutputStateForOverwrite ( & outputState , ramdiskFSPathInIPSW ) , pRamdiskKey , pRamdiskIV ) ) ;
2008-07-22 05:30:24 +04:00
} else {
2008-07-23 21:27:35 +04:00
XLOG ( 0 , " unencrypted ramdisk \n " ) ;
2008-07-22 06:32:41 +04:00
ramdiskFS = IOFuncFromAbstractFile ( openAbstractFile ( getFileFromOutputStateForOverwrite ( & outputState , ramdiskFSPathInIPSW ) ) ) ;
2008-07-22 05:30:24 +04:00
}
ramdiskVolume = openVolume ( ramdiskFS ) ;
2008-07-23 21:27:35 +04:00
XLOG ( 0 , " growing ramdisk: %d -> %d \n " , ramdiskVolume - > volumeHeader - > totalBlocks * ramdiskVolume - > volumeHeader - > blockSize , ( ramdiskVolume - > volumeHeader - > totalBlocks + 4 ) * ramdiskVolume - > volumeHeader - > blockSize ) ;
2008-07-22 06:32:41 +04:00
grow_hfs ( ramdiskVolume , ( ramdiskVolume - > volumeHeader - > totalBlocks + 4 ) * ramdiskVolume - > volumeHeader - > blockSize ) ;
2008-07-21 06:15:03 +04:00
2008-07-22 05:30:24 +04:00
if ( doBootNeuter ) {
2008-05-21 18:01:39 +04:00
firmwarePatches = ( Dictionary * ) getValueByKey ( info , " BasebandPatches " ) ;
if ( firmwarePatches ! = NULL ) {
patchDict = ( Dictionary * ) firmwarePatches - > values ;
while ( patchDict ! = NULL ) {
pathValue = ( StringValue * ) getValueByKey ( patchDict , " Path " ) ;
fileValue = ( StringValue * ) getValueByKey ( patchDict , " File " ) ;
if ( fileValue ) {
2008-07-23 21:27:35 +04:00
XLOG ( 0 , " copying %s -> %s... " , fileValue - > value , pathValue - > value ) ; fflush ( stdout ) ;
2008-05-21 18:01:39 +04:00
if ( copyAcrossVolumes ( ramdiskVolume , rootVolume , fileValue - > value , pathValue - > value ) ) {
patchValue = ( StringValue * ) getValueByKey ( patchDict , " Patch " ) ;
if ( patchValue ) {
patchPath = malloc ( sizeof ( char ) * ( strlen ( bundlePath ) + strlen ( patchValue - > value ) + 2 ) ) ;
strcpy ( patchPath , bundlePath ) ;
strcat ( patchPath , " / " ) ;
strcat ( patchPath , patchValue - > value ) ;
2008-07-23 21:27:35 +04:00
XLOG ( 0 , " patching %s (%s)... " , pathValue - > value , patchPath ) ; fflush ( stdout ) ;
2008-05-21 18:01:39 +04:00
doPatchInPlace ( rootVolume , pathValue - > value , patchPath ) ;
free ( patchPath ) ;
}
}
}
if ( strcmp ( patchDict - > dValue . key , " Bootloader 3.9 " ) = = 0 & & bootloader39 ! = NULL ) {
add_hfs ( rootVolume , bootloader39 , pathValue - > value ) ;
}
if ( strcmp ( patchDict - > dValue . key , " Bootloader 4.6 " ) = = 0 & & bootloader46 ! = NULL ) {
add_hfs ( rootVolume , bootloader46 , pathValue - > value ) ;
}
patchDict = ( Dictionary * ) patchDict - > dValue . next ;
}
}
fixupBootNeuterArgs ( rootVolume , unlockBaseband , selfDestruct , use39 , use46 ) ;
}
2008-07-29 21:48:01 +04:00
createRestoreOptions ( ramdiskVolume , preferredRootSize , updateBB ) ;
2008-07-22 05:30:24 +04:00
closeVolume ( ramdiskVolume ) ;
CLOSE ( ramdiskFS ) ;
2008-05-21 18:01:39 +04:00
closeVolume ( rootVolume ) ;
CLOSE ( rootFS ) ;
2008-07-23 22:30:19 +04:00
buildDmg ( openRoot ( ( void * * ) & buffer , & rootSize ) , getFileFromOutputStateForOverwrite ( & outputState , rootFSPathInIPSW ) ) ;
2008-05-21 18:01:39 +04:00
2008-07-23 22:30:19 +04:00
closeRoot ( buffer ) ;
2008-05-21 18:01:39 +04:00
writeOutput ( & outputState , outputIPSW ) ;
releaseDictionary ( info ) ;
free ( bundlePath ) ;
return 0 ;
}