summaryrefslogtreecommitdiff
path: root/zen
diff options
context:
space:
mode:
Diffstat (limited to 'zen')
-rw-r--r--zen/IFileOperation/file_op.cpp20
-rw-r--r--zen/basic_math.h2
-rw-r--r--zen/debug_memory_leaks.cpp4
-rw-r--r--zen/file_handling.cpp120
-rw-r--r--zen/file_handling.h11
-rw-r--r--zen/file_traverser.h6
-rw-r--r--zen/format_unit.cpp4
-rw-r--r--zen/guid.h3
-rw-r--r--zen/perf.h6
-rw-r--r--zen/process_priority.h6
-rw-r--r--zen/recycler.h3
-rw-r--r--zen/string_base.h19
-rw-r--r--zen/thread.h14
13 files changed, 125 insertions, 93 deletions
diff --git a/zen/IFileOperation/file_op.cpp b/zen/IFileOperation/file_op.cpp
index 5d4cfdc9..0691ac5b 100644
--- a/zen/IFileOperation/file_op.cpp
+++ b/zen/IFileOperation/file_op.cpp
@@ -84,14 +84,14 @@ public:
//IFileOperationProgressSink
virtual HRESULT STDMETHODCALLTYPE StartOperations() { return S_OK; }
virtual HRESULT STDMETHODCALLTYPE FinishOperations(HRESULT hrResult) { return S_OK; }
- virtual HRESULT STDMETHODCALLTYPE PreRenameItem(DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt_string LPCWSTR pszNewName) { return S_OK; }
- virtual HRESULT STDMETHODCALLTYPE PostRenameItem(DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_string LPCWSTR pszNewName, HRESULT hrRename, __RPC__in_opt IShellItem* psiNewlyCreated) { return S_OK; }
- virtual HRESULT STDMETHODCALLTYPE PreMoveItem(DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName) { return S_OK; }
- virtual HRESULT STDMETHODCALLTYPE PostMoveItem(DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName, HRESULT hrMove, __RPC__in_opt IShellItem* psiNewlyCreated) { return S_OK; }
- virtual HRESULT STDMETHODCALLTYPE PreCopyItem(DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName) { return S_OK; }
- virtual HRESULT STDMETHODCALLTYPE PostCopyItem(DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName, HRESULT hrCopy, __RPC__in_opt IShellItem* psiNewlyCreated) { return S_OK; }
- virtual HRESULT STDMETHODCALLTYPE PreNewItem(DWORD dwFlags, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName) { return S_OK; }
- virtual HRESULT STDMETHODCALLTYPE PostNewItem(DWORD dwFlags, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName, __RPC__in_opt_string LPCWSTR pszTemplateName, DWORD dwFileAttributes, HRESULT hrNew, __RPC__in_opt IShellItem* psiNewItem) { return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE PreRenameItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt_string LPCWSTR pszNewName) { return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE PostRenameItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_string LPCWSTR pszNewName, HRESULT hrRename, __RPC__in_opt IShellItem* psiNewlyCreated) { return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE PreMoveItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName) { return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE PostMoveItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName, HRESULT hrMove, __RPC__in_opt IShellItem* psiNewlyCreated) { return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE PreCopyItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName) { return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE PostCopyItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiItem, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName, HRESULT hrCopy, __RPC__in_opt IShellItem* psiNewlyCreated) { return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE PreNewItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName) { return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE PostNewItem (DWORD dwFlags, __RPC__in_opt IShellItem* psiDestinationFolder, __RPC__in_opt_string LPCWSTR pszNewName, __RPC__in_opt_string LPCWSTR pszTemplateName, DWORD dwFileAttributes, HRESULT hrNew, __RPC__in_opt IShellItem* psiNewItem) { return S_OK; }
virtual HRESULT STDMETHODCALLTYPE PreDeleteItem(DWORD dwFlags, __RPC__in_opt IShellItem* psiItem)
{
@@ -138,8 +138,8 @@ public:
//=> defer cancellation to PreDeleteItem()/PostDeleteItem()
return S_OK;
}
- virtual HRESULT STDMETHODCALLTYPE ResetTimer() { return S_OK; }
- virtual HRESULT STDMETHODCALLTYPE PauseTimer() { return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE ResetTimer () { return S_OK; }
+ virtual HRESULT STDMETHODCALLTYPE PauseTimer () { return S_OK; }
virtual HRESULT STDMETHODCALLTYPE ResumeTimer() { return S_OK; }
//call after IFileOperation::PerformOperations()
diff --git a/zen/basic_math.h b/zen/basic_math.h
index f8a7affd..d83a7f77 100644
--- a/zen/basic_math.h
+++ b/zen/basic_math.h
@@ -146,7 +146,7 @@ T confineCpy(const T& val, const T& minVal, const T& maxVal)
}
template <class T> inline
-void confine(T& val, const T& minVal, const T& maxVal) //name trim?
+void confine(T& val, const T& minVal, const T& maxVal) //name trim, clamp?
{
assert(minVal <= maxVal);
if (val < minVal)
diff --git a/zen/debug_memory_leaks.cpp b/zen/debug_memory_leaks.cpp
index 990f2ec7..2359b6ef 100644
--- a/zen/debug_memory_leaks.cpp
+++ b/zen/debug_memory_leaks.cpp
@@ -8,7 +8,7 @@
//Usage: just include this file into a Visual Studio project
-#ifndef NDEBUG
+#ifdef _DEBUG //When _DEBUG is not defined, calls to _CrtSetDbgFlag are removed during preprocessing.
#define _CRTDBG_MAP_ALLOC //
#include <stdlib.h> //keep this order: "The #include statements must be in the order shown here. If you change the order, the functions you use may not work properly."
#include <crtdbg.h> //overwrites "operator new" ect; no need to include this in every compilation unit!
@@ -27,4 +27,4 @@ struct OnStartup
} dummy;
}
-#endif \ No newline at end of file
+#endif //_DEBUG \ No newline at end of file
diff --git a/zen/file_handling.cpp b/zen/file_handling.cpp
index c052435a..4f34814f 100644
--- a/zen/file_handling.cpp
+++ b/zen/file_handling.cpp
@@ -479,8 +479,7 @@ Zstring findUnused8Dot3Name(const Zstring& filename) //find a unique 8.3 short n
if (!somethingExists(output)) //ensure uniqueness
return output;
}
-
- throw std::runtime_error(std::string("100000000 files, one for each number, exist in this directory? You're kidding...\n") + utfCvrtTo<std::string>(pathPrefix));
+ throw std::runtime_error(std::string("100000000 files, one for each number, exist in this directory? You're kidding...") + utfCvrtTo<std::string>(pathPrefix));
}
@@ -566,10 +565,12 @@ void zen::renameFile(const Zstring& oldName, const Zstring& newName) //throw Fil
}
-class FilesDirsOnlyTraverser : public zen::TraverseCallback
+namespace
+{
+class CollectFilesFlat : public zen::TraverseCallback
{
public:
- FilesDirsOnlyTraverser(std::vector<Zstring>& files, std::vector<Zstring>& dirs) :
+ CollectFilesFlat(std::vector<Zstring>& files, std::vector<Zstring>& dirs) :
m_files(files),
m_dirs(dirs) {}
@@ -593,19 +594,17 @@ public:
virtual HandleError onError(const std::wstring& msg) { throw FileError(msg); }
private:
- FilesDirsOnlyTraverser(const FilesDirsOnlyTraverser&);
- FilesDirsOnlyTraverser& operator=(const FilesDirsOnlyTraverser&);
+ CollectFilesFlat(const CollectFilesFlat&);
+ CollectFilesFlat& operator=(const CollectFilesFlat&);
std::vector<Zstring>& m_files;
std::vector<Zstring>& m_dirs;
};
-void zen::removeDirectory(const Zstring& directory, CallbackRemoveDir* callback)
+void removeDirectoryImpl(const Zstring& directory, CallbackRemoveDir* callback) //throw FileError
{
- //no error situation if directory is not existing! manual deletion relies on it!
- if (!somethingExists(directory))
- return; //neither directory nor any other object (e.g. broken symlink) with that name existing
+ assert(somethingExists(directory)); //[!]
#ifdef FFS_WIN
const Zstring directoryFmt = applyLongPathPrefix(directory); //support for \\?\-prefix
@@ -617,55 +616,66 @@ void zen::removeDirectory(const Zstring& directory, CallbackRemoveDir* callback)
//attention: check if directory is a symlink! Do NOT traverse into it deleting contained files!!!
if (symlinkExists(directory)) //remove symlink directly
{
+ if (callback) callback->onBeforeDirDeletion(directory); //once per symlink
#ifdef FFS_WIN
if (!::RemoveDirectory(directoryFmt.c_str()))
#elif defined FFS_LINUX
if (::unlink(directory.c_str()) != 0)
#endif
throw FileError(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtFileName(directory)) + L"\n\n" + getLastErrorFormatted());
-
- if (callback)
- callback->notifyDirDeletion(directory); //once per symlink
- return;
}
-
- std::vector<Zstring> fileList;
- std::vector<Zstring> dirList;
+ else
{
- //get all files and directories from current directory (WITHOUT subdirectories!)
- FilesDirsOnlyTraverser traverser(fileList, dirList);
- traverseFolder(directory, traverser); //don't follow symlinks
- }
+ std::vector<Zstring> fileList;
+ std::vector<Zstring> dirList;
+ {
+ //get all files and directories from current directory (WITHOUT subdirectories!)
+ CollectFilesFlat cff(fileList, dirList);
+ traverseFolder(directory, cff); //don't follow symlinks
+ }
- //delete directories recursively
- for (auto it = dirList.begin(); it != dirList.end(); ++it)
- removeDirectory(*it, callback); //call recursively to correctly handle symbolic links
+ //delete directories recursively
+ std::for_each(dirList.begin(), dirList.end(),
+ [&](const Zstring& dirname)
+ {
+ removeDirectoryImpl(dirname, callback); //throw FileError; call recursively to correctly handle symbolic links
+ });
- //delete files
- for (auto it = fileList.begin(); it != fileList.end(); ++it)
- {
- const bool workDone = removeFile(*it);
- if (callback && workDone)
- callback->notifyFileDeletion(*it); //call once per file
- }
+ //delete files
+ std::for_each(fileList.begin(), fileList.end(),
+ [&](const Zstring& filename)
+ {
+ if (callback) callback->onBeforeFileDeletion(filename); //call once per file
+ removeFile(filename); //throw FileError
+ });
- //parent directory is deleted last
+ //parent directory is deleted last
+ if (callback) callback->onBeforeDirDeletion(directory); //and once per folder
#ifdef FFS_WIN
- if (!::RemoveDirectory(directoryFmt.c_str()))
+ if (!::RemoveDirectory(directoryFmt.c_str()))
#else
- if (::rmdir(directory.c_str()) != 0)
+ if (::rmdir(directory.c_str()) != 0)
#endif
- throw FileError(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtFileName(directory)) + L"\n\n" + getLastErrorFormatted());
- //may spuriously fail with ERROR_DIR_NOT_EMPTY(145) even though all child items have
- //successfully been *marked* for deletion, but some application still has a handle open!
- //e.g. Open "C:\Test\Dir1\Dir2" (filled with lots of files) in Explorer, then delete "C:\Test\Dir1" via ::RemoveDirectory() => Error 145
- //Sample code: http://us.generation-nt.com/answer/createfile-directory-handles-removing-parent-help-29126332.html
-
- if (callback)
- callback->notifyDirDeletion(directory); //and once per folder
+ throw FileError(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtFileName(directory)) + L"\n\n" + getLastErrorFormatted());
+ //may spuriously fail with ERROR_DIR_NOT_EMPTY(145) even though all child items have
+ //successfully been *marked* for deletion, but some application still has a handle open!
+ //e.g. Open "C:\Test\Dir1\Dir2" (filled with lots of files) in Explorer, then delete "C:\Test\Dir1" via ::RemoveDirectory() => Error 145
+ //Sample code: http://us.generation-nt.com/answer/createfile-directory-handles-removing-parent-help-29126332.html
+ }
+}
}
+void zen::removeDirectory(const Zstring& directory, CallbackRemoveDir* callback)
+{
+ //no error situation if directory is not existing! manual deletion relies on it!
+ if (!somethingExists(directory))
+ return; //neither directory nor any other object (e.g. broken symlink) with that name existing
+ removeDirectoryImpl(directory, callback);
+}
+
+
+
void zen::setFileTime(const Zstring& filename, const Int64& modificationTime, ProcSymlink procSl) //throw FileError
{
#ifdef FFS_WIN
@@ -917,11 +927,6 @@ void zen::setFileTime(const Zstring& filename, const Int64& modificationTime, Pr
assert(::CompareFileTime(&creationTimeDbg, &creationTime) == 0);
assert(::CompareFileTime(&lastWriteTimeDbg, &lastWriteTime) == 0);
}
- //CAVEAT on FAT/FAT32: the sequence of deleting the target file and renaming "file.txt.ffs_tmp" to "file.txt" seems to
- //NOT PRESERVE the creation time of the .ffs_tmp file, but "reuses" whatever creation time the old "file.txt" had!
- //this problem is therefore NOT detected by the check above!
- //However during the next comparison the DST hack will be applied correctly.
-
#endif
#elif defined FFS_LINUX
@@ -2303,6 +2308,27 @@ void zen::copyFile(const Zstring& sourceFile, //throw FileError, ErrorTargetPath
//perf: this call is REALLY expensive on unbuffered volumes! ~40% performance decrease on FAT USB stick!
renameFile(temporary, targetFile); //throw FileError
+ /*
+ CAVEAT on FAT/FAT32: the sequence of deleting the target file and renaming "file.txt.ffs_tmp" to "file.txt" does
+ NOT PRESERVE the creation time of the .ffs_tmp file, but SILENTLY "reuses" whatever creation time the old "file.txt" had!
+ This "feature" is called "File System Tunneling":
+ http://blogs.msdn.com/b/oldnewthing/archive/2005/07/15/439261.aspx
+ http://support.microsoft.com/kb/172190/en-us
+
+ However during the next comparison the DST hack will be applied correctly since the DST-hash of the mod.time is invalid.
+
+ EXCEPTION: the hash may match!!! reproduce:
+ 1. set system time back to date within previous DST
+ 2. save some file on FAT32 usb stick and FFS-compare to make sure the DST hack is applied correctly
+ 4. pull out usb stick, put back in
+ 3. restore system time
+ 4. copy file from USB to local drive via explorer
+ =>
+ NTFS <-> FAT, file exists on both sides; mod times match, DST hack on USB stick causes 1-hour offset when comparing in FFS.
+ When syncing modification time is copied correctly, but new DST hack fails to apply and old creation time is reused (see above).
+ Unfortunately, the old DST hash matches mod time! => On next comparison FFS will *still* see both sides as different!!!!!!!!!
+ */
+
guardTempFile.dismiss();
}
else
diff --git a/zen/file_handling.h b/zen/file_handling.h
index e9e1685d..5739dc2a 100644
--- a/zen/file_handling.h
+++ b/zen/file_handling.h
@@ -47,7 +47,7 @@ UInt64 getFilesize(const Zstring& filename); //throw FileError
UInt64 getFreeDiskSpace(const Zstring& path); //throw FileError
//file handling
-bool removeFile(const Zstring& filename); //throw FileError; return "true" if file was actually deleted
+bool removeFile(const Zstring& filename); //throw FileError; return "false" if file is not existing
void removeDirectory(const Zstring& directory, CallbackRemoveDir* callback = nullptr); //throw FileError
//rename file or directory: no copying!!!
@@ -57,7 +57,7 @@ bool supportsPermissions(const Zstring& dirname); //throw FileError, derefernces
//creates superdirectories automatically:
void makeDirectory(const Zstring& directory); //throw FileError; do nothing if directory already exists!
-void makeNewDirectory(const Zstring& directory, const Zstring& templateDir, bool copyFilePermissions); //FileError, ErrorTargetExisting
+void makeNewDirectory(const Zstring& directory, const Zstring& templateDir, bool copyFilePermissions); //throw FileError, ErrorTargetExisting
struct FileAttrib
{
@@ -85,16 +85,15 @@ void copySymlink(const Zstring& sourceLink, const Zstring& targetLink, bool copy
struct CallbackRemoveDir
{
virtual ~CallbackRemoveDir() {}
- virtual void notifyFileDeletion(const Zstring& filename) = 0; //one call for each (existing) object!
- virtual void notifyDirDeletion (const Zstring& dirname ) = 0; //
+ virtual void onBeforeFileDeletion(const Zstring& filename) = 0; //one call for each *existing* object!
+ virtual void onBeforeDirDeletion (const Zstring& dirname ) = 0; //
};
-
struct CallbackCopyFile
{
virtual ~CallbackCopyFile() {}
- //if target is existing user needs to implement deletion: copyFile() NEVER deletes target if already existing!
+ //if target is existing user needs to implement deletion: copyFile() NEVER overwrites target if already existing!
//if transactionalCopy == true, full read access on source had been proven at this point, so it's safe to delete it.
virtual void deleteTargetFile(const Zstring& targetFile) = 0; //may throw exceptions
diff --git a/zen/file_traverser.h b/zen/file_traverser.h
index d8a99a4d..c8ef6550 100644
--- a/zen/file_traverser.h
+++ b/zen/file_traverser.h
@@ -12,7 +12,6 @@
#include "int64.h"
#include "file_id_def.h"
-
//advanced file traverser returning metadata and hierarchical information on files and directories
namespace zen
@@ -25,8 +24,8 @@ struct TraverseCallback
{
UInt64 fileSize; //unit: bytes!
Int64 lastWriteTimeRaw; //number of seconds since Jan. 1st 1970 UTC
- FileId id; //optional: may be initial!
- //bool isFollowedSymlink;
+ FileId id; //optional: initial if not supported!
+ //std::unique_ptr<SymlinkInfo> symlinkInfo; //only filled if file is dereferenced symlink
};
struct SymlinkInfo
@@ -48,7 +47,6 @@ struct TraverseCallback
ON_ERROR_IGNORE
};
- //overwrite these virtual methods
virtual std::shared_ptr<TraverseCallback> //nullptr: ignore directory, non-nullptr: traverse into using the (new) callback
/**/ onDir (const Zchar* shortName, const Zstring& fullName) = 0;
virtual void onFile (const Zchar* shortName, const Zstring& fullName, const FileInfo& details) = 0;
diff --git a/zen/format_unit.cpp b/zen/format_unit.cpp
index 8e5b04d3..6455029f 100644
--- a/zen/format_unit.cpp
+++ b/zen/format_unit.cpp
@@ -199,7 +199,7 @@ private:
//convert LOCALE_SGROUPING to Grouping: http://blogs.msdn.com/b/oldnewthing/archive/2006/04/18/578251.aspx
replace(grouping, L';', L"");
if (endsWith(grouping, L'0'))
- grouping.resize(grouping.size() - 1);
+ grouping.pop_back();
else
grouping += L'0';
fmt.Grouping = stringTo<UINT>(grouping);
@@ -253,7 +253,7 @@ std::wstring zen::ffs_Impl::includeNumberSeparator(const std::wstring& number)
if (i <= 3)
break;
i -= 3;
- if (!isDigit(output[i - 1]))
+ if (!isDigit(output[i - 1])) //stop on +, - signs
break;
output.insert(i, thousandSep);
}
diff --git a/zen/guid.h b/zen/guid.h
index 823f4431..0c03bd9f 100644
--- a/zen/guid.h
+++ b/zen/guid.h
@@ -28,7 +28,8 @@ namespace zen
inline
std::string generateGUID() //creates a 16 byte GUID
{
- boost::uuids::uuid nativeRep = boost::uuids::random_generator()(); //generator is thread-safe like an int
+ boost::uuids::uuid nativeRep = boost::uuids::random_generator()();
+ //generator is only thread-safe like an int, so we keep it local until we need to optimize perf
//perf: generator: 0.22ms per call; retrieve GUID: 0.12µs per call
return std::string(nativeRep.begin(), nativeRep.end());
}
diff --git a/zen/perf.h b/zen/perf.h
index 92350602..4a334bff 100644
--- a/zen/perf.h
+++ b/zen/perf.h
@@ -29,11 +29,13 @@ public:
class TimerError {};
ZEN_DEPRECATE
- PerfTimer() : ticksPerSec_(ticksPerSec()), startTime(), resultShown(false)
+ PerfTimer() : //throw TimerError
+ ticksPerSec_(ticksPerSec()), startTime(), resultShown(false)
{
//std::clock() - "counts CPU time in C and wall time in VC++" - WTF!???
#ifdef FFS_WIN
- if (::SetThreadAffinityMask(::GetCurrentThread(), 1) == 0) throw TimerError(); //"should not be required unless there are bugs in BIOS or HAL" - msdn, QueryPerformanceCounter
+ if (::SetThreadAffinityMask(::GetCurrentThread(), 1) == 0) //"should not be required unless there are bugs in BIOS or HAL" - msdn, QueryPerformanceCounter
+ throw TimerError();
#endif
startTime = getTicks();
if (ticksPerSec_ == 0 || !startTime.isValid())
diff --git a/zen/process_priority.h b/zen/process_priority.h
index 15266b28..c0bae667 100644
--- a/zen/process_priority.h
+++ b/zen/process_priority.h
@@ -12,7 +12,7 @@ namespace zen
struct PreventStandby //signal a "busy" state to the operating system
{
#ifdef FFS_WIN
- PreventStandby() { ::SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED /* | ES_AWAYMODE_REQUIRED*/ ); }
+ PreventStandby () { ::SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED /* | ES_AWAYMODE_REQUIRED*/ ); }
~PreventStandby() { ::SetThreadExecutionState(ES_CONTINUOUS); }
#endif
};
@@ -26,8 +26,8 @@ struct ScheduleForBackgroundProcessing //lower CPU and file I/O priorities
#define PROCESS_MODE_BACKGROUND_END 0x00200000 //
#endif
- ScheduleForBackgroundProcessing() { ::SetPriorityClass(::GetCurrentProcess(), PROCESS_MODE_BACKGROUND_BEGIN); } //this call lowers CPU priority, too!!
- ~ScheduleForBackgroundProcessing() { ::SetPriorityClass(::GetCurrentProcess(), PROCESS_MODE_BACKGROUND_END); }
+ ScheduleForBackgroundProcessing () { ::SetPriorityClass(::GetCurrentProcess(), PROCESS_MODE_BACKGROUND_BEGIN); } //this call lowers CPU priority, too!!
+ ~ScheduleForBackgroundProcessing() { ::SetPriorityClass(::GetCurrentProcess(), PROCESS_MODE_BACKGROUND_END ); }
#elif defined FFS_LINUX
/*
diff --git a/zen/recycler.h b/zen/recycler.h
index 4d33477d..8aca0ff3 100644
--- a/zen/recycler.h
+++ b/zen/recycler.h
@@ -42,13 +42,14 @@ enum StatusRecycler
STATUS_REC_UNKNOWN
};
StatusRecycler recycleBinStatus(const Zstring& pathName); //test existence of Recycle Bin API for certain path
+//Win: blocks heavily if recycle bin is really full and drive is slow!!!
struct CallbackRecycling
{
virtual ~CallbackRecycling() {}
//may throw: first exception is swallowed, updateStatus() is then called again where it should throw again and the exception will propagate as expected
- virtual void updateStatus(const Zstring& currentItem) = 0;
+ virtual void updateStatus(const Zstring& currentItem) = 0; //currentItem may be empty
};
void recycleOrDelete(const std::vector<Zstring>& filenames, //throw FileError, return "true" if file/dir was actually deleted
diff --git a/zen/string_base.h b/zen/string_base.h
index bfe573e9..e4e21716 100644
--- a/zen/string_base.h
+++ b/zen/string_base.h
@@ -15,7 +15,6 @@
//Zbase - a policy based string class optimizing performance and genericity
-
namespace zen
{
/*
@@ -59,8 +58,8 @@ template <typename Char, //Character Type
void setLength(Char* ptr, size_t newLength)
*/
-template <typename Char, //Character Type
- class AP> //Allocator Policy
+template <class Char, //Character Type
+ class AP> //Allocator Policy
class StorageDeepCopy : public AP
{
protected:
@@ -112,8 +111,8 @@ private:
};
-template <typename Char, //Character Type
- class AP> //Allocator Policy
+template <class Char, //Character Type
+ class AP> //Allocator Policy
class StorageRefCountThreadSafe : public AP
{
protected:
@@ -169,7 +168,7 @@ private:
{
Descriptor(long rc, size_t len, size_t cap) :
refCount(rc),
- length(static_cast<std::uint32_t>(len)),
+ length (static_cast<std::uint32_t>(len)),
capacity(static_cast<std::uint32_t>(cap)) {}
boost::detail::atomic_count refCount; //practically no perf loss: ~0.2%! (FFS comparison)
@@ -181,8 +180,8 @@ private:
static Descriptor* descr( Char* ptr) { return reinterpret_cast< Descriptor*>(ptr) - 1; }
static const Descriptor* descr(const Char* ptr) { return reinterpret_cast<const Descriptor*>(ptr) - 1; }
};
-//################################################################################################################################################################
+//################################################################################################################################################################
//perf note: interstingly StorageDeepCopy and StorageRefCountThreadSafe show same performance in FFS comparison
@@ -386,7 +385,7 @@ size_t Zbase<Char, SP, AP>::find(const Zbase& str, size_t pos) const
assert(pos <= length());
const Char* thisEnd = end(); //respect embedded 0
const Char* it = std::search(begin() + pos, thisEnd,
- str.begin(), str.end());
+ str.begin(), str.end());
return it == thisEnd ? npos : it - begin();
}
@@ -397,7 +396,7 @@ size_t Zbase<Char, SP, AP>::find(const Char* str, size_t pos) const
assert(pos <= length());
const Char* thisEnd = end(); //respect embedded 0
const Char* it = std::search(begin() + pos, thisEnd,
- str, str + strLength(str));
+ str, str + strLength(str));
return it == thisEnd ? npos : it - begin();
}
@@ -433,7 +432,7 @@ size_t Zbase<Char, SP, AP>::rfind(const Char* str, size_t pos) const
const Char* currEnd = pos == npos ? end() : begin() + std::min(pos + strLen, length());
const Char* it = search_last(begin(), currEnd,
- str, str + strLen);
+ str, str + strLen);
return it == currEnd ? npos : it - begin();
}
diff --git a/zen/thread.h b/zen/thread.h
index 31d762c7..43917d13 100644
--- a/zen/thread.h
+++ b/zen/thread.h
@@ -33,8 +33,11 @@
namespace zen
{
-//until std::async is available:
/*
+std::async replacement without crappy semantics:
+ 1. guaranteed to run asynchronous
+ 2. does not follow C++11 [futures.async], Paragraph 5, where std::future waits for thread in destructor
+
Example:
Zstring dirname = ...
auto ft = zen::async([=](){ return zen::dirExists(dirname); });
@@ -93,10 +96,13 @@ private:
template <class T, class Function> inline
auto async2(Function fun) -> boost::unique_future<T> //support for workaround of VS2010 bug: bool (*fun)(); decltype(fun()) == int!
{
- boost::packaged_task<T> pt(std::move(fun)); //packaged task seems to even require r-value reference: https://sourceforge.net/p/freefilesync/bugs/234/
+#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK //mirror "boost/thread/future.hpp", hopefully they know what they're doing
+ boost::packaged_task<T()> pt(std::move(fun)); //packaged task seems to even require r-value reference: https://sourceforge.net/p/freefilesync/bugs/234/
+#else
+ boost::packaged_task<T> pt(std::move(fun));
+#endif
auto fut = pt.get_future();
- boost::thread t(std::move(pt));
- t.detach(); //we have to be explicit since C++11: [thread.thread.destr] ~thread() calls std::terminate() if joinable()!!!
+ boost::thread(std::move(pt)).detach(); //we have to explicitly detach since C++11: [thread.thread.destr] ~thread() calls std::terminate() if joinable()!!!
return std::move(fut); //compiler error without "move", why needed???
}
bgstack15