* nandBin: add format()

* ohneswanzenegger: allow using format on an already existing nand.bin

git-svn-id: http://wiiqt.googlecode.com/svn/trunk@62 389f4c8b-5dfe-645f-db0e-df882bc27289
This commit is contained in:
giantpune@gmail.com 2011-01-18 19:30:36 +00:00
parent 192789e01f
commit 6b5441637b
6 changed files with 178 additions and 20 deletions

View File

@ -48,7 +48,14 @@ bool NandBin::SetPath( const QString &path )
return ret; return ret;
} }
#if 0 // apparently you dont need any extra reserved blocks for the thing to boot? const QString NandBin::FilePath()
{
if( !f.isOpen() )
return QString();
return QFileInfo( f ).absoluteFilePath();
}
//#if 0 // apparently you dont need any extra reserved blocks for the thing to boot?
bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByteArray &first8, const QList<quint16> &badBlocks ) bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByteArray &first8, const QList<quint16> &badBlocks )
{ {
#ifndef NAND_BIN_CAN_WRITE #ifndef NAND_BIN_CAN_WRITE
@ -73,7 +80,7 @@ bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByt
} }
f.write( first8 ); f.write( first8 );
QByteArray block( 0x4200, 0xff );//generic empty block QByteArray block( 0x4200, 0xff );//generic empty cluster
for( quint16 i = 0; i < 0x7fc0; i++ ) for( quint16 i = 0; i < 0x7fc0; i++ )
f.write( block ); f.write( block );
@ -87,7 +94,7 @@ bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByt
//setup variables //setup variables
nandPath = path; nandPath = path;
currentSuperCluster = 0x7f00; currentSuperCluster = 0x7f00;
superClusterVersion = 0xf0000000; superClusterVersion = 1;
type = 2; type = 2;
fats.clear(); fats.clear();
memset( &fsts, 0, sizeof( fst_t ) * 0x17ff ); memset( &fsts, 0, sizeof( fst_t ) * 0x17ff );
@ -100,16 +107,6 @@ bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByt
{ {
fats << 0xfffc; fats << 0xfffc;
} }
//find 90 blocks to reserve. they always appear to be close to the end of the nand
//TODO - this isnt always 90, all my nands have a different number, and 90 is right in the middle
//quint16 bCnt = badBlocks.size();
/*quint16 offset = 0;
for( quint16 i = 0; i < bCnt; i++ )
{
if( i >= 3998 )
offset++;
}*/
//mark all the "normal" blocks - free, or bad //mark all the "normal" blocks - free, or bad
for( quint16 i = 0x40; i < 0x7f00; i++ ) for( quint16 i = 0x40; i < 0x7f00; i++ )
{ {
@ -119,7 +116,7 @@ bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByt
fats << 0xfffe; fats << 0xfffe;
} }
//mark the 90 reserved ones from above and reserve the superclusters //reserve the superclusters
for( quint16 i = 0x7f00; i < 0x8000; i++ ) for( quint16 i = 0x7f00; i < 0x8000; i++ )
{ {
fats << 0xfffc; fats << 0xfffc;
@ -156,8 +153,67 @@ bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByt
return true; return true;
} }
//#endif
bool NandBin::Format( bool secure )
{
#ifndef NAND_BIN_CAN_WRITE
qWarning() << __FILE__ << "was built without write support";
return false;
#endif #endif
//#if 0 // this boots ok on real HW if( !f.isOpen() || fats.size() != 0x8000 )
{
qWarning() << "NandBin::Format -> error" << hex << fats.size() << f.isOpen();
return false;
}
//mark any currently used clusters free
QByteArray cluster( 0x4200, 0xff );//generic empty cluster
for( quint16 i = 0x40; i < 0x7f00; i++ )
{
if( fats.at( i ) >= 0xf000 && fats.at( i ) != 0xfffe ) //preserve special marked ones
continue;
fats[ i ] = 0xfffe; //free the cluster
if( !secure )
continue;
f.seek( 0x4200 * i ); //overwrite anything there with the unused cluster
f.write( cluster );
}
//reset fsts
memset( &fsts, 0, sizeof( fst_t ) * 0x17ff );
for( quint16 i = 0; i < 0x17ff; i++ )
fsts[ i ].fst_pos = i;
//make the root item
fsts[ 0 ].filename[ 0 ] = '/';
fsts[ 0 ].attr = 0x16;
fsts[ 0 ].sib = 0xffff;
fsts[ 0 ].sub = 0xffff;
//write the metada to each of the superblocks
for( quint8 i = 0; i < 0x10; i++ )
{
if( !WriteMetaData() )
{
qWarning() << "NandBin::Format -> error writing superblock" << i;
return false;
}
}
//build the tree
if( root )
delete root;
root = new QTreeWidgetItem( QStringList() << nandPath );
AddChildren( root, 0 );
return true;
}
#if 0 // this boots ok on real HW. trap15 thinks these reserved blocks are IOS's way of marking ones it thinks are bad
bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByteArray &first8, const QList<quint16> &badBlocks ) bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByteArray &first8, const QList<quint16> &badBlocks )
{ {
#ifndef NAND_BIN_CAN_WRITE #ifndef NAND_BIN_CAN_WRITE
@ -283,7 +339,7 @@ bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByt
return true; return true;
} }
//#endif #endif
QTreeWidgetItem *NandBin::GetTree() QTreeWidgetItem *NandBin::GetTree()
{ {
//qDebug() << "NandBin::GetTree()"; //qDebug() << "NandBin::GetTree()";

View File

@ -134,6 +134,14 @@ public:
//expects 0x7f00 - 0x7ff0 //expects 0x7f00 - 0x7ff0
bool CheckHmacMeta( quint16 clNo ); bool CheckHmacMeta( quint16 clNo );
//wipe out all data within the nand FS, leaving only the root entry
//preserve all bad/reserved clusters
//if secure is true, overwrite old file data with 0xff
bool Format( bool secure = true );
//get the path of this nand
const QString FilePath();
private: private:
QByteArray key; QByteArray key;

View File

@ -266,6 +266,7 @@ void MainWindow::on_pushButton_nandPath_clicked()
return; return;
ui->lineEdit_nandPath->setText( f ); ui->lineEdit_nandPath->setText( f );
InitNand( ui->lineEdit_nandPath->text() );
} }
void MainWindow::on_pushButton_CachePathBrowse_clicked() void MainWindow::on_pushButton_CachePathBrowse_clicked()
@ -452,7 +453,6 @@ bool MainWindow::InitNand( const QString &path )
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" );
nandInited = true; nandInited = true;
ui->menuContent->setEnabled( true ); ui->menuContent->setEnabled( true );
@ -899,3 +899,90 @@ void MainWindow::on_actionWrite_meta_entries_triggered()
{ {
AddStuffToMetaFolder(); AddStuffToMetaFolder();
} }
//content -> format
void MainWindow::on_actionFormat_triggered()
{
if( nand.FilePath().isEmpty() )
return;
if( QMessageBox::warning( this, tr( "Format" ), \
tr( "You are about to format<br>%1.<br><br>This cannot be undone. Are you sure you want to do it?" ).arg( nand.FilePath() ),\
QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
return;
ShowMessage( "Formatting nand..." );
if( !nand.Format() )
{
ShowMessage( "<b>Error! This nand may be broken now :(</b>" );
return;
}
//add folders to root
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( "/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( "/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( "/meta", 0x1000, 1, NAND_DIR, NAND_RW, NAND_RW, NAND_RW )
|| !nand.CreateEntry( "/tmp", 0, 0, NAND_DIR, NAND_RW, NAND_RW, NAND_RW ) )
{
ShowMessage( "<b>Error! Can't create base folders in the new nand.</b>" );
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( handle, QByteArray( (const char*)&certs_dat, CERTS_DAT_SIZE ) ) )
{
ShowMessage( "<b>Error! Can't cert.sys.</b>" );
return;
}
//wipe all user-created entries from uid.sys
QByteArray uidData = uid.Data();
QBuffer buf( &uidData );
buf.open( QIODevice::ReadWrite );
quint64 tid;
quint16 titles = 0;
quint32 cnt = uidData.size() / 12;
for( quint32 i = 0; i < cnt; i++ )
{
buf.seek( i * 12 );
buf.read( (char*)&tid, 8 );
tid = qFromBigEndian( tid );
quint32 upper = ( ( tid >> 32 ) & 0xffffffff );
quint32 lower = ( tid & 0xffffffff );
qDebug() << hex << i << QString( "%1" ).arg( tid, 16, 16, QChar( '0' ) ) << upper << lower << QChar( ( lower >> 24 ) & 0xff ) << ( lower & 0xffffff00 );
if( ( upper == 0x10001 && ( ( lower >> 24 ) & 0xff ) != 0x48 ) || //a channel, not starting with 'H'
( upper == 0x10000 && ( ( lower & 0xffffff00 ) == 0x555000 ) ) ) //a disc update partition
break;
titles++;
}
buf.close();
uidData.resize( 12 * titles );
hexdump12( uidData );
uid = UIDmap( uidData );
//clear content.map
shared = SharedContentMap();
if( !nand.CreateEntry( "/sys/uid.sys", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ) )
{
ShowMessage( "<b>Error! Can't /sys/uid.sys</b>" );
return;
}
if( !nand.CreateEntry( "/shared1/content.map", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ) )
{
ShowMessage( "<b>Error! Can't /shared1/content.map</b>" );
return;
}
//commit
if( !nand.WriteMetaData() || !UpdateTree() )
{
ShowMessage( "<b>Error finalizing formatting!</b>" );
return;
}
ShowMessage( "Done!" );
}

View File

@ -62,6 +62,7 @@ public slots:
void ReceiveTitleFromNus( NusJob job ); void ReceiveTitleFromNus( NusJob job );
private slots: private slots:
void on_actionFormat_triggered();
void on_actionWrite_meta_entries_triggered(); void on_actionWrite_meta_entries_triggered();
void on_pushButton_CachePathBrowse_clicked(); void on_pushButton_CachePathBrowse_clicked();
void on_actionAbout_triggered(); void on_actionAbout_triggered();

View File

@ -198,6 +198,7 @@
<addaction name="actionFlush"/> <addaction name="actionFlush"/>
<addaction name="actionSetting_txt"/> <addaction name="actionSetting_txt"/>
<addaction name="actionWrite_meta_entries"/> <addaction name="actionWrite_meta_entries"/>
<addaction name="actionFormat"/>
</widget> </widget>
<addaction name="menuNand_Dump"/> <addaction name="menuNand_Dump"/>
<addaction name="menuContent"/> <addaction name="menuContent"/>
@ -248,6 +249,11 @@
<string>Write meta entries</string> <string>Write meta entries</string>
</property> </property>
</action> </action>
<action name="actionFormat">
<property name="text">
<string>Format</string>
</property>
</action>
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<resources/> <resources/>

View File

@ -353,7 +353,7 @@ QByteArray NewNandBin::GetCleanUid( QByteArray old )
quint32 lower = ( tid & 0xffffffff ); quint32 lower = ( tid & 0xffffffff );
//qDebug() << QString( "%1" ).arg( tid, 16, 16, QChar( '0' ) ) << hex << upper << lower << ( ( lower >> 24 ) & 0xff ) << ( lower & 0xffff00 ); //qDebug() << QString( "%1" ).arg( tid, 16, 16, QChar( '0' ) ) << hex << upper << lower << ( ( lower >> 24 ) & 0xff ) << ( lower & 0xffff00 );
if( ( upper == 0x10001 && ( ( lower >> 24 ) & 0xff ) != 0x48 ) || //a channel, not starting with 'H' if( ( upper == 0x10001 && ( ( lower >> 24 ) & 0xff ) != 0x48 ) || //a channel, not starting with 'H'
( upper == 0x10000 && ( ( lower & 0xffff00 ) == 0x555000 ) ) ) //a disc update partition ( upper == 0x10000 && ( ( lower & 0xffffff00 ) == 0x555000 ) ) ) //a disc update partition
break; break;
titles++; titles++;