mirror of
https://github.com/martravi/wiiqt6.git
synced 2024-11-21 21:19:15 +01:00
* fix bug in nand.bin class: when creating a new nand.bin, initialize fst_pos in fst entries
* insert new entries in nand.bin at the start of the chain instead of at the end ( to closer mimic IOS FS behavior ) * oneswanzenegger: create /sys/cert.sys when creating a new nand.bin git-svn-id: http://wiiqt.googlecode.com/svn/trunk@42 389f4c8b-5dfe-645f-db0e-df882bc27289
This commit is contained in:
parent
d9a2a2e012
commit
1801f7f8cf
@ -90,6 +90,9 @@ bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByt
|
|||||||
fats.clear();
|
fats.clear();
|
||||||
memset( &fsts, 0, sizeof( fst_t ) * 0x17ff );
|
memset( &fsts, 0, sizeof( fst_t ) * 0x17ff );
|
||||||
|
|
||||||
|
for( quint16 i = 0; i < 0x17ff; i++ )
|
||||||
|
fsts[ i ].fst_pos = i;
|
||||||
|
|
||||||
//reserve blocks 0 - 7
|
//reserve blocks 0 - 7
|
||||||
for( quint16 i = 0; i < 0x40; i++ )
|
for( quint16 i = 0; i < 0x40; i++ )
|
||||||
{
|
{
|
||||||
@ -1193,7 +1196,12 @@ quint16 NandBin::CreateEntry( const QString &path, quint32 uid, quint16 gid, qui
|
|||||||
if( !ret )
|
if( !ret )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
fsts[ entryNo ].sib = ret;
|
//method 1: this works, and the nand is bootable. but doesnt mimic the IOS FS driver. ( my entries appear in reversed order when walking the FS )
|
||||||
|
//fsts[ entryNo ].sib = ret;
|
||||||
|
|
||||||
|
//method 2: trying to mimic the IOS FS driver ( insert new entries at the start of the chain, instead of the end )
|
||||||
|
fsts[ ret ].sib = fsts[ parIdx ].sub;
|
||||||
|
fsts[ parIdx ].sub = ret;
|
||||||
}
|
}
|
||||||
QTreeWidgetItem *child = CreateItem( par, name, 0, ret, uid, gid, 0, fsts[ ret ].attr, 0 );
|
QTreeWidgetItem *child = CreateItem( par, name, 0, ret, uid, gid, 0, fsts[ ret ].attr, 0 );
|
||||||
if( attr == NAND_FILE )
|
if( attr == NAND_FILE )
|
||||||
|
@ -56,13 +56,13 @@ void MainWindow::GetError( const QString &message, NusJob job )
|
|||||||
{
|
{
|
||||||
QString dataStuff = QString( "%1 items:" ).arg( job.data.size() );
|
QString dataStuff = QString( "%1 items:" ).arg( job.data.size() );
|
||||||
for( int i = 0; i < job.data.size(); i++ )
|
for( int i = 0; i < job.data.size(); i++ )
|
||||||
dataStuff += QString( " %1" ).arg( job.data.at( i ).size(), 0, 16, QChar( ' ' ) );
|
dataStuff += QString( " %1" ).arg( job.data.at( i ).size(), 0, 16, QChar( ' ' ) );
|
||||||
|
|
||||||
QString str = tr( "<b>Error getting title from NUS: %1</b>" ).arg( message );
|
QString str = tr( "<b>Error getting title from NUS: %1</b>" ).arg( message );
|
||||||
QString j = QString( "NusJob( %1, %2, %3, %4 )<br>" )
|
QString j = QString( "NusJob( %1, %2, %3, %4 )<br>" )
|
||||||
.arg( job.tid, 16, 16, QChar( '0' ) )
|
.arg( job.tid, 16, 16, QChar( '0' ) )
|
||||||
.arg( job.version ).arg( job.decrypt ? "decrypted" : "encrypted" )
|
.arg( job.version ).arg( job.decrypt ? "decrypted" : "encrypted" )
|
||||||
.arg( dataStuff );
|
.arg( dataStuff );
|
||||||
|
|
||||||
|
|
||||||
ui->plainTextEdit_log->appendHtml( str );
|
ui->plainTextEdit_log->appendHtml( str );
|
||||||
@ -92,44 +92,44 @@ void MainWindow::NusIsDone()
|
|||||||
QTreeWidgetItem *item = ItemFromPath( "/title/00000001/00000002/data/setting.txt" );
|
QTreeWidgetItem *item = ItemFromPath( "/title/00000001/00000002/data/setting.txt" );
|
||||||
if( !item )
|
if( !item )
|
||||||
{
|
{
|
||||||
quint8 reg = SETTING_TXT_UNK;
|
quint8 reg = SETTING_TXT_UNK;
|
||||||
if( ui->lineEdit_tid->text().endsWith( "e", Qt::CaseInsensitive ) && ui->lineEdit_tid->text().size() == 4 )
|
if( ui->lineEdit_tid->text().endsWith( "e", Qt::CaseInsensitive ) && ui->lineEdit_tid->text().size() == 4 )
|
||||||
reg = SETTING_TXT_PAL;
|
reg = SETTING_TXT_PAL;
|
||||||
if( ui->lineEdit_tid->text().endsWith( "j", Qt::CaseInsensitive ) && ui->lineEdit_tid->text().size() == 4 )
|
if( ui->lineEdit_tid->text().endsWith( "j", Qt::CaseInsensitive ) && ui->lineEdit_tid->text().size() == 4 )
|
||||||
reg = SETTING_TXT_JAP;
|
reg = SETTING_TXT_JAP;
|
||||||
if( ui->lineEdit_tid->text().endsWith( "k", Qt::CaseInsensitive ) && ui->lineEdit_tid->text().size() == 4 )
|
if( ui->lineEdit_tid->text().endsWith( "k", Qt::CaseInsensitive ) && ui->lineEdit_tid->text().size() == 4 )
|
||||||
reg = SETTING_TXT_KOR;
|
reg = SETTING_TXT_KOR;
|
||||||
QByteArray ba = SettingTxtDialog::Edit( this, QByteArray(), reg ); //call a dialog to create a new setting.txt
|
QByteArray ba = SettingTxtDialog::Edit( this, QByteArray(), reg ); //call a dialog to create a new setting.txt
|
||||||
if( !ba.isEmpty() ) //if the dialog returned anything ( cancel wasnt pressed ) write that new setting.txt to the nand
|
if( !ba.isEmpty() ) //if the dialog returned anything ( cancel wasnt pressed ) write that new setting.txt to the nand
|
||||||
{
|
|
||||||
quint16 r = nand.CreateEntry( "/title/00000001/00000002/data/setting.txt", 0x1000, 1, NAND_FILE, NAND_READ, NAND_READ, NAND_READ );
|
|
||||||
if( !r )
|
|
||||||
{
|
|
||||||
ShowMessage( "<b>Error creating setting.txt. maybe some folders are missing?</b>" );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( !nand.SetData( r, ba) )
|
|
||||||
{
|
{
|
||||||
ShowMessage( "<b>Error writing data for setting.txt.</b>" );
|
quint16 r = nand.CreateEntry( "/title/00000001/00000002/data/setting.txt", 0x1000, 1, NAND_FILE, NAND_READ, NAND_READ, NAND_READ );
|
||||||
|
if( !r )
|
||||||
|
{
|
||||||
|
ShowMessage( "<b>Error creating setting.txt. maybe some folders are missing?</b>" );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if( !nand.SetData( r, ba) )
|
||||||
|
{
|
||||||
|
ShowMessage( "<b>Error writing data for setting.txt.</b>" );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nandDirty = true;
|
||||||
|
UpdateTree();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
nandDirty = true;
|
|
||||||
UpdateTree();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//nand.Delete( "/title/00000001/00000002/content/title.tmd" );
|
//nand.Delete( "/title/00000001/00000002/content/title.tmd" );
|
||||||
if( nandDirty )
|
if( nandDirty )
|
||||||
{
|
{
|
||||||
if( !FlushNand() )
|
if( !FlushNand() )
|
||||||
{
|
{
|
||||||
ShowMessage( "<b>Error flushing nand. Maybe you used too much TP?</b>" );
|
ShowMessage( "<b>Error flushing nand. Maybe you used too much TP?</b>" );
|
||||||
}
|
}
|
||||||
nandDirty = false;
|
nandDirty = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,7 +142,7 @@ void MainWindow::ReceiveTitleFromNus( NusJob job )
|
|||||||
|
|
||||||
//do something with the data we got
|
//do something with the data we got
|
||||||
if( InstallNUSItem( job ) )
|
if( InstallNUSItem( job ) )
|
||||||
nandDirty = true;
|
nandDirty = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +150,7 @@ void MainWindow::ReceiveTitleFromNus( NusJob job )
|
|||||||
void MainWindow::on_pushButton_GetTitle_clicked()
|
void MainWindow::on_pushButton_GetTitle_clicked()
|
||||||
{
|
{
|
||||||
if( !nandInited && !InitNand( ui->lineEdit_nandPath->text() ) )
|
if( !nandInited && !InitNand( ui->lineEdit_nandPath->text() ) )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
bool wholeUpdate = false;
|
bool wholeUpdate = false;
|
||||||
@ -158,46 +158,46 @@ void MainWindow::on_pushButton_GetTitle_clicked()
|
|||||||
quint32 ver = 0;
|
quint32 ver = 0;
|
||||||
if( ui->lineEdit_tid->text().size() == 4 )
|
if( ui->lineEdit_tid->text().size() == 4 )
|
||||||
{
|
{
|
||||||
wholeUpdate = true;
|
wholeUpdate = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
tid = ui->lineEdit_tid->text().toLongLong( &ok, 16 );
|
tid = ui->lineEdit_tid->text().toLongLong( &ok, 16 );
|
||||||
if( !ok )
|
if( !ok )
|
||||||
{
|
{
|
||||||
ShowMessage( "<b>Error converting \"" + ui->lineEdit_tid->text() + "\" to a hex number.</b>" );
|
ShowMessage( "<b>Error converting \"" + ui->lineEdit_tid->text() + "\" to a hex number.</b>" );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ver = TITLE_LATEST_VERSION;
|
ver = TITLE_LATEST_VERSION;
|
||||||
if( !ui->lineEdit_version->text().isEmpty() )
|
if( !ui->lineEdit_version->text().isEmpty() )
|
||||||
{
|
{
|
||||||
ver = ui->lineEdit_version->text().toInt( &ok, 10 );
|
ver = ui->lineEdit_version->text().toInt( &ok, 10 );
|
||||||
if( !ok )
|
if( !ok )
|
||||||
{
|
{
|
||||||
ShowMessage( "<b>Error converting \"" + ui->lineEdit_version->text() + "\" to a decimal number.</b>" );
|
ShowMessage( "<b>Error converting \"" + ui->lineEdit_version->text() + "\" to a decimal number.</b>" );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if( ver > 0xffff )
|
if( ver > 0xffff )
|
||||||
{
|
{
|
||||||
ShowMessage( tr( "<b>Version %1 is too high. Max is 65535</b>" ).arg( ver ) );
|
ShowMessage( tr( "<b>Version %1 is too high. Max is 65535</b>" ).arg( ver ) );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//decide how we want nus to give us the title
|
//decide how we want nus to give us the title
|
||||||
bool decrypt = true;
|
bool decrypt = true;
|
||||||
nus.SetCachePath( ui->lineEdit_cachePath->text() );
|
nus.SetCachePath( ui->lineEdit_cachePath->text() );
|
||||||
if( wholeUpdate )
|
if( wholeUpdate )
|
||||||
{
|
{
|
||||||
if( !nus.GetUpdate( ui->lineEdit_tid->text(), decrypt ) )
|
if( !nus.GetUpdate( ui->lineEdit_tid->text(), decrypt ) )
|
||||||
{
|
{
|
||||||
ShowMessage( tr( "<b>I dont know the titles that were in the %1 update</b>" ).arg( ui->lineEdit_tid->text() ) );
|
ShowMessage( tr( "<b>I dont know the titles that were in the %1 update</b>" ).arg( ui->lineEdit_tid->text() ) );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
nus.Get( tid, decrypt, ver );
|
nus.Get( tid, decrypt, ver );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,7 +206,7 @@ void MainWindow::on_pushButton_nandPath_clicked()
|
|||||||
{
|
{
|
||||||
QString f = QFileDialog::getOpenFileName( this, tr( "Select nand.bin" ) );
|
QString f = QFileDialog::getOpenFileName( this, tr( "Select nand.bin" ) );
|
||||||
if( f.isEmpty() )
|
if( f.isEmpty() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ui->lineEdit_nandPath->setText( f );
|
ui->lineEdit_nandPath->setText( f );
|
||||||
}
|
}
|
||||||
@ -215,7 +215,7 @@ void MainWindow::on_pushButton_CachePathBrowse_clicked()
|
|||||||
{
|
{
|
||||||
QString f = QFileDialog::getExistingDirectory( this, tr( "Select NUS Cache base folder" ) );
|
QString f = QFileDialog::getExistingDirectory( this, tr( "Select NUS Cache base folder" ) );
|
||||||
if( f.isEmpty() )
|
if( f.isEmpty() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ui->lineEdit_cachePath->setText( f );
|
ui->lineEdit_cachePath->setText( f );
|
||||||
nus.SetCachePath( ui->lineEdit_cachePath->text() );
|
nus.SetCachePath( ui->lineEdit_cachePath->text() );
|
||||||
@ -225,26 +225,26 @@ void MainWindow::on_pushButton_CachePathBrowse_clicked()
|
|||||||
void MainWindow::on_actionSetting_txt_triggered()
|
void MainWindow::on_actionSetting_txt_triggered()
|
||||||
{
|
{
|
||||||
if( !nandInited )
|
if( !nandInited )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QTreeWidgetItem *it = ItemFromPath( "/title/00000001/00000002/data/setting.txt" );
|
QTreeWidgetItem *it = ItemFromPath( "/title/00000001/00000002/data/setting.txt" );
|
||||||
if( !it )
|
if( !it )
|
||||||
{
|
{
|
||||||
ShowMessage( tr( "<b>There is no setting.txt found in %1</b>" )
|
ShowMessage( tr( "<b>There is no setting.txt found in %1</b>" )
|
||||||
.arg( QFileInfo( ui->lineEdit_nandPath->text() ).absoluteFilePath() ) );
|
.arg( QFileInfo( ui->lineEdit_nandPath->text() ).absoluteFilePath() ) );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QByteArray ba = nand.GetData( "/title/00000001/00000002/data/setting.txt" ); //read the current setting.txt
|
QByteArray ba = nand.GetData( "/title/00000001/00000002/data/setting.txt" ); //read the current setting.txt
|
||||||
ba = SettingTxtDialog::Edit( this, ba ); //call a dialog to edit that existing file and store the result in the same bytearray
|
ba = SettingTxtDialog::Edit( this, ba ); //call a dialog to edit that existing file and store the result in the same bytearray
|
||||||
if( !ba.isEmpty() ) //if the dialog returned anything ( cancel wasnt pressed ) write that new setting.txt to the nand dump
|
if( !ba.isEmpty() ) //if the dialog returned anything ( cancel wasnt pressed ) write that new setting.txt to the nand dump
|
||||||
nand.SetData( "/title/00000001/00000002/data/setting.txt", ba );
|
nand.SetData( "/title/00000001/00000002/data/setting.txt", ba );
|
||||||
}
|
}
|
||||||
|
|
||||||
//nand-dump -> flush
|
//nand-dump -> flush
|
||||||
void MainWindow::on_actionFlush_triggered()
|
void MainWindow::on_actionFlush_triggered()
|
||||||
{
|
{
|
||||||
if( !nandInited )
|
if( !nandInited )
|
||||||
FlushNand();
|
FlushNand();
|
||||||
}
|
}
|
||||||
|
|
||||||
//nand-dump -> ImportWad
|
//nand-dump -> ImportWad
|
||||||
@ -252,23 +252,23 @@ void MainWindow::on_actionImportWad_triggered()
|
|||||||
{
|
{
|
||||||
if( !nandInited && !InitNand( ui->lineEdit_nandPath->text() ) )
|
if( !nandInited && !InitNand( ui->lineEdit_nandPath->text() ) )
|
||||||
{
|
{
|
||||||
ShowMessage( tr( "<b>Error setting the basepath of the nand to %1</b>" ).arg( QFileInfo( ui->lineEdit_nandPath->text() ).absoluteFilePath() ) );
|
ShowMessage( tr( "<b>Error setting the basepath of the nand to %1</b>" ).arg( QFileInfo( ui->lineEdit_nandPath->text() ).absoluteFilePath() ) );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QString fn = QFileDialog::getOpenFileName( this, tr("Wad files(*.wad)"), QCoreApplication::applicationDirPath(), tr("WadFiles (*.wad)") );
|
QString fn = QFileDialog::getOpenFileName( this, tr("Wad files(*.wad)"), QCoreApplication::applicationDirPath(), tr("WadFiles (*.wad)") );
|
||||||
|
|
||||||
if( fn.isEmpty() )
|
if( fn.isEmpty() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
QByteArray data = ReadFile( fn );
|
QByteArray data = ReadFile( fn );
|
||||||
if( data.isEmpty() )
|
if( data.isEmpty() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Wad wad( data );
|
Wad wad( data );
|
||||||
if( !wad.IsOk() )
|
if( !wad.IsOk() )
|
||||||
{
|
{
|
||||||
ShowMessage( tr( "Wad data not ok for \"%1\"" ).arg( fn ) );
|
ShowMessage( tr( "Wad data not ok for \"%1\"" ).arg( fn ) );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//work smart, not hard... just turn the wad into a NUSJob and reused the same code to install it
|
//work smart, not hard... just turn the wad into a NUSJob and reused the same code to install it
|
||||||
@ -282,7 +282,7 @@ void MainWindow::on_actionImportWad_triggered()
|
|||||||
quint16 cnt = t.Count();
|
quint16 cnt = t.Count();
|
||||||
for( quint16 i = 0; i < cnt; i++ )
|
for( quint16 i = 0; i < cnt; i++ )
|
||||||
{
|
{
|
||||||
job.data << wad.Content( i );
|
job.data << wad.Content( i );
|
||||||
}
|
}
|
||||||
|
|
||||||
job.decrypt = true;
|
job.decrypt = true;
|
||||||
@ -295,7 +295,7 @@ void MainWindow::on_actionNew_nand_from_keys_triggered()
|
|||||||
{
|
{
|
||||||
QString path = NewNandBin::GetNewNandPath( this );
|
QString path = NewNandBin::GetNewNandPath( this );
|
||||||
if( path.isEmpty() )
|
if( path.isEmpty() )
|
||||||
return;
|
return;
|
||||||
InitNand( path );
|
InitNand( path );
|
||||||
ui->lineEdit_nandPath->setText( path );
|
ui->lineEdit_nandPath->setText( path );
|
||||||
}
|
}
|
||||||
@ -304,8 +304,8 @@ void MainWindow::on_pushButton_initNand_clicked()
|
|||||||
{
|
{
|
||||||
if( ui->lineEdit_nandPath->text().isEmpty() )
|
if( ui->lineEdit_nandPath->text().isEmpty() )
|
||||||
{
|
{
|
||||||
ShowMessage( "<b>Please enter a path for nand.bin<\b>" );
|
ShowMessage( "<b>Please enter a path for nand.bin<\b>" );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
InitNand( ui->lineEdit_nandPath->text() );
|
InitNand( ui->lineEdit_nandPath->text() );
|
||||||
}
|
}
|
||||||
@ -316,45 +316,45 @@ bool MainWindow::InitNand( const QString &path )
|
|||||||
sharedDirty = false;
|
sharedDirty = false;
|
||||||
nandDirty = false;
|
nandDirty = false;
|
||||||
if( !nand.SetPath( path ) || !nand.InitNand() )
|
if( !nand.SetPath( path ) || !nand.InitNand() )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if( !UpdateTree() )
|
if( !UpdateTree() )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//setup the uid
|
//setup the uid
|
||||||
QTreeWidgetItem *it = ItemFromPath( "/sys/uid.sys" );
|
QTreeWidgetItem *it = ItemFromPath( "/sys/uid.sys" );
|
||||||
if( !it )
|
if( !it )
|
||||||
{
|
{
|
||||||
uid.CreateNew( true );
|
uid.CreateNew( true );
|
||||||
if( !nand.CreateEntry( "/sys/uid.sys", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ) )
|
if( !nand.CreateEntry( "/sys/uid.sys", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ) )
|
||||||
{
|
{
|
||||||
ShowMessage( "<b>Error creating new uid.sys</b>" );
|
ShowMessage( "<b>Error creating new uid.sys</b>" );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uidDirty = true;
|
uidDirty = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QByteArray ba = nand.GetData( "/sys/uid.sys" );
|
QByteArray ba = nand.GetData( "/sys/uid.sys" );
|
||||||
uid = UIDmap( ba );
|
uid = UIDmap( ba );
|
||||||
}
|
}
|
||||||
//set up the shared map
|
//set up the shared map
|
||||||
it = ItemFromPath( "/shared1/content.map" );
|
it = ItemFromPath( "/shared1/content.map" );
|
||||||
if( !it )
|
if( !it )
|
||||||
{
|
{
|
||||||
if( !nand.CreateEntry( "/shared1/content.map", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ) )
|
if( !nand.CreateEntry( "/shared1/content.map", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ) )
|
||||||
{
|
{
|
||||||
sharedDirty = true;
|
sharedDirty = true;
|
||||||
ShowMessage( "<b>Error creating new content.map</b>" );
|
ShowMessage( "<b>Error creating new content.map</b>" );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QByteArray ba = nand.GetData( "/shared1/content.map" );
|
QByteArray ba = nand.GetData( "/shared1/content.map" );
|
||||||
shared = SharedContentMap( ba );
|
shared = SharedContentMap( ba );
|
||||||
if( !shared.Check() )//i really dont want to create a new one and rewrite all the contents to match it
|
if( !shared.Check() )//i really dont want to create a new one and rewrite all the contents to match it
|
||||||
ShowMessage( "<b>Something about the shared map isnt right, but im using it anyways</b>" );
|
ShowMessage( "<b>Something about the shared map isnt right, but im using it anyways</b>" );
|
||||||
}
|
}
|
||||||
//nand.Delete( "/title/00000001/00000002/content/title.tmd" );
|
//nand.Delete( "/title/00000001/00000002/content/title.tmd" );
|
||||||
|
|
||||||
@ -372,15 +372,15 @@ bool MainWindow::FlushNand()
|
|||||||
bool r1 = true;
|
bool r1 = true;
|
||||||
bool r2 = true;
|
bool r2 = true;
|
||||||
if( uidDirty && !nand.SetData( "/sys/uid.sys", uid.Data() ) )
|
if( uidDirty && !nand.SetData( "/sys/uid.sys", uid.Data() ) )
|
||||||
r1 = false;
|
r1 = false;
|
||||||
else
|
else
|
||||||
uidDirty = false;
|
uidDirty = false;
|
||||||
|
|
||||||
|
|
||||||
if( sharedDirty && !nand.SetData( "/shared1/content.map", shared.Data() ) )
|
if( sharedDirty && !nand.SetData( "/shared1/content.map", shared.Data() ) )
|
||||||
r2 = false;
|
r2 = false;
|
||||||
else
|
else
|
||||||
sharedDirty = false;
|
sharedDirty = false;
|
||||||
|
|
||||||
return ( nand.WriteMetaData() && r1 && r2 );
|
return ( nand.WriteMetaData() && r1 && r2 );
|
||||||
}
|
}
|
||||||
@ -390,11 +390,11 @@ QTreeWidgetItem *MainWindow::FindItem( const QString &s, QTreeWidgetItem *parent
|
|||||||
int cnt = parent->childCount();
|
int cnt = parent->childCount();
|
||||||
for( int i = 0; i <cnt; i++ )
|
for( int i = 0; i <cnt; i++ )
|
||||||
{
|
{
|
||||||
QTreeWidgetItem *r = parent->child( i );
|
QTreeWidgetItem *r = parent->child( i );
|
||||||
if( r->text( 0 ) == s )
|
if( r->text( 0 ) == s )
|
||||||
{
|
{
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -404,20 +404,20 @@ QTreeWidgetItem *MainWindow::ItemFromPath( const QString &path )
|
|||||||
QTreeWidgetItem *item = root;
|
QTreeWidgetItem *item = root;
|
||||||
if( !path.startsWith( "/" ) || path.contains( "//" ))
|
if( !path.startsWith( "/" ) || path.contains( "//" ))
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
int slash = 1;
|
int slash = 1;
|
||||||
while( slash )
|
while( slash )
|
||||||
{
|
{
|
||||||
int nextSlash = path.indexOf( "/", slash + 1 );
|
int nextSlash = path.indexOf( "/", slash + 1 );
|
||||||
QString lookingFor = path.mid( slash, nextSlash - slash );
|
QString lookingFor = path.mid( slash, nextSlash - slash );
|
||||||
item = FindItem( lookingFor, item );
|
item = FindItem( lookingFor, item );
|
||||||
if( !item )
|
if( !item )
|
||||||
{
|
{
|
||||||
//qWarning() << "ItemFromPath ->item not found" << path;
|
//qWarning() << "ItemFromPath ->item not found" << path;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
slash = nextSlash + 1;
|
slash = nextSlash + 1;
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
@ -427,10 +427,10 @@ QString MainWindow::PathFromItem( QTreeWidgetItem *item )
|
|||||||
QString ret;
|
QString ret;
|
||||||
while( item )
|
while( item )
|
||||||
{
|
{
|
||||||
ret.prepend( "/" + item->text( 0 ) );
|
ret.prepend( "/" + item->text( 0 ) );
|
||||||
item = item->parent();
|
item = item->parent();
|
||||||
if( item->text( 0 ) == "/" )// dont add the root
|
if( item->text( 0 ) == "/" )// dont add the root
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -439,12 +439,12 @@ bool MainWindow::UpdateTree()
|
|||||||
{
|
{
|
||||||
//set up the tree so we know what all is in the nand without asking for it every time
|
//set up the tree so we know what all is in the nand without asking for it every time
|
||||||
if( root )
|
if( root )
|
||||||
delete root;
|
delete root;
|
||||||
QTreeWidgetItem *r = nand.GetTree();
|
QTreeWidgetItem *r = nand.GetTree();
|
||||||
if( r->childCount() != 1 || r->child( 0 )->text( 0 ) != "/" )
|
if( r->childCount() != 1 || r->child( 0 )->text( 0 ) != "/" )
|
||||||
{
|
{
|
||||||
ShowMessage( "The nand FS is seriously broken. I Couldn't even find a correct root" );
|
ShowMessage( "The nand FS is seriously broken. I Couldn't even find a correct root" );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
root = r->takeChild( 0 );
|
root = r->takeChild( 0 );
|
||||||
delete r;
|
delete r;
|
||||||
@ -454,14 +454,14 @@ bool MainWindow::UpdateTree()
|
|||||||
|
|
||||||
quint16 MainWindow::CreateIfNeeded( const QString &path, quint32 uid, quint16 gid, quint8 attr, quint8 user_perm, quint8 group_perm, quint8 other_perm )
|
quint16 MainWindow::CreateIfNeeded( const QString &path, quint32 uid, quint16 gid, quint8 attr, quint8 user_perm, quint8 group_perm, quint8 other_perm )
|
||||||
{
|
{
|
||||||
// qDebug() << "MainWindow::CreateIfNeeded" << path;
|
// qDebug() << "MainWindow::CreateIfNeeded" << path;
|
||||||
QTreeWidgetItem *item = ItemFromPath( path );
|
QTreeWidgetItem *item = ItemFromPath( path );
|
||||||
if( !item )
|
if( !item )
|
||||||
{
|
{
|
||||||
quint16 ret = nand.CreateEntry( path, uid, gid, attr, user_perm, group_perm, other_perm );
|
quint16 ret = nand.CreateEntry( path, uid, gid, attr, user_perm, group_perm, other_perm );
|
||||||
if( ret && UpdateTree() )
|
if( ret && UpdateTree() )
|
||||||
return ret;
|
return ret;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
//TODO - if the item already exists, check that its attributes match the expected ones
|
//TODO - if the item already exists, check that its attributes match the expected ones
|
||||||
return item->text( 1 ).toInt();
|
return item->text( 1 ).toInt();
|
||||||
@ -472,13 +472,13 @@ bool MainWindow::InstallSharedContent( const QByteArray stuff, const QByteArray
|
|||||||
//qDebug() << "MainWindow::InstallSharedContent";
|
//qDebug() << "MainWindow::InstallSharedContent";
|
||||||
QByteArray h;
|
QByteArray h;
|
||||||
if( hash.isEmpty() )
|
if( hash.isEmpty() )
|
||||||
h = GetSha1( stuff );
|
h = GetSha1( stuff );
|
||||||
else
|
else
|
||||||
h = hash;
|
h = hash;
|
||||||
|
|
||||||
QString cid = shared.GetAppFromHash( hash );
|
QString cid = shared.GetAppFromHash( hash );
|
||||||
if( !cid.isEmpty() ) //this one is already installed
|
if( !cid.isEmpty() ) //this one is already installed
|
||||||
return true;
|
return true;
|
||||||
//qDebug() << "will create new";
|
//qDebug() << "will create new";
|
||||||
|
|
||||||
//get next available cid in the shared map
|
//get next available cid in the shared map
|
||||||
@ -490,7 +490,7 @@ bool MainWindow::InstallSharedContent( const QByteArray stuff, const QByteArray
|
|||||||
//create the file
|
//create the file
|
||||||
quint16 r = CreateIfNeeded( "/shared1/" + cid + ".app", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 );
|
quint16 r = CreateIfNeeded( "/shared1/" + cid + ".app", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 );
|
||||||
if( !r )
|
if( !r )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
//write the data to the file
|
//write the data to the file
|
||||||
return nand.SetData( r, stuff );
|
return nand.SetData( r, stuff );
|
||||||
@ -509,9 +509,9 @@ bool MainWindow::InstallNUSItem( NusJob job )
|
|||||||
QTreeWidgetItem *content;
|
QTreeWidgetItem *content;
|
||||||
if( !job.tid || !job.data.size() > 2 )
|
if( !job.tid || !job.data.size() > 2 )
|
||||||
{
|
{
|
||||||
qWarning() << "bad sizes";
|
qWarning() << "bad sizes";
|
||||||
ShowMessage( "<b>Error installing title " + title + " to nand</b>" );
|
ShowMessage( "<b>Error installing title " + title + " to nand</b>" );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
QString tid = QString( "%1" ).arg( job.tid, 16, 16, QChar( '0' ) );
|
QString tid = QString( "%1" ).arg( job.tid, 16, 16, QChar( '0' ) );
|
||||||
QString upper = tid.left( 8 );
|
QString upper = tid.left( 8 );
|
||||||
@ -521,19 +521,19 @@ bool MainWindow::InstallNUSItem( NusJob job )
|
|||||||
Ticket ticket( job.data.takeFirst() );
|
Ticket ticket( job.data.takeFirst() );
|
||||||
if( t.Tid() != job.tid || ticket.Tid() != job.tid )
|
if( t.Tid() != job.tid || ticket.Tid() != job.tid )
|
||||||
{
|
{
|
||||||
qWarning() << "bad tid";
|
qWarning() << "bad tid";
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
cnt = t.Count();
|
cnt = t.Count();
|
||||||
if( job.data.size() != cnt )
|
if( job.data.size() != cnt )
|
||||||
{
|
{
|
||||||
qWarning() << "content count";
|
qWarning() << "content count";
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
//qDebug() << "uidDirty" << uidDirty;
|
//qDebug() << "uidDirty" << uidDirty;
|
||||||
if( !uidDirty )
|
if( !uidDirty )
|
||||||
{
|
{
|
||||||
uidDirty = !uid.GetUid( job.tid, false );
|
uidDirty = !uid.GetUid( job.tid, false );
|
||||||
}
|
}
|
||||||
//qDebug() << "uidDirty" << uidDirty;
|
//qDebug() << "uidDirty" << uidDirty;
|
||||||
_uid = uid.GetUid( job.tid );
|
_uid = uid.GetUid( job.tid );
|
||||||
@ -541,8 +541,8 @@ bool MainWindow::InstallNUSItem( NusJob job )
|
|||||||
_gid = t.Gid();
|
_gid = t.Gid();
|
||||||
if( !_uid )
|
if( !_uid )
|
||||||
{
|
{
|
||||||
qWarning() << "no uid";
|
qWarning() << "no uid";
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
//create all the folders
|
//create all the folders
|
||||||
@ -566,15 +566,15 @@ bool MainWindow::InstallNUSItem( NusJob job )
|
|||||||
cnt = content->childCount();
|
cnt = content->childCount();
|
||||||
for ( quint16 i = 0; i < cnt; i++ )
|
for ( quint16 i = 0; i < cnt; i++ )
|
||||||
{
|
{
|
||||||
if( !nand.Delete( "/title/" + upper + "/" + lower + "/content/" + content->child( i )->text( 0 ) ) )
|
if( !nand.Delete( "/title/" + upper + "/" + lower + "/content/" + content->child( i )->text( 0 ) ) )
|
||||||
{ qWarning() << "error deleting old title"; goto error; }
|
{ qWarning() << "error deleting old title"; goto error; }
|
||||||
deleted = true;
|
deleted = true;
|
||||||
}
|
}
|
||||||
if( deleted )
|
if( deleted )
|
||||||
{
|
{
|
||||||
//nand.WriteMetaData();
|
//nand.WriteMetaData();
|
||||||
UpdateTree();
|
UpdateTree();
|
||||||
ShowMessage( tr( "Deleted old TMD and private contents for<br>%1" ).arg( title ) );
|
ShowMessage( tr( "Deleted old TMD and private contents for<br>%1" ).arg( title ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
cnt = t.Count();
|
cnt = t.Count();
|
||||||
@ -597,64 +597,64 @@ bool MainWindow::InstallNUSItem( NusJob job )
|
|||||||
//qDebug() << "will install" << cnt << "contents";
|
//qDebug() << "will install" << cnt << "contents";
|
||||||
for( quint16 i = 0; i < cnt; i++ )
|
for( quint16 i = 0; i < cnt; i++ )
|
||||||
{
|
{
|
||||||
//qDebug() << "installing" << i;
|
//qDebug() << "installing" << i;
|
||||||
//make sure the data is decrypted
|
//make sure the data is decrypted
|
||||||
QByteArray decData;
|
QByteArray decData;
|
||||||
QByteArray hash;
|
QByteArray hash;
|
||||||
if( job.decrypt )
|
if( job.decrypt )
|
||||||
{
|
{
|
||||||
decData = job.data.takeFirst();
|
decData = job.data.takeFirst();
|
||||||
if( (quint32)decData.size() != t.Size( i ) )
|
if( (quint32)decData.size() != t.Size( i ) )
|
||||||
{
|
{
|
||||||
qDebug() << "wtf - size";
|
qDebug() << "wtf - size";
|
||||||
decData.resize( t.Size( i ) );
|
decData.resize( t.Size( i ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//decrypt the data
|
//decrypt the data
|
||||||
QByteArray encData = job.data.takeFirst();
|
QByteArray encData = job.data.takeFirst();
|
||||||
AesSetKey( ticket.DecryptedKey() );
|
AesSetKey( ticket.DecryptedKey() );
|
||||||
decData = AesDecrypt( i, encData );
|
decData = AesDecrypt( i, encData );
|
||||||
decData.resize( t.Size( i ) );
|
decData.resize( t.Size( i ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
//check the hash
|
//check the hash
|
||||||
hash = GetSha1( decData );
|
hash = GetSha1( decData );
|
||||||
if( hash != t.Hash( i ) )
|
if( hash != t.Hash( i ) )
|
||||||
{
|
{
|
||||||
qWarning() << "hash" << i << "\n" << hash.toHex() << "\n" << t.Hash( i ).toHex();
|
qWarning() << "hash" << i << "\n" << hash.toHex() << "\n" << t.Hash( i ).toHex();
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
//install the content
|
//install the content
|
||||||
if( t.Type( i ) == 1 )//private
|
if( t.Type( i ) == 1 )//private
|
||||||
{
|
{
|
||||||
r = CreateIfNeeded( "/title/" + upper + "/" + lower + "/content/" + t.Cid( i ) + ".app" , 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 );
|
r = CreateIfNeeded( "/title/" + upper + "/" + lower + "/content/" + t.Cid( i ) + ".app" , 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 );
|
||||||
if( !r )
|
if( !r )
|
||||||
{
|
{
|
||||||
qWarning() << "cant create content" << i;
|
qWarning() << "cant create content" << i;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if ( !nand.SetData( r, decData ) )
|
if ( !nand.SetData( r, decData ) )
|
||||||
{
|
{
|
||||||
qWarning() << "cant write content" << i;
|
qWarning() << "cant write content" << i;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if( t.Type( i ) == 0x8001 )//shared
|
else if( t.Type( i ) == 0x8001 )//shared
|
||||||
{
|
{
|
||||||
if ( !InstallSharedContent( decData, hash ) )
|
if ( !InstallSharedContent( decData, hash ) )
|
||||||
{
|
{
|
||||||
qWarning() << "error installing shared" << i << hash.toHex();
|
qWarning() << "error installing shared" << i << hash.toHex();
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
qWarning() << "type" << hex << t.Type( i );
|
qWarning() << "type" << hex << t.Type( i );
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
qDebug() << "done installing";
|
qDebug() << "done installing";
|
||||||
ShowMessage( "Installed title " + title + " to nand" );
|
ShowMessage( "Installed title " + title + " to nand" );
|
||||||
@ -662,7 +662,7 @@ bool MainWindow::InstallNUSItem( NusJob job )
|
|||||||
//nand.Delete( "/title/" + upper );
|
//nand.Delete( "/title/" + upper );
|
||||||
//UpdateTree();
|
//UpdateTree();
|
||||||
return true;
|
return true;
|
||||||
error:
|
error:
|
||||||
ShowMessage( "<b>Error installing title " + title + " to nand</b>" );
|
ShowMessage( "<b>Error installing title " + title + " to nand</b>" );
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -671,9 +671,9 @@ error:
|
|||||||
void MainWindow::on_actionAbout_triggered()
|
void MainWindow::on_actionAbout_triggered()
|
||||||
{
|
{
|
||||||
QString txt = tr( "This is an example program from WiiQt. It is designed to write titles to a nand.bin and even create one from scratch."
|
QString txt = tr( "This is an example program from WiiQt. It is designed to write titles to a nand.bin and even create one from scratch."
|
||||||
"<br><br>PLEASE BE AWARE, THIS IS NOT VERY WELL TESTED AND AS OF RIGHT NOW."
|
"<br><br>PLEASE BE AWARE, THIS IS NOT VERY WELL TESTED AND AS OF RIGHT NOW."
|
||||||
" IT SHOULD ONLY BE USED BY PEOPLE THAT KNOW HOW TO VERIFY THE FILES IT PRODUCES. AND HAVE A WAY TO FIX A BRICKED WII SHOULD THIS PROGRAM HAVE BUGS"
|
" IT SHOULD ONLY BE USED BY PEOPLE THAT KNOW HOW TO VERIFY THE FILES IT PRODUCES. AND HAVE A WAY TO FIX A BRICKED WII SHOULD THIS PROGRAM HAVE BUGS"
|
||||||
"<br><br>YOU HAVE BEEN WARNED"
|
"<br><br>YOU HAVE BEEN WARNED"
|
||||||
"<br>giantpune" );
|
"<br>giantpune" );
|
||||||
QMessageBox::critical( this, tr( "About" ), txt );
|
QMessageBox::critical( this, tr( "About" ), txt );
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,9 @@ NewNandBin::NewNandBin( QWidget *parent, QList<quint16> badBlocks ) : QDialog(pa
|
|||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
foreach( quint16 block, badBlocks )
|
foreach( quint16 block, badBlocks )
|
||||||
{
|
{
|
||||||
QString txt = QString( "%1" ).arg( block );
|
QString txt = QString( "%1" ).arg( block );
|
||||||
if( !ui->listWidget_badBlocks->findItems( txt, Qt::MatchExactly ).isEmpty() )
|
if( !ui->listWidget_badBlocks->findItems( txt, Qt::MatchExactly ).isEmpty() )
|
||||||
ui->listWidget_badBlocks->addItem( txt );
|
ui->listWidget_badBlocks->addItem( txt );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ void NewNandBin::on_pushButton_keys_clicked()
|
|||||||
{
|
{
|
||||||
QString f = QFileDialog::getOpenFileName( this, tr( "Select Keys.bin" ), dir );
|
QString f = QFileDialog::getOpenFileName( this, tr( "Select Keys.bin" ), dir );
|
||||||
if( f.isEmpty() )
|
if( f.isEmpty() )
|
||||||
return;
|
return;
|
||||||
ui->lineEdit_keys->setText( f );
|
ui->lineEdit_keys->setText( f );
|
||||||
dir = QFileInfo( f ).canonicalPath();
|
dir = QFileInfo( f ).canonicalPath();
|
||||||
}
|
}
|
||||||
@ -32,7 +32,7 @@ void NewNandBin::on_pushButton_boot_clicked()
|
|||||||
{
|
{
|
||||||
QString f = QFileDialog::getOpenFileName( this, tr( "Select Boot 1 & 2" ), dir );
|
QString f = QFileDialog::getOpenFileName( this, tr( "Select Boot 1 & 2" ), dir );
|
||||||
if( f.isEmpty() )
|
if( f.isEmpty() )
|
||||||
return;
|
return;
|
||||||
ui->lineEdit_boot->setText( f );
|
ui->lineEdit_boot->setText( f );
|
||||||
dir = QFileInfo( f ).canonicalPath();
|
dir = QFileInfo( f ).canonicalPath();
|
||||||
}
|
}
|
||||||
@ -41,7 +41,7 @@ void NewNandBin::on_pushButton_dest_clicked()
|
|||||||
{
|
{
|
||||||
QString f = QFileDialog::getSaveFileName( this, tr( "Output file" ), dir );
|
QString f = QFileDialog::getSaveFileName( this, tr( "Output file" ), dir );
|
||||||
if( f.isEmpty() )
|
if( f.isEmpty() )
|
||||||
return;
|
return;
|
||||||
ui->lineEdit_dest->setText( f );
|
ui->lineEdit_dest->setText( f );
|
||||||
dir = QFileInfo( f ).canonicalPath();
|
dir = QFileInfo( f ).canonicalPath();
|
||||||
}
|
}
|
||||||
@ -52,10 +52,10 @@ QList<quint16> NewNandBin::BadBlocks()
|
|||||||
quint16 cnt = ui->listWidget_badBlocks->count();
|
quint16 cnt = ui->listWidget_badBlocks->count();
|
||||||
for( quint16 i = 0; i < cnt; i++ )
|
for( quint16 i = 0; i < cnt; i++ )
|
||||||
{
|
{
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
quint16 num = ui->listWidget_badBlocks->item( i )->text().toInt( &ok );
|
quint16 num = ui->listWidget_badBlocks->item( i )->text().toInt( &ok );
|
||||||
if( ok )
|
if( ok )
|
||||||
ret << num;
|
ret << num;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -65,7 +65,7 @@ void NewNandBin::on_pushButton_bb_add_clicked()
|
|||||||
quint16 val = ui->spinBox->value();
|
quint16 val = ui->spinBox->value();
|
||||||
if( !BadBlocks().contains( val ) )
|
if( !BadBlocks().contains( val ) )
|
||||||
{
|
{
|
||||||
ui->listWidget_badBlocks->addItem( QString( "%1" ).arg( val ) );
|
ui->listWidget_badBlocks->addItem( QString( "%1" ).arg( val ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,8 +74,8 @@ void NewNandBin::on_pushButton_bb_rm_clicked()
|
|||||||
QList<QListWidgetItem *> items = ui->listWidget_badBlocks->selectedItems();
|
QList<QListWidgetItem *> items = ui->listWidget_badBlocks->selectedItems();
|
||||||
foreach( QListWidgetItem *item, items )
|
foreach( QListWidgetItem *item, items )
|
||||||
{
|
{
|
||||||
ui->listWidget_badBlocks->removeItemWidget( item );
|
ui->listWidget_badBlocks->removeItemWidget( item );
|
||||||
delete item;
|
delete item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,35 +84,48 @@ void NewNandBin::on_buttonBox_accepted()
|
|||||||
{
|
{
|
||||||
if( ui->lineEdit_keys->text().isEmpty() || ui->lineEdit_boot->text().isEmpty() || ui->lineEdit_dest->text().isEmpty() )
|
if( ui->lineEdit_keys->text().isEmpty() || ui->lineEdit_boot->text().isEmpty() || ui->lineEdit_dest->text().isEmpty() )
|
||||||
{
|
{
|
||||||
QMessageBox::warning( this, tr( "Error" ), tr( "Required feilds are empty" ) );
|
QMessageBox::warning( this, tr( "Error" ), tr( "Required feilds are empty" ) );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QByteArray keys = ReadFile( ui->lineEdit_keys->text() );
|
QByteArray keys = ReadFile( ui->lineEdit_keys->text() );
|
||||||
QByteArray boots = ReadFile( ui->lineEdit_boot->text() );
|
QByteArray boots = ReadFile( ui->lineEdit_boot->text() );
|
||||||
if( keys.size() != 0x400 || boots.size() != 0x108000 )
|
if( keys.size() != 0x400 || boots.size() != 0x108000 )
|
||||||
{
|
{
|
||||||
QMessageBox::warning( this, tr( "Error" ), tr( "The keys or boot1/2 is not correct" ) );
|
QMessageBox::warning( this, tr( "Error" ), tr( "The keys or boot1/2 is not correct" ) );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if( !nand.CreateNew( ui->lineEdit_dest->text(), keys, boots, BadBlocks() ) )
|
if( !nand.CreateNew( ui->lineEdit_dest->text(), keys, boots, BadBlocks() ) )
|
||||||
{
|
{
|
||||||
qDebug() << "error creating nand.bin";
|
qDebug() << "error creating nand.bin";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
//qDebug() << "created nand, trying to add default entries";
|
//qDebug() << "created nand, trying to add default entries";
|
||||||
if( !nand.CreateEntry( "/sys", 0, 0, NAND_DIR, NAND_RW, NAND_RW, 0 )
|
if( !nand.CreateEntry( "/sys", 0, 0, NAND_DIR, NAND_RW, NAND_RW, 0 )
|
||||||
|| !nand.CreateEntry( "/ticket", 0, 0, NAND_DIR, NAND_RW, NAND_RW, 0 )
|
|| !nand.CreateEntry( "/ticket", 0, 0, NAND_DIR, NAND_RW, NAND_RW, 0 )
|
||||||
|| !nand.CreateEntry( "/title", 0, 0, NAND_DIR, NAND_RW, NAND_RW, NAND_READ )
|
|| !nand.CreateEntry( "/title", 0, 0, NAND_DIR, NAND_RW, NAND_RW, NAND_READ )
|
||||||
|| !nand.CreateEntry( "/shared1", 0, 0, NAND_DIR, NAND_RW, NAND_RW, 0 )
|
|| !nand.CreateEntry( "/shared1", 0, 0, NAND_DIR, NAND_RW, NAND_RW, 0 )
|
||||||
|| !nand.CreateEntry( "/shared2", 0, 0, NAND_DIR, NAND_RW, NAND_RW, NAND_RW )
|
|| !nand.CreateEntry( "/shared2", 0, 0, NAND_DIR, NAND_RW, NAND_RW, NAND_RW )
|
||||||
|| !nand.CreateEntry( "/import", 0, 0, NAND_DIR, NAND_RW, NAND_RW, 0 )
|
|| !nand.CreateEntry( "/import", 0, 0, NAND_DIR, NAND_RW, NAND_RW, 0 )
|
||||||
|| !nand.CreateEntry( "/meta", 0x1000, 1, NAND_DIR, NAND_RW, NAND_RW, NAND_RW )
|
|| !nand.CreateEntry( "/meta", 0x1000, 1, NAND_DIR, NAND_RW, NAND_RW, NAND_RW )
|
||||||
|| !nand.CreateEntry( "/tmp", 0, 0, NAND_DIR, NAND_RW, NAND_RW, NAND_RW )
|
|| !nand.CreateEntry( "/tmp", 0, 0, NAND_DIR, NAND_RW, NAND_RW, NAND_RW )
|
||||||
|| !nand.WriteMetaData() )
|
|| !nand.WriteMetaData() )
|
||||||
{
|
{
|
||||||
qWarning() << "NewNandBin::on_buttonBox_accepted -> error creating the new nand";
|
qWarning() << "NewNandBin::on_buttonBox_accepted -> error creating directories in the new nand";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
//add cert.sys
|
||||||
|
quint16 handle = nand.CreateEntry( "/sys/cert.sys", 0, 0, NAND_FILE, NAND_RW, NAND_RW, NAND_READ );
|
||||||
|
if( !handle || !nand.SetData( "/sys/cert.sys", QByteArray( (const char*)&certs_dat, CERTS_DAT_SIZE ) ) )
|
||||||
|
{
|
||||||
|
qWarning() << "NewNandBin::on_buttonBox_accepted -> error creating cert in the new nand";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//commit changes to metadata
|
||||||
|
if( !nand.WriteMetaData() )
|
||||||
|
{
|
||||||
|
qWarning() << "NewNandBin::on_buttonBox_accepted -> error writing metadata";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ret = ui->lineEdit_dest->text();
|
ret = ui->lineEdit_dest->text();
|
||||||
}
|
}
|
||||||
@ -121,7 +134,7 @@ QString NewNandBin::GetNewNandPath( QWidget *parent, QList<quint16> badBlocks )
|
|||||||
{
|
{
|
||||||
NewNandBin d( parent, badBlocks );
|
NewNandBin d( parent, badBlocks );
|
||||||
if( !d.exec() )
|
if( !d.exec() )
|
||||||
return QString();
|
return QString();
|
||||||
return d.ret;
|
return d.ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,13 +143,13 @@ void NewNandBin::on_pushButton_badBlockFile_clicked()
|
|||||||
{
|
{
|
||||||
QString f = QFileDialog::getOpenFileName( this, tr( "Select File with Bad Block List" ), dir );
|
QString f = QFileDialog::getOpenFileName( this, tr( "Select File with Bad Block List" ), dir );
|
||||||
if( f.isEmpty() )
|
if( f.isEmpty() )
|
||||||
return;
|
return;
|
||||||
dir = QFileInfo( f ).canonicalPath();
|
dir = QFileInfo( f ).canonicalPath();
|
||||||
QString str = QString( ReadFile( f ) );
|
QString str = QString( ReadFile( f ) );
|
||||||
if( str.isEmpty() )
|
if( str.isEmpty() )
|
||||||
{
|
{
|
||||||
qWarning() << "NewNandBin::on_pushButton_badBlockFile_clicked -> error reading file";
|
qWarning() << "NewNandBin::on_pushButton_badBlockFile_clicked -> error reading file";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ui->listWidget_badBlocks->clear();
|
ui->listWidget_badBlocks->clear();
|
||||||
|
|
||||||
@ -144,17 +157,17 @@ void NewNandBin::on_pushButton_badBlockFile_clicked()
|
|||||||
QStringList lines = str.split( "\n", QString::SkipEmptyParts );
|
QStringList lines = str.split( "\n", QString::SkipEmptyParts );
|
||||||
foreach( QString line, lines )
|
foreach( QString line, lines )
|
||||||
{
|
{
|
||||||
if( line.size() > 5 )
|
if( line.size() > 5 )
|
||||||
continue;
|
continue;
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
|
|
||||||
if( ui->listWidget_badBlocks->findItems( line, Qt::MatchExactly ).size() )//this one is already in the list
|
if( ui->listWidget_badBlocks->findItems( line, Qt::MatchExactly ).size() )//this one is already in the list
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
quint16 bb = line.toInt( &ok );
|
quint16 bb = line.toInt( &ok );
|
||||||
if( !ok || bb < 8 || bb > 4079 )
|
if( !ok || bb < 8 || bb > 4079 )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ui->listWidget_badBlocks->addItem( line );
|
ui->listWidget_badBlocks->addItem( line );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
this is a tool to list saves in an extracted nand dump
|
this is a tool to list/extract/delete saves to/from an extracted nand dump. saves are extracted, packed into a data.bin, zipped up with a txt file
|
||||||
|
that says a bit about the save, and then stored in a folder. you must designate a folder and provide the necessary keys before extracting saves
|
||||||
|
will work. i chose to go with data.bin as it is a way to store the entire save in 1 file and also allow the save to be installed using the
|
||||||
|
system menu. and i went with the zip format 1) to save space, and 2) to keep a save and the description all in 1 compact file.
|
||||||
|
|
||||||
|
saves are extracted to "<the folder you specify>/<TID upper>/<TID lower>/#.zip". the # is chosen by the lowest available number starting with 1.
|
||||||
|
there is no need for the saves to be in numerical order, if you have 10 zips for the same game and you decide to delete "3.zip", it will cause
|
||||||
|
no issues, and next time you extract a save for this game, it will use the filename "3.zip".
|
||||||
|
|
||||||
TODO:
|
TODO:
|
||||||
add some sort of extract/delete/install functionality
|
installing saves back to sneek nand still isnt done
|
||||||
|
Loading…
Reference in New Issue
Block a user