diff --git a/WiiQt/nandbin.cpp b/WiiQt/nandbin.cpp index fb07df0..807c3c2 100755 --- a/WiiQt/nandbin.cpp +++ b/WiiQt/nandbin.cpp @@ -48,7 +48,14 @@ bool NandBin::SetPath( const QString &path ) 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 &badBlocks ) { #ifndef NAND_BIN_CAN_WRITE @@ -73,7 +80,7 @@ bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByt } f.write( first8 ); - QByteArray block( 0x4200, 0xff );//generic empty block + QByteArray block( 0x4200, 0xff );//generic empty cluster for( quint16 i = 0; i < 0x7fc0; i++ ) f.write( block ); @@ -87,7 +94,7 @@ bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByt //setup variables nandPath = path; currentSuperCluster = 0x7f00; - superClusterVersion = 0xf0000000; + superClusterVersion = 1; type = 2; fats.clear(); memset( &fsts, 0, sizeof( fst_t ) * 0x17ff ); @@ -100,16 +107,6 @@ bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByt { 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 for( quint16 i = 0x40; i < 0x7f00; i++ ) { @@ -119,7 +116,7 @@ bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByt fats << 0xfffe; } - //mark the 90 reserved ones from above and reserve the superclusters + //reserve the superclusters for( quint16 i = 0x7f00; i < 0x8000; i++ ) { fats << 0xfffc; @@ -156,8 +153,67 @@ bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByt return true; } +//#endif + +bool NandBin::Format( bool secure ) +{ +#ifndef NAND_BIN_CAN_WRITE + qWarning() << __FILE__ << "was built without write support"; + return false; #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 &badBlocks ) { #ifndef NAND_BIN_CAN_WRITE @@ -283,7 +339,7 @@ bool NandBin::CreateNew( const QString &path, const QByteArray &keys, const QByt return true; } -//#endif +#endif QTreeWidgetItem *NandBin::GetTree() { //qDebug() << "NandBin::GetTree()"; diff --git a/WiiQt/nandbin.h b/WiiQt/nandbin.h index b78bae6..a159afc 100755 --- a/WiiQt/nandbin.h +++ b/WiiQt/nandbin.h @@ -134,6 +134,14 @@ public: //expects 0x7f00 - 0x7ff0 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: QByteArray key; diff --git a/ohneschwanzenegger/mainwindow.cpp b/ohneschwanzenegger/mainwindow.cpp index 74cfd91..a3e2119 100644 --- a/ohneschwanzenegger/mainwindow.cpp +++ b/ohneschwanzenegger/mainwindow.cpp @@ -266,6 +266,7 @@ void MainWindow::on_pushButton_nandPath_clicked() return; ui->lineEdit_nandPath->setText( f ); + InitNand( ui->lineEdit_nandPath->text() ); } void MainWindow::on_pushButton_CachePathBrowse_clicked() @@ -451,8 +452,7 @@ bool MainWindow::InitNand( const QString &path ) shared = SharedContentMap( ba ); if( !shared.Check() )//i really dont want to create a new one and rewrite all the contents to match it ShowMessage( "Something about the shared map isnt right, but im using it anyways" ); - } - //nand.Delete( "/title/00000001/00000002/content/title.tmd" ); + } nandInited = true; ui->menuContent->setEnabled( true ); @@ -899,3 +899,90 @@ void MainWindow::on_actionWrite_meta_entries_triggered() { 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
%1.

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( "Error! This nand may be broken now :(" ); + 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( "Error! Can't create base folders in the new nand." ); + 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( "Error! Can't cert.sys." ); + 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( "Error! Can't /sys/uid.sys" ); + return; + } + if( !nand.CreateEntry( "/shared1/content.map", 0, 0, NAND_FILE, NAND_RW, NAND_RW, 0 ) ) + { + ShowMessage( "Error! Can't /shared1/content.map" ); + return; + } + + //commit + if( !nand.WriteMetaData() || !UpdateTree() ) + { + ShowMessage( "Error finalizing formatting!" ); + return; + } + ShowMessage( "Done!" ); +} diff --git a/ohneschwanzenegger/mainwindow.h b/ohneschwanzenegger/mainwindow.h index 8d1a3c6..30c231e 100644 --- a/ohneschwanzenegger/mainwindow.h +++ b/ohneschwanzenegger/mainwindow.h @@ -62,7 +62,8 @@ public slots: void ReceiveTitleFromNus( NusJob job ); private slots: - void on_actionWrite_meta_entries_triggered(); + void on_actionFormat_triggered(); + void on_actionWrite_meta_entries_triggered(); void on_pushButton_CachePathBrowse_clicked(); void on_actionAbout_triggered(); void on_pushButton_initNand_clicked(); diff --git a/ohneschwanzenegger/mainwindow.ui b/ohneschwanzenegger/mainwindow.ui index ffe7479..3470e6f 100644 --- a/ohneschwanzenegger/mainwindow.ui +++ b/ohneschwanzenegger/mainwindow.ui @@ -198,6 +198,7 @@ + @@ -248,6 +249,11 @@ Write meta entries + + + Format + + diff --git a/ohneschwanzenegger/newnandbin.cpp b/ohneschwanzenegger/newnandbin.cpp index e71db11..b56a88f 100644 --- a/ohneschwanzenegger/newnandbin.cpp +++ b/ohneschwanzenegger/newnandbin.cpp @@ -353,7 +353,7 @@ QByteArray NewNandBin::GetCleanUid( QByteArray old ) quint32 lower = ( tid & 0xffffffff ); //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' - ( upper == 0x10000 && ( ( lower & 0xffff00 ) == 0x555000 ) ) ) //a disc update partition + ( upper == 0x10000 && ( ( lower & 0xffffff00 ) == 0x555000 ) ) ) //a disc update partition break; titles++;