summaryrefslogtreecommitdiff
path: root/zen
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:28:01 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:28:01 +0200
commitfe9eb89ebc1b3c33cbac00a3fa095a14faef9113 (patch)
tree8a3bb620a9acb83fe0057061a86e8f2cb91a9fe1 /zen
parent5.21 (diff)
downloadFreeFileSync-fe9eb89ebc1b3c33cbac00a3fa095a14faef9113.tar.gz
FreeFileSync-fe9eb89ebc1b3c33cbac00a3fa095a14faef9113.tar.bz2
FreeFileSync-fe9eb89ebc1b3c33cbac00a3fa095a14faef9113.zip
5.22
Diffstat (limited to 'zen')
-rw-r--r--zen/FindFilePlus/FindFilePlus.vcxproj10
-rw-r--r--zen/IFileOperation/FileOperation_Vista.vcxproj18
-rw-r--r--zen/IFileOperation/file_op.cpp12
-rw-r--r--zen/com_util.h8
-rw-r--r--zen/dir_watcher.cpp236
-rw-r--r--zen/dir_watcher.h1
-rw-r--r--zen/error_log.h2
-rw-r--r--zen/file_error.h4
-rw-r--r--zen/file_handling.cpp59
-rw-r--r--zen/file_handling.h1
-rw-r--r--zen/file_io.cpp11
-rw-r--r--zen/file_io.h6
-rw-r--r--zen/file_traverser.cpp10
-rw-r--r--zen/file_traverser.h4
-rw-r--r--zen/fixed_list.h4
-rw-r--r--zen/format_unit.cpp15
-rw-r--r--zen/i18n.h41
-rw-r--r--zen/notify_removal.cpp8
-rw-r--r--zen/osx_string.h2
-rw-r--r--zen/privilege.cpp11
-rw-r--r--zen/process_priority.cpp4
-rw-r--r--zen/read_txt.cpp10
-rw-r--r--zen/read_txt.h4
-rw-r--r--zen/scroll_window_under_cursor.cpp6
-rw-r--r--zen/shell_execute.h104
-rw-r--r--zen/string_tools.h2
-rw-r--r--zen/symlink_target.h2
-rw-r--r--zen/sys_error.h13
-rw-r--r--zen/zstring.cpp14
29 files changed, 443 insertions, 179 deletions
diff --git a/zen/FindFilePlus/FindFilePlus.vcxproj b/zen/FindFilePlus/FindFilePlus.vcxproj
index 15ea6adf..56650735 100644
--- a/zen/FindFilePlus/FindFilePlus.vcxproj
+++ b/zen/FindFilePlus/FindFilePlus.vcxproj
@@ -78,10 +78,10 @@
<TargetName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">FindFilePlus_$(Platform)</TargetName>
<TargetName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">FindFilePlus_$(Platform)</TargetName>
<TargetName Condition="'$(Configuration)|$(Platform)'=='Release|x64'">FindFilePlus_$(Platform)</TargetName>
- <IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">C:\Data\WinDDK\inc\ddk;C:\Data\WinDDK\inc\api;C:\Data\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include</IncludePath>
- <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">C:\Data\WinDDK\inc\ddk;C:\Data\WinDDK\inc\api;C:\Data\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include</IncludePath>
- <IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">C:\Data\WinDDK\inc\ddk;C:\Data\WinDDK\inc\api;C:\Data\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include</IncludePath>
- <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">C:\Data\WinDDK\inc\ddk;C:\Data\WinDDK\inc\api;C:\Data\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include</IncludePath>
+ <IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">C:\Data\C++\WinDDK\inc\ddk;C:\Data\C++\WinDDK\inc\api;C:\Data\C++\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include</IncludePath>
+ <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">C:\Data\C++\WinDDK\inc\ddk;C:\Data\C++\WinDDK\inc\api;C:\Data\C++\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include</IncludePath>
+ <IncludePath Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">C:\Data\C++\WinDDK\inc\ddk;C:\Data\C++\WinDDK\inc\api;C:\Data\C++\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include</IncludePath>
+ <IncludePath Condition="'$(Configuration)|$(Platform)'=='Release|x64'">C:\Data\C++\WinDDK\inc\ddk;C:\Data\C++\WinDDK\inc\api;C:\Data\C++\WinDDK\inc\crt;$(WindowsSdkDir)\include;$(VCInstallDir)include</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<BuildLog>
@@ -102,6 +102,7 @@
<AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
<SmallerTypeCheck>true</SmallerTypeCheck>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
@@ -171,6 +172,7 @@
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<AdditionalIncludeDirectories>../..</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
diff --git a/zen/IFileOperation/FileOperation_Vista.vcxproj b/zen/IFileOperation/FileOperation_Vista.vcxproj
index 20f09a00..3ff45843 100644
--- a/zen/IFileOperation/FileOperation_Vista.vcxproj
+++ b/zen/IFileOperation/FileOperation_Vista.vcxproj
@@ -96,10 +96,11 @@
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>EditAndContinue</DebugInformationFormat>
<DisableSpecificWarnings>4100;4996;4512</DisableSpecificWarnings>
- <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../..;C:\Data\C++\boost</AdditionalIncludeDirectories>
<SmallerTypeCheck>true</SmallerTypeCheck>
<ForcedIncludeFiles>zen/warn_static.h</ForcedIncludeFiles>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
@@ -111,7 +112,7 @@
</ProfileGuidedDatabase>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
- <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories>
+ <AdditionalLibraryDirectories>C:\Data\C++\Boost\stage\lib</AdditionalLibraryDirectories>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
@@ -134,7 +135,7 @@
<SuppressStartupBanner>true</SuppressStartupBanner>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<DisableSpecificWarnings>4100;4996;4512</DisableSpecificWarnings>
- <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../..;C:\Data\C++\boost</AdditionalIncludeDirectories>
<SmallerTypeCheck>true</SmallerTypeCheck>
<ForcedIncludeFiles>zen/warn_static.h</ForcedIncludeFiles>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
@@ -149,7 +150,7 @@
</ProfileGuidedDatabase>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX64</TargetMachine>
- <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib</AdditionalLibraryDirectories>
+ <AdditionalLibraryDirectories>C:\Data\C++\Boost\stage_x64\lib</AdditionalLibraryDirectories>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
@@ -170,9 +171,10 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<DisableSpecificWarnings>4100;4996;4512</DisableSpecificWarnings>
- <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../..;C:\Data\C++\boost</AdditionalIncludeDirectories>
<ForcedIncludeFiles>zen/warn_static.h</ForcedIncludeFiles>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
</ClCompile>
<Link>
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
@@ -186,7 +188,7 @@
</ProfileGuidedDatabase>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine>
- <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage\lib</AdditionalLibraryDirectories>
+ <AdditionalLibraryDirectories>C:\Data\C++\Boost\stage\lib</AdditionalLibraryDirectories>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
@@ -210,7 +212,7 @@
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
<DisableSpecificWarnings>4100;4996;4512</DisableSpecificWarnings>
- <AdditionalIncludeDirectories>../..;C:\Program Files\C++\boost</AdditionalIncludeDirectories>
+ <AdditionalIncludeDirectories>../..;C:\Data\C++\boost</AdditionalIncludeDirectories>
<ForcedIncludeFiles>zen/warn_static.h</ForcedIncludeFiles>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
</ClCompile>
@@ -226,7 +228,7 @@
</ProfileGuidedDatabase>
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
<TargetMachine>MachineX64</TargetMachine>
- <AdditionalLibraryDirectories>C:\Program Files\C++\Boost\stage_x64\lib</AdditionalLibraryDirectories>
+ <AdditionalLibraryDirectories>C:\Data\C++\Boost\stage_x64\lib</AdditionalLibraryDirectories>
<AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
diff --git a/zen/IFileOperation/file_op.cpp b/zen/IFileOperation/file_op.cpp
index 218c6f99..27a2565b 100644
--- a/zen/IFileOperation/file_op.cpp
+++ b/zen/IFileOperation/file_op.cpp
@@ -229,7 +229,7 @@ void moveToRecycleBin(const wchar_t* fileNames[], //throw SysError
if (!somethingExists(fileNames[i]))
continue;
}
- throw SysError(formatComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for file:\n") + L"\'" + fileNames[i] + L"\'.", hr));
+ throw SysError(formatComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for file:\n") + L"\"" + fileNames[i] + L"\".", hr));
}
ZEN_COM_CHECK(fileOp->DeleteItem(psiFile.get(), nullptr));
@@ -256,11 +256,11 @@ void moveToRecycleBin(const wchar_t* fileNames[], //throw SysError
if (!processes.empty())
{
- std::wstring errorMsg = L"The file \'" + lastError->first + L"\' is locked by another process:";
+ std::wstring errorMsg = L"The file \"" + lastError->first + L"\" is locked by another process:";
std::for_each(processes.begin(), processes.end(), [&](const std::wstring& proc) { errorMsg += L'\n'; errorMsg += proc; });
throw SysError(errorMsg); //message is descriptive enough, no need to evaluate HRESULT!
}
- throw SysError(formatComError(std::wstring(L"Error during \"PerformOperations\" for file:\n") + L"\'" + lastError->first + L"\'.", lastError->second));
+ throw SysError(formatComError(std::wstring(L"Error during \"PerformOperations\" for file:\n") + L"\"" + lastError->first + L"\".", lastError->second));
}
throw;
}
@@ -298,7 +298,7 @@ void copyFile(const wchar_t* sourceFile, //throw SysError
nullptr,
IID_PPV_ARGS(psiSourceFile.init()));
if (FAILED(hr))
- throw SysError(formatComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for file:\n") + L"\'" + sourceFile + L"\'.", hr));
+ throw SysError(formatComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for file:\n") + L"\"" + sourceFile + L"\".", hr));
}
const size_t pos = std::wstring(targetFile).find_last_of(L'\\');
@@ -315,7 +315,7 @@ void copyFile(const wchar_t* sourceFile, //throw SysError
nullptr,
IID_PPV_ARGS(psiTargetFolder.init()));
if (FAILED(hr))
- throw SysError(formatComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for folder:\n") + L"\'" + targetFolder + L"\'.", hr));
+ throw SysError(formatComError(std::wstring(L"Error calling \"SHCreateItemFromParsingName\" for folder:\n") + L"\"" + targetFolder + L"\".", hr));
}
//schedule file copy operation
@@ -440,7 +440,7 @@ std::vector<std::wstring> getLockingProcesses(const wchar_t* filename) //throw S
&buffer[0], //__out LPTSTR lpExeName,
&bufferSize)) //__inout PDWORD lpdwSize
if (bufferSize < buffer.size())
- processName += std::wstring(L", ") + L"\'" + &buffer[0] + L"\'";
+ processName += std::wstring(L", ") + L"\"" + &buffer[0] + L"\"";
}
}
output.push_back(processName);
diff --git a/zen/com_util.h b/zen/com_util.h
index 4f7cd0b8..5189b48e 100644
--- a/zen/com_util.h
+++ b/zen/com_util.h
@@ -15,7 +15,7 @@ namespace zen
{
//get an enumeration interface as a std::vector of bound(!) ComPtr(s)
template <class T, class U>
-std::vector<ComPtr<T> > convertEnum(const ComPtr<U>& enumObj); //enumObj: must have the "_NewEnum" property that supports the IEnumUnknown interface
+std::vector<ComPtr<T>> convertEnum(const ComPtr<U>& enumObj); //enumObj: must have the "_NewEnum" property that supports the IEnumUnknown interface
/*
extract text from com object member function returning a single BSTR: HRESULT ComInterface::MemFun([out] BSTR *pbstr);
@@ -68,9 +68,9 @@ private:
//############################ inline implemenatation ##################################
template <class T, class U> inline
-std::vector<ComPtr<T> > convertEnum(const ComPtr<U>& enumObj)
+std::vector<ComPtr<T>> convertEnum(const ComPtr<U>& enumObj)
{
- std::vector<ComPtr<T> > output;
+ std::vector<ComPtr<T>> output;
if (enumObj)
{
@@ -118,4 +118,4 @@ std::wstring getText(ComPtr<T> comObj, MemFun memFun)
}
-#endif //COM_UTILITY_HEADER \ No newline at end of file
+#endif //COM_UTILITY_HEADER
diff --git a/zen/dir_watcher.cpp b/zen/dir_watcher.cpp
index e53b63e2..17efda00 100644
--- a/zen/dir_watcher.cpp
+++ b/zen/dir_watcher.cpp
@@ -21,7 +21,10 @@
#include "file_traverser.h"
#elif defined ZEN_MAC
-//#include <CoreFoundation/FSEvents.h>
+//#include <sys/types.h>
+#include <sys/event.h>
+//#include <sys/time.h>
+#include "file_traverser.h"
#endif
using namespace zen;
@@ -39,7 +42,7 @@ public:
boost::lock_guard<boost::mutex> dummy(lockAccess);
if (bytesWritten == 0) //according to docu this may happen in case of internal buffer overflow: report some "dummy" change
- changedFiles.push_back(DirWatcher::Entry(DirWatcher::ACTION_CREATE, L"Overflow!"));
+ changedFiles.push_back(DirWatcher::Entry(DirWatcher::ACTION_CREATE, L"Overflow."));
else
{
const char* bufPos = &buffer[0];
@@ -49,13 +52,10 @@ public:
const Zstring fullname = dirname + Zstring(notifyInfo.FileName, notifyInfo.FileNameLength / sizeof(WCHAR));
- //skip modifications sent by changed directories: reason for change, child element creation/deletion, will notify separately!
- //and if this child element is a .ffs_lock file we'll want to ignore all associated events!
[&]
{
- //if (notifyInfo.Action == FILE_ACTION_RENAMED_OLD_NAME) //reporting FILE_ACTION_RENAMED_NEW_NAME should suffice;
- // return; //note: this is NOT a cross-directory move, which will show up as create + delete
-
+ //skip modifications sent by changed directories: reason for change, child element creation/deletion, will notify separately!
+ //and if this child element is a .ffs_lock file we'll want to ignore all associated events!
if (notifyInfo.Action == FILE_ACTION_MODIFIED)
{
//note: this check will not work if top watched directory has been renamed
@@ -64,6 +64,7 @@ public:
return;
}
+ //note: a move across directories will show up as FILE_ACTION_ADDED/FILE_ACTION_REMOVED!
switch (notifyInfo.Action)
{
case FILE_ACTION_ADDED:
@@ -156,12 +157,7 @@ public:
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
nullptr);
if (hDir == INVALID_HANDLE_VALUE)
- {
- const DWORD lastError = ::GetLastError(); //copy before making other system calls!
- const std::wstring errorMsg = replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(directory));
- const std::wstring errorDescr = formatSystemError(L"CreateFile", lastError);
- throw FileError(errorMsg, errorDescr);
- }
+ throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(directory)), formatSystemError(L"CreateFile", getLastError()));
//end of constructor, no need to start managing "hDir"
}
@@ -374,14 +370,6 @@ std::vector<DirWatcher::Entry> DirWatcher::getChanges(const std::function<void()
#elif defined ZEN_LINUX
-struct DirWatcher::Pimpl
-{
- Zstring dirname;
- int notifDescr;
- std::map<int, Zstring> watchDescrs; //watch descriptor and corresponding (sub-)directory name (postfixed with separator!)
-};
-
-
namespace
{
class DirsOnlyTraverser : public zen::TraverseCallback
@@ -396,8 +384,8 @@ public:
dirs_.push_back(fullName);
return this;
}
- virtual HandleError reportDirError (const std::wstring& msg) { throw FileError(msg); }
- virtual HandleError reportItemError(const std::wstring& msg, const Zchar* shortName) { throw FileError(msg); }
+ virtual HandleError reportDirError (const std::wstring& msg, size_t retryNumber) { throw FileError(msg); }
+ virtual HandleError reportItemError(const std::wstring& msg, size_t retryNumber, const Zchar* shortName) { throw FileError(msg); }
private:
std::vector<Zstring>& dirs_;
@@ -405,26 +393,33 @@ private:
}
+struct DirWatcher::Pimpl
+{
+ Zstring baseDirname;
+ int notifDescr;
+ std::map<int, Zstring> watchDescrs; //watch descriptor and (sub-)directory name (postfixed with separator) -> owned by "notifDescr"
+};
+
+
DirWatcher::DirWatcher(const Zstring& directory) : //throw FileError
pimpl_(new Pimpl)
{
- //still in main thread
+ //get all subdirectories
Zstring dirname = directory;
if (endsWith(dirname, FILE_NAME_SEPARATOR))
dirname.resize(dirname.size() - 1);
- //get all subdirectories
- std::vector<Zstring> fullDirList;
- fullDirList.push_back(dirname);
-
- DirsOnlyTraverser traverser(fullDirList); //throw FileError
- zen::traverseFolder(dirname, traverser); //don't traverse into symlinks (analog to windows build)
+ std::vector<Zstring> fullDirList { dirname };
+ {
+ DirsOnlyTraverser traverser(fullDirList); //throw FileError
+ zen::traverseFolder(dirname, traverser); //don't traverse into symlinks (analog to windows build)
+ }
//init
- pimpl_->dirname = directory;
+ pimpl_->baseDirname = directory;
pimpl_->notifDescr = ::inotify_init();
if (pimpl_->notifDescr == -1)
- throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(dirname)), formatSystemError(L"inotify_init", getLastError()));
+ throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(directory)), formatSystemError(L"inotify_init", getLastError()));
zen::ScopeGuard guardDescr = zen::makeGuard([&] { ::close(pimpl_->notifDescr); });
@@ -436,14 +431,13 @@ DirWatcher::DirWatcher(const Zstring& directory) : //throw FileError
initSuccess = ::fcntl(pimpl_->notifDescr, F_SETFL, flags | O_NONBLOCK) != -1;
}
if (!initSuccess)
- throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(dirname)), formatSystemError(L"fcntl", getLastError()));
+ throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(directory)), formatSystemError(L"fcntl", getLastError()));
//add watches
- std::for_each(fullDirList.begin(), fullDirList.end(),
- [&](Zstring subdir)
+ for (const Zstring& subdir : fullDirList)
{
int wd = ::inotify_add_watch(pimpl_->notifDescr, subdir.c_str(),
- IN_ONLYDIR | //watch directories only
+ IN_ONLYDIR | //"Only watch pathname if it is a directory."
IN_DONT_FOLLOW | //don't follow symbolic links
IN_CREATE |
IN_MODIFY |
@@ -454,15 +448,10 @@ DirWatcher::DirWatcher(const Zstring& directory) : //throw FileError
IN_MOVED_TO |
IN_MOVE_SELF);
if (wd == -1)
- {
- const ErrorCode lastError = getLastError(); //copy before making other system calls!
- const std::wstring errorMsg = replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(subdir));
- const std::wstring errorDescr = formatSystemError(L"inotify_add_watch", lastError);
- throw FileError(errorMsg, errorDescr);
- }
+ throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(subdir)), formatSystemError(L"inotify_add_watch", getLastError()));
pimpl_->watchDescrs.insert(std::make_pair(wd, appendSeparator(subdir)));
- });
+ }
guardDescr.dismiss();
}
@@ -476,12 +465,12 @@ DirWatcher::~DirWatcher()
std::vector<DirWatcher::Entry> DirWatcher::getChanges(const std::function<void()>&) //throw FileError
{
- //non-blocking call, see O_NONBLOCK
- std::vector<char> buffer(1024 * (sizeof(struct ::inotify_event) + 16));
+ std::vector<char> buffer(512 * (sizeof(struct ::inotify_event) + NAME_MAX + 1));
ssize_t bytesRead = 0;
do
{
+ //non-blocking call, see O_NONBLOCK
bytesRead = ::read(pimpl_->notifDescr, &buffer[0], buffer.size());
}
while (bytesRead < 0 && errno == EINTR); //"Interrupted function call; When this happens, you should try the call again."
@@ -491,7 +480,7 @@ std::vector<DirWatcher::Entry> DirWatcher::getChanges(const std::function<void()
if (errno == EAGAIN) //this error is ignored in all inotify wrappers I found
return std::vector<Entry>();
- throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(pimpl_->dirname)), formatSystemError(L"read", getLastError()));
+ throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(pimpl_->baseDirname)), formatSystemError(L"read", getLastError()));
}
std::vector<Entry> output;
@@ -530,27 +519,178 @@ std::vector<DirWatcher::Entry> DirWatcher::getChanges(const std::function<void()
}
#elif defined ZEN_MAC
+namespace
+{
+class DirsOnlyTraverser : public zen::TraverseCallback
+{
+public:
+ DirsOnlyTraverser(std::vector<Zstring>& dirs) : dirs_(dirs) {}
+
+ virtual void onFile (const Zchar* shortName, const Zstring& fullName, const FileInfo& details) {}
+ virtual HandleLink onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details) { return LINK_SKIP; }
+ virtual TraverseCallback* onDir(const Zchar* shortName, const Zstring& fullName)
+ {
+ dirs_.push_back(fullName);
+ return this;
+ }
+ virtual HandleError reportDirError (const std::wstring& msg, size_t retryNumber) { throw FileError(msg); }
+ virtual HandleError reportItemError(const std::wstring& msg, size_t retryNumber, const Zchar* shortName) { throw FileError(msg); }
+
+private:
+ std::vector<Zstring>& dirs_;
+};
+
+
+class DirDescriptor //throw FileError
+{
+public:
+ DirDescriptor(const Zstring& dirname) : dirname_(dirname)
+ {
+ fdDir = ::open(dirname.c_str(), O_EVTONLY); //"descriptor requested for event notifications only"; O_EVTONLY does not exist on Linux
+ if (fdDir == -1)
+ throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(dirname)), formatSystemError(L"open", getLastError()));
+ }
+
+ ~DirDescriptor() { if (fdDir != -1) ::close(fdDir); } //check for "-1" only needed by move-constructor
+
+ DirDescriptor(DirDescriptor&& other) : fdDir(other.fdDir), dirname_(std::move(other.dirname_)) { other.fdDir = -1; }
+
+ int getDescriptor() const { return fdDir; }
+ Zstring getDirname() const { return dirname_; }
+
+private:
+ DirDescriptor(const DirDescriptor&) = delete;
+ DirDescriptor& operator=(const DirDescriptor&) = delete;
+
+ int fdDir;
+ Zstring dirname_;
+};
+}
warn_static("finish")
struct DirWatcher::Pimpl
{
+ Zstring baseDirname;
+ int queueDescr;
+ std::map<int, DirDescriptor> watchDescrs; //directory descriptors and corresponding (sub-)directory name (postfixed with separator!)
+ std::vector<struct ::kevent> changelist;
};
-DirWatcher::DirWatcher(const Zstring& directory) //throw FileError
+DirWatcher::DirWatcher(const Zstring& directory) : //throw FileError
+ pimpl_(new Pimpl)
{
- throw FileError(L"Dir Watcher is not yet implemented!");
+ //get all subdirectories
+ Zstring dirname = directory;
+ if (endsWith(dirname, FILE_NAME_SEPARATOR))
+ dirname.resize(dirname.size() - 1);
+
+ std::vector<Zstring> fullDirList { dirname };
+ {
+ DirsOnlyTraverser traverser(fullDirList); //throw FileError
+ zen::traverseFolder(dirname, traverser); //don't traverse into symlinks (analog to windows build)
+ }
+
+ pimpl_->baseDirname = directory;
+
+ pimpl_->queueDescr = ::kqueue();
+ if (pimpl_->queueDescr == -1)
+ throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(directory)), formatSystemError(L"kqueue", getLastError()));
+ zen::ScopeGuard guardDescr = zen::makeGuard([&] { ::close(pimpl_->queueDescr); });
+
+ for (const Zstring& subdir : fullDirList)
+ {
+ DirDescriptor descr(subdir);
+ const int rawDescr = descr.getDescriptor();
+ pimpl_->watchDescrs.insert(std::make_pair(rawDescr, std::move(descr)));
+
+ pimpl_->changelist.push_back({});
+ EV_SET(&pimpl_->changelist.back(),
+ rawDescr, //identifier for this event
+ EVFILT_VNODE, //filter for event
+ EV_ADD | EV_CLEAR, //general flags
+ NOTE_DELETE | NOTE_REVOKE | NOTE_RENAME | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB, //filter-specific flags
+ 0, //filter-specific data
+ nullptr); //opaque user data identifier
+ }
+
+ //what about EINTR?
+ struct ::timespec timeout = {}; //=> poll
+ if (::kevent(pimpl_->queueDescr, &pimpl_->changelist[0], pimpl_->changelist.size(), nullptr, 0, &timeout) < 0)
+ throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(directory)), formatSystemError(L"kevent", getLastError()));
+
+ guardDescr.dismiss();
}
DirWatcher::~DirWatcher()
{
+ ::close(pimpl_->queueDescr);
}
std::vector<DirWatcher::Entry> DirWatcher::getChanges(const std::function<void()>&) //throw FileError
{
std::vector<Entry> output;
+
+ std::vector<struct ::kevent> events(512);
+ for (;;)
+ {
+ assert(!pimpl_->changelist.empty()); //contains at least parent directory
+ struct ::timespec timeout = {}; //=> poll
+
+ int evtCount = 0;
+ do
+ {
+ evtCount = ::kevent(pimpl_->queueDescr, //int kq,
+ &pimpl_->changelist[0], //const struct kevent* changelist,
+ pimpl_->changelist.size(), //int nchanges,
+ &events[0], //struct kevent* eventlist,
+ events.size(), //int nevents,
+ &timeout); //const struct timespec* timeout
+ }
+ while (evtCount < 0 && errno == EINTR);
+
+ if (evtCount == -1)
+ throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(pimpl_->baseDirname)), formatSystemError(L"kevent", getLastError()));
+
+ for (int i = 0; i < evtCount; ++i)
+ {
+ const auto& evt = events[i];
+
+ auto it = pimpl_->watchDescrs.find(static_cast<int>(evt.ident));
+ if (it == pimpl_->watchDescrs.end())
+ throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(pimpl_->baseDirname)), L"Received event from unknown source.");
+
+ //"If an error occurs [...] and there is enough room in the eventlist, then the event will
+ // be placed in the eventlist with EV_ERROR set in flags and the system error in data."
+ if (evt.flags & EV_ERROR)
+ throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(it->second.getDirname())), formatSystemError(L"kevent", static_cast<ErrorCode>(evt.data)));
+
+ assert(evt.filter == EVFILT_VNODE);
+ if (evt.filter == EVFILT_VNODE)
+ {
+ if (evt.fflags & NOTE_DELETE)
+ wxMessageBox(L"NOTE_DELETE "+ it->second.getDirname());
+ else if (evt.fflags & NOTE_REVOKE)
+ wxMessageBox(L"NOTE_REVOKE "+ it->second.getDirname());
+ else if (evt.fflags & NOTE_RENAME)
+ wxMessageBox(L"NOTE_RENAME "+ it->second.getDirname());
+ else if (evt.fflags & NOTE_WRITE)
+ wxMessageBox(L"NOTE_WRITE "+ it->second.getDirname());
+ else if (evt.fflags & NOTE_EXTEND)
+ wxMessageBox(L"NOTE_EXTEND "+ it->second.getDirname());
+ else if (evt.fflags & NOTE_ATTRIB)
+ wxMessageBox(L"NOTE_ATTRIB "+ it->second.getDirname());
+ else
+ assert(false);
+ }
+ }
+
+ if (evtCount < events.size())
+ break;
+ }
+
return output;
}
#endif
diff --git a/zen/dir_watcher.h b/zen/dir_watcher.h
index eaee5aab..233bdc59 100644
--- a/zen/dir_watcher.h
+++ b/zen/dir_watcher.h
@@ -16,6 +16,7 @@ namespace zen
{
//Windows: ReadDirectoryChangesW http://msdn.microsoft.com/en-us/library/aa365465(v=vs.85).aspx
//Linux: inotify http://linux.die.net/man/7/inotify
+//OS X: kqueue http://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/kqueue.2.html
//watch directory including subdirectories
/*
diff --git a/zen/error_log.h b/zen/error_log.h
index 05049d27..de4d3c9e 100644
--- a/zen/error_log.h
+++ b/zen/error_log.h
@@ -96,7 +96,7 @@ String formatMessageImpl(const LogEntry& entry) //internal linkage
case TYPE_ERROR:
return _("Error");
case TYPE_FATAL_ERROR:
- return _("Fatal Error");
+ return _("Serious Error");
}
assert(false);
return std::wstring();
diff --git a/zen/file_error.h b/zen/file_error.h
index db8b371d..5d655239 100644
--- a/zen/file_error.h
+++ b/zen/file_error.h
@@ -49,9 +49,9 @@ inline
std::wstring fmtFileName(const Zstring& filename)
{
std::wstring output;
- output += L'\'';
+ output += L'\"';
output += utfCvrtTo<std::wstring>(filename);
- output += L'\'';
+ output += L'\"';
return output;
}
}
diff --git a/zen/file_handling.cpp b/zen/file_handling.cpp
index 3f8d5bbd..fd4239ed 100644
--- a/zen/file_handling.cpp
+++ b/zen/file_handling.cpp
@@ -205,29 +205,29 @@ void getFileAttrib(const Zstring& filename, FileAttrib& attr, ProcSymlink procSl
const int rv = procSl == SYMLINK_FOLLOW ?
:: stat(filename.c_str(), &fileInfo) :
::lstat(filename.c_str(), &fileInfo);
- if (rv != 0) //follow symbolic links
+ if (rv != 0)
throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)), formatSystemError(L"stat", getLastError()));
attr.fileSize = UInt64(fileInfo.st_size);
attr.modificationTime = fileInfo.st_mtime;
#endif
}
-}
-UInt64 zen::getFilesize(const Zstring& filename) //throw FileError
+Int64 getFileTime(const Zstring& filename, ProcSymlink procSl) //throw FileError
{
FileAttrib attr;
- getFileAttrib(filename, attr, SYMLINK_FOLLOW); //throw FileError
- return attr.fileSize;
+ getFileAttrib(filename, attr, procSl); //throw FileError
+ return attr.modificationTime;
+}
}
-Int64 zen::getFileTime(const Zstring& filename, ProcSymlink procSl) //throw FileError
+UInt64 zen::getFilesize(const Zstring& filename) //throw FileError
{
FileAttrib attr;
- getFileAttrib(filename, attr, procSl); //throw FileError
- return attr.modificationTime;
+ getFileAttrib(filename, attr, SYMLINK_FOLLOW); //throw FileError
+ return attr.fileSize;
}
@@ -537,8 +537,8 @@ public:
dirs_.push_back(fullName);
return nullptr; //DON'T traverse into subdirs; removeDirectory works recursively!
}
- virtual HandleError reportDirError (const std::wstring& msg) { throw FileError(msg); }
- virtual HandleError reportItemError(const std::wstring& msg, const Zchar* shortName) { throw FileError(msg); }
+ virtual HandleError reportDirError (const std::wstring& msg, size_t retryNumber) { throw FileError(msg); }
+ virtual HandleError reportItemError(const std::wstring& msg, size_t retryNumber, const Zchar* shortName) { throw FileError(msg); }
private:
CollectFilesFlat(const CollectFilesFlat&);
@@ -1821,14 +1821,17 @@ struct CallbackData
const Zstring& targetFile) :
sourceFile_(sourceFile),
targetFile_(targetFile),
- userCallback(cb) {}
+ userCallback(cb),
+ fileInfoSrc(),
+ fileInfoTrg() {}
const Zstring& sourceFile_;
const Zstring& targetFile_;
CallbackCopyFile* const userCallback; //optional!
ErrorHandling errorHandler;
- FileAttrib newAttrib; //modified by CopyFileEx() at beginning
+ BY_HANDLE_FILE_INFORMATION fileInfoSrc; //modified by CopyFileEx() at beginning
+ BY_HANDLE_FILE_INFORMATION fileInfoTrg; //
Int64 bytesReported; //used internally to calculate bytes transferred delta
};
@@ -1852,7 +1855,7 @@ DWORD CALLBACK copyCallbackInternal(LARGE_INTEGER totalFileSize,
if source is a symlink and COPY_FILE_COPY_SYMLINK is NOT specified, this callback is called and hSourceFile is a handle to the *target* of the link!
file time handling:
- ::CopyFileEx() will copy file modification time (only) over from source file AFTER the last invokation of this callback
+ ::CopyFileEx() will (only) copy file modification time over from source file AFTER the last invokation of this callback
=> it is possible to adapt file creation time of target in here, but NOT file modification time!
CAVEAT: if ::CopyFileEx() fails to set modification time, it silently ignores this error and returns success!!!
see procmon log in: https://sourceforge.net/tracker/?func=detail&atid=1093080&aid=3514569&group_id=234430
@@ -1870,38 +1873,31 @@ DWORD CALLBACK copyCallbackInternal(LARGE_INTEGER totalFileSize,
dwStreamNumber == 1) //consider ADS!
{
//#################### return source file attributes ################################
- BY_HANDLE_FILE_INFORMATION fileInfoSrc = {};
- if (!::GetFileInformationByHandle(hSourceFile, &fileInfoSrc))
+ if (!::GetFileInformationByHandle(hSourceFile, &cbd.fileInfoSrc))
{
cbd.errorHandler.reportError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(cbd.sourceFile_)), formatSystemError(L"GetFileInformationByHandle", getLastError()));
return PROGRESS_CANCEL;
}
- BY_HANDLE_FILE_INFORMATION fileInfoTrg = {};
- if (!::GetFileInformationByHandle(hDestinationFile, &fileInfoTrg))
+ if (!::GetFileInformationByHandle(hDestinationFile, &cbd.fileInfoTrg))
{
cbd.errorHandler.reportError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(cbd.targetFile_)), formatSystemError(L"GetFileInformationByHandle", getLastError()));
return PROGRESS_CANCEL;
}
- cbd.newAttrib.fileSize = UInt64(fileInfoSrc.nFileSizeLow, fileInfoSrc.nFileSizeHigh);
- cbd.newAttrib.modificationTime = toTimeT(fileInfoSrc.ftLastWriteTime); //no DST hack (yet)
- cbd.newAttrib.sourceFileId = extractFileID(fileInfoSrc);
- cbd.newAttrib.targetFileId = extractFileID(fileInfoTrg);
-
//#################### switch to sparse file copy if req. #######################
- if (canCopyAsSparse(fileInfoSrc.dwFileAttributes, cbd.targetFile_)) //throw ()
+ if (canCopyAsSparse(cbd.fileInfoSrc.dwFileAttributes, cbd.targetFile_)) //throw ()
{
cbd.errorHandler.reportErrorShouldCopyAsSparse(); //use a different copy routine!
return PROGRESS_CANCEL;
}
//#################### copy file creation time ################################
- ::SetFileTime(hDestinationFile, &fileInfoSrc.ftCreationTime, nullptr, nullptr); //no error handling!
+ ::SetFileTime(hDestinationFile, &cbd.fileInfoSrc.ftCreationTime, nullptr, nullptr); //no error handling!
//#################### copy NTFS compressed attribute #########################
- const bool sourceIsCompressed = (fileInfoSrc.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) != 0;
- const bool targetIsCompressed = (fileInfoTrg.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) != 0; //already set by CopyFileEx if target parent folder is compressed!
+ const bool sourceIsCompressed = (cbd.fileInfoSrc.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) != 0;
+ const bool targetIsCompressed = (cbd.fileInfoTrg.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) != 0; //already set by CopyFileEx if target parent folder is compressed!
if (sourceIsCompressed && !targetIsCompressed)
{
USHORT cmpState = COMPRESSION_FORMAT_DEFAULT;
@@ -2026,7 +2022,7 @@ void copyFileWindowsDefault(const Zstring& sourceFile,
if (lastError == ERROR_INVALID_PARAMETER &&
dst::isFatDrive(targetFile) &&
getFilesize(sourceFile) >= 4U * UInt64(1024U * 1024 * 1024)) //throw FileError
- errorDescr += L"\nFAT volume cannot store files larger than 4 gigabyte!";
+ errorDescr += L"\nFAT volumes cannot store files larger than 4 gigabyte.";
//note: ERROR_INVALID_PARAMETER can also occur when copying to a SharePoint server or MS SkyDrive and the target filename is of a restricted type.
}
@@ -2036,13 +2032,18 @@ void copyFileWindowsDefault(const Zstring& sourceFile,
}
if (newAttrib)
- *newAttrib = cbd.newAttrib;
+ {
+ newAttrib->fileSize = UInt64(cbd.fileInfoSrc.nFileSizeLow, cbd.fileInfoSrc.nFileSizeHigh);
+ newAttrib->modificationTime = toTimeT(cbd.fileInfoSrc.ftLastWriteTime); //no DST hack (yet)
+ newAttrib->sourceFileId = extractFileID(cbd.fileInfoSrc);
+ newAttrib->targetFileId = extractFileID(cbd.fileInfoTrg);
+ }
{
//DST hack
const Int64 modTime = getFileTime(sourceFile, SYMLINK_FOLLOW); //throw FileError
setFileTime(targetFile, modTime, SYMLINK_FOLLOW); //throw FileError
- //caveat: - ::CopyFileEx() silently *ignores* failure to set modification time!!! => we need to set again in order to catch such errors!
+ //caveat: - ::CopyFileEx() silently *ignores* failure to set modification time!!! => we need to set it again but with proper error checking!
// - this sequence leads to a loss of precision of up to 1 sec!
// - perf-loss on USB sticks with many small files of about 30%! damn!
diff --git a/zen/file_handling.h b/zen/file_handling.h
index c437e7bc..2c4f7938 100644
--- a/zen/file_handling.h
+++ b/zen/file_handling.h
@@ -29,7 +29,6 @@ enum ProcSymlink
SYMLINK_FOLLOW
};
-Int64 getFileTime(const Zstring& filename, ProcSymlink procSl); //throw FileError
void setFileTime(const Zstring& filename, const Int64& modificationTime, ProcSymlink procSl); //throw FileError
//symlink handling: always evaluate target
diff --git a/zen/file_io.cpp b/zen/file_io.cpp
index 45cbd028..fbca9089 100644
--- a/zen/file_io.cpp
+++ b/zen/file_io.cpp
@@ -177,7 +177,7 @@ size_t FileInput::read(void* buffer, size_t bytesToRead) //returns actual number
if (bytesRead < bytesToRead)
if (!eof()) //pathologic!?
- throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(getFilename())), L"Incomplete read!"); //user should never see this
+ throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(getFilename())), L"Incomplete read."); //user should never see this
#endif
if (bytesRead > bytesToRead)
@@ -305,7 +305,7 @@ void FileOutput::write(const void* buffer, size_t bytesToWrite) //throw FileErro
throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(getFilename())), formatSystemError(functionName, getLastError()));
if (bytesWritten != bytesToWrite) //must be fulfilled for synchronous writes!
- throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(getFilename())), L"Incomplete write!"); //user should never see this
+ throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(getFilename())), L"Incomplete write."); //user should never see this
}
@@ -318,12 +318,7 @@ FileInputUnbuffered::FileInputUnbuffered(const Zstring& filename) : FileInputBas
fdFile = ::open(filename.c_str(), O_RDONLY);
if (fdFile == -1) //don't check "< 0" -> docu seems to allow "-2" to be a valid file handle
- {
- const ErrorCode lastError = getLastError(); //copy before making other system calls!
- const std::wstring errorMsg = replaceCpy(_("Cannot open file %x."), L"%x", fmtFileName(filename));
- const std::wstring errorDescr = formatSystemError(L"open", lastError);
- throw FileError(errorMsg, errorDescr);
- }
+ throw FileError(replaceCpy(_("Cannot open file %x."), L"%x", fmtFileName(filename)), formatSystemError(L"open", getLastError()));
}
diff --git a/zen/file_io.h b/zen/file_io.h
index 0c7506a1..2e9e828e 100644
--- a/zen/file_io.h
+++ b/zen/file_io.h
@@ -22,10 +22,8 @@ namespace zen
{
#ifdef ZEN_WIN
static const char LINE_BREAK[] = "\r\n";
-#elif defined ZEN_LINUX
-static const char LINE_BREAK[] = "\n";
-#elif defined ZEN_MAC
-static const char LINE_BREAK[] = "\r";
+#elif defined ZEN_LINUX || defined ZEN_MAC
+static const char LINE_BREAK[] = "\n"; //since OS X apple uses newline, too
#endif
//buffered file IO optimized for sequential read/write accesses + better error reporting + long path support (following symlinks)
diff --git a/zen/file_traverser.cpp b/zen/file_traverser.cpp
index a3e8491a..959a6071 100644
--- a/zen/file_traverser.cpp
+++ b/zen/file_traverser.cpp
@@ -36,7 +36,7 @@ namespace
template <class Command> inline //function object expecting to throw FileError if operation fails
bool tryReportingDirError(Command cmd, zen::TraverseCallback& callback) //return "true" on success, "false" if error was ignored
{
- for (;;)
+ for (size_t retryNumber = 0;; ++retryNumber)
try
{
cmd(); //throw FileError
@@ -44,7 +44,7 @@ bool tryReportingDirError(Command cmd, zen::TraverseCallback& callback) //return
}
catch (const FileError& e)
{
- switch (callback.reportDirError(e.toString()))
+ switch (callback.reportDirError(e.toString(), retryNumber))
{
case TraverseCallback::ON_ERROR_RETRY:
break;
@@ -57,7 +57,7 @@ bool tryReportingDirError(Command cmd, zen::TraverseCallback& callback) //return
template <class Command> inline //function object expecting to throw FileError if operation fails
bool tryReportingItemError(Command cmd, zen::TraverseCallback& callback, const Zchar* shortName) //return "true" on success, "false" if error was ignored
{
- for (;;)
+ for (size_t retryNumber = 0;; ++retryNumber)
try
{
cmd(); //throw FileError
@@ -65,7 +65,7 @@ bool tryReportingItemError(Command cmd, zen::TraverseCallback& callback, const Z
}
catch (const FileError& e)
{
- switch (callback.reportItemError(e.toString(), shortName))
+ switch (callback.reportItemError(e.toString(), retryNumber, shortName))
{
case TraverseCallback::ON_ERROR_RETRY:
break;
@@ -559,7 +559,7 @@ private:
{
bufferUtfDecomposed.resize(lenMax);
if (::CFStringGetFileSystemRepresentation(cfStr, &bufferUtfDecomposed[0], lenMax)) //get decomposed UTF form (verified!) despite ambiguous documentation
- shortName = &bufferUtfDecomposed[0];
+ shortName = &bufferUtfDecomposed[0]; //attention: => don't access "shortName" after recursion in "traverse"!
}
}
//const char* sampleDecomposed = "\x6f\xcc\x81.txt";
diff --git a/zen/file_traverser.h b/zen/file_traverser.h
index a1d8ac9e..d686e9b8 100644
--- a/zen/file_traverser.h
+++ b/zen/file_traverser.h
@@ -52,8 +52,8 @@ struct TraverseCallback
//nullptr: ignore directory, non-nullptr: traverse into using the (new) callback => implement releaseDirTraverser() if necessary!
virtual void releaseDirTraverser(TraverseCallback* trav) {}
- virtual HandleError reportDirError (const std::wstring& msg) = 0; //failed directory traversal -> consider directory data as incomplete!
- virtual HandleError reportItemError(const std::wstring& msg, const Zchar* shortName) = 0; //failed to get data for single file/dir/symlink only!
+ virtual HandleError reportDirError (const std::wstring& msg, size_t retryNumber) = 0; //failed directory traversal -> consider directory data as incomplete!
+ virtual HandleError reportItemError(const std::wstring& msg, size_t retryNumber, const Zchar* shortName) = 0; //failed to get data for single file/dir/symlink only!
};
diff --git a/zen/fixed_list.h b/zen/fixed_list.h
index e3083c89..d38dbae5 100644
--- a/zen/fixed_list.h
+++ b/zen/fixed_list.h
@@ -12,7 +12,7 @@
namespace zen
{
//std::list(C++11) compatible class for inplace element construction supporting non-copyable/movable types
-//may be replaced by C++11 std::list when available
+//may be replaced by C++11 std::list when available...or never...
template <class T>
class FixedList
{
@@ -48,7 +48,7 @@ public:
ListIterator& operator++() { iter = iter->next; return *this; }
inline friend bool operator==(const ListIterator& lhs, const ListIterator& rhs) { return lhs.iter == rhs.iter; }
inline friend bool operator!=(const ListIterator& lhs, const ListIterator& rhs) { return !(lhs == rhs); }
- U& operator* () { return iter->val; }
+ U& operator* () { return iter->val; }
U* operator->() { return &iter->val; }
private:
NodeT* iter;
diff --git a/zen/format_unit.cpp b/zen/format_unit.cpp
index 4f16e3e1..4b39d5a9 100644
--- a/zen/format_unit.cpp
+++ b/zen/format_unit.cpp
@@ -40,7 +40,7 @@ std::wstring zen::filesizeToShortString(Int64 size)
//if (size < 0) return _("Error"); -> really?
if (numeric::abs(size) <= 999)
- return replaceCpy(_P("1 byte", "%x bytes", to<int>(size)), L"%x", numberTo<std::wstring>(size));
+ return _P("1 byte", "%x bytes", to<int>(size));
double sizeInUnit = to<double>(size);
auto formatUnit = [&](const std::wstring& unitTxt) { return replaceCpy(unitTxt, L"%x", formatThreeDigitPrecision(sizeInUnit)); };
@@ -79,17 +79,16 @@ enum UnitRemTime
std::wstring formatUnitTime(int val, UnitRemTime unit)
{
- auto subst = [&](const std::wstring& output) { return replaceCpy(output, L"%x", zen::numberTo<std::wstring>(val)); };
switch (unit)
{
case URT_SEC:
- return subst(_P("1 sec", "%x sec", val));
+ return _P("1 sec", "%x sec", val);
case URT_MIN:
- return subst(_P("1 min", "%x min", val));
+ return _P("1 min", "%x min", val);
case URT_HOUR:
- return subst(_P("1 hour", "%x hours", val));
+ return _P("1 hour", "%x hours", val);
case URT_DAY:
- return subst(_P("1 day", "%x days", val));
+ return _P("1 day", "%x days", val);
}
assert(false);
return _("Error");
@@ -256,8 +255,8 @@ std::wstring zen::ffs_Impl::includeNumberSeparator(const std::wstring& number)
const lconv* localInfo = ::localeconv(); //always bound according to doc
const std::wstring& thousandSep = utfCvrtTo<std::wstring>(localInfo->thousands_sep);
- // THOUSANDS_SEPARATOR = std::use_facet<std::numpunct<wchar_t> >(std::locale("")).thousands_sep(); - why not working?
- // DECIMAL_POINT = std::use_facet<std::numpunct<wchar_t> >(std::locale("")).decimal_point();
+ // THOUSANDS_SEPARATOR = std::use_facet<std::numpunct<wchar_t>>(std::locale("")).thousands_sep(); - why not working?
+ // DECIMAL_POINT = std::use_facet<std::numpunct<wchar_t>>(std::locale("")).decimal_point();
std::wstring output(number);
size_t i = output.size();
diff --git a/zen/i18n.h b/zen/i18n.h
index b7d10d3c..6b8cf142 100644
--- a/zen/i18n.h
+++ b/zen/i18n.h
@@ -9,16 +9,20 @@
#include <string>
#include <memory>
+#include <cstdint>
+#include "string_tools.h"
+
//minimal layer enabling text translation - without platform/library dependencies!
#ifndef WXINTL_NO_GETTEXT_MACRO
#error WXINTL_NO_GETTEXT_MACRO must be defined to deactivate wxWidgets underscore macro
#endif
-#define ZEN_CONCAT_SUB(X, Y) X ## Y
-#define _(s) zen::implementation::translate(ZEN_CONCAT_SUB(L, s))
-#define _P(s, p, n) zen::implementation::translate(ZEN_CONCAT_SUB(L, s), ZEN_CONCAT_SUB(L, p), n)
-
+#define ZEN_TRANS_CONCAT_SUB(X, Y) X ## Y
+#define _(s) zen::implementation::translate(ZEN_TRANS_CONCAT_SUB(L, s))
+#define _P(s, p, n) zen::implementation::translate(ZEN_TRANS_CONCAT_SUB(L, s), ZEN_TRANS_CONCAT_SUB(L, p), n)
+//source and translation are required to use %x as number placeholder
+//for plural form, which will be substituted automatically!!!
namespace zen
{
@@ -28,7 +32,7 @@ struct TranslationHandler
virtual ~TranslationHandler() {}
virtual std::wstring translate(const std::wstring& text) = 0; //simple translation
- virtual std::wstring translate(const std::wstring& singular, const std::wstring& plural, int n) = 0;
+ virtual std::wstring translate(const std::wstring& singular, const std::wstring& plural, std::int64_t n) = 0;
};
void setTranslator(TranslationHandler* newHandler = nullptr); //takes ownership
@@ -46,14 +50,6 @@ TranslationHandler* getTranslator();
-
-
-
-
-
-
-
-
//######################## implementation ##############################
namespace implementation
{
@@ -64,18 +60,27 @@ std::wstring translate(const std::wstring& text)
}
//translate plural forms: "%x day" "%x days"
-//returns "%x day" if n == 1; "%x days" else for english language
+//returns "1 day" if n == 1; "123 days" if n == 123 for english language
inline
-std::wstring translate(const std::wstring& singular, const std::wstring& plural, int n)
+std::wstring translate(const std::wstring& singular, const std::wstring& plural, std::int64_t n)
{
- if (n < 0) n = -n;
- return getTranslator() ? getTranslator()->translate(singular, plural, n) : n == 1 ? singular : plural;
+ assert(contains(plural, L"%x"));
+
+ if (getTranslator())
+ {
+ std::wstring translation = getTranslator()->translate(singular, plural, n);
+ assert(!contains(translation, L"%x"));
+ return translation;
+ }
+ else
+ return replaceCpy(std::abs(n) == 1 ? singular : plural, L"%x", zen::numberTo<std::wstring>(n));
}
template <class T> inline
std::wstring translate(const std::wstring& singular, const std::wstring& plural, T n)
{
- return translate(singular, plural, static_cast<int>(n % 1000000));
+ static_assert(sizeof(n) <= sizeof(std::int64_t), "");
+ return translate(singular, plural, static_cast<std::int64_t>(n));
}
inline
diff --git a/zen/notify_removal.cpp b/zen/notify_removal.cpp
index 4b00cadf..d1fbc6ed 100644
--- a/zen/notify_removal.cpp
+++ b/zen/notify_removal.cpp
@@ -82,7 +82,7 @@ MessageProvider::MessageProvider() :
windowHandle(nullptr)
{
if (!hMainModule)
- throw FileError(_("Failed to register to receive system messages."), formatSystemError(L"GetModuleHandle", getLastError()));
+ throw FileError(_("Unable to register to receive system messages."), formatSystemError(L"GetModuleHandle", getLastError()));
//register the main window class
WNDCLASS wc = {};
@@ -91,7 +91,7 @@ MessageProvider::MessageProvider() :
wc.lpszClassName = dummyWindowName;
if (::RegisterClass(&wc) == 0)
- throw FileError(_("Failed to register to receive system messages."), formatSystemError(L"RegisterClass", getLastError()));
+ throw FileError(_("Unable to register to receive system messages."), formatSystemError(L"RegisterClass", getLastError()));
ScopeGuard guardClass = makeGuard([&] { ::UnregisterClass(dummyWindowName, hMainModule); });
@@ -108,7 +108,7 @@ MessageProvider::MessageProvider() :
hMainModule, //HINSTANCE hInstance,
nullptr); //LPVOID lpParam
if (!windowHandle)
- throw FileError(_("Failed to register to receive system messages."), formatSystemError(L"CreateWindow", getLastError()));
+ throw FileError(_("Unable to register to receive system messages."), formatSystemError(L"CreateWindow", getLastError()));
guardClass.dismiss();
}
@@ -156,7 +156,7 @@ public:
if (lastError != ERROR_CALL_NOT_IMPLEMENTED && //fail on SAMBA share: this shouldn't be a showstopper!
lastError != ERROR_SERVICE_SPECIFIC_ERROR && //neither should be fail for "Pogoplug" mapped network drives
lastError != ERROR_INVALID_DATA) //this seems to happen for a NetDrive-mapped FTP server
- throw zen::FileError(_("Failed to register to receive system messages."), formatSystemError(L"RegisterDeviceNotification", lastError));
+ throw zen::FileError(_("Unable to register to receive system messages."), formatSystemError(L"RegisterDeviceNotification", lastError));
}
guardProvider.dismiss();
diff --git a/zen/osx_string.h b/zen/osx_string.h
index 0d77345c..38c54023 100644
--- a/zen/osx_string.h
+++ b/zen/osx_string.h
@@ -48,7 +48,7 @@ Zstring cfStringToZstring(const CFStringRef& cfStr)
if (::CFStringGetCString(cfStr, &*buffer.begin(), bufferSize, kCFStringEncodingUTF8))
{
- buffer.resize(zen::strLength(&*buffer.begin())); //caveat: memory consumption of returned string!
+ buffer.resize(zen::strLength(buffer.c_str())); //caveat: memory consumption of returned string!
return buffer;
}
}
diff --git a/zen/privilege.cpp b/zen/privilege.cpp
index d4f956a8..98eaad43 100644
--- a/zen/privilege.cpp
+++ b/zen/privilege.cpp
@@ -3,6 +3,7 @@
#include "thread.h" //includes <boost/thread.hpp>
#include "zstring.h"
#include "scope_guard.h"
+#include "win_ver.h"
using namespace zen;
@@ -68,9 +69,17 @@ void setPrivilege(LPCTSTR privilege, bool enable) //throw FileError
nullptr)) //__out_opt PDWORD ReturnLength
throw FileError(replaceCpy(_("Cannot set privilege %x."), L"%x", std::wstring(L"\"") + privilege + L"\""), formatSystemError(L"AdjustTokenPrivileges", getLastError()));
- const ErrorCode lastError = getLastError();
+ ErrorCode lastError = getLastError();
if (lastError == ERROR_NOT_ALL_ASSIGNED) //check although previous function returned with success!
+ {
+#ifdef __MINGW32__ //Shobjidl.h
+#define ERROR_ELEVATION_REQUIRED 740L
+#endif
+ if (vistaOrLater()) //replace this useless error code with what it *really* means!
+ lastError = ERROR_ELEVATION_REQUIRED;
+
throw FileError(replaceCpy(_("Cannot set privilege %x."), L"%x", std::wstring(L"\"") + privilege + L"\""), formatSystemError(L"AdjustTokenPrivileges", lastError));
+ }
}
diff --git a/zen/process_priority.cpp b/zen/process_priority.cpp
index b09b35f5..3ac2f068 100644
--- a/zen/process_priority.cpp
+++ b/zen/process_priority.cpp
@@ -28,7 +28,7 @@ struct PreventStandby::Pimpl {};
PreventStandby::PreventStandby()
{
if (::SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED) == 0)
- throw FileError(_("Failed to suspend system sleep mode.")); //no GetLastError() support?
+ throw FileError(_("Unable to suspend system sleep mode.")); //no GetLastError() support?
}
@@ -116,7 +116,7 @@ PreventStandby::PreventStandby() : pimpl(make_unique<Pimpl>())
CFSTR("FreeFileSync"),
&pimpl->assertionID);
if (rv != kIOReturnSuccess)
- throw FileError(_("Failed to suspend system sleep mode."), replaceCpy<std::wstring>(L"IOReturn Code %x", L"%x", numberTo<std::wstring>(rv))); //could not find a better way to convert IOReturn to string
+ throw FileError(_("Unable to suspend system sleep mode."), replaceCpy<std::wstring>(L"IOReturn Code %x", L"%x", numberTo<std::wstring>(rv))); //could not find a better way to convert IOReturn to string
}
PreventStandby::~PreventStandby()
diff --git a/zen/read_txt.cpp b/zen/read_txt.cpp
index 7566ff14..23649846 100644
--- a/zen/read_txt.cpp
+++ b/zen/read_txt.cpp
@@ -1,3 +1,9 @@
+// **************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
+// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
+// **************************************************************************
+
#include "read_txt.h"
using namespace zen;
@@ -42,7 +48,7 @@ std::string detectLineBreak(const Zstring& filename) //throw FileError
}
-ExtractLines::ExtractLines(const Zstring& filename, const std::string& lineBreak) : //throw FileError
+LineExtractor::LineExtractor(const Zstring& filename, const std::string& lineBreak) : //throw FileError
inputStream(filename), bufferLogBegin(buffer.begin()), lineBreak_(lineBreak)
{
if (lineBreak.empty())
@@ -50,7 +56,7 @@ ExtractLines::ExtractLines(const Zstring& filename, const std::string& lineBreak
}
-bool ExtractLines::getLine(std::string& output) //throw FileError
+bool LineExtractor::getLine(std::string& output) //throw FileError
{
warn_static("don't use lineBreak, but support any of r, n, rn!!!")
for (;;)
diff --git a/zen/read_txt.h b/zen/read_txt.h
index 0678ac52..92892716 100644
--- a/zen/read_txt.h
+++ b/zen/read_txt.h
@@ -13,10 +13,10 @@
namespace zen
{
-class ExtractLines
+class LineExtractor
{
public:
- ExtractLines(const Zstring& filename, const std::string& lineBreak = std::string()); //throw FileError
+ LineExtractor(const Zstring& filename, const std::string& lineBreak = std::string()); //throw FileError
bool getLine(std::string& output); //throw FileError
private:
diff --git a/zen/scroll_window_under_cursor.cpp b/zen/scroll_window_under_cursor.cpp
index ccc00bcf..76a5ab4a 100644
--- a/zen/scroll_window_under_cursor.cpp
+++ b/zen/scroll_window_under_cursor.cpp
@@ -49,9 +49,9 @@ LRESULT CALLBACK mouseInputHook(int nCode, WPARAM wParam, LPARAM lParam)
return ::CallNextHookEx(nullptr, nCode, wParam, lParam);
}
-struct Dummy
+struct InstallMouseHook
{
- Dummy()
+ InstallMouseHook()
{
hHook = ::SetWindowsHookEx(WH_GETMESSAGE, //__in int idHook,
mouseInputHook, //__in HOOKPROC lpfn,
@@ -60,7 +60,7 @@ struct Dummy
assert(hHook);
}
- ~Dummy()
+ ~InstallMouseHook()
{
if (hHook)
::UnhookWindowsHookEx(hHook);
diff --git a/zen/shell_execute.h b/zen/shell_execute.h
new file mode 100644
index 00000000..14a6a40e
--- /dev/null
+++ b/zen/shell_execute.h
@@ -0,0 +1,104 @@
+// **************************************************************************
+// * This file is part of the FreeFileSync project. It is distributed under *
+// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
+// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
+// **************************************************************************
+
+#ifndef EXECUTE_HEADER_23482134578134134
+#define EXECUTE_HEADER_23482134578134134
+
+#include "file_error.h"
+
+#ifdef ZEN_WIN
+#include "scope_guard.h"
+#include "win.h" //includes "windows.h"
+
+#elif defined ZEN_LINUX || defined ZEN_MAC
+#include "thread.h"
+#include <stdlib.h> //::system()
+#endif
+
+
+namespace zen
+{
+//launch commandline and report errors via popup dialog
+//windows: COM needs to be initialized before calling this function!
+enum ExecutionType
+{
+ EXEC_TYPE_SYNC,
+ EXEC_TYPE_ASYNC
+};
+
+namespace
+{
+void shellExecute2(const Zstring& command, ExecutionType type) //throw FileError
+{
+#ifdef ZEN_WIN
+ //parse commandline
+ Zstring commandTmp = command;
+ trim(commandTmp, true, false); //CommandLineToArgvW() does not like leading spaces
+
+ std::vector<Zstring> argv;
+ int argc = 0;
+ if (LPWSTR* tmp = ::CommandLineToArgvW(commandTmp.c_str(), &argc))
+ {
+ ZEN_ON_SCOPE_EXIT(::LocalFree(tmp));
+ std::copy(tmp, tmp + argc, std::back_inserter(argv));
+ }
+
+ Zstring filename;
+ Zstring arguments;
+ if (!argv.empty())
+ {
+ filename = argv[0];
+ for (auto iter = argv.begin() + 1; iter != argv.end(); ++iter)
+ arguments += (iter != argv.begin() ? L" " : L"") +
+ (iter->empty() || std::any_of(iter->begin(), iter->end(), &isWhiteSpace<wchar_t>) ? L"\"" + *iter + L"\"" : *iter);
+ }
+
+ SHELLEXECUTEINFO execInfo = {};
+ execInfo.cbSize = sizeof(execInfo);
+
+ //SEE_MASK_NOASYNC is equal to SEE_MASK_FLAG_DDEWAIT, but former is defined not before Win SDK 6.0
+ execInfo.fMask = type == EXEC_TYPE_SYNC ? (SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT) : 0; //don't use SEE_MASK_ASYNCOK -> returns successful despite errors!
+ execInfo.fMask |= SEE_MASK_UNICODE | SEE_MASK_FLAG_NO_UI; //::ShellExecuteEx() shows a non-blocking pop-up dialog on errors -> we want a blocking one
+ execInfo.lpVerb = nullptr;
+ execInfo.lpFile = filename.c_str();
+ execInfo.lpParameters = arguments.c_str();
+ execInfo.nShow = SW_SHOWNORMAL;
+
+ if (!::ShellExecuteEx(&execInfo)) //__inout LPSHELLEXECUTEINFO lpExecInfo
+ throw FileError(_("Incorrect command line:") + L"\nFile: " + filename + L"\nArg: " + arguments,
+ formatSystemError(L"ShellExecuteEx", getLastError()));
+
+ if (execInfo.hProcess)
+ {
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(execInfo.hProcess));
+
+ if (type == EXEC_TYPE_SYNC)
+ ::WaitForSingleObject(execInfo.hProcess, INFINITE);
+ }
+
+#elif defined ZEN_LINUX || defined ZEN_MAC
+ /*
+ we cannot use wxExecute due to various issues:
+ - screws up encoding on OS X for non-ASCII characters
+ - does not provide any reasonable error information
+ - uses a zero-sized dummy window as a hack to keep focus which leaves a useless empty icon in ALT-TAB list in Windows
+ */
+
+ if (type == EXEC_TYPE_SYNC)
+ {
+ //Posix::system - execute a shell command
+ int rv = ::system(command.c_str()); //do NOT use std::system as its documentation says nothing about "WEXITSTATUS(rv)", ect...
+ if (rv == -1 || WEXITSTATUS(rv) == 127) //http://linux.die.net/man/3/system "In case /bin/sh could not be executed, the exit status will be that of a command that does exit(127)"
+ throw FileError(_("Incorrect command line:") + L"\n" + command);
+ }
+ else
+ async([=] { int rv = ::system(command.c_str()); (void)rv; });
+#endif
+}
+}
+}
+
+#endif //EXECUTE_HEADER_23482134578134134
diff --git a/zen/string_tools.h b/zen/string_tools.h
index 180056cb..35e5af2b 100644
--- a/zen/string_tools.h
+++ b/zen/string_tools.h
@@ -535,7 +535,7 @@ Num stringTo(const S& str, Int2Type<NUM_TYPE_OTHER>) //default string to number
{
typedef typename GetCharType<S>::Type CharType;
Num number = 0;
- std::basic_istringstream<CharType>(copyStringTo<std::basic_string<CharType> >(str)) >> number;
+ std::basic_istringstream<CharType>(copyStringTo<std::basic_string<CharType>>(str)) >> number;
return number;
}
diff --git a/zen/symlink_target.h b/zen/symlink_target.h
index e3e2ac4d..73d67927 100644
--- a/zen/symlink_target.h
+++ b/zen/symlink_target.h
@@ -132,7 +132,7 @@ Zstring getSymlinkRawTargetString_impl(const Zstring& linkPath) //throw FileErro
reparseData.MountPointReparseBuffer.SubstituteNameLength / sizeof(WCHAR));
}
else
- throw FileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkPath)), L"Not a symbolic link or junction!");
+ throw FileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkPath)), L"Not a symbolic link or junction.");
//absolute symlinks and junctions technically start with \??\ while relative ones do not
if (startsWith(output, Zstr("\\??\\")))
diff --git a/zen/sys_error.h b/zen/sys_error.h
index cea2f5f9..dc60c77f 100644
--- a/zen/sys_error.h
+++ b/zen/sys_error.h
@@ -73,13 +73,17 @@ std::wstring formatSystemError(const std::wstring& functionName, long long lastE
inline
std::wstring formatSystemError(const std::wstring& functionName, ErrorCode lastError)
{
- //determine error code if none was specified -> still required??
+ const ErrorCode currentError = getLastError(); //not necessarily == lastError
+
+ //determine error code if none was specified
if (lastError == 0)
- lastError = getLastError();
+ lastError = currentError;
std::wstring output = replaceCpy(_("Error Code %x:"), L"%x", numberTo<std::wstring>(lastError));
#ifdef ZEN_WIN
+ ZEN_ON_SCOPE_EXIT(::SetLastError(currentError)); //this function must not change active system error variable!
+
LPWSTR buffer = nullptr;
if (::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_MAX_WIDTH_MASK |
@@ -91,13 +95,12 @@ std::wstring formatSystemError(const std::wstring& functionName, ErrorCode lastE
output += L" ";
output += buffer;
}
- ::SetLastError(lastError); //restore last error
#elif defined ZEN_LINUX || defined ZEN_MAC
+ ZEN_ON_SCOPE_EXIT(errno = currentError);
+
output += L" ";
output += utfCvrtTo<std::wstring>(::strerror(lastError));
-
- errno = lastError; //restore errno
#endif
if (!endsWith(output, L" ")) //Windows messages seem to end with a blank...
output += L" ";
diff --git a/zen/zstring.cpp b/zen/zstring.cpp
index 6eb68f7b..83eb5127 100644
--- a/zen/zstring.cpp
+++ b/zen/zstring.cpp
@@ -34,14 +34,14 @@ public:
{
boost::lock_guard<boost::mutex> dummy(lockActStrings);
if (!activeStrings.insert(std::make_pair(ptr, size)).second)
- reportProblem("Fatal Error: New memory points into occupied space: " + rawMemToString(ptr, size));
+ reportProblem("Serious Error: New memory points into occupied space: " + rawMemToString(ptr, size));
}
void remove(const void* ptr)
{
boost::lock_guard<boost::mutex> dummy(lockActStrings);
if (activeStrings.erase(ptr) != 1)
- reportProblem("Fatal Error: No memory available for deallocation at this location!");
+ reportProblem("Serious Error: No memory available for deallocation at this location!");
}
static LeakChecker& instance() { static LeakChecker inst; return inst; }
@@ -154,7 +154,7 @@ int z_impl::compareFilenamesNoCase(const wchar_t* lhs, const wchar_t* rhs, size_
static_cast<int>(sizeRhs), //__in int cchCount2,
true); //__in BOOL bIgnoreCase
if (rv <= 0)
- throw std::runtime_error("Error comparing strings (ordinal)!");
+ throw std::runtime_error("Error comparing strings (CompareStringOrdinal).");
else
return rv - 2; //convert to C-style string compare result
}
@@ -179,10 +179,10 @@ int z_impl::compareFilenamesNoCase(const wchar_t* lhs, const wchar_t* rhs, size_
minSize, //__in int cchSrc,
bufferA, //__out LPTSTR lpDestStr,
MAX_PATH) == 0) //__in int cchDest
- throw std::runtime_error("Error comparing strings! (LCMapString)");
+ throw std::runtime_error("Error comparing strings (LCMapString).");
if (::LCMapString(ZSTRING_INVARIANT_LOCALE, LCMAP_UPPERCASE, rhs, minSize, bufferB, MAX_PATH) == 0)
- throw std::runtime_error("Error comparing strings! (LCMapString)");
+ throw std::runtime_error("Error comparing strings (LCMapString).");
const int rv = ::wmemcmp(bufferA, bufferB, minSize);
if (rv != 0)
@@ -194,10 +194,10 @@ int z_impl::compareFilenamesNoCase(const wchar_t* lhs, const wchar_t* rhs, size_
std::vector<wchar_t> bufferB(minSize);
if (::LCMapString(ZSTRING_INVARIANT_LOCALE, LCMAP_UPPERCASE, lhs, minSize, &bufferA[0], minSize) == 0)
- throw std::runtime_error("Error comparing strings! (LCMapString: FS)");
+ throw std::runtime_error("Error comparing strings (LCMapString: FS).");
if (::LCMapString(ZSTRING_INVARIANT_LOCALE, LCMAP_UPPERCASE, rhs, minSize, &bufferB[0], minSize) == 0)
- throw std::runtime_error("Error comparing strings! (LCMapString: FS)");
+ throw std::runtime_error("Error comparing strings (LCMapString: FS).");
const int rv = ::wmemcmp(&bufferA[0], &bufferB[0], minSize);
if (rv != 0)
bgstack15