Improved temp_folder() function + we will now clean-up the TEMP folder on application exit.

This commit is contained in:
LoRd_MuldeR 2014-11-25 02:17:11 +01:00
parent 570289edb4
commit 2086c3dde6
9 changed files with 305 additions and 110 deletions

View File

@ -27,6 +27,7 @@
<ClInclude Include="include\MUtils\Global.h" /> <ClInclude Include="include\MUtils\Global.h" />
<ClInclude Include="include\MUtils\KeccakHash.h" /> <ClInclude Include="include\MUtils\KeccakHash.h" />
<ClInclude Include="include\MUtils\OSSupport.h" /> <ClInclude Include="include\MUtils\OSSupport.h" />
<ClInclude Include="src\DirLocker.h" />
<CustomBuild Include="include\Mutils\UpdateChecker.h"> <CustomBuild Include="include\Mutils\UpdateChecker.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>
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">MOC "$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp"</Message> <Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">MOC "$(SolutionDir)tmp\$(ProjectName)\MOC_%(Filename).cpp"</Message>

View File

@ -59,6 +59,9 @@
<ClInclude Include="include\MUtils\KeccakHash.h"> <ClInclude Include="include\MUtils\KeccakHash.h">
<Filter>Public Headers</Filter> <Filter>Public Headers</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="src\DirLocker.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="include\Mutils\UpdateChecker.h"> <CustomBuild Include="include\Mutils\UpdateChecker.h">

View File

@ -50,17 +50,24 @@ class QProcess;
//Check Debug Flags //Check Debug Flags
#if defined(_DEBUG) || defined(DEBUG) || (!defined(NDEBUG)) #if defined(_DEBUG) || defined(DEBUG) || (!defined(NDEBUG))
# define MUTILS_DEBUG 1 # define MUTILS_DEBUG (1)
# if defined(NDEBUG) || defined(QT_NO_DEBUG) || (!defined(QT_DEBUG)) # if defined(NDEBUG) || defined(QT_NO_DEBUG) || (!defined(QT_DEBUG))
# error Inconsistent DEBUG flags have been detected! # error Inconsistent DEBUG flags have been detected!
# endif # endif
#else #else
# define MUTILS_DEBUG 0 # define MUTILS_DEBUG (0)
# if (!defined(NDEBUG)) || (!defined(QT_NO_DEBUG)) || defined(QT_DEBUG) # if (!defined(NDEBUG)) || (!defined(QT_NO_DEBUG)) || defined(QT_DEBUG)
# error Inconsistent DEBUG flags have been detected! # error Inconsistent DEBUG flags have been detected!
# endif # endif
#endif #endif
//Check CPU options
#if defined(_MSC_VER) && (!defined(_M_X64)) && defined(_M_IX86_FP)
#if (_M_IX86_FP != 0)
#error We should not enabled SSE or SSE2 in release builds!
#endif
#endif
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
namespace MUtils namespace MUtils
@ -77,9 +84,14 @@ namespace MUtils
MUTILS_API quint32 next_rand32(void); MUTILS_API quint32 next_rand32(void);
MUTILS_API quint64 next_rand64(void); MUTILS_API quint64 next_rand64(void);
//Remove File/Dir
MUTILS_API bool remove_file(const QString &fileName);
MUTILS_API bool remove_directory(const QString &folderPath);
//Version //Version
MUTILS_API const char* mutils_build_date(void); MUTILS_API const char* mutils_build_date(void);
MUTILS_API const char* mutils_build_time(void); MUTILS_API const char* mutils_build_time(void);
//Internal //Internal
namespace Internal namespace Internal
{ {
@ -110,6 +122,10 @@ while(0)
} \ } \
while(0) while(0)
#define MUTILS_QSTR2WCHAR(STR) (reinterpret_cast<const wchar_t*>((STR).utf16())) //String conversion macros
#define MUTILS_QSTR2QUTF8(STR) ((STR).toUtf8().constData()) #define MUTILS_WCHR(STR) (reinterpret_cast<const wchar_t*>((STR).utf16()))
#define MUTILS_WCHAR2QSTR(STR) (QString::fromUtf16(reinterpret_cast<const unsigned short*>((STR)))) #define MUTILS_UTF8(STR) ((STR).toUtf8().constData())
#define MUTILS_QSTR(STR) (QString::fromUtf16(reinterpret_cast<const unsigned short*>((STR))))
//Boolean helper
#define MUTILS_BOOL2STR(X) ((X) ? "1" : "0")

View File

@ -31,17 +31,17 @@
namespace MUtils namespace MUtils
{ {
class MUTILS_API Version class Version
{ {
public: public:
//Get Build Date //Get Build Date
static const QDate build_date(const char *const date_str = build_date_raw()); MUTILS_API static const QDate build_date(const char *const date_str = build_date_raw());
//Get Build Time //Get Build Time
static const QTime build_time(const char *const time_str = build_time_raw()); MUTILS_API static const QTime build_time(const char *const time_str = build_time_raw());
//Compiler detection //Compiler detection
static const char *const compiler_version(void) MUTILS_API static const char *const compiler_version(void)
{ {
#if defined(__INTEL_COMPILER) #if defined(__INTEL_COMPILER)
#if (__INTEL_COMPILER >= 1500) #if (__INTEL_COMPILER >= 1500)
@ -109,7 +109,7 @@ namespace MUtils
} }
//Architecture detection //Architecture detection
static const char *const compiler_arch(void) MUTILS_API static const char *const compiler_arch(void)
{ {
#if defined(_M_X64) #if defined(_M_X64)
static const char *const COMPILER_ARCH = "x64"; static const char *const COMPILER_ARCH = "x64";
@ -130,7 +130,7 @@ namespace MUtils
return RAW_BUILD_DATE; return RAW_BUILD_DATE;
} }
//Raw Build date //Raw Build time
static const char *const build_time_raw(void) static const char *const build_time_raw(void)
{ {
static const char *const RAW_BUILD_TIME = __TIME__; static const char *const RAW_BUILD_TIME = __TIME__;

View File

@ -29,70 +29,76 @@
// CRITICAL SECTION // CRITICAL SECTION
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
/* namespace MUtils
* wrapper for native Win32 critical sections
*/
class CriticalSection
{ {
public: namespace Internal
inline CriticalSection(void)
{ {
InitializeCriticalSection(&m_win32criticalSection); /*
} * wrapper for native Win32 critical sections
*/
inline ~CriticalSection(void) class CriticalSection
{
DeleteCriticalSection(&m_win32criticalSection);
}
inline void enter(void)
{
EnterCriticalSection(&m_win32criticalSection);
}
inline bool tryEnter(void)
{
return TryEnterCriticalSection(&m_win32criticalSection);
}
inline void leave(void)
{
LeaveCriticalSection(&m_win32criticalSection);
}
protected:
CRITICAL_SECTION m_win32criticalSection;
};
/*
* RAII-style critical section locker
*/
class CSLocker
{
public:
inline CSLocker(CriticalSection &criticalSection)
:
m_locked(false),
m_criticalSection(criticalSection)
{
m_criticalSection.enter();
m_locked = true;
}
inline ~CSLocker(void)
{
forceUnlock();
}
inline void forceUnlock(void)
{
if(m_locked)
{ {
m_criticalSection.leave(); public:
m_locked = false; inline CriticalSection(void)
} {
InitializeCriticalSection(&m_win32criticalSection);
}
inline ~CriticalSection(void)
{
DeleteCriticalSection(&m_win32criticalSection);
}
inline void enter(void)
{
EnterCriticalSection(&m_win32criticalSection);
}
inline bool tryEnter(void)
{
return TryEnterCriticalSection(&m_win32criticalSection);
}
inline void leave(void)
{
LeaveCriticalSection(&m_win32criticalSection);
}
protected:
CRITICAL_SECTION m_win32criticalSection;
};
/*
* RAII-style critical section locker
*/
class CSLocker
{
public:
inline CSLocker(CriticalSection &criticalSection)
:
m_locked(false),
m_criticalSection(criticalSection)
{
m_criticalSection.enter();
m_locked = true;
}
inline ~CSLocker(void)
{
forceUnlock();
}
inline void forceUnlock(void)
{
if(m_locked)
{
m_criticalSection.leave();
m_locked = false;
}
}
protected:
volatile bool m_locked;
CriticalSection &m_criticalSection;
};
} }
protected: }
volatile bool m_locked;
CriticalSection &m_criticalSection;
};

112
src/DirLocker.h Normal file
View File

@ -0,0 +1,112 @@
///////////////////////////////////////////////////////////////////////////////
// MuldeR's Utilities for Qt
// Copyright (C) 2004-2014 LoRd_MuldeR <MuldeR2@GMX.de>
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
// http://www.gnu.org/licenses/lgpl-2.1.txt
//////////////////////////////////////////////////////////////////////////////////
#pragma once
//MUtils
#include <MUtils/Global.h>
//StdLib
#include <stdexcept>
//Qt
#include <QString>
#include <QFile>
///////////////////////////////////////////////////////////////////////////////
// Directory Locker
///////////////////////////////////////////////////////////////////////////////
namespace MUtils
{
namespace Internal
{
class DirLockException : public std::runtime_error
{
public:
DirLockException(const char *const message)
:
std::runtime_error(message)
{
}
};
class DirLock
{
public:
DirLock(const QString dirPath)
:
m_dirPath(dirPath)
{
if(m_dirPath.isEmpty())
{
throw DirLockException("Path must not be empty!");
}
const QByteArray testData = QByteArray(TEST_DATA);
bool okay = false;
for(int i = 0; i < 32; i++)
{
m_lockFile.reset(new QFile(QString("%1/~%2.lck").arg(m_dirPath, MUtils::rand_str())));
if(m_lockFile->open(QIODevice::WriteOnly | QIODevice::Truncate))
{
if(m_lockFile->write(testData) >= testData.size())
{
okay = true;
break;
}
m_lockFile->remove();
}
}
if(!okay)
{
throw DirLockException("Locking has failed!");
}
}
~DirLock(void)
{
if(!m_lockFile.isNull())
{
m_lockFile->remove();
}
for(int i = 0; i < 8; i++)
{
if(MUtils::remove_directory(m_dirPath))
{
break;
}
}
}
inline const QString &path(void) const
{
return m_dirPath;
}
private:
static const char *const TEST_DATA;
const QString m_dirPath;
QScopedPointer<QFile> m_lockFile;
};
const char *const DirLock::TEST_DATA = "7QtDxPWotHGQYv1xHyQHFKjTB5u5VYKHE20NMDAgLRYoy16CZN7mEYijbjCJpORnoBbtHCzqyy1a6BLCMMiTUZpLzgjg4qnN505egUBqk3wMhPsYjFpkng9i37mWd1iF";
}
}

View File

@ -23,8 +23,10 @@
#define _CRT_RAND_S 1 #define _CRT_RAND_S 1
#endif #endif
//MUtils
#include <MUtils/Global.h> #include <MUtils/Global.h>
#include <MUtils/OSSupport.h> #include <MUtils/OSSupport.h>
#include "DirLocker.h"
//Qt //Qt
#include <QDir> #include <QDir>
@ -102,9 +104,8 @@ QString MUtils::rand_str(const bool &bLong)
// TEMP FOLDER // TEMP FOLDER
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
static QScopedPointer<QFile> g_temp_folder_file; static QScopedPointer<MUtils::Internal::DirLock> g_temp_folder_file;
static QScopedPointer<QString> g_temp_folder_path; static QReadWriteLock g_temp_folder_lock;
static QReadWriteLock g_temp_folder_lock;
static QString try_create_subfolder(const QString &baseDir, const QString &postfix) static QString try_create_subfolder(const QString &baseDir, const QString &postfix)
{ {
@ -120,29 +121,26 @@ static QString try_create_subfolder(const QString &baseDir, const QString &postf
return QString(); return QString();
} }
static QString try_init_temp_folder(const QString &baseDir) static MUtils::Internal::DirLock *try_init_temp_folder(const QString &baseDir)
{ {
static const char *TEST_DATA = "Lorem ipsum dolor sit amet, consectetur, adipisci velit!"; const QString tempPath = try_create_subfolder(baseDir, MUtils::rand_str());
QString tempPath = try_create_subfolder(baseDir, MUtils::rand_str());
if(!tempPath.isEmpty()) if(!tempPath.isEmpty())
{ {
const QByteArray testData = QByteArray(TEST_DATA);
for(int i = 0; i < 32; i++) for(int i = 0; i < 32; i++)
{ {
g_temp_folder_file.reset(new QFile(QString("%1/~%2.lck").arg(tempPath, MUtils::rand_str()))); MUtils::Internal::DirLock *lockFile = NULL;
if(g_temp_folder_file->open(QIODevice::ReadWrite | QIODevice::Truncate)) try
{ {
if(g_temp_folder_file->write(testData) >= testData.size()) lockFile = new MUtils::Internal::DirLock(tempPath);
{ return lockFile;
return tempPath; }
} catch(MUtils::Internal::DirLockException&)
g_temp_folder_file->remove(); {
/*ignore error and try again*/
} }
} }
} }
return NULL;
return QString();
} }
const QString &MUtils::temp_folder(void) const QString &MUtils::temp_folder(void)
@ -150,9 +148,9 @@ const QString &MUtils::temp_folder(void)
QReadLocker readLock(&g_temp_folder_lock); QReadLocker readLock(&g_temp_folder_lock);
//Already initialized? //Already initialized?
if((!g_temp_folder_path.isNull()) && (!g_temp_folder_path->isEmpty())) if(!g_temp_folder_file.isNull())
{ {
return (*g_temp_folder_path.data()); return g_temp_folder_file->path();
} }
//Obtain the write lock to initilaize //Obtain the write lock to initilaize
@ -160,17 +158,16 @@ const QString &MUtils::temp_folder(void)
QWriteLocker writeLock(&g_temp_folder_lock); QWriteLocker writeLock(&g_temp_folder_lock);
//Still uninitilaized? //Still uninitilaized?
if((!g_temp_folder_path.isNull()) && (!g_temp_folder_path->isEmpty())) if(!g_temp_folder_file.isNull())
{ {
return (*g_temp_folder_path.data()); return g_temp_folder_file->path();
} }
//Try the %TMP% or %TEMP% directory first //Try the %TMP% or %TEMP% directory first
QString tempPath = try_init_temp_folder(QDir::tempPath()); if(MUtils::Internal::DirLock *lockFile = try_init_temp_folder(QDir::tempPath()))
if(!tempPath.isEmpty())
{ {
g_temp_folder_path.reset(new QString(tempPath)); g_temp_folder_file.reset(lockFile);
return (*g_temp_folder_path.data()); return lockFile->path();
} }
qWarning("%%TEMP%% directory not found -> trying fallback mode now!"); qWarning("%%TEMP%% directory not found -> trying fallback mode now!");
@ -183,11 +180,10 @@ const QString &MUtils::temp_folder(void)
const QString tempRoot = try_create_subfolder(knownFolder, QLatin1String("TEMP")); const QString tempRoot = try_create_subfolder(knownFolder, QLatin1String("TEMP"));
if(!tempRoot.isEmpty()) if(!tempRoot.isEmpty())
{ {
tempPath = try_init_temp_folder(tempRoot); if(MUtils::Internal::DirLock *lockFile = try_init_temp_folder(tempRoot))
if(!tempPath.isEmpty())
{ {
g_temp_folder_path.reset(new QString(tempPath)); g_temp_folder_file.reset(lockFile);
return (*g_temp_folder_path.data()); return lockFile->path();
} }
} }
} }
@ -197,6 +193,65 @@ const QString &MUtils::temp_folder(void)
return (*((QString*)NULL)); return (*((QString*)NULL));
} }
///////////////////////////////////////////////////////////////////////////////
// REMOVE DIRECTORY / FILE
///////////////////////////////////////////////////////////////////////////////
bool MUtils::remove_file(const QString &fileName)
{
QFileInfo fileInfo(fileName);
if(!(fileInfo.exists() && fileInfo.isFile()))
{
return true;
}
for(int i = 0; i < 32; i++)
{
QFile file(fileName);
file.setPermissions(QFile::ReadOther | QFile::WriteOther);
if(file.remove())
{
return true;
}
}
qWarning("Could not delete \"%s\"", MUTILS_UTF8(fileName));
return false;
}
bool MUtils::remove_directory(const QString &folderPath)
{
QDir folder(folderPath);
if(!folder.exists())
{
return true;
}
const QFileInfoList entryList = folder.entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::Hidden);
for(int i = 0; i < entryList.count(); i++)
{
if(entryList.at(i).isDir())
{
remove_directory(entryList.at(i).canonicalFilePath());
}
else
{
remove_file(entryList.at(i).canonicalFilePath());
}
}
for(int i = 0; i < 32; i++)
{
if(folder.rmdir("."))
{
return true;
}
}
qWarning("Could not rmdir \"%s\"", MUTILS_UTF8(folderPath));
return false;
}
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// PROCESS UTILS // PROCESS UTILS
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////

View File

@ -153,7 +153,7 @@ const QString &MUtils::OS::known_folder(known_folder_t folder_id)
if(g_known_folders_fpGetKnownFolderPath(s_folders[folderId].guid, KF_FLAG_CREATE, NULL, &path) == S_OK) if(g_known_folders_fpGetKnownFolderPath(s_folders[folderId].guid, KF_FLAG_CREATE, NULL, &path) == S_OK)
{ {
//MessageBoxW(0, path, L"SHGetKnownFolderPath", MB_TOPMOST); //MessageBoxW(0, path, L"SHGetKnownFolderPath", MB_TOPMOST);
QDir folderTemp = QDir(QDir::fromNativeSeparators(MUTILS_WCHAR2QSTR(path))); QDir folderTemp = QDir(QDir::fromNativeSeparators(MUTILS_QSTR(path)));
if(folderTemp.exists()) if(folderTemp.exists())
{ {
folderPath = folderTemp.canonicalPath(); folderPath = folderTemp.canonicalPath();
@ -167,7 +167,7 @@ const QString &MUtils::OS::known_folder(known_folder_t folder_id)
if(g_known_folders_fpGetFolderPath(NULL, s_folders[folderId].csidl | CSIDL_FLAG_CREATE, NULL, NULL, path.data()) == S_OK) if(g_known_folders_fpGetFolderPath(NULL, s_folders[folderId].csidl | CSIDL_FLAG_CREATE, NULL, NULL, path.data()) == S_OK)
{ {
//MessageBoxW(0, path, L"SHGetFolderPathW", MB_TOPMOST); //MessageBoxW(0, path, L"SHGetFolderPathW", MB_TOPMOST);
QDir folderTemp = QDir(QDir::fromNativeSeparators(MUTILS_WCHAR2QSTR(path.data()))); QDir folderTemp = QDir(QDir::fromNativeSeparators(MUTILS_QSTR(path.data())));
if(folderTemp.exists()) if(folderTemp.exists())
{ {
folderPath = folderTemp.canonicalPath(); folderPath = folderTemp.canonicalPath();
@ -259,8 +259,8 @@ int MUtils::OS::network_status(void)
// FATAL EXIT // FATAL EXIT
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
static CriticalSection g_fatal_exit_lock; static MUtils::Internal::CriticalSection g_fatal_exit_lock;
static volatile bool g_fatal_exit_flag = true; static volatile bool g_fatal_exit_flag = true;
static DWORD WINAPI fatal_exit_helper(LPVOID lpParameter) static DWORD WINAPI fatal_exit_helper(LPVOID lpParameter)
{ {

View File

@ -58,18 +58,19 @@ const QDate MUtils::Version::build_date(const char *const date_str)
ok = ok && (_snscanf(&date_str[0x0], 3, "%s", &month_s) == 1); ok = ok && (_snscanf(&date_str[0x0], 3, "%s", &month_s) == 1);
ok = ok && ((date[1] = month2int(month_s)) > 0); ok = ok && ((date[1] = month2int(month_s)) > 0);
ok = ok && (_snscanf(&date_str[0x4], 2, "%d", &date[0]) == 1); ok = ok && (_snscanf(&date_str[0x4], 2, "%d", &date[2]) == 1);
ok = ok && (_snscanf(&date_str[0x7], 4, "%d", &date[2]) == 1); ok = ok && (_snscanf(&date_str[0x7], 4, "%d", &date[0]) == 1);
if(!ok) if(!ok)
{ {
MUTILS_THROW("Internal error: Date format could not be recognized!"); MUTILS_THROW("Internal error: Date format could not be recognized!");
} }
//qWarning("MUtils::Version::build_date: y=%d, m=%d, d=%d", date[0], date[1], date[2]);
return QDate(date[0], date[1], date[2]); return QDate(date[0], date[1], date[2]);
} }
static const QTime build_time(const char *const time_str) const QTime MUtils::Version::build_time(const char *const time_str)
{ {
bool ok = true; bool ok = true;
int time[3] = {0, 0, 0}; int time[3] = {0, 0, 0};
@ -83,6 +84,7 @@ static const QTime build_time(const char *const time_str)
MUTILS_THROW("Internal error: Time format could not be recognized!"); MUTILS_THROW("Internal error: Time format could not be recognized!");
} }
//qWarning("MUtils::Version::build_date: h=%d, m=%d, s=%d", time[0], time[1], time[2]);
return QTime(time[0], time[1], time[2]); return QTime(time[0], time[1], time[2]);
} }