2019-11-01 20:00:28 +00:00
/*
Copyright ( c ) 2017 - 2018 Adubbz
Permission is hereby granted , free of charge , to any person obtaining a copy
of this software and associated documentation files ( the " Software " ) , to deal
in the Software without restriction , including without limitation the rights
to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
copies of the Software , and to permit persons to whom the Software is
furnished to do so , subject to the following conditions :
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software .
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE .
*/
2019-10-18 03:59:34 +00:00
# include "install/install_nsp.hpp"
# include <cstdlib>
# include <cstring>
# include <stdexcept>
# include <memory>
# include <string>
# include <machine/endian.h>
# include "nx/ncm.hpp"
2019-11-16 04:13:30 +00:00
# include "install/nca.hpp"
# include "util/config.hpp"
# include "util/crypto.hpp"
2019-11-03 18:18:42 +00:00
# include "nx/nca_writer.h"
2019-10-22 22:14:37 +00:00
# include "util/debug.h"
# include "util/error.hpp"
2019-11-16 04:13:30 +00:00
# include "util/file_util.hpp"
# include "util/title_util.hpp"
2019-10-25 01:33:41 +00:00
# include "nspInstall.hpp"
2019-11-16 04:13:30 +00:00
# include "ui/MainApplication.hpp"
namespace inst : : ui {
extern MainApplication * mainApp ;
}
2019-10-18 03:59:34 +00:00
namespace tin : : install : : nsp
{
2019-11-14 19:04:40 +00:00
NSPInstallTask : : NSPInstallTask ( tin : : install : : nsp : : SimpleFileSystem & simpleFileSystem , NcmStorageId destStorageId , bool ignoreReqFirmVersion ) :
2019-10-18 03:59:34 +00:00
Install ( destStorageId , ignoreReqFirmVersion ) , m_simpleFileSystem ( & simpleFileSystem )
{
}
std : : tuple < nx : : ncm : : ContentMeta , NcmContentInfo > NSPInstallTask : : ReadCNMT ( )
{
NcmContentInfo cnmtRecord = tin : : util : : CreateNSPCNMTContentRecord ( this - > m_simpleFileSystem - > m_absoluteRootPath . substr ( 0 , this - > m_simpleFileSystem - > m_absoluteRootPath . size ( ) - 1 ) ) ;
nx : : ncm : : ContentStorage contentStorage ( m_destStorageId ) ;
this - > InstallNCA ( cnmtRecord . content_id ) ;
std : : string cnmtNCAFullPath = contentStorage . GetPath ( cnmtRecord . content_id ) ;
return { tin : : util : : GetContentMetaFromNCA ( cnmtNCAFullPath ) , cnmtRecord } ;
}
2019-11-03 18:18:42 +00:00
2019-10-18 03:59:34 +00:00
void NSPInstallTask : : InstallTicketCert ( )
{
// Read the tik file and put it into a buffer
auto tikName = m_simpleFileSystem - > GetFileNameFromExtension ( " " , " tik " ) ;
printf ( " > Getting tik size \n " ) ;
auto tikFile = m_simpleFileSystem - > OpenFile ( tikName ) ;
u64 tikSize = tikFile . GetSize ( ) ;
auto tikBuf = std : : make_unique < u8 [ ] > ( tikSize ) ;
printf ( " > Reading tik \n " ) ;
tikFile . Read ( 0x0 , tikBuf . get ( ) , tikSize ) ;
// Read the cert file and put it into a buffer
auto certName = m_simpleFileSystem - > GetFileNameFromExtension ( " " , " cert " ) ;
printf ( " > Getting cert size \n " ) ;
auto certFile = m_simpleFileSystem - > OpenFile ( certName ) ;
u64 certSize = certFile . GetSize ( ) ;
auto certBuf = std : : make_unique < u8 [ ] > ( certSize ) ;
printf ( " > Reading cert \n " ) ;
certFile . Read ( 0x0 , certBuf . get ( ) , certSize ) ;
// Finally, let's actually import the ticket
ASSERT_OK ( esImportTicket ( tikBuf . get ( ) , tikSize , certBuf . get ( ) , certSize ) , " Failed to import ticket " ) ;
2019-10-18 19:01:51 +00:00
//consoleUpdate(NULL);
2019-10-18 03:59:34 +00:00
}
2019-10-25 01:33:41 +00:00
void NSPInstallTask : : InstallNCA ( const NcmContentId & ncaId )
2019-10-18 03:59:34 +00:00
{
std : : string ncaName = tin : : util : : GetNcaIdString ( ncaId ) ;
if ( m_simpleFileSystem - > HasFile ( ncaName + " .nca " ) )
ncaName + = " .nca " ;
else if ( m_simpleFileSystem - > HasFile ( ncaName + " .cnmt.nca " ) )
ncaName + = " .cnmt.nca " ;
2019-11-03 18:18:42 +00:00
else if ( m_simpleFileSystem - > HasFile ( ncaName + " .ncz " ) )
ncaName + = " .ncz " ;
else if ( m_simpleFileSystem - > HasFile ( ncaName + " .cnmt.ncz " ) )
ncaName + = " .cnmt.ncz " ;
2019-10-18 03:59:34 +00:00
else
{
throw std : : runtime_error ( ( " Failed to find NCA file " + ncaName + " .nca/.cnmt.nca " ) . c_str ( ) ) ;
}
printf ( " NcaId: %s \n " , ncaName . c_str ( ) ) ;
printf ( " Dest storage Id: %u \n " , m_destStorageId ) ;
2019-11-03 18:18:42 +00:00
std : : shared_ptr < nx : : ncm : : ContentStorage > contentStorage ( new nx : : ncm : : ContentStorage ( m_destStorageId ) ) ;
2019-10-18 03:59:34 +00:00
// Attempt to delete any leftover placeholders
try
{
2019-11-09 14:09:31 +00:00
contentStorage - > DeletePlaceholder ( * ( NcmPlaceHolderId * ) & ncaId ) ;
2019-10-18 03:59:34 +00:00
}
catch ( . . . ) { }
auto ncaFile = m_simpleFileSystem - > OpenFile ( ncaName ) ;
2019-11-16 04:13:30 +00:00
if ( inst : : config : : validateNCAs )
{
tin : : install : : NcaHeader header ;
ncaFile . Read ( 0 , & header , 0xc00 ) ;
Crypto : : AesXtr crypto ( Crypto : : Keys ( ) . headerKey ) ;
crypto . decrypt ( & header , & header , sizeof ( header ) , 0 , 0x200 ) ;
if ( header . magic ! = MAGIC_NCA3 )
throw " Invalid NCA magic " ;
if ( ! Crypto : : rsa2048PssVerify ( & header . magic , 0x200 , header . fixed_key_sig , Crypto : : NCAHeaderSignature ) )
{
int rc = inst : : ui : : mainApp - > CreateShowDialog ( " NCA validation failed " , " The followings NCA's signature failed: \n " + tin : : util : : GetNcaIdString ( ncaId ) + " \n \n Do you really want to risk bricking your switch? " , { " No " , " Of cause not " , " *sigh* Yes " , " Cancel " } , true ) ;
if ( rc ! = 2 )
return ; // should be a throw but that will get stuck and idk sh my head...
}
}
2019-10-18 03:59:34 +00:00
size_t ncaSize = ncaFile . GetSize ( ) ;
u64 fileOff = 0 ;
size_t readSize = 0x400000 ; // 4MB buff
auto readBuffer = std : : make_unique < u8 [ ] > ( readSize ) ;
if ( readBuffer = = NULL )
throw std : : runtime_error ( ( " Failed to allocate read buffer for " + ncaName ) . c_str ( ) ) ;
printf ( " Size: 0x%lx \n " , ncaSize ) ;
2019-11-03 18:18:42 +00:00
2019-11-16 02:18:01 +00:00
NcaWriter writer ( ncaId , contentStorage ) ;
2019-11-03 18:18:42 +00:00
2019-10-18 03:59:34 +00:00
float progress ;
2019-11-16 02:18:01 +00:00
bool failed = false ;
2019-10-18 03:59:34 +00:00
2019-10-18 19:01:51 +00:00
//consoleUpdate(NULL);
2019-11-03 18:18:42 +00:00
2019-11-03 20:01:41 +00:00
try
{
inst : : ui : : setInstInfoText ( " Installing " + ncaName + " ... " ) ;
inst : : ui : : setInstBarPerc ( 0 ) ;
while ( fileOff < ncaSize )
{
// Clear the buffer before we read anything, just to be sure
progress = ( float ) fileOff / ( float ) ncaSize ;
if ( fileOff % ( 0x400000 * 3 ) = = 0 ) {
printf ( " > Progress: %lu/%lu MB (%d%s) \r " , ( fileOff / 1000000 ) , ( ncaSize / 1000000 ) , ( int ) ( progress * 100.0 ) , " % " ) ;
inst : : ui : : setInstBarPerc ( ( double ) ( progress * 100.0 ) ) ;
}
if ( fileOff + readSize > = ncaSize ) readSize = ncaSize - fileOff ;
ncaFile . Read ( fileOff , readBuffer . get ( ) , readSize ) ;
writer . write ( readBuffer . get ( ) , readSize ) ;
fileOff + = readSize ;
//consoleUpdate(NULL);
}
2019-11-04 00:13:10 +00:00
inst : : ui : : setInstBarPerc ( 100 ) ;
2019-11-03 20:01:41 +00:00
}
catch ( . . . )
{
2019-11-16 02:18:01 +00:00
failed = true ;
2019-11-03 20:01:41 +00:00
}
writer . close ( ) ;
2019-10-18 03:59:34 +00:00
// Clean up the line for whatever comes next
printf ( " \r " ) ;
printf ( " Registering placeholder... \n " ) ;
2019-11-03 18:18:42 +00:00
2019-11-16 02:18:01 +00:00
if ( ! failed )
2019-10-18 03:59:34 +00:00
{
2019-11-16 02:18:01 +00:00
try
{
contentStorage - > Register ( * ( NcmPlaceHolderId * ) & ncaId , ncaId ) ;
}
catch ( . . . )
{
printf ( ( " Failed to register " + ncaName + " . It may already exist. \n " ) . c_str ( ) ) ;
}
2019-10-18 03:59:34 +00:00
}
try
{
2019-11-09 14:09:31 +00:00
contentStorage - > DeletePlaceholder ( * ( NcmPlaceHolderId * ) & ncaId ) ;
2019-10-18 03:59:34 +00:00
}
catch ( . . . ) { }
}
2019-11-03 18:18:42 +00:00
}