Refactored the "LockedFile" class + moved hash computation to a separate class, for clarity.

This commit is contained in:
LoRd_MuldeR 2015-08-30 13:47:08 +02:00
parent 9a00f1ce23
commit 1714af0a4d
15 changed files with 298 additions and 131 deletions

View File

@ -314,6 +314,7 @@ copy /Y "$(SolutionDir)\..\Prerequisites\Qt4\$(PlatformToolset)\Shared\plugins\i
<ClCompile Include="src\Encoder_Opus.cpp" /> <ClCompile Include="src\Encoder_Opus.cpp" />
<ClCompile Include="src\Encoder_Vorbis.cpp" /> <ClCompile Include="src\Encoder_Vorbis.cpp" />
<ClCompile Include="src\Encoder_Wave.cpp" /> <ClCompile Include="src\Encoder_Wave.cpp" />
<ClCompile Include="src\FileHash.cpp" />
<ClCompile Include="src\Filter_Abstract.cpp" /> <ClCompile Include="src\Filter_Abstract.cpp" />
<ClCompile Include="src\Filter_Downmix.cpp" /> <ClCompile Include="src\Filter_Downmix.cpp" />
<ClCompile Include="src\Filter_Normalize.cpp" /> <ClCompile Include="src\Filter_Normalize.cpp" />
@ -427,6 +428,7 @@ copy /Y "$(SolutionDir)\..\Prerequisites\Qt4\$(PlatformToolset)\Shared\plugins\i
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release_Static|Win32'">$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)</Outputs> <Outputs Condition="'$(Configuration)|$(Platform)'=='Release_Static|Win32'">$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)</Outputs> <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)</Outputs>
</CustomBuild> </CustomBuild>
<ClInclude Include="src\FileHash.h" />
<ClInclude Include="src\IPCCommands.h" /> <ClInclude Include="src\IPCCommands.h" />
<CustomBuild Include="src\Model_FileExts.h"> <CustomBuild Include="src\Model_FileExts.h">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp" "%(FullPath)"</Command> <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp" "%(FullPath)"</Command>

View File

@ -421,6 +421,9 @@
<ClCompile Include="tmp\LameXP\MOC_Model_FileExts.cpp"> <ClCompile Include="tmp\LameXP\MOC_Model_FileExts.cpp">
<Filter>Generated Files\MOC</Filter> <Filter>Generated Files\MOC</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\FileHash.cpp">
<Filter>Source Files\Misc</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="src\Config.h"> <ClInclude Include="src\Config.h">
@ -555,6 +558,9 @@
<ClInclude Include="src\MimeTypes.h"> <ClInclude Include="src\MimeTypes.h">
<Filter>Header Files\Misc</Filter> <Filter>Header Files\Misc</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\FileHash.h">
<Filter>Header Files\Misc</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="gui\DropBox.ui"> <CustomBuild Include="gui\DropBox.ui">

View File

@ -314,6 +314,7 @@ copy /Y "$(SolutionDir)\..\Prerequisites\Qt4\$(PlatformToolset)\Shared\plugins\i
<ClCompile Include="src\Encoder_Opus.cpp" /> <ClCompile Include="src\Encoder_Opus.cpp" />
<ClCompile Include="src\Encoder_Vorbis.cpp" /> <ClCompile Include="src\Encoder_Vorbis.cpp" />
<ClCompile Include="src\Encoder_Wave.cpp" /> <ClCompile Include="src\Encoder_Wave.cpp" />
<ClCompile Include="src\FileHash.cpp" />
<ClCompile Include="src\Filter_Abstract.cpp" /> <ClCompile Include="src\Filter_Abstract.cpp" />
<ClCompile Include="src\Filter_Downmix.cpp" /> <ClCompile Include="src\Filter_Downmix.cpp" />
<ClCompile Include="src\Filter_Normalize.cpp" /> <ClCompile Include="src\Filter_Normalize.cpp" />
@ -427,6 +428,7 @@ copy /Y "$(SolutionDir)\..\Prerequisites\Qt4\$(PlatformToolset)\Shared\plugins\i
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release_Static|Win32'">$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)</Outputs> <Outputs Condition="'$(Configuration)|$(Platform)'=='Release_Static|Win32'">$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)</Outputs>
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)</Outputs> <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp;%(Outputs)</Outputs>
</CustomBuild> </CustomBuild>
<ClInclude Include="src\FileHash.h" />
<ClInclude Include="src\IPCCommands.h" /> <ClInclude Include="src\IPCCommands.h" />
<CustomBuild Include="src\Model_FileExts.h"> <CustomBuild Include="src\Model_FileExts.h">
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp" "%(FullPath)"</Command> <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" -o "$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp" "%(FullPath)"</Command>

View File

@ -421,6 +421,9 @@
<ClCompile Include="tmp\LameXP\MOC_Model_FileExts.cpp"> <ClCompile Include="tmp\LameXP\MOC_Model_FileExts.cpp">
<Filter>Generated Files\MOC</Filter> <Filter>Generated Files\MOC</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="src\FileHash.cpp">
<Filter>Source Files\Misc</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="src\Config.h"> <ClInclude Include="src\Config.h">
@ -555,6 +558,9 @@
<ClInclude Include="src\MimeTypes.h"> <ClInclude Include="src\MimeTypes.h">
<Filter>Header Files\Misc</Filter> <Filter>Header Files\Misc</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\FileHash.h">
<Filter>Header Files\Misc</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="gui\DropBox.ui"> <CustomBuild Include="gui\DropBox.ui">

View File

@ -84,12 +84,12 @@
<ul> <ul>
<li>Upgraded build environment to Microsoft Visual Studio 2013 with Update-5<br /></li> <li>Upgraded build environment to Microsoft Visual Studio 2013 with Update-5<br /></li>
<li>Updated Qt runtime libraries to v4.8.7 Final (2015-05-25), compiled with MSVC 12.0<br /></li> <li>Updated Qt runtime libraries to v4.8.7 Final (2015-05-25), compiled with MSVC 12.0<br /></li>
<li>Added Hungarian translation, contributed by Zityi's Translator Team <script type="text/javascript"> <li>Added Hungarian translation, contributed by Zityi's Translator Team &lt;<script type="text/javascript">
<!-- <!--
h='&#x67;&#x6d;&#x61;&#x69;&#108;&#46;&#x63;&#x6f;&#x6d;';a='&#64;';n='&#122;&#x69;&#116;&#x79;&#x69;&#x73;&#x6f;&#102;&#116;';e=n+a+h; h='&#x67;&#x6d;&#x61;&#x69;&#108;&#46;&#x63;&#x6f;&#x6d;';a='&#64;';n='&#122;&#x69;&#116;&#x79;&#x69;&#x73;&#x6f;&#102;&#116;';e=n+a+h;
document.write('<a h'+'ref'+'="ma'+'ilto'+':'+e+'">'+e+'<\/'+'a'+'>'); document.write('<a h'+'ref'+'="ma'+'ilto'+':'+e+'">'+e+'<\/'+'a'+'>');
// --> // -->
</script><noscript>&#122;&#x69;&#116;&#x79;&#x69;&#x73;&#x6f;&#102;&#116;&#32;&#x61;&#116;&#32;&#x67;&#x6d;&#x61;&#x69;&#108;&#32;&#100;&#x6f;&#116;&#32;&#x63;&#x6f;&#x6d;</noscript><br /></li> </script><noscript>&#122;&#x69;&#116;&#x79;&#x69;&#x73;&#x6f;&#102;&#116;&#32;&#x61;&#116;&#32;&#x67;&#x6d;&#x61;&#x69;&#108;&#32;&#100;&#x6f;&#116;&#32;&#x63;&#x6f;&#x6d;</noscript>&gt;<br /></li>
<li>Added optional support for the <em>libfdk-aac</em> encoder, using the <a href="https://github.com/nu774/fdkaac">fdkaac</a> front-end by nu774<br /></li> <li>Added optional support for the <em>libfdk-aac</em> encoder, using the <a href="https://github.com/nu774/fdkaac">fdkaac</a> front-end by nu774<br /></li>
<li>Added detection of the <em>64-Bit</em> version of QAAC encoder, requires 64-Bit Apple Application Support<br /></li> <li>Added detection of the <em>64-Bit</em> version of QAAC encoder, requires 64-Bit Apple Application Support<br /></li>
<li>Added enhanced file renaming option: Default file extensions can now be overwritten<br /></li> <li>Added enhanced file renaming option: Default file extensions can now be overwritten<br /></li>

View File

@ -6,7 +6,7 @@
* Upgraded build environment to Microsoft Visual Studio 2013 with Update-5 * Upgraded build environment to Microsoft Visual Studio 2013 with Update-5
* Updated Qt runtime libraries to v4.8.7 Final (2015-05-25), compiled with MSVC 12.0 * Updated Qt runtime libraries to v4.8.7 Final (2015-05-25), compiled with MSVC 12.0
* Added Hungarian translation, contributed by Zityi's Translator Team <zityisoft@gmail.com> * Added Hungarian translation, contributed by Zityi's Translator Team <<zityisoft@gmail.com>>
* Added optional support for the *libfdk-aac* encoder, using the [fdkaac](https://github.com/nu774/fdkaac) front-end by nu774 * Added optional support for the *libfdk-aac* encoder, using the [fdkaac](https://github.com/nu774/fdkaac) front-end by nu774
* Added detection of the *64-Bit* version of QAAC encoder, requires 64-Bit Apple Application Support * Added detection of the *64-Bit* version of QAAC encoder, requires 64-Bit Apple Application Support
* Added enhanced file renaming option: Default file extensions can now be overwritten * Added enhanced file renaming option: Default file extensions can now be overwritten

View File

@ -526,6 +526,7 @@ FunctionEnd
Delete ${options} "$INSTDIR\vcruntime*.dll" Delete ${options} "$INSTDIR\vcruntime*.dll"
Delete ${options} "$INSTDIR\vccorlib*.dll" Delete ${options} "$INSTDIR\vccorlib*.dll"
RMDir /r ${options} "$INSTDIR\cache"
RMDir /r ${options} "$INSTDIR\img" RMDir /r ${options} "$INSTDIR\img"
RMDir /r ${options} "$INSTDIR\imageformats" RMDir /r ${options} "$INSTDIR\imageformats"
RMDir /r ${options} "$INSTDIR\redist" RMDir /r ${options} "$INSTDIR\redist"

View File

@ -35,7 +35,7 @@
#define VER_LAMEXP_MINOR_LO 2 #define VER_LAMEXP_MINOR_LO 2
#define VER_LAMEXP_TYPE Beta #define VER_LAMEXP_TYPE Beta
#define VER_LAMEXP_PATCH 6 #define VER_LAMEXP_PATCH 6
#define VER_LAMEXP_BUILD 1798 #define VER_LAMEXP_BUILD 1800
#define VER_LAMEXP_CONFG 1700 #define VER_LAMEXP_CONFG 1700
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -815,7 +815,7 @@ void AboutDialog::initSoftwareTab(void)
tr("dcaenc"), tr("dcaenc"),
"dcaenc.exe", "????-??-??", "dcaenc.exe", "????-??-??",
tr("Copyright (c) 2008-2011 Alexander E. Patrakov. Distributed under the LGPL."), tr("Copyright (c) 2008-2011 Alexander E. Patrakov. Distributed under the LGPL."),
"http://gitorious.org/dtsenc/dtsenc/trees/master" "https://gitlab.com/patrakov/dcaenc"
); );
moreAboutText += makeToolText moreAboutText += makeToolText
( (

68
src/FileHash.cpp Normal file
View File

@ -0,0 +1,68 @@
///////////////////////////////////////////////////////////////////////////////
// LameXP - Audio Encoder Front-End
// Copyright (C) 2004-2015 LoRd_MuldeR <MuldeR2@GMX.de>
//
// 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, but always including the *additional*
// restrictions defined in the "License.txt" file.
//
// 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 "FileHash.h"
//MUtils
#include <MUtils/Hash_Keccak.h>
#include <MUtils/Exception.h>
static const char *g_blnk = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef";
static const char *g_seed = "c375d83b4388329408dfcbb4d9a065b6e06d28272f25ef299c70b506e26600af79fd2f866ae24602daf38f25c9d4b7e1";
static const char *g_salt = "ee9f7bdabc170763d2200a7e3030045aafe380011aefc1730e547e9244c62308aac42a976feeca224ba553de0c4bb883";
QByteArray FileHash::computeHash(QFile &file)
{
QByteArray hash = QByteArray::fromHex(g_blnk);
if(file.isOpen() && file.reset())
{
MUtils::Hash::Keccak keccak;
const QByteArray data = file.readAll();
const QByteArray seed = QByteArray::fromHex(g_seed);
const QByteArray salt = QByteArray::fromHex(g_salt);
if(keccak.init(MUtils::Hash::Keccak::hb384))
{
bool ok = true;
ok = ok && keccak.addData(seed);
ok = ok && keccak.addData(data);
ok = ok && keccak.addData(salt);
if(ok)
{
const QByteArray digest = keccak.finalize();
if(!digest.isEmpty()) hash = digest.toHex();
}
}
}
return hash;
}
void FileHash::selfTest(void)
{
if(!MUtils::Hash::Keccak::selfTest())
{
MUTILS_THROW("QKeccakHash self-test has failed!");
}
}

37
src/FileHash.h Normal file
View File

@ -0,0 +1,37 @@
///////////////////////////////////////////////////////////////////////////////
// LameXP - Audio Encoder Front-End
// Copyright (C) 2004-2015 LoRd_MuldeR <MuldeR2@GMX.de>
//
// 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, but always including the *additional*
// restrictions defined in the "License.txt" file.
//
// 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
///////////////////////////////////////////////////////////////////////////////
#pragma once
#include <QFile>
#include <QByteArray>
class FileHash
{
public:
static QByteArray computeHash(QFile &file);
static void selfTest(void);
private:
FileHash() {}
~FileHash() {};
};

View File

@ -94,6 +94,11 @@ void lamexp_tools_register(const QString &toolName, LockedFile *const file, cons
{ {
QWriteLocker writeLock(&g_lamexp_tools_lock); QWriteLocker writeLock(&g_lamexp_tools_lock);
if(!file)
{
MUTILS_THROW("lamexp_register_tool: Tool file must not be NULL!");
}
if(g_lamexp_tools_data.isNull()) if(g_lamexp_tools_data.isNull())
{ {
g_lamexp_tools_data.reset(new tool_hash_t()); g_lamexp_tools_data.reset(new tool_hash_t());

View File

@ -21,11 +21,13 @@
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
#include "LockedFile.h" #include "LockedFile.h"
//Internal
#include "Global.h" #include "Global.h"
#include "FileHash.h"
//MUtils //MUtils
#include <MUtils/OSSupport.h> #include <MUtils/OSSupport.h>
#include <MUtils/Hash_Keccak.h>
#include <MUtils/Exception.h> #include <MUtils/Exception.h>
//Qt //Qt
@ -35,6 +37,7 @@
#include <QDir> #include <QDir>
#include <QCryptographicHash> #include <QCryptographicHash>
//CRT
#include <stdio.h> #include <stdio.h>
#include <io.h> #include <io.h>
#include <fcntl.h> #include <fcntl.h>
@ -67,63 +70,19 @@ static void CLOSE_HANDLE(HANDLE &h)
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
static const char *g_blnk = "deadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef"; static __forceinline void doWriteOutput(QFile &outFile, const QResource *const resource)
static const char *g_seed = "c375d83b4388329408dfcbb4d9a065b6e06d28272f25ef299c70b506e26600af79fd2f866ae24602daf38f25c9d4b7e1";
static const char *g_salt = "ee9f7bdabc170763d2200a7e3030045aafe380011aefc1730e547e9244c62308aac42a976feeca224ba553de0c4bb883";
QByteArray LockedFile::fileHash(QFile &file)
{ {
QByteArray hash = QByteArray::fromHex(g_blnk);
if(file.isOpen() && file.reset())
{
MUtils::Hash::Keccak keccak;
const QByteArray data = file.readAll();
const QByteArray seed = QByteArray::fromHex(g_seed);
const QByteArray salt = QByteArray::fromHex(g_salt);
if(keccak.init(MUtils::Hash::Keccak::hb384))
{
bool ok = true;
ok = ok && keccak.addData(seed);
ok = ok && keccak.addData(data);
ok = ok && keccak.addData(salt);
if(ok)
{
const QByteArray digest = keccak.finalize();
if(!digest.isEmpty()) hash = digest.toHex();
}
}
}
return hash;
}
///////////////////////////////////////////////////////////////////////////////
LockedFile::LockedFile(QResource *const resource, const QString &outPath, const QByteArray &expectedHash, const bool bOwnsFile)
:
m_bOwnsFile(bOwnsFile),
m_filePath(QFileInfo(outPath).absoluteFilePath())
{
m_fileDescriptor = -1;
HANDLE fileHandle = NULL;
//Make sure the resource is valid
if(!(resource->isValid() && resource->data()))
{
MUTILS_THROW_FMT("The resource at %p is invalid!", resource);
}
QFile outFile(m_filePath);
//Open output file
for(int i = 0; i < 64; i++) for(int i = 0; i < 64; i++)
{ {
if(outFile.open(QIODevice::WriteOnly)) break; if(outFile.open(QIODevice::WriteOnly))
if(!i) qWarning("Failed to open file on first attemp, retrying..."); {
Sleep(100); break;
}
if(i == 0)
{
qWarning("Failed to open file on first attemp, retrying...");
}
Sleep(25);
} }
//Write data to file //Write data to file
@ -142,40 +101,68 @@ LockedFile::LockedFile(QResource *const resource, const QString &outPath, const
//Close file after it has been written //Close file after it has been written
outFile.close(); outFile.close();
}
//Now lock the file! static __forceinline void doValidateFileExists(const QString &filePath)
{
QFileInfo existingFileInfo(filePath);
existingFileInfo.setCaching(false);
//Make sure the file exists, before we try to lock it
if((!existingFileInfo.exists()) || (!existingFileInfo.isFile()) || filePath.isEmpty())
{
MUTILS_THROW_FMT("File '%s' does not exist!", MUTILS_UTF8(filePath));
}
}
static __forceinline void doLockFile(HANDLE &fileHandle, const QString &filePath, QFile *const outFile)
{
for(int i = 0; i < 64; i++) for(int i = 0; i < 64; i++)
{ {
fileHandle = CreateFileW(MUTILS_WCHR(QDir::toNativeSeparators(m_filePath)), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL); fileHandle = CreateFileW(MUTILS_WCHR(QDir::toNativeSeparators(filePath)), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
if(VALID_HANDLE(fileHandle)) break; if(VALID_HANDLE(fileHandle))
if(!i) qWarning("Failed to lock file on first attemp, retrying..."); {
Sleep(100); break;
}
if(i == 0)
{
qWarning("Failed to lock file on first attemp, retrying...");
}
Sleep(25);
} }
//Locked successfully? //Locked successfully?
if(!VALID_HANDLE(fileHandle)) if(!VALID_HANDLE(fileHandle))
{ {
QFile::remove(QFileInfo(outFile).canonicalFilePath()); if(outFile)
MUTILS_THROW_FMT("File '%s' could not be locked!", MUTILS_UTF8(QFileInfo(m_filePath).fileName())); {
QFile::remove(QFileInfo(*outFile).canonicalFilePath());
}
MUTILS_THROW_FMT("File '%s' could not be locked!", MUTILS_UTF8(QFileInfo(filePath).fileName()));
}
} }
//Get file descriptor static __forceinline void doInitFileDescriptor(const HANDLE &fileHandle, int &fileDescriptor)
m_fileDescriptor = _open_osfhandle(reinterpret_cast<intptr_t>(fileHandle), _O_RDONLY | _O_BINARY); {
if(m_fileDescriptor < 0) fileDescriptor = _open_osfhandle(reinterpret_cast<intptr_t>(fileHandle), _O_RDONLY | _O_BINARY);
if(fileDescriptor < 0)
{ {
MUTILS_THROW_FMT("Failed to obtain C Runtime file descriptor!"); MUTILS_THROW_FMT("Failed to obtain C Runtime file descriptor!");
} }
}
static __forceinline void doValidateHash(HANDLE &fileHandle, const int &fileDescriptor, const QByteArray &expectedHash, const QString &filePath)
{
QFile checkFile; QFile checkFile;
//Now re-open the file for reading //Now re-open the file for reading
if(g_useFileDescrForQFile) if(g_useFileDescrForQFile)
{ {
checkFile.open(m_fileDescriptor, QIODevice::ReadOnly); checkFile.open(fileDescriptor, QIODevice::ReadOnly);
} }
else else
{ {
checkFile.setFileName(m_filePath); checkFile.setFileName(filePath);
for(int i = 0; i < 64; i++) for(int i = 0; i < 64; i++)
{ {
if(checkFile.open(QIODevice::ReadOnly)) break; if(checkFile.open(QIODevice::ReadOnly)) break;
@ -187,12 +174,12 @@ LockedFile::LockedFile(QResource *const resource, const QString &outPath, const
//Opened successfully //Opened successfully
if(!checkFile.isOpen()) if(!checkFile.isOpen())
{ {
QFile::remove(m_filePath); QFile::remove(filePath);
MUTILS_THROW_FMT("File '%s' could not be read!", MUTILS_UTF8(QFileInfo(m_filePath).fileName())); MUTILS_THROW_FMT("File '%s' could not be read!", MUTILS_UTF8(QFileInfo(filePath).fileName()));
} }
//Verify file contents //Verify file contents
const QByteArray hash = fileHash(checkFile); const QByteArray hash = FileHash::computeHash(checkFile);
checkFile.close(); checkFile.close();
//Compare hashes //Compare hashes
@ -200,11 +187,62 @@ LockedFile::LockedFile(QResource *const resource, const QString &outPath, const
{ {
qWarning("\nFile checksum error:\n A = %s\n B = %s\n", expectedHash.constData(), hash.constData()); qWarning("\nFile checksum error:\n A = %s\n B = %s\n", expectedHash.constData(), hash.constData());
CLOSE_HANDLE(fileHandle); CLOSE_HANDLE(fileHandle);
QFile::remove(m_filePath); QFile::remove(filePath);
MUTILS_THROW_FMT("File '%s' is corruputed, take care!", MUTILS_UTF8(QFileInfo(m_filePath).fileName())); MUTILS_THROW_FMT("File '%s' is corruputed, take care!", MUTILS_UTF8(QFileInfo(filePath).fileName()));
} }
} }
///////////////////////////////////////////////////////////////////////////////
LockedFile::LockedFile(QResource *const resource, const QString &outPath, const QByteArray &expectedHash, const bool bOwnsFile)
:
m_bOwnsFile(bOwnsFile),
m_filePath(QFileInfo(outPath).absoluteFilePath())
{
m_fileDescriptor = -1;
HANDLE fileHandle = NULL;
//Make sure the resource is valid
if(!(resource->isValid() && resource->data()))
{
MUTILS_THROW_FMT("The resource at %p is invalid!", resource);
}
//Write data to output file
QFile outFile(m_filePath);
doWriteOutput(outFile, resource);
//Now lock the file!
doLockFile(fileHandle, m_filePath, &outFile);
//Get file descriptor
doInitFileDescriptor(fileHandle, m_fileDescriptor);
//Validate file hash
doValidateHash(fileHandle, m_fileDescriptor, expectedHash, m_filePath);
}
LockedFile::LockedFile(const QString &filePath, const QByteArray &expectedHash, const bool bOwnsFile)
:
m_bOwnsFile(bOwnsFile),
m_filePath(QFileInfo(filePath).absoluteFilePath())
{
m_fileDescriptor = -1;
HANDLE fileHandle = NULL;
//Make sure the file exists, before we try to lock it
doValidateFileExists(m_filePath);
//Now lock the file!
doLockFile(fileHandle, m_filePath, NULL);
//Get file descriptor
doInitFileDescriptor(fileHandle, m_fileDescriptor);
//Validate file hash
doValidateHash(fileHandle, m_fileDescriptor, expectedHash, m_filePath);
}
LockedFile::LockedFile(const QString &filePath, const bool bOwnsFile) LockedFile::LockedFile(const QString &filePath, const bool bOwnsFile)
: :
m_bOwnsFile(bOwnsFile), m_bOwnsFile(bOwnsFile),
@ -213,36 +251,14 @@ LockedFile::LockedFile(const QString &filePath, const bool bOwnsFile)
m_fileDescriptor = -1; m_fileDescriptor = -1;
HANDLE fileHandle = NULL; HANDLE fileHandle = NULL;
QFileInfo existingFileInfo(filePath);
existingFileInfo.setCaching(false);
//Make sure the file exists, before we try to lock it //Make sure the file exists, before we try to lock it
if((!existingFileInfo.exists()) || (!existingFileInfo.isFile()) || m_filePath.isEmpty()) doValidateFileExists(m_filePath);
{
MUTILS_THROW_FMT("File '%s' does not exist!", MUTILS_UTF8(filePath));
}
//Now lock the file //Now lock the file!
for(int i = 0; i < 64; i++) doLockFile(fileHandle, m_filePath, NULL);
{
fileHandle = CreateFileW(MUTILS_WCHR(QDir::toNativeSeparators(m_filePath)), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
if(VALID_HANDLE(fileHandle)) break;
if(!i) qWarning("Failed to lock file on first attemp, retrying...");
Sleep(100);
}
//Locked successfully?
if(!VALID_HANDLE(fileHandle))
{
MUTILS_THROW_FMT("File '%s' could not be locked!", MUTILS_UTF8(QFileInfo(m_filePath).fileName()));
}
//Get file descriptor //Get file descriptor
m_fileDescriptor = _open_osfhandle(reinterpret_cast<intptr_t>(fileHandle), _O_RDONLY | _O_BINARY); doInitFileDescriptor(fileHandle, m_fileDescriptor);
if(m_fileDescriptor < 0)
{
MUTILS_THROW_FMT("Failed to obtain C Runtime file descriptor!");
}
} }
LockedFile::~LockedFile(void) LockedFile::~LockedFile(void)
@ -269,11 +285,3 @@ const QString &LockedFile::filePath()
{ {
return m_filePath; return m_filePath;
} }
void LockedFile::selfTest()
{
if(!MUtils::Hash::Keccak::selfTest())
{
MUTILS_THROW("QKeccakHash self-test has failed!");
}
}

View File

@ -31,14 +31,12 @@ class LockedFile
{ {
public: public:
LockedFile(QResource *const resource, const QString &outPath, const QByteArray &expectedHash = QByteArray(), const bool bOwnsFile = true); LockedFile(QResource *const resource, const QString &outPath, const QByteArray &expectedHash = QByteArray(), const bool bOwnsFile = true);
LockedFile(const QString &filePath, const QByteArray &expectedHash, const bool bOwnsFile = false);
LockedFile(const QString &filePath, const bool bOwnsFile = false); LockedFile(const QString &filePath, const bool bOwnsFile = false);
~LockedFile(void); ~LockedFile(void);
const QString &filePath(); const QString &filePath();
static void selfTest();
static QByteArray fileHash(QFile &file);
private: private:
const bool m_bOwnsFile; const bool m_bOwnsFile;
const QString m_filePath; const QString m_filePath;

View File

@ -26,6 +26,7 @@
#define LAMEXP_INC_TOOLS 1 #define LAMEXP_INC_TOOLS 1
#include "Tools.h" #include "Tools.h"
#include "LockedFile.h" #include "LockedFile.h"
#include "FileHash.h"
#include "Tool_Abstract.h" #include "Tool_Abstract.h"
//MUtils //MUtils
@ -49,6 +50,9 @@
#include <QElapsedTimer> #include <QElapsedTimer>
#include <QVector> #include <QVector>
/* enable custom tools? */
static const bool ENABLE_CUSTOM_TOOLS = true;
/* helper macros */ /* helper macros */
#define PRINT_CPU_TYPE(X) case X: qDebug("Selected CPU is: " #X) #define PRINT_CPU_TYPE(X) case X: qDebug("Selected CPU is: " #X)
#define MAKE_REGEXP(STR) (((STR) && ((STR)[0])) ? QRegExp((STR)) : QRegExp()) #define MAKE_REGEXP(STR) (((STR) && ((STR)[0])) ? QRegExp((STR)) : QRegExp())
@ -208,28 +212,58 @@ public:
protected: protected:
void taskMain(void) void taskMain(void)
{ {
LockedFile *lockedFile = NULL; QScopedPointer<LockedFile> lockedFile;
unsigned int version = m_toolVersion; unsigned int version = m_toolVersion;
QFileInfo toolFileInfo(m_toolName); const QFileInfo toolFileInfo(m_toolName);
const QString toolShortName = QString("%1.%2").arg(toolFileInfo.baseName().toLower(), toolFileInfo.suffix().toLower()); const QString toolShrtName = QString("%1.%2").arg(toolFileInfo.baseName().toLower(), toolFileInfo.suffix().toLower());
QFileInfo customTool(QString("%1/tools/%2/%3").arg(m_appDir.canonicalPath(), QString::number(lamexp_version_build()), toolShortName)); //Try to load a "custom" tool first
if(ENABLE_CUSTOM_TOOLS)
{
const QFileInfo customTool(QString("%1/tools/%2/%3").arg(m_appDir.canonicalPath(), QString::number(lamexp_version_build()), toolShrtName));
if(customTool.exists() && customTool.isFile()) if(customTool.exists() && customTool.isFile())
{ {
qDebug("Setting up file: %s <- %s", toolShortName.toLatin1().constData(), m_appDir.relativeFilePath(customTool.canonicalFilePath()).toLatin1().constData()); qDebug("Setting up file: %s <- %s", toolShrtName.toLatin1().constData(), m_appDir.relativeFilePath(customTool.canonicalFilePath()).toLatin1().constData());
lockedFile = new LockedFile(customTool.canonicalFilePath()); version = UINT_MAX; s_bCustom = true; try
}
else
{ {
qDebug("Extracting file: %s -> %s", m_toolName.toLatin1().constData(), toolShortName.toLatin1().constData()); lockedFile.reset(new LockedFile(customTool.canonicalFilePath()));
lockedFile = new LockedFile(m_toolResource.data(), QString("%1/lxp_%2").arg(MUtils::temp_folder(), toolShortName), m_toolHash); version = UINT_MAX; s_bCustom = true;
}
catch(std::runtime_error&)
{
lockedFile.reset();
}
}
} }
if(lockedFile) //Try to load the tool from the "cache" next
if(lockedFile.isNull())
{ {
lamexp_tools_register(toolShortName, lockedFile, version, m_toolTag); const QFileInfo chachedTool(QString("%1/cache/%2").arg(m_appDir.canonicalPath(), toolFileInfo.fileName()));
if(chachedTool.exists() && chachedTool.isFile())
{
qDebug("Validating file: %s <- %s", toolShrtName.toLatin1().constData(), m_appDir.relativeFilePath(chachedTool.canonicalFilePath()).toLatin1().constData());
try
{
lockedFile.reset(new LockedFile(chachedTool.canonicalFilePath(), m_toolHash));
} }
catch(std::runtime_error&)
{
lockedFile.reset();
}
}
}
//If still not initialized, extract tool now!
if(lockedFile.isNull())
{
qDebug("Extracting file: %s -> %s", m_toolName.toLatin1().constData(), toolShrtName.toLatin1().constData());
lockedFile.reset(new LockedFile(m_toolResource.data(), QString("%1/lxp_%2").arg(MUtils::temp_folder(), toolShrtName), m_toolHash));
}
//Register tool
lamexp_tools_register(toolShrtName, lockedFile.take(), version, m_toolTag);
} }
private: private:
@ -379,7 +413,7 @@ double InitializationThread::doInit(const size_t threadCount)
pool->setMaxThreadCount((threadCount > 0) ? threadCount : qBound(2U, cores2threads(m_cpuFeatures.count), EXPECTED_TOOL_COUNT)); pool->setMaxThreadCount((threadCount > 0) ? threadCount : qBound(2U, cores2threads(m_cpuFeatures.count), EXPECTED_TOOL_COUNT));
/* qWarning("Using %u threads for extraction.", pool->maxThreadCount()); */ /* qWarning("Using %u threads for extraction.", pool->maxThreadCount()); */
LockedFile::selfTest(); FileHash::selfTest();
ExtractorTask::clearFlags(); ExtractorTask::clearFlags();
//Start the timer //Start the timer
@ -697,7 +731,7 @@ void InitializationThread::selfTest(void)
{ {
const unsigned int cpu[4] = {CPU_TYPE_X86_GEN, CPU_TYPE_X86_SSE, CPU_TYPE_X64_GEN, CPU_TYPE_X64_SSE}; const unsigned int cpu[4] = {CPU_TYPE_X86_GEN, CPU_TYPE_X86_SSE, CPU_TYPE_X64_GEN, CPU_TYPE_X64_SSE};
LockedFile::selfTest(); FileHash::selfTest();
for(size_t k = 0; k < 4; k++) for(size_t k = 0; k < 4; k++)
{ {
@ -730,7 +764,7 @@ void InitializationThread::selfTest(void)
qFatal("The resource for \"%s\" could not be opened!", MUTILS_UTF8(toolName)); qFatal("The resource for \"%s\" could not be opened!", MUTILS_UTF8(toolName));
break; break;
} }
QByteArray hash = LockedFile::fileHash(resource); QByteArray hash = FileHash::computeHash(resource);
if(hash.isNull() || _stricmp(hash.constData(), expectedHash.constData())) if(hash.isNull() || _stricmp(hash.constData(), expectedHash.constData()))
{ {
qFatal("Hash check for tool \"%s\" has failed!", MUTILS_UTF8(toolName)); qFatal("Hash check for tool \"%s\" has failed!", MUTILS_UTF8(toolName));