2010-11-06 23:04:47 +01:00
///////////////////////////////////////////////////////////////////////////////
// LameXP - Audio Encoder Front-End
2013-02-08 23:50:51 +01:00
// Copyright (C) 2004-2013 LoRd_MuldeR <MuldeR2@GMX.de>
2010-11-06 23:04:47 +01:00
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//
// http://www.gnu.org/licenses/gpl-2.0.txt
///////////////////////////////////////////////////////////////////////////////
# include "LockedFile.h"
# include "Global.h"
# include <QResource>
# include <QFile>
# include <QFileInfo>
# include <QDir>
# include <QCryptographicHash>
2012-11-12 00:32:39 +01:00
# include <QKeccakHash>
2010-11-06 23:04:47 +01:00
2011-06-26 19:21:00 +02:00
# include <stdio.h>
# include <io.h>
# include <fcntl.h>
2013-10-06 19:28:12 +02:00
//Windows includes
# define NOMINMAX
# define WIN32_LEAN_AND_MEAN
# include <Windows.h>
2011-06-26 19:21:00 +02:00
///////////////////////////////////////////////////////////////////////////////
2011-06-23 16:50:02 +02:00
# define THROW(STR) \
{ \
char error_msg [ 512 ] ; \
strcpy_s ( error_msg , 512 , STR ) ; \
throw error_msg ; \
}
2011-06-26 19:21:00 +02:00
// WARNING: Passing file descriptors into Qt does NOT work with dynamically linked CRT!
# ifdef QT_NODLL
static const bool g_useFileDescr = 1 ;
# else
static const bool g_useFileDescr = 0 ;
# endif
///////////////////////////////////////////////////////////////////////////////
2012-11-12 00:32:39 +01:00
static const char * g_blnk = " deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef " ;
static const char * g_seed = " c375d83b4388329408dfcbb4d9a065b6e06d28272f25ef299c70b506e26600af79fd2f866ae24602daf38f25c9d4b7e1 " ;
static const char * g_salt = " ee9f7bdabc170763d2200a7e3030045aafe380011aefc1730e547e9244c62308aac42a976feeca224ba553de0c4bb883 " ;
2011-07-02 16:38:46 +02:00
static QByteArray fileHash ( QFile & file )
{
2012-11-12 00:32:39 +01:00
QByteArray hash = QByteArray : : fromHex ( g_blnk ) ;
2011-07-02 16:38:46 +02:00
if ( file . isOpen ( ) & & file . reset ( ) )
{
2012-11-12 00:32:39 +01:00
QKeccakHash keccak ;
2011-07-02 16:38:46 +02:00
2012-11-27 01:02:55 +01:00
const QByteArray data = file . readAll ( ) ;
const QByteArray seed = QByteArray : : fromHex ( g_seed ) ;
const QByteArray salt = QByteArray : : fromHex ( g_salt ) ;
2012-11-12 00:32:39 +01:00
2012-11-27 01:02:55 +01:00
if ( keccak . init ( QKeccakHash : : hb384 ) )
2011-07-02 16:38:46 +02:00
{
2012-11-27 01:02:55 +01:00
bool ok = true ;
ok = ok & & keccak . addData ( seed ) ;
ok = ok & & keccak . addData ( data ) ;
ok = ok & & keccak . addData ( salt ) ;
if ( ok )
2012-11-12 00:32:39 +01:00
{
2012-11-27 01:02:55 +01:00
const QByteArray digest = keccak . finalize ( ) ;
if ( ! digest . isEmpty ( ) ) hash = digest . toHex ( ) ;
2012-11-12 00:32:39 +01:00
}
2011-07-02 16:38:46 +02:00
}
}
return hash ;
}
///////////////////////////////////////////////////////////////////////////////
LockedFile : : LockedFile ( const QString & resourcePath , const QString & outPath , const QByteArray & expectedHash )
2010-11-06 23:04:47 +01:00
{
m_fileHandle = NULL ;
QResource resource ( resourcePath ) ;
2011-06-23 16:50:02 +02:00
//Make sure the resource is valid
if ( ! resource . isValid ( ) )
{
THROW ( QString ( " Resource '%1' is invalid! " ) . arg ( QFileInfo ( resourcePath ) . absoluteFilePath ( ) . replace ( QRegExp ( " ^:/ " ) , QString ( ) ) ) . toUtf8 ( ) . constData ( ) ) ;
}
QFile outFile ( outPath ) ;
2010-11-06 23:04:47 +01:00
m_filePath = QFileInfo ( outFile ) . absoluteFilePath ( ) ;
2011-06-23 16:50:02 +02:00
//Open output file
for ( int i = 0 ; i < 64 ; i + + )
{
if ( outFile . open ( QIODevice : : WriteOnly ) ) break ;
if ( ! i ) qWarning ( " Failed to open file on first attemp, retrying... " ) ;
Sleep ( 100 ) ;
}
2010-11-06 23:04:47 +01:00
//Write data to file
2011-06-23 16:50:02 +02:00
if ( outFile . isOpen ( ) & & outFile . isWritable ( ) )
2010-11-06 23:04:47 +01:00
{
if ( outFile . write ( reinterpret_cast < const char * > ( resource . data ( ) ) , resource . size ( ) ) ! = resource . size ( ) )
{
2010-11-15 22:07:46 +01:00
QFile : : remove ( QFileInfo ( outFile ) . canonicalFilePath ( ) ) ;
2011-06-23 16:50:02 +02:00
THROW ( QString ( " File '%1' could not be written! " ) . arg ( QFileInfo ( outFile ) . fileName ( ) ) . toUtf8 ( ) . constData ( ) ) ;
2010-11-06 23:04:47 +01:00
}
outFile . close ( ) ;
}
else
{
2011-06-23 16:50:02 +02:00
THROW ( QString ( " File '%1' could not be created! " ) . arg ( QFileInfo ( outFile ) . fileName ( ) ) . toUtf8 ( ) . constData ( ) ) ;
2010-11-06 23:04:47 +01:00
}
2011-06-21 14:35:46 +02:00
//Now lock the file!
2011-06-21 16:23:42 +02:00
for ( int i = 0 ; i < 64 ; i + + )
2011-06-21 14:35:46 +02:00
{
2011-06-21 16:23:42 +02:00
m_fileHandle = CreateFileW ( QWCHAR ( QDir : : toNativeSeparators ( m_filePath ) ) , GENERIC_READ , FILE_SHARE_READ , NULL , OPEN_EXISTING , NULL , NULL ) ;
if ( ( m_fileHandle ! = NULL ) & & ( m_fileHandle ! = INVALID_HANDLE_VALUE ) ) break ;
2011-06-23 16:50:02 +02:00
if ( ! i ) qWarning ( " Failed to lock file on first attemp, retrying... " ) ;
2011-06-21 14:35:46 +02:00
Sleep ( 100 ) ;
}
2011-06-21 16:23:42 +02:00
//Locked successfully?
2011-06-21 14:35:46 +02:00
if ( ( m_fileHandle = = NULL ) | | ( m_fileHandle = = INVALID_HANDLE_VALUE ) )
2010-11-06 23:04:47 +01:00
{
2010-11-15 22:07:46 +01:00
QFile : : remove ( QFileInfo ( outFile ) . canonicalFilePath ( ) ) ;
2010-11-11 22:58:02 +01:00
char error_msg [ 512 ] ;
strcpy_s ( error_msg , 512 , QString ( " File '%1' could not be locked! " ) . arg ( QFileInfo ( outFile ) . fileName ( ) ) . toLatin1 ( ) . constData ( ) ) ;
2010-11-06 23:04:47 +01:00
throw error_msg ;
}
2011-06-26 19:21:00 +02:00
//Open file for reading
if ( g_useFileDescr )
{
int fd = _open_osfhandle ( reinterpret_cast < intptr_t > ( m_fileHandle ) , _O_RDONLY | _O_BINARY ) ;
if ( fd > = 0 ) outFile . open ( fd , QIODevice : : ReadOnly ) ;
}
else
{
for ( int i = 0 ; i < 64 ; i + + )
{
if ( outFile . open ( QIODevice : : ReadOnly ) ) break ;
if ( ! i ) qWarning ( " Failed to re-open file on first attemp, retrying... " ) ;
Sleep ( 100 ) ;
}
}
2010-11-06 23:04:47 +01:00
//Verify file contents
2011-07-02 16:38:46 +02:00
QByteArray hash ;
if ( outFile . isOpen ( ) )
2010-11-06 23:04:47 +01:00
{
2012-11-12 00:32:39 +01:00
hash = fileHash ( outFile ) ;
2010-11-06 23:04:47 +01:00
outFile . close ( ) ;
}
2011-06-21 14:35:46 +02:00
else
{
2011-06-26 19:21:00 +02:00
QFile : : remove ( m_filePath ) ;
2011-06-23 16:50:02 +02:00
THROW ( QString ( " File '%1' could not be read! " ) . arg ( QFileInfo ( outFile ) . fileName ( ) ) . toLatin1 ( ) . constData ( ) ) ;
2011-06-21 14:35:46 +02:00
}
2010-11-06 23:04:47 +01:00
2011-02-23 02:19:50 +01:00
//Compare hashes
2011-07-02 16:38:46 +02:00
if ( hash . isNull ( ) | | _stricmp ( hash . constData ( ) , expectedHash . constData ( ) ) )
2010-11-06 23:04:47 +01:00
{
2011-07-06 23:30:43 +02:00
qWarning ( " \n File checksum error: \n A = %s \n B = %s \n " , expectedHash . constData ( ) , hash . constData ( ) ) ;
2010-11-06 23:04:47 +01:00
LAMEXP_CLOSE ( m_fileHandle ) ;
2011-06-26 19:21:00 +02:00
QFile : : remove ( m_filePath ) ;
2011-06-23 16:50:02 +02:00
THROW ( QString ( " File '%1' is corruputed, take care! " ) . arg ( QFileInfo ( resourcePath ) . absoluteFilePath ( ) . replace ( QRegExp ( " ^:/ " ) , QString ( ) ) ) . toLatin1 ( ) . constData ( ) ) ;
2010-11-11 22:58:02 +01:00
}
}
LockedFile : : LockedFile ( const QString & filePath )
{
m_fileHandle = NULL ;
QFileInfo existingFile ( filePath ) ;
2011-02-23 02:19:50 +01:00
existingFile . setCaching ( false ) ;
2010-11-11 22:58:02 +01:00
2011-02-23 02:19:50 +01:00
//Make sure the file exists, before we try to lock it
2010-11-11 22:58:02 +01:00
if ( ! existingFile . exists ( ) )
{
char error_msg [ 256 ] ;
strcpy_s ( error_msg , 256 , QString ( " File '%1' does not exist! " ) . arg ( existingFile . fileName ( ) ) . toLatin1 ( ) . constData ( ) ) ;
throw error_msg ;
}
2010-12-03 23:01:17 +01:00
//Remember file path
m_filePath = existingFile . canonicalFilePath ( ) ;
2010-11-11 22:58:02 +01:00
//Now lock the file
2011-06-21 16:23:42 +02:00
for ( int i = 0 ; i < 64 ; i + + )
2011-02-23 02:19:50 +01:00
{
m_fileHandle = CreateFileW ( QWCHAR ( QDir : : toNativeSeparators ( filePath ) ) , GENERIC_READ , FILE_SHARE_READ , NULL , OPEN_EXISTING , NULL , NULL ) ;
if ( ( m_fileHandle ! = NULL ) & & ( m_fileHandle ! = INVALID_HANDLE_VALUE ) ) break ;
2011-06-23 16:50:02 +02:00
if ( ! i ) qWarning ( " Failed to lock file on first attemp, retrying... " ) ;
2011-02-23 02:19:50 +01:00
Sleep ( 100 ) ;
}
2010-11-11 22:58:02 +01:00
2011-02-23 02:19:50 +01:00
//Locked successfully?
if ( ( m_fileHandle = = NULL ) | | ( m_fileHandle = = INVALID_HANDLE_VALUE ) )
2010-11-11 22:58:02 +01:00
{
2011-06-23 16:50:02 +02:00
THROW ( QString ( " File '%1' could not be locked! " ) . arg ( existingFile . fileName ( ) ) . toLatin1 ( ) . constData ( ) ) ;
2010-11-06 23:04:47 +01:00
}
}
LockedFile : : ~ LockedFile ( void )
{
LAMEXP_CLOSE ( m_fileHandle ) ;
}
const QString & LockedFile : : filePath ( )
{
return m_filePath ;
2012-11-27 01:02:55 +01:00
}
void LockedFile : : selfTest ( )
{
if ( ! QKeccakHash : : selfTest ( ) )
{
qFatal ( " QKeccakHash self-test has failed! " ) ;
}
}