summaryrefslogtreecommitdiff
path: root/zen
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2015-10-02 14:57:46 +0200
committerDaniel Wilhelm <daniel@wili.li>2015-10-02 14:57:46 +0200
commitad4e3d2c55e75193c41356c23619f80add41db18 (patch)
treedd836d120f50e472106e04968ef8185c25e4242e /zen
parent7.4 (diff)
downloadFreeFileSync-ad4e3d2c55e75193c41356c23619f80add41db18.tar.gz
FreeFileSync-ad4e3d2c55e75193c41356c23619f80add41db18.tar.bz2
FreeFileSync-ad4e3d2c55e75193c41356c23619f80add41db18.zip
7.5
Diffstat (limited to 'zen')
-rw-r--r--zen/async_task.h73
-rw-r--r--zen/build_info.h34
-rw-r--r--zen/dir_watcher.cpp32
-rw-r--r--zen/dir_watcher.h16
-rw-r--r--zen/file_access.cpp289
-rw-r--r--zen/file_error.h23
-rw-r--r--zen/file_io.cpp20
-rw-r--r--zen/file_traverser.cpp60
-rw-r--r--zen/file_traverser.h3
-rw-r--r--zen/fixed_list.h11
-rw-r--r--zen/i18n.h1
-rw-r--r--zen/long_path_prefix.h6
-rw-r--r--zen/process_priority.cpp50
-rw-r--r--zen/recycler.cpp12
-rw-r--r--zen/recycler.h12
-rw-r--r--zen/scope_guard.h10
-rw-r--r--zen/serialize.h2
-rw-r--r--zen/shell_execute.h26
-rw-r--r--zen/stl_tools.h38
-rw-r--r--zen/string_base.h29
-rw-r--r--zen/string_tools.h8
-rw-r--r--zen/string_traits.h18
-rw-r--r--zen/symlink_target.h24
-rw-r--r--zen/thread.h52
-rw-r--r--zen/tick_count.h8
-rw-r--r--zen/time.h14
-rw-r--r--zen/type_traits.h80
-rw-r--r--zen/warn_static.h2
-rw-r--r--zen/zstring.cpp7
29 files changed, 478 insertions, 482 deletions
diff --git a/zen/async_task.h b/zen/async_task.h
deleted file mode 100644
index 76e7824f..00000000
--- a/zen/async_task.h
+++ /dev/null
@@ -1,73 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0 *
-// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
-// **************************************************************************
-
-#ifndef ASYNC_JOB_839147839170432143214321
-#define ASYNC_JOB_839147839170432143214321
-
-#include <list>
-#include <functional>
-#include "thread.h"
-#include "scope_guard.h"
-
-
-namespace zen
-{
-//run a job in an async thread, but process result on GUI event loop
-class AsyncTasks
-{
-public:
- AsyncTasks() {}
-
- template <class Fun, class Fun2>
- void add(Fun runAsync, Fun2 evalOnGui)
- //equivalent to "evalOnGui(runAsync())"
- // -> runAsync: the usual thread-safety requirements apply!
- // -> evalOnGui: no thread-safety concerns, but must only reference variables with greater-equal lifetime than the AsyncTask instance!
- {
- tasks.push_back(zen::runAsync([=]() -> std::function<void()>
- {
- auto result = runAsync();
- return [=]{ evalOnGui(result); };
- }));
- }
-
- template <class Fun, class Fun2>
- void add2(Fun runAsync, Fun2 evalOnGui) //for evalOnGui taking no parameters
- {
- tasks.push_back(zen::runAsync([runAsync, evalOnGui]() -> std::function<void()> { runAsync(); return [evalOnGui]{ evalOnGui(); }; }));
- }
-
- void evalResults() //call from gui thread repreatedly
- {
- if (!inRecursion) //prevent implicit recursion, e.g. if we're called from an idle event and spawn another one via the callback below
- {
- inRecursion = true;
- ZEN_ON_SCOPE_EXIT(inRecursion = false);
-
- tasks.remove_if([](std::future<std::function<void()>>& ft) -> bool
- {
- if (isReady(ft))
- {
- (ft.get())();
- return true;
- }
- return false;
- });
- }
- }
-
- bool empty() const { return tasks.empty(); }
-
-private:
- AsyncTasks (const AsyncTasks&) = delete;
- AsyncTasks& operator=(const AsyncTasks&) = delete;
-
- bool inRecursion = false;
- std::list<std::future<std::function<void()>>> tasks;
-};
-}
-
-#endif //ASYNC_JOB_839147839170432143214321
diff --git a/zen/build_info.h b/zen/build_info.h
index 4eeb8195..7c738847 100644
--- a/zen/build_info.h
+++ b/zen/build_info.h
@@ -4,17 +4,35 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef BUILDINFO_H_INCLUDED
-#define BUILDINFO_H_INCLUDED
+#ifndef BUILDINFO_H_5928539285603428657
+#define BUILDINFO_H_5928539285603428657
namespace zen
{
-//determine build info
-//safer than checking for _WIN64 (defined on windows for 64-bit compilations only) while _WIN32 is always defined (even for x64 compiler!)
-static const bool is32BitBuild = sizeof(void*) == 4;
-static const bool is64BitBuild = sizeof(void*) == 8;
+//determine build info: defines ZEN_BUILD_32BIT or ZEN_BUILD_64BIT
-static_assert(is32BitBuild || is64BitBuild, "");
+#ifdef ZEN_WIN
+ #ifdef _WIN64
+ #define ZEN_BUILD_64BIT
+ #else
+ #define ZEN_BUILD_32BIT
+ #endif
+
+#else
+ #ifdef __LP64__
+ #define ZEN_BUILD_64BIT
+ #else
+ #define ZEN_BUILD_32BIT
+ #endif
+#endif
+
+#ifdef ZEN_BUILD_32BIT
+ static_assert(sizeof(void*) == 4, "");
+#endif
+
+#ifdef ZEN_BUILD_64BIT
+ static_assert(sizeof(void*) == 8, "");
+#endif
}
-#endif //BUILDINFO_H_INCLUDED
+#endif //BUILDINFO_H_5928539285603428657
diff --git a/zen/dir_watcher.cpp b/zen/dir_watcher.cpp
index 4abf3c0a..3bab8d34 100644
--- a/zen/dir_watcher.cpp
+++ b/zen/dir_watcher.cpp
@@ -121,7 +121,7 @@ public:
std::lock_guard<std::mutex> dummy(lockAccess);
ErrorInfo newInfo = { copyStringTo<BasicWString>(msg), copyStringTo<BasicWString>(description), errorCode };
- errorInfo = make_unique<ErrorInfo>(newInfo);
+ errorInfo = std::make_unique<ErrorInfo>(newInfo);
}
private:
@@ -159,7 +159,7 @@ public:
FILE_FLAG_OVERLAPPED, //_In_ DWORD dwFlagsAndAttributes,
nullptr); //_In_opt_ HANDLE hTemplateFile
if (hDir == INVALID_HANDLE_VALUE)
- throwFileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(directory)), L"CreateFile", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(directory)), L"CreateFile");
//end of constructor, no need to start managing "hDir"
}
@@ -193,7 +193,7 @@ public:
nullptr); //__in_opt LPCTSTR lpName
if (overlapped.hEvent == nullptr)
{
- const DWORD ec = ::GetLastError(); //copy before directly or indirectly making other system calls!
+ const DWORD ec = ::GetLastError(); //copy before directly/indirectly making other system calls!
return shared_->reportError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(dirpathPf)), formatSystemError(L"CreateEvent", ec), ec);
}
ZEN_ON_SCOPE_EXIT(::CloseHandle(overlapped.hEvent));
@@ -213,7 +213,7 @@ public:
&overlapped, // __inout_opt LPOVERLAPPED lpOverlapped,
nullptr)) // __in_opt LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine
{
- const DWORD ec = ::GetLastError(); //copy before directly or indirectly making other system calls!
+ const DWORD ec = ::GetLastError(); //copy before directly/indirectly making other system calls!
return shared_->reportError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(dirpathPf)), formatSystemError(L"ReadDirectoryChangesW", ec), ec);
}
@@ -239,7 +239,7 @@ public:
&bytesWritten, //__out LPDWORD lpNumberOfBytesTransferred,
false)) //__in BOOL bWait
{
- const DWORD ec = ::GetLastError(); //copy before directly or indirectly making other system calls!
+ const DWORD ec = ::GetLastError(); //copy before directly/indirectly making other system calls!
if (ec != ERROR_IO_INCOMPLETE)
return shared_->reportError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(dirpathPf)), formatSystemError(L"GetOverlappedResult", ec), ec);
@@ -327,12 +327,12 @@ struct DirWatcher::Pimpl
DirWatcher::DirWatcher(const Zstring& dirPath) : //throw FileError
baseDirPath(dirPath),
- pimpl_(zen::make_unique<Pimpl>())
+ pimpl_(std::make_unique<Pimpl>())
{
pimpl_->shared = std::make_shared<SharedData>();
ReadChangesAsync reader(dirPath, pimpl_->shared); //throw FileError
- pimpl_->volRemoval = zen::make_unique<HandleVolumeRemoval>(reader.getDirHandle(), dirPath, pimpl_->worker); //throw FileError
+ pimpl_->volRemoval = std::make_unique<HandleVolumeRemoval>(reader.getDirHandle(), dirPath, pimpl_->worker); //throw FileError
pimpl_->worker = InterruptibleThread(std::move(reader));
}
@@ -384,7 +384,7 @@ struct DirWatcher::Pimpl
DirWatcher::DirWatcher(const Zstring& dirPath) : //throw FileError
baseDirPath(dirPath),
- pimpl_(zen::make_unique<Pimpl>())
+ pimpl_(std::make_unique<Pimpl>())
{
//get all subdirectories
std::vector<Zstring> fullDirList { baseDirPath };
@@ -405,7 +405,7 @@ DirWatcher::DirWatcher(const Zstring& dirPath) : //throw FileError
//init
pimpl_->notifDescr = ::inotify_init();
if (pimpl_->notifDescr == -1)
- throwFileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(baseDirPath)), L"inotify_init", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(baseDirPath)), L"inotify_init");
zen::ScopeGuard guardDescr = zen::makeGuard([&] { ::close(pimpl_->notifDescr); });
@@ -417,7 +417,7 @@ DirWatcher::DirWatcher(const Zstring& dirPath) : //throw FileError
initSuccess = ::fcntl(pimpl_->notifDescr, F_SETFL, flags | O_NONBLOCK) != -1;
}
if (!initSuccess)
- throwFileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(baseDirPath)), L"fcntl", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(baseDirPath)), L"fcntl");
//add watches
for (const Zstring& subDirPath : fullDirList)
@@ -425,17 +425,17 @@ DirWatcher::DirWatcher(const Zstring& dirPath) : //throw FileError
int wd = ::inotify_add_watch(pimpl_->notifDescr, subDirPath.c_str(),
IN_ONLYDIR | //"Only watch pathname if it is a directory."
IN_DONT_FOLLOW | //don't follow symbolic links
- IN_CREATE |
- IN_MODIFY |
+ IN_CREATE |
+ IN_MODIFY |
IN_CLOSE_WRITE |
- IN_DELETE |
+ IN_DELETE |
IN_DELETE_SELF |
IN_MOVED_FROM |
IN_MOVED_TO |
IN_MOVE_SELF);
if (wd == -1)
{
- const auto ec = getLastError();
+ const ErrorCode ec = getLastError(); //copy before directly/indirectly making other system calls!
if (ec == ENOSPC) //fix misleading system message "No space left on device"
throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(subDirPath)),
formatSystemError(L"inotify_add_watch", ec, L"The user limit on the total number of inotify watches was reached or the kernel failed to allocate a needed resource."));
@@ -473,7 +473,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>();
- throwFileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(baseDirPath)), L"read", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtPath(baseDirPath)), L"read");
}
std::vector<Entry> output;
@@ -565,7 +565,7 @@ struct DirWatcher::Pimpl
DirWatcher::DirWatcher(const Zstring& dirPath) :
baseDirPath(dirPath),
- pimpl_(zen::make_unique<Pimpl>())
+ pimpl_(std::make_unique<Pimpl>())
{
CFStringRef dirpathCf = osx::createCFString(baseDirPath.c_str()); //returns nullptr on error
if (!dirpathCf)
diff --git a/zen/dir_watcher.h b/zen/dir_watcher.h
index 7a1ada96..1d6d53cc 100644
--- a/zen/dir_watcher.h
+++ b/zen/dir_watcher.h
@@ -22,18 +22,18 @@ namespace zen
//watch directory including subdirectories
/*
!Note handling of directories!:
- Windows: removal of top watched directory is NOT notified when watching the dir handle, e.g. brute force usb stick removal,
- (watchting for GUID_DEVINTERFACE_WPD OTOH works fine!)
- however manual unmount IS notified (e.g. usb stick removal, then re-insert), but watching is stopped!
- Renaming of top watched directory handled incorrectly: Not notified(!) + additional changes in subfolders
- now do report FILE_ACTION_MODIFIED for directory (check that should prevent this fails!)
+ Windows: removal of top watched directory is NOT notified when watching the dir handle, e.g. brute force usb stick removal,
+ (watchting for GUID_DEVINTERFACE_WPD OTOH works fine!)
+ however manual unmount IS notified (e.g. usb stick removal, then re-insert), but watching is stopped!
+ Renaming of top watched directory handled incorrectly: Not notified(!) + additional changes in subfolders
+ now do report FILE_ACTION_MODIFIED for directory (check that should prevent this fails!)
Linux: newly added subdirectories are reported but not automatically added for watching! -> reset Dirwatcher!
- removal of top watched directory is NOT notified!
+ removal of top watched directory is NOT notified!
- OS X: everything works as expected; renaming of top level folder is also detected
+ OS X: everything works as expected; renaming of top level folder is also detected
- Overcome all issues portably: check existence of top watched directory externally + reinstall watch after changes in directory structure (added directories) are detected
+ Overcome all issues portably: check existence of top watched directory externally + reinstall watch after changes in directory structure (added directories) are detected
*/
class DirWatcher
{
diff --git a/zen/file_access.cpp b/zen/file_access.cpp
index c898c5d2..e04673d3 100644
--- a/zen/file_access.cpp
+++ b/zen/file_access.cpp
@@ -21,7 +21,7 @@
#include "long_path_prefix.h"
#include "win_ver.h"
#ifdef ZEN_WIN_VISTA_AND_LATER
- #include <zen/vista_file_op.h>
+ #include <zen/vista_file_op.h> //requires COM initialization!
#endif
@@ -105,14 +105,14 @@ bool zen::somethingExists(const Zstring& itemPath)
const DWORD attr = ::GetFileAttributes(applyLongPathPrefix(itemPath).c_str());
if (attr != INVALID_FILE_ATTRIBUTES)
return true;
- const DWORD lastError = ::GetLastError();
+ const DWORD ec = ::GetLastError(); //copy before directly/indirectly making other system calls!
//handle obscure file permission problem where ::GetFileAttributes() fails with ERROR_ACCESS_DENIED or ERROR_SHARING_VIOLATION
//while parent directory traversal is successful: e.g. "C:\pagefile.sys"
- if (lastError != ERROR_PATH_NOT_FOUND && //perf: short circuit for common "not existing" error codes
- lastError != ERROR_FILE_NOT_FOUND && //
- lastError != ERROR_BAD_NETPATH && //
- lastError != ERROR_BAD_NET_NAME) //
+ if (ec != ERROR_PATH_NOT_FOUND && //perf: short circuit for common "not existing" error codes
+ ec != ERROR_FILE_NOT_FOUND && //
+ ec != ERROR_BAD_NETPATH && //
+ ec != ERROR_BAD_NET_NAME) //
{
WIN32_FIND_DATA fileInfo = {};
const HANDLE searchHandle = ::FindFirstFile(applyLongPathPrefix(itemPath).c_str(), &fileInfo);
@@ -179,7 +179,7 @@ std::uint64_t zen::getFilesize(const Zstring& filePath) //throw FileError
WIN32_FIND_DATA fileInfo = {};
const HANDLE searchHandle = ::FindFirstFile(applyLongPathPrefix(filePath).c_str(), &fileInfo);
if (searchHandle == INVALID_HANDLE_VALUE)
- throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(filePath)), L"FindFirstFile", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(filePath)), L"FindFirstFile");
::FindClose(searchHandle);
if (!isSymlink(fileInfo))
@@ -199,20 +199,20 @@ std::uint64_t zen::getFilesize(const Zstring& filePath) //throw FileError
FILE_FLAG_BACKUP_SEMANTICS, /*needed to open a directory*/ //_In_ DWORD dwFlagsAndAttributes,
nullptr); //_In_opt_ HANDLE hTemplateFile
if (hFile == INVALID_HANDLE_VALUE)
- throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(filePath)), L"CreateFile", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(filePath)), L"CreateFile");
ZEN_ON_SCOPE_EXIT(::CloseHandle(hFile));
//why not use ::GetFileSizeEx() instead???
BY_HANDLE_FILE_INFORMATION fileInfoHnd = {};
if (!::GetFileInformationByHandle(hFile, &fileInfoHnd))
- throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(filePath)), L"GetFileInformationByHandle", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(filePath)), L"GetFileInformationByHandle");
return get64BitUInt(fileInfoHnd.nFileSizeLow, fileInfoHnd.nFileSizeHigh);
#elif defined ZEN_LINUX || defined ZEN_MAC
struct ::stat fileInfo = {};
if (::stat(filePath.c_str(), &fileInfo) != 0)
- throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(filePath)), L"stat", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(filePath)), L"stat");
return fileInfo.st_size;
#endif
@@ -227,7 +227,7 @@ std::uint64_t zen::getFreeDiskSpace(const Zstring& path) //throw FileError, retu
&bytesFree, //__out_opt PULARGE_INTEGER lpFreeBytesAvailable,
nullptr, //__out_opt PULARGE_INTEGER lpTotalNumberOfBytes,
nullptr)) //__out_opt PULARGE_INTEGER lpTotalNumberOfFreeBytes
- throwFileError(replaceCpy(_("Cannot determine free disk space for %x."), L"%x", fmtPath(path)), L"GetDiskFreeSpaceEx", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot determine free disk space for %x."), L"%x", fmtPath(path)), L"GetDiskFreeSpaceEx");
//return 0 if info is not available: "The GetDiskFreeSpaceEx function returns zero for lpFreeBytesAvailable for all CD requests"
return get64BitUInt(bytesFree.LowPart, bytesFree.HighPart);
@@ -235,7 +235,7 @@ std::uint64_t zen::getFreeDiskSpace(const Zstring& path) //throw FileError, retu
#elif defined ZEN_LINUX || defined ZEN_MAC
struct ::statfs info = {};
if (::statfs(path.c_str(), &info) != 0)
- throwFileError(replaceCpy(_("Cannot determine free disk space for %x."), L"%x", fmtPath(path)), L"statfs", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot determine free disk space for %x."), L"%x", fmtPath(path)), L"statfs");
return static_cast<std::uint64_t>(info.f_bsize) * info.f_bavail;
#endif
@@ -253,15 +253,15 @@ bool zen::removeFile(const Zstring& filePath) //throw FileError
if (::unlink(filePath.c_str()) != 0)
#endif
{
- ErrorCode lastError = getLastError();
+ ErrorCode ec = getLastError(); //copy before directly/indirectly making other system calls!
#ifdef ZEN_WIN
- if (lastError == ERROR_ACCESS_DENIED) //function fails if file is read-only
+ if (ec == ERROR_ACCESS_DENIED) //function fails if file is read-only
{
::SetFileAttributes(applyLongPathPrefix(filePath).c_str(), FILE_ATTRIBUTE_NORMAL); //(try to) normalize file attributes
if (::DeleteFile(applyLongPathPrefix(filePath).c_str())) //now try again...
return true;
- lastError = ::GetLastError();
+ ec = ::GetLastError();
}
#endif
if (!somethingExists(filePath)) //warning: changes global error code!!
@@ -269,11 +269,11 @@ bool zen::removeFile(const Zstring& filePath) //throw FileError
//begin of "regular" error reporting
const std::wstring errorMsg = replaceCpy(_("Cannot delete file %x."), L"%x", fmtPath(filePath));
- std::wstring errorDescr = formatSystemError(functionName, lastError);
+ std::wstring errorDescr = formatSystemError(functionName, ec);
#ifdef ZEN_WIN_VISTA_AND_LATER
- if (lastError == ERROR_SHARING_VIOLATION || //-> enhance error message!
- lastError == ERROR_LOCK_VIOLATION)
+ if (ec == ERROR_SHARING_VIOLATION || //-> enhance error message!
+ ec == ERROR_LOCK_VIOLATION)
{
const std::wstring procList = vista::getLockingProcesses(filePath); //noexcept
if (!procList.empty())
@@ -299,7 +299,7 @@ void zen::removeDirectorySimple(const Zstring& dirPath) //throw FileError
if (::rmdir(dirPath.c_str()) != 0)
#endif
{
- const ErrorCode ec = getLastError();
+ const ErrorCode ec = getLastError(); //copy before making other system calls!
if (!somethingExists(dirPath)) //warning: changes global error code!!
return;
@@ -308,12 +308,12 @@ void zen::removeDirectorySimple(const Zstring& dirPath) //throw FileError
if (symlinkExists(dirPath))
{
if (::unlink(dirPath.c_str()) != 0)
- throwFileError(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtPath(dirPath)), L"unlink", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtPath(dirPath)), L"unlink");
return;
}
#endif
- throwFileError(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtPath(dirPath)), functionName, ec);
+ throw FileError(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtPath(dirPath)), formatSystemError(functionName, ec));
}
//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!
@@ -332,10 +332,11 @@ void removeDirectoryImpl(const Zstring& dirPath) //throw FileError
std::vector<Zstring> fileList;
std::vector<Zstring> dirLinkList;
std::vector<Zstring> dirList;
+
//get all files and directories from current directory (WITHOUT subdirectories!)
traverseFolder(dirPath,
[&](const FileInfo& fi) { fileList.push_back(fi.fullPath); },
- [&](const DirInfo& di) { dirList .push_back(di.fullPath); },
+ [&](const DirInfo& di) { dirList .push_back(di.fullPath); }, //defer recursion => save stack space and allow deletion of extremely deep hierarchies!
[&](const SymlinkInfo& si)
{
#ifdef ZEN_WIN
@@ -391,9 +392,9 @@ void renameFile_sub(const Zstring& pathSource, const Zstring& pathTarget) //thro
pathTargetFmt.c_str(), //__in_opt LPCTSTR lpNewFileName,
0)) //__in DWORD dwFlags
{
- DWORD lastError = ::GetLastError(); //copy before directly or indirectly making other system calls!
+ DWORD ec = ::GetLastError(); //copy before directly/indirectly making other system calls!
- if (lastError == ERROR_ACCESS_DENIED) //MoveFileEx may fail to rename a read-only file on a SAMBA-share -> (try to) handle this
+ if (ec == ERROR_ACCESS_DENIED) //MoveFileEx may fail to rename a read-only file on a SAMBA-share -> (try to) handle this
{
const DWORD oldAttr = ::GetFileAttributes(pathSourceFmt.c_str());
if (oldAttr != INVALID_FILE_ATTRIBUTES && (oldAttr & FILE_ATTRIBUTE_READONLY))
@@ -411,7 +412,7 @@ void renameFile_sub(const Zstring& pathSource, const Zstring& pathTarget) //thro
}
else
{
- lastError = ::GetLastError(); //use error code from second call to ::MoveFileEx()
+ ec = ::GetLastError(); //use error code from second call to ::MoveFileEx()
//cleanup: (try to) restore file attributes: assume pathSource is still existing
::SetFileAttributes(pathSourceFmt.c_str(), oldAttr);
}
@@ -420,11 +421,11 @@ void renameFile_sub(const Zstring& pathSource, const Zstring& pathTarget) //thro
}
//begin of "regular" error reporting
const std::wstring errorMsg = replaceCpy(replaceCpy(_("Cannot move file %x to %y."), L"%x", L"\n" + fmtPath(pathSource)), L"%y", L"\n" + fmtPath(pathTarget));
- std::wstring errorDescr = formatSystemError(L"MoveFileEx", lastError);
+ std::wstring errorDescr = formatSystemError(L"MoveFileEx", ec);
#ifdef ZEN_WIN_VISTA_AND_LATER //(try to) enhance error message
- if (lastError == ERROR_SHARING_VIOLATION ||
- lastError == ERROR_LOCK_VIOLATION)
+ if (ec == ERROR_SHARING_VIOLATION ||
+ ec == ERROR_LOCK_VIOLATION)
{
const std::wstring procList = vista::getLockingProcesses(pathSource); //noexcept
if (!procList.empty())
@@ -432,37 +433,37 @@ void renameFile_sub(const Zstring& pathSource, const Zstring& pathTarget) //thro
}
#endif
- if (lastError == ERROR_NOT_SAME_DEVICE)
+ if (ec == ERROR_NOT_SAME_DEVICE)
throw ErrorDifferentVolume(errorMsg, errorDescr);
- if (lastError == ERROR_ALREADY_EXISTS || //-> used on Win7 x64
- lastError == ERROR_FILE_EXISTS) //-> used by XP???
+ if (ec == ERROR_ALREADY_EXISTS || //-> used on Win7 x64
+ ec == ERROR_FILE_EXISTS) //-> used by XP???
throw ErrorTargetExisting(errorMsg, errorDescr);
throw FileError(errorMsg, errorDescr);
}
#elif defined ZEN_LINUX || defined ZEN_MAC
- //rename() will never fail with EEXIST, but always overwrite!
- //=> Linux: renameat2() with RENAME_NOREPLACE -> still new, probably buggy
- //=> OS X: no solution
+ //rename() will never fail with EEXIST, but always overwrite!
+ //=> Linux: renameat2() with RENAME_NOREPLACE -> still new, probably buggy
+ //=> OS X: no solution
- auto throwException = [&](int ec)
- {
+ auto throwException = [&](int ec)
+ {
const std::wstring errorMsg = replaceCpy(replaceCpy(_("Cannot move file %x to %y."), L"%x", L"\n" + fmtPath(pathSource)), L"%y", L"\n" + fmtPath(pathTarget));
const std::wstring errorDescr = formatSystemError(L"rename", ec);
if (ec == EXDEV)
throw ErrorDifferentVolume(errorMsg, errorDescr);
- if (ec == EEXIST)
- throw ErrorTargetExisting(errorMsg, errorDescr);
+ if (ec == EEXIST)
+ throw ErrorTargetExisting(errorMsg, errorDescr);
throw FileError(errorMsg, errorDescr);
- };
+ };
- if (!EqualFilePath()(pathSource, pathTarget)) //OS X: changing file name case is not an "already exists" error!
- if (somethingExists(pathTarget))
- throwException(EEXIST);
+ if (!EqualFilePath()(pathSource, pathTarget)) //OS X: changing file name case is not an "already exists" error!
+ if (somethingExists(pathTarget))
+ throwException(EEXIST);
if (::rename(pathSource.c_str(), pathTarget.c_str()) != 0)
- throwException(errno);
+ throwException(errno);
#endif
}
@@ -645,12 +646,12 @@ void setFileTimeRaw(const Zstring& filePath,
{
const DWORD tmpAttr = ::GetFileAttributes(applyLongPathPrefix(filePath).c_str());
if (tmpAttr == INVALID_FILE_ATTRIBUTES)
- throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(filePath)), L"GetFileAttributes", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(filePath)), L"GetFileAttributes");
if (tmpAttr & FILE_ATTRIBUTE_READONLY)
{
if (!::SetFileAttributes(applyLongPathPrefix(filePath).c_str(), FILE_ATTRIBUTE_NORMAL))
- throwFileError(replaceCpy(_("Cannot write file attributes of %x."), L"%x", fmtPath(filePath)), L"SetFileAttributes", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write file attributes of %x."), L"%x", fmtPath(filePath)), L"SetFileAttributes");
attribs = tmpAttr; //reapplied on scope exit
return true;
@@ -694,13 +695,13 @@ void setFileTimeRaw(const Zstring& filePath,
hFile = openFile(false);
if (hFile == INVALID_HANDLE_VALUE)
{
- const DWORD lastError = ::GetLastError(); //copy before directly or indirectly making other system calls!
- if (lastError == ERROR_ACCESS_DENIED)
+ const DWORD ec = ::GetLastError(); //copy before directly/indirectly making other system calls!
+ if (ec == ERROR_ACCESS_DENIED)
if (removeReadonly()) //throw FileError
continue;
//3. after these herculean stunts we give up...
- throwFileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(filePath)), L"CreateFile", lastError);
+ throw FileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(filePath)), formatSystemError(L"CreateFile", ec));
}
}
break;
@@ -713,10 +714,10 @@ void setFileTimeRaw(const Zstring& filePath,
nullptr, //__in_opt const FILETIME *lpLastAccessTime,
&lastWriteTime)) //__in_opt const FILETIME *lpLastWriteTime
{
- ErrorCode lastError = getLastError(); //copy before directly or indirectly making other system calls!
+ DWORD ec = ::GetLastError(); //copy before directly/indirectly making other system calls!
//function may fail if file is read-only: https://sourceforge.net/tracker/?func=detail&atid=1093080&aid=3514569&group_id=234430
- if (lastError == ERROR_ACCESS_DENIED)
+ if (ec == ERROR_ACCESS_DENIED)
{
//dynamically load windows API function: available with Windows Vista and later
typedef BOOL (WINAPI* SetFileInformationByHandleFunc)(HANDLE hFile, FILE_INFO_BY_HANDLE_CLASS FileInformationClass, LPVOID lpFileInformation, DWORD dwBufferSize);
@@ -730,7 +731,7 @@ void setFileTimeRaw(const Zstring& filePath,
FileBasicInfo, //__in FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
&basicInfo, //__in LPVOID lpFileInformation,
sizeof(basicInfo))) //__in DWORD dwBufferSize
- throwFileError(replaceCpy(_("Cannot write file attributes of %x."), L"%x", fmtPath(filePath)), L"SetFileInformationByHandle", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write file attributes of %x."), L"%x", fmtPath(filePath)), L"SetFileInformationByHandle");
};
auto toLargeInteger = [](const FILETIME& ft) -> LARGE_INTEGER
@@ -763,7 +764,7 @@ void setFileTimeRaw(const Zstring& filePath,
}
catch (FileError&) {}
- lastError = ERROR_SUCCESS;
+ ec = ERROR_SUCCESS;
}
}
}
@@ -771,7 +772,7 @@ void setFileTimeRaw(const Zstring& filePath,
std::wstring errorMsg = replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(filePath));
//add more meaningful message: FAT accepts only a subset of the NTFS date range
- if (lastError == ERROR_INVALID_PARAMETER &&
+ if (ec == ERROR_INVALID_PARAMETER &&
isFatDrive(filePath))
{
//we need a low-level reliable routine to format a potentially invalid date => don't use strftime!!!
@@ -790,10 +791,10 @@ void setFileTimeRaw(const Zstring& filePath,
std::vector<wchar_t> buffer(bufferSize);
if (::GetDateFormat(LOCALE_USER_DEFAULT, //_In_ LCID Locale,
0, //_In_ DWORD dwFlags,
- &st, //_In_opt_ const SYSTEMTIME *lpDate,
- nullptr, //_In_opt_ LPCTSTR lpFormat,
- &buffer[0], //_Out_opt_ LPTSTR lpDateStr,
- bufferSize) > 0) //_In_ int cchDate
+ &st, //_In_opt_ const SYSTEMTIME *lpDate,
+ nullptr, //_In_opt_ LPCTSTR lpFormat,
+ &buffer[0], //_Out_opt_ LPTSTR lpDateStr,
+ bufferSize) > 0) //_In_ int cchDate
dateTime = &buffer[0]; //GetDateFormat() returns char count *including* 0-termination!
}
}
@@ -816,8 +817,8 @@ void setFileTimeRaw(const Zstring& filePath,
(creationTime ? L"\n\tcreate (UTC): \t" + fmtDate(*creationTime) : L"");
}
- if (lastError != ERROR_SUCCESS)
- throwFileError(errorMsg, L"SetFileTime", lastError);
+ if (ec != ERROR_SUCCESS)
+ throw FileError(errorMsg, formatSystemError(L"SetFileTime", ec));
}
}
#ifndef NDEBUG //verify written data: mainly required to check consistency of DST hack
@@ -877,17 +878,17 @@ void setFileTimeRaw(const Zstring& filePath, const struct ::timespec& modTime, P
if (errno == EACCES) //bullshit, access denied even with 0777 permissions! => utimes should work!
throw ErrorLinuxFallbackToUtimes(L"");
- throwFileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(filePath)), L"open", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(filePath)), L"open");
}
ZEN_ON_SCOPE_EXIT(::close(fdFile));
if (::futimens(fdFile, newTimes) != 0)
- throwFileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(filePath)), L"futimens", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(filePath)), L"futimens");
}
else
{
if (::utimensat(AT_FDCWD, filePath.c_str(), newTimes, AT_SYMLINK_NOFOLLOW) != 0)
- throwFileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(filePath)), L"utimensat", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(filePath)), L"utimensat");
}
}
@@ -929,7 +930,7 @@ void setFileTimeRaw(const Zstring& filePath,
(createTime ? sizeof(newTimes.createTime) : 0) + sizeof(newTimes.writeTime), //size_t attrBufSize,
procSl == ProcSymlink::DIRECT ? FSOPT_NOFOLLOW : 0); //unsigned long options
if (rv != 0)
- throwFileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(filePath)), L"setattrlist", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(filePath)), L"setattrlist");
}
/*
@@ -951,7 +952,7 @@ void getFileTimeRaw(int fd, //throw FileError
sizeof(fileTimes), //size_t attrBufSize,
0); //unsigned long options
if (rv != 0)
- throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(filePath)), L"getattrlist", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(filePath)), L"getattrlist");
createTime.tv_sec = fileTimes.createTime.tv_sec;
createTime.tv_nsec = fileTimes.createTime.tv_nsec;
@@ -984,12 +985,12 @@ void zen::setFileTime(const Zstring& filePath, std::int64_t modTime, ProcSymlink
if (procSl == ProcSymlink::FOLLOW)
{
if (::utimes(filePath.c_str(), writeTime) != 0)
- throwFileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(filePath)), L"utimes", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(filePath)), L"utimes");
}
else
{
if (::lutimes(filePath.c_str(), writeTime) != 0)
- throwFileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(filePath)), L"lutimes", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(filePath)), L"lutimes");
}
}
@@ -1010,7 +1011,7 @@ bool zen::supportsPermissions(const Zstring& dirpath) //throw FileError
if (!::GetVolumePathName(dirpath.c_str(), //__in LPCTSTR lpszFileName,
&buffer[0], //__out LPTSTR lpszVolumePathName,
bufferSize)) //__in DWORD cchBufferLength
- throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(dirpath)), L"GetVolumePathName", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(dirpath)), L"GetVolumePathName");
const Zstring volumePath = appendSeparator(&buffer[0]);
@@ -1023,7 +1024,7 @@ bool zen::supportsPermissions(const Zstring& dirpath) //throw FileError
&fsFlags, //__out_opt LPDWORD lpFileSystemFlags,
nullptr, //__out LPTSTR lpFileSystemNameBuffer,
0)) //__in DWORD nFileSystemNameSize
- throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(dirpath)), L"GetVolumeInformation", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(dirpath)), L"GetVolumeInformation");
return (fsFlags & FILE_PERSISTENT_ACLS) != 0;
@@ -1049,7 +1050,7 @@ void copySecurityContext(const Zstring& source, const Zstring& target, ProcSymli
errno == EOPNOTSUPP) //extended attributes are not supported by the filesystem
return;
- throwFileError(replaceCpy(_("Cannot read security context of %x."), L"%x", fmtPath(source)), L"getfilecon", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read security context of %x."), L"%x", fmtPath(source)), L"getfilecon");
}
ZEN_ON_SCOPE_EXIT(::freecon(contextSource));
@@ -1077,7 +1078,7 @@ void copySecurityContext(const Zstring& source, const Zstring& target, ProcSymli
::setfilecon(target.c_str(), contextSource) :
::lsetfilecon(target.c_str(), contextSource);
if (rv3 < 0)
- throwFileError(replaceCpy(_("Cannot write security context of %x."), L"%x", fmtPath(target)), L"setfilecon", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write security context of %x."), L"%x", fmtPath(target)), L"setfilecon");
}
#endif //HAVE_SELINUX
@@ -1128,7 +1129,7 @@ void copyItemPermissions(const Zstring& sourcePath, const Zstring& targetPath, P
if (bytesNeeded > buffer.size())
buffer.resize(bytesNeeded);
else
- throwFileError(replaceCpy(_("Cannot read permissions of %x."), L"%x", fmtPath(sourceResolved)), L"GetFileSecurity", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read permissions of %x."), L"%x", fmtPath(sourceResolved)), L"GetFileSecurity");
}
SECURITY_DESCRIPTOR& secDescr = reinterpret_cast<SECURITY_DESCRIPTOR&>(buffer[0]);
@@ -1152,7 +1153,7 @@ void copyItemPermissions(const Zstring& sourcePath, const Zstring& targetPath, P
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION, //__in SECURITY_INFORMATION SecurityInformation,
&secDescr)) //__in PSECURITY_DESCRIPTOR pSecurityDescriptor
- throwFileError(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtPath(targetResolved)), L"SetFileSecurity", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtPath(targetResolved)), L"SetFileSecurity");
/*
PSECURITY_DESCRIPTOR buffer = nullptr;
@@ -1212,13 +1213,13 @@ void copyItemPermissions(const Zstring& sourcePath, const Zstring& targetPath, P
if (targetHandle.get() == INVALID_HANDLE_VALUE)
throw FileError
- SECURITY_INFORMATION secFlags = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
+ SECURITY_INFORMATION secFlags = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION;
- //SACL/DACL inheritence flag is NOT copied by default: we have to tell ::SetSecurityInfo(() to enable/disable it manually!
- //if (secCtrl & SE_DACL_PRESENT)
- secFlags |= (secCtrl & SE_DACL_PROTECTED) ? PROTECTED_DACL_SECURITY_INFORMATION : UNPROTECTED_DACL_SECURITY_INFORMATION;
- //if (secCtrl & SE_SACL_PRESENT)
- secFlags |= (secCtrl & SE_SACL_PROTECTED) ? PROTECTED_SACL_SECURITY_INFORMATION : UNPROTECTED_SACL_SECURITY_INFORMATION;
+ //SACL/DACL inheritence flag is NOT copied by default: we have to tell ::SetSecurityInfo(() to enable/disable it manually!
+ //if (secCtrl & SE_DACL_PRESENT)
+ secFlags |= (secCtrl & SE_DACL_PROTECTED) ? PROTECTED_DACL_SECURITY_INFORMATION : UNPROTECTED_DACL_SECURITY_INFORMATION;
+ //if (secCtrl & SE_SACL_PRESENT)
+ secFlags |= (secCtrl & SE_SACL_PROTECTED) ? PROTECTED_SACL_SECURITY_INFORMATION : UNPROTECTED_SACL_SECURITY_INFORMATION;
// rc = ::SetNamedSecurityInfo(const_cast<WCHAR*>(applyLongPathPrefix(target).c_str()), //__in LPTSTR pObjectName, -> does NOT dereference symlinks!
@@ -1232,7 +1233,7 @@ void copyItemPermissions(const Zstring& sourcePath, const Zstring& targetPath, P
if (rc != ERROR_SUCCESS)
throw FileError
- */
+ */
#elif defined ZEN_LINUX
@@ -1244,25 +1245,25 @@ void copyItemPermissions(const Zstring& sourcePath, const Zstring& targetPath, P
if (procSl == ProcSymlink::FOLLOW)
{
if (::stat(sourcePath.c_str(), &fileInfo) != 0)
- throwFileError(replaceCpy(_("Cannot read permissions of %x."), L"%x", fmtPath(sourcePath)), L"stat", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read permissions of %x."), L"%x", fmtPath(sourcePath)), L"stat");
if (::chown(targetPath.c_str(), fileInfo.st_uid, fileInfo.st_gid) != 0) // may require admin rights!
- throwFileError(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtPath(targetPath)), L"chown", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtPath(targetPath)), L"chown");
if (::chmod(targetPath.c_str(), fileInfo.st_mode) != 0)
- throwFileError(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtPath(targetPath)), L"chmod", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtPath(targetPath)), L"chmod");
}
else
{
if (::lstat(sourcePath.c_str(), &fileInfo) != 0)
- throwFileError(replaceCpy(_("Cannot read permissions of %x."), L"%x", fmtPath(sourcePath)), L"lstat", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read permissions of %x."), L"%x", fmtPath(sourcePath)), L"lstat");
if (::lchown(targetPath.c_str(), fileInfo.st_uid, fileInfo.st_gid) != 0) // may require admin rights!
- throwFileError(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtPath(targetPath)), L"lchown", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtPath(targetPath)), L"lchown");
if (!symlinkExists(targetPath) && //setting access permissions doesn't make sense for symlinks on Linux: there is no lchmod()
::chmod(targetPath.c_str(), fileInfo.st_mode) != 0)
- throwFileError(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtPath(targetPath)), L"chmod", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtPath(targetPath)), L"chmod");
}
#elif defined ZEN_MAC
@@ -1271,7 +1272,7 @@ void copyItemPermissions(const Zstring& sourcePath, const Zstring& targetPath, P
flags |= COPYFILE_NOFOLLOW;
if (::copyfile(sourcePath.c_str(), targetPath.c_str(), 0, flags) != 0)
- throwFileError(replaceCpy(replaceCpy(_("Cannot copy permissions from %x to %y."), L"%x", L"\n" + fmtPath(sourcePath)), L"%y", L"\n" + fmtPath(targetPath)), L"copyfile", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(replaceCpy(_("Cannot copy permissions from %x to %y."), L"%x", L"\n" + fmtPath(sourcePath)), L"%y", L"\n" + fmtPath(targetPath)), L"copyfile");
//owner is *not* copied with ::copyfile():
@@ -1279,18 +1280,18 @@ void copyItemPermissions(const Zstring& sourcePath, const Zstring& targetPath, P
if (procSl == ProcSymlink::FOLLOW)
{
if (::stat(sourcePath.c_str(), &fileInfo) != 0)
- throwFileError(replaceCpy(_("Cannot read permissions of %x."), L"%x", fmtPath(sourcePath)), L"stat", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read permissions of %x."), L"%x", fmtPath(sourcePath)), L"stat");
if (::chown(targetPath.c_str(), fileInfo.st_uid, fileInfo.st_gid) != 0) // may require admin rights!
- throwFileError(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtPath(targetPath)), L"chown", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtPath(targetPath)), L"chown");
}
else
{
if (::lstat(sourcePath.c_str(), &fileInfo) != 0)
- throwFileError(replaceCpy(_("Cannot read permissions of %x."), L"%x", fmtPath(sourcePath)), L"lstat", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read permissions of %x."), L"%x", fmtPath(sourcePath)), L"lstat");
if (::lchown(targetPath.c_str(), fileInfo.st_uid, fileInfo.st_gid) != 0) // may require admin rights!
- throwFileError(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtPath(targetPath)), L"lchown", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtPath(targetPath)), L"lchown");
}
#endif
}
@@ -1365,29 +1366,29 @@ void zen::copyNewDirectory(const Zstring& sourcePath, const Zstring& targetPath,
if (!::CreateDirectory(applyLongPathPrefixCreateDir(targetPath).c_str(), //__in LPCTSTR lpPathName,
nullptr)) //__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes
{
- DWORD lastError = ::GetLastError(); //copy before directly or indirectly making other system calls!
+ DWORD ec = ::GetLastError(); //copy before directly/indirectly making other system calls!
//handle issues with already existing short 8.3 file names on Windows
- if (lastError == ERROR_ALREADY_EXISTS)
+ if (ec == ERROR_ALREADY_EXISTS)
if (have8dot3NameClash(targetPath))
{
Fix8Dot3NameClash dummy(targetPath); //throw FileError; move clashing object to the side
//now try again...
if (::CreateDirectory(applyLongPathPrefixCreateDir(targetPath).c_str(), nullptr))
- lastError = ERROR_SUCCESS;
+ ec = ERROR_SUCCESS;
else
- lastError = ::GetLastError();
+ ec = ::GetLastError();
}
- if (lastError != ERROR_SUCCESS)
+ if (ec != ERROR_SUCCESS)
{
const std::wstring errorMsg = replaceCpy(_("Cannot create directory %x."), L"%x", fmtPath(targetPath));
- const std::wstring errorDescr = formatSystemError(L"CreateDirectory", lastError);
+ const std::wstring errorDescr = formatSystemError(L"CreateDirectory", ec);
- if (lastError == ERROR_ALREADY_EXISTS)
+ if (ec == ERROR_ALREADY_EXISTS)
throw ErrorTargetExisting(errorMsg, errorDescr);
- else if (lastError == ERROR_PATH_NOT_FOUND)
+ else if (ec == ERROR_PATH_NOT_FOUND)
throw ErrorTargetPathMissing(errorMsg, errorDescr);
throw FileError(errorMsg, errorDescr);
}
@@ -1525,7 +1526,7 @@ void zen::copySymlink(const Zstring& sourceLink, const Zstring& targetLink, bool
const wchar_t functionName[] = L"symlink";
if (::symlink(linkPath.c_str(), targetLink.c_str()) != 0)
#endif
- throwFileError(replaceCpy(replaceCpy(_("Cannot copy symbolic link %x to %y."), L"%x", L"\n" + fmtPath(sourceLink)), L"%y", L"\n" + fmtPath(targetLink)), functionName, getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(replaceCpy(_("Cannot copy symbolic link %x to %y."), L"%x", L"\n" + fmtPath(sourceLink)), L"%y", L"\n" + fmtPath(targetLink)), functionName);
//allow only consistent objects to be created -> don't place before ::symlink, targetLink may already exist!
zen::ScopeGuard guardNewLink = zen::makeGuard([&]
@@ -1548,24 +1549,24 @@ void zen::copySymlink(const Zstring& sourceLink, const Zstring& targetLink, bool
if (!::GetFileAttributesEx(applyLongPathPrefix(sourceLink).c_str(), //__in LPCTSTR lpFileName,
GetFileExInfoStandard, //__in GET_FILEEX_INFO_LEVELS fInfoLevelId,
&sourceAttr)) //__out LPVOID lpFileInformation
- throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(sourceLink)), L"GetFileAttributesEx", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(sourceLink)), L"GetFileAttributesEx");
setFileTimeRaw(targetLink, &sourceAttr.ftCreationTime, sourceAttr.ftLastWriteTime, ProcSymlink::DIRECT); //throw FileError
#elif defined ZEN_LINUX
struct ::stat sourceInfo = {};
if (::lstat(sourceLink.c_str(), &sourceInfo) != 0)
- throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(sourceLink)), L"lstat", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(sourceLink)), L"lstat");
setFileTime(targetLink, sourceInfo.st_mtime, ProcSymlink::DIRECT); //throw FileError
#elif defined ZEN_MAC
struct ::stat sourceInfo = {};
if (::lstat(sourceLink.c_str(), &sourceInfo) != 0)
- throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(sourceLink)), L"lstat", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(sourceLink)), L"lstat");
if (::copyfile(sourceLink.c_str(), targetLink.c_str(), 0, COPYFILE_XATTR | COPYFILE_NOFOLLOW) != 0)
- throwFileError(replaceCpy(replaceCpy(_("Cannot copy attributes from %x to %y."), L"%x", L"\n" + fmtPath(sourceLink)), L"%y", L"\n" + fmtPath(targetLink)), L"copyfile", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(replaceCpy(_("Cannot copy attributes from %x to %y."), L"%x", L"\n" + fmtPath(sourceLink)), L"%y", L"\n" + fmtPath(targetLink)), L"copyfile");
setFileTimeRaw(targetLink, &sourceInfo.st_birthtimespec, sourceInfo.st_mtimespec, ProcSymlink::DIRECT); //throw FileError
#endif
@@ -1582,15 +1583,15 @@ namespace
#ifdef ZEN_WIN
/*
CopyFileEx() BackupRead() FileRead()
- --------------------------------------------
-Attributes YES NO NO
+ --------------------------------------------
+Attributes YES NO NO
create time NO NO NO
-ADS YES YES NO
-Encrypted YES NO(silent fail!) NO
-Compressed NO NO NO
-Sparse NO YES NO
+ADS YES YES NO
+Encrypted YES NO(silent fail!) NO
+Compressed NO NO NO
+Sparse NO YES NO
Nonstandard FS YES UNKNOWN -> error writing ADS to Samba, issues reading from NAS, error copying files having "blocked" state... ect.
-PERF - 6% faster
+PERF - 6% faster
Mark stream as compressed: FSCTL_SET_COMPRESSION - compatible with both BackupRead() and FileRead()
@@ -1730,14 +1731,14 @@ InSyncAttributes copyFileWindowsBackupStream(const Zstring& sourceFile, //throw
nullptr); //_In_opt_ HANDLE hTemplateFile
if (hFileSource == INVALID_HANDLE_VALUE)
{
- const DWORD lastError = ::GetLastError(); //copy before directly or indirectly making other system calls!
+ const DWORD ec = ::GetLastError(); //copy before directly/indirectly making other system calls!
const std::wstring errorMsg = replaceCpy(_("Cannot read file %x."), L"%x", fmtPath(sourceFile));
- std::wstring errorDescr = formatSystemError(L"CreateFile", lastError);
+ std::wstring errorDescr = formatSystemError(L"CreateFile", ec);
//if file is locked throw "ErrorFileLocked" instead!
- if (lastError == ERROR_SHARING_VIOLATION ||
- lastError == ERROR_LOCK_VIOLATION)
+ if (ec == ERROR_SHARING_VIOLATION ||
+ ec == ERROR_LOCK_VIOLATION)
{
#ifdef ZEN_WIN_VISTA_AND_LATER //(try to) enhance error message
const std::wstring procList = vista::getLockingProcesses(sourceFile); //noexcept
@@ -1754,7 +1755,7 @@ InSyncAttributes copyFileWindowsBackupStream(const Zstring& sourceFile, //throw
//----------------------------------------------------------------------
BY_HANDLE_FILE_INFORMATION fileInfoSource = {};
if (!::GetFileInformationByHandle(hFileSource, &fileInfoSource))
- throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(sourceFile)), L"GetFileInformationByHandle", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(sourceFile)), L"GetFileInformationByHandle");
//encrypted files cannot be read with BackupRead which would fail silently!
const bool sourceIsEncrypted = (fileInfoSource.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) != 0;
@@ -1785,15 +1786,15 @@ InSyncAttributes copyFileWindowsBackupStream(const Zstring& sourceFile, //throw
nullptr); //_In_opt_ HANDLE hTemplateFile
if (hFileTarget == INVALID_HANDLE_VALUE)
{
- const DWORD lastError = ::GetLastError(); //copy before directly or indirectly making other system calls!
+ const DWORD ec = ::GetLastError(); //copy before directly/indirectly making other system calls!
const std::wstring errorMsg = replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(targetFile));
- const std::wstring errorDescr = formatSystemError(L"CreateFile", lastError);
+ const std::wstring errorDescr = formatSystemError(L"CreateFile", ec);
- if (lastError == ERROR_FILE_EXISTS || //confirmed to be used
- lastError == ERROR_ALREADY_EXISTS) //comment on msdn claims, this one is used on Windows Mobile 6
+ if (ec == ERROR_FILE_EXISTS || //confirmed to be used
+ ec == ERROR_ALREADY_EXISTS) //comment on msdn claims, this one is used on Windows Mobile 6
throw ErrorTargetExisting(errorMsg, errorDescr);
- //if (lastError == ERROR_PATH_NOT_FOUND) throw ErrorTargetPathMissing(errorMsg, errorDescr);
+ //if (ec == ERROR_PATH_NOT_FOUND) throw ErrorTargetPathMissing(errorMsg, errorDescr);
throw FileError(errorMsg, errorDescr);
}
@@ -1803,7 +1804,7 @@ InSyncAttributes copyFileWindowsBackupStream(const Zstring& sourceFile, //throw
//----------------------------------------------------------------------
BY_HANDLE_FILE_INFORMATION fileInfoTarget = {};
if (!::GetFileInformationByHandle(hFileTarget, &fileInfoTarget))
- throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(targetFile)), L"GetFileInformationByHandle", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(targetFile)), L"GetFileInformationByHandle");
//return up-to-date file attributes
InSyncAttributes newAttrib = {};
@@ -1854,7 +1855,7 @@ InSyncAttributes copyFileWindowsBackupStream(const Zstring& sourceFile, //throw
0, //_In_ DWORD nOutBufferSize,
&bytesReturned, //_Out_opt_ LPDWORD lpBytesReturned,
nullptr)) //_Inout_opt_ LPOVERLAPPED lpOverlapped
- throwFileError(replaceCpy(_("Cannot write file attributes of %x."), L"%x", fmtPath(targetFile)), L"DeviceIoControl, FSCTL_SET_SPARSE", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write file attributes of %x."), L"%x", fmtPath(targetFile)), L"DeviceIoControl, FSCTL_SET_SPARSE");
}
//----------------------------------------------------------------------
@@ -1881,7 +1882,7 @@ InSyncAttributes copyFileWindowsBackupStream(const Zstring& sourceFile, //throw
false, //__in BOOL bAbort,
false, //__in BOOL bProcessSecurity,
&contextRead)) //__out LPVOID *lpContext
- throwFileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtPath(sourceFile)), L"BackupRead", getLastError()); //better use fine-granular error messages "reading/writing"!
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file %x."), L"%x", fmtPath(sourceFile)), L"BackupRead"); //better use fine-granular error messages "reading/writing"!
if (bytesRead > BUFFER_SIZE)
throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtPath(sourceFile)), L"BackupRead: buffer overflow."); //user should never see this
@@ -1897,7 +1898,7 @@ InSyncAttributes copyFileWindowsBackupStream(const Zstring& sourceFile, //throw
false, //__in BOOL bAbort,
false, //__in BOOL bProcessSecurity,
&contextWrite)) //__out LPVOID *lpContext
- throwFileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(targetFile)), L"BackupWrite", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(targetFile)), L"BackupWrite");
if (bytesWritten != bytesRead)
throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(targetFile)), L"BackupWrite: incomplete write."); //user should never see this
@@ -1920,7 +1921,7 @@ InSyncAttributes copyFileWindowsBackupStream(const Zstring& sourceFile, //throw
&fileInfoSource.ftCreationTime,
nullptr,
&fileInfoSource.ftLastWriteTime))
- throwFileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(targetFile)), L"SetFileTime", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtPath(targetFile)), L"SetFileTime");
guardTarget.dismiss();
return newAttrib;
@@ -1975,13 +1976,13 @@ DWORD CALLBACK copyCallbackInternal(LARGE_INTEGER totalFileSize,
file time handling:
::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!!! (confirmed with Process Monitor)
+ CAVEAT: if ::CopyFileEx() fails to set modification time, it silently ignores this error and returns success!!! (confirmed with Process Monitor)
alternate data stream handling:
CopyFileEx() processes multiple streams one after another, stream 1 is the file data stream and always available!
Each stream is initialized with CALLBACK_STREAM_SWITCH and provides *new* hSourceFile, hDestinationFile.
Calling GetFileInformationByHandle() on hDestinationFile for stream > 1 results in ERROR_ACCESS_DENIED!
- totalBytesTransferred contains size of *all* streams and so can be larger than the "file size" file attribute
+ totalBytesTransferred contains size of *all* streams and so can be larger than the "file size" file attribute
*/
CallbackData& cbd = *static_cast<CallbackData*>(lpData);
@@ -1993,10 +1994,10 @@ DWORD CALLBACK copyCallbackInternal(LARGE_INTEGER totalFileSize,
{
//#################### return source file attributes ################################
if (!::GetFileInformationByHandle(hSourceFile, &cbd.fileInfoSrc))
- throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(cbd.sourceFile_)), L"GetFileInformationByHandle", ::GetLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(cbd.sourceFile_)), L"GetFileInformationByHandle");
if (!::GetFileInformationByHandle(hDestinationFile, &cbd.fileInfoTrg))
- throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(cbd.targetFile_)), L"GetFileInformationByHandle", ::GetLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(cbd.targetFile_)), L"GetFileInformationByHandle");
//#################### switch to sparse file copy if req. #######################
#ifdef ZEN_WIN_VISTA_AND_LATER
@@ -2087,7 +2088,7 @@ InSyncAttributes copyFileWindowsDefault(const Zstring& sourceFile, //throw FileE
if (!success)
{
- const DWORD lastError = ::GetLastError(); //copy before directly or indirectly making other system calls!
+ const DWORD ec = ::GetLastError(); //copy before directly/indirectly making other system calls!
//don't suppress "lastError == ERROR_REQUEST_ABORTED": a user aborted operation IS an error condition!
@@ -2095,23 +2096,23 @@ InSyncAttributes copyFileWindowsDefault(const Zstring& sourceFile, //throw FileE
if (canCopyAsSparse(sourceFile, targetFile)) //noexcept
throw ErrorFallbackToCopyAsBackupStream(L"sparse, copy failure");
- if (lastError == ERROR_ACCESS_DENIED && backupPrivilegesActive)
+ if (ec == ERROR_ACCESS_DENIED && backupPrivilegesActive)
//chances are good this will work with copyFileWindowsBackupStream: https://sourceforge.net/p/freefilesync/discussion/open-discussion/thread/1998ebf2/
throw ErrorFallbackToCopyAsBackupStream(L"access denied");
//copying ADS may incorrectly fail with ERROR_FILE_NOT_FOUND: https://sourceforge.net/p/freefilesync/discussion/help/thread/a18a2c02/
- if (lastError == ERROR_FILE_NOT_FOUND &&
+ if (ec == ERROR_FILE_NOT_FOUND &&
cbd.fileInfoSrc.nNumberOfLinks > 0 &&
cbd.fileInfoTrg.nNumberOfLinks > 0)
throw ErrorFallbackToCopyAsBackupStream(L"bogus file not found");
//assemble error message...
const std::wstring errorMsg = replaceCpy(replaceCpy(_("Cannot copy file %x to %y."), L"%x", L"\n" + fmtPath(sourceFile)), L"%y", L"\n" + fmtPath(targetFile));
- std::wstring errorDescr = formatSystemError(L"CopyFileEx", lastError);
+ std::wstring errorDescr = formatSystemError(L"CopyFileEx", ec);
//if file is locked throw "ErrorFileLocked" instead!
- if (lastError == ERROR_SHARING_VIOLATION ||
- lastError == ERROR_LOCK_VIOLATION)
+ if (ec == ERROR_SHARING_VIOLATION ||
+ ec == ERROR_LOCK_VIOLATION)
{
#ifdef ZEN_WIN_VISTA_AND_LATER //(try to) enhance error message
const std::wstring procList = vista::getLockingProcesses(sourceFile); //noexcept
@@ -2122,8 +2123,8 @@ InSyncAttributes copyFileWindowsDefault(const Zstring& sourceFile, //throw FileE
}
//if target is existing this functions is expected to throw ErrorTargetExisting!!!
- if (lastError == ERROR_FILE_EXISTS || //confirmed to be used
- lastError == ERROR_ALREADY_EXISTS) //not sure if used -> better be safe than sorry!!!
+ if (ec == ERROR_FILE_EXISTS || //confirmed to be used
+ ec == ERROR_ALREADY_EXISTS) //not sure if used -> better be safe than sorry!!!
{
guardTarget.dismiss(); //don't delete file that existed previously!
throw ErrorTargetExisting(errorMsg, errorDescr);
@@ -2134,7 +2135,7 @@ InSyncAttributes copyFileWindowsDefault(const Zstring& sourceFile, //throw FileE
try //add more meaningful message
{
//trying to copy > 4GB file to FAT/FAT32 volume gives obscure ERROR_INVALID_PARAMETER (FAT can indeed handle files up to 4 Gig, tested!)
- if (lastError == ERROR_INVALID_PARAMETER &&
+ if (ec == ERROR_INVALID_PARAMETER &&
isFatDrive(targetFile) &&
getFilesize(sourceFile) >= 4U * std::uint64_t(1024U * 1024 * 1024)) //throw FileError
errorDescr += L"\nFAT volumes cannot store files larger than 4 gigabytes.";
@@ -2148,7 +2149,7 @@ InSyncAttributes copyFileWindowsDefault(const Zstring& sourceFile, //throw FileE
}
//caveat: - ::CopyFileEx() silently *ignores* failure to set modification time!!! => we always need to set it again but with proper error checking!
- // - perf: recent measurements show no slow down at all for buffered USB sticks!
+ // - perf: recent measurements show no slow down at all for buffered USB sticks!
setFileTimeRaw(targetFile, &cbd.fileInfoSrc.ftCreationTime, cbd.fileInfoSrc.ftLastWriteTime, ProcSymlink::FOLLOW); //throw FileError
guardTarget.dismiss(); //target has been created successfully!
@@ -2209,7 +2210,7 @@ InSyncAttributes copyFileOsSpecific(const Zstring& sourceFile, //throw FileError
struct ::stat sourceInfo = {};
if (::fstat(fileIn.getHandle(), &sourceInfo) != 0)
- throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(sourceFile)), L"fstat", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(sourceFile)), L"fstat");
const int fdTarget = ::open(targetFile.c_str(), O_WRONLY | O_CREAT | O_EXCL,
sourceInfo.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)); //analog to "cp" which copies "mode" (considering umask) by default
@@ -2240,7 +2241,7 @@ InSyncAttributes copyFileOsSpecific(const Zstring& sourceFile, //throw FileError
struct ::stat targetInfo = {};
if (::fstat(fileOut.getHandle(), &targetInfo) != 0)
- throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(targetFile)), L"fstat", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(targetFile)), L"fstat");
newAttrib.fileSize = sourceInfo.st_size;
#ifdef ZEN_MAC
@@ -2258,7 +2259,7 @@ InSyncAttributes copyFileOsSpecific(const Zstring& sourceFile, //throw FileError
//docs: http://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/copyfile.3.html
//source: http://www.opensource.apple.com/source/copyfile/copyfile-103.92.1/copyfile.c
if (::fcopyfile(fileIn.getHandle(), fileOut.getHandle(), 0, COPYFILE_XATTR) != 0)
- throwFileError(replaceCpy(replaceCpy(_("Cannot copy attributes from %x to %y."), L"%x", L"\n" + fmtPath(sourceFile)), L"%y", L"\n" + fmtPath(targetFile)), L"copyfile", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(replaceCpy(_("Cannot copy attributes from %x to %y."), L"%x", L"\n" + fmtPath(sourceFile)), L"%y", L"\n" + fmtPath(targetFile)), L"copyfile");
#endif
fileOut.close(); //throw FileError -> optional, but good place to catch errors when closing stream!
@@ -2290,8 +2291,8 @@ InSyncAttributes copyFileOsSpecific(const Zstring& sourceFile, //throw FileError
|
copyFileOsSpecific (solve 8.3 issue on Windows)
|
- copyFileWindowsSelectRoutine
- / \
+ copyFileWindowsSelectRoutine
+ / \
copyFileWindowsDefault(::CopyFileEx) copyFileWindowsBackupStream(::BackupRead/::BackupWrite)
*/
}
diff --git a/zen/file_error.h b/zen/file_error.h
index d8c6224c..7be52282 100644
--- a/zen/file_error.h
+++ b/zen/file_error.h
@@ -36,14 +36,23 @@ DEFINE_NEW_FILE_ERROR(ErrorFileLocked);
DEFINE_NEW_FILE_ERROR(ErrorDifferentVolume);
-//CAVEAT: evalulate global error code *before* "throw" statement which may overwrite error code
-//due to a memory allocation before it creates the thrown instance! (e.g. affects MinGW + Win XP!!!)
-template <class FE = FileError> inline
-void throwFileError(const std::wstring& msg, const std::wstring& functionName, const ErrorCode ec) //throw FileError
-{
- throw FE(msg, formatSystemError(functionName, ec));
-}
+//CAVEAT: thread-local Win32 error code is easily overwritten => evaluate *before* making any (indirect) system calls:
+//-> MinGW + Win XP: "throw" statement allocates memory to hold the exception object => error code is cleared
+//-> VC 2015, Debug: std::wstring allocator internally calls ::FlsGetValue() => error code is cleared
+#ifdef _MSC_VER
+#define THROW_LAST_FILE_ERROR(msg, functionName) \
+ do \
+ { \
+ const ErrorCode ecInternal = getLastError(); \
+ throw FileError(msg, formatSystemError(functionName, ecInternal)); \
+ \
+ __pragma(warning(suppress: 4127)) /*"conditional expression is constant"*/ \
+ } while (false)
+#else //variant witout "__pragma":
+#define THROW_LAST_FILE_ERROR(msg, functionName) \
+ do { const ErrorCode ecInternal = getLastError(); throw FileError(msg, formatSystemError(functionName, ecInternal)); } while (false)
+#endif
//----------- facilitate usage of std::wstring for error messages --------------------
diff --git a/zen/file_io.cpp b/zen/file_io.cpp
index 1ea8b1b1..68e852da 100644
--- a/zen/file_io.cpp
+++ b/zen/file_io.cpp
@@ -121,7 +121,7 @@ FileInput::FileInput(const Zstring& filepath) : //throw FileError, ErrorFileLock
//begin of "regular" error reporting
if (fileHandle == INVALID_HANDLE_VALUE)
{
- const DWORD ec = ::GetLastError(); //copy before directly or indirectly making other system calls!
+ const DWORD ec = ::GetLastError(); //copy before directly/indirectly making other system calls!
const std::wstring errorMsg = replaceCpy(_("Cannot open file %x."), L"%x", fmtPath(filepath));
std::wstring errorDescr = formatSystemError(L"CreateFile", ec);
@@ -145,7 +145,7 @@ FileInput::FileInput(const Zstring& filepath) : //throw FileError, ErrorFileLock
//don't use O_DIRECT: http://yarchive.net/comp/linux/o_direct.html
fileHandle = ::open(filepath.c_str(), O_RDONLY);
if (fileHandle == -1) //don't check "< 0" -> docu seems to allow "-2" to be a valid file handle
- throwFileError(replaceCpy(_("Cannot open file %x."), L"%x", fmtPath(filepath)), L"open", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot open file %x."), L"%x", fmtPath(filepath)), L"open");
#endif
//------------------------------------------------------------------------------------------------------
@@ -162,7 +162,7 @@ FileInput::FileInput(const Zstring& filepath) : //throw FileError, ErrorFileLock
#ifdef ZEN_LINUX //handle still un-owned => need constructor guard
//optimize read-ahead on input file:
if (::posix_fadvise(fileHandle, 0, 0, POSIX_FADV_SEQUENTIAL) != 0)
- throwFileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtPath(filepath)), L"posix_fadvise", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file %x."), L"%x", fmtPath(filepath)), L"posix_fadvise");
#elif defined ZEN_MAC
//"dtruss" doesn't show use of "fcntl() F_RDAHEAD/F_RDADVISE" for "cp")
@@ -197,7 +197,7 @@ size_t FileInput::read(void* buffer, size_t bytesToRead) //throw FileError; retu
static_cast<DWORD>(bytesToRead), //__in DWORD nNumberOfBytesToRead,
&bytesRead, //__out_opt LPDWORD lpNumberOfBytesRead,
nullptr)) //__inout_opt LPOVERLAPPED lpOverlapped
- throwFileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtPath(getFilePath())), L"ReadFile", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file %x."), L"%x", fmtPath(getFilePath())), L"ReadFile");
#elif defined ZEN_LINUX || defined ZEN_MAC
ssize_t bytesRead = 0;
@@ -208,7 +208,7 @@ size_t FileInput::read(void* buffer, size_t bytesToRead) //throw FileError; retu
while (bytesRead < 0 && errno == EINTR); //Compare copy_reg() in copy.c: ftp://ftp.gnu.org/gnu/coreutils/coreutils-8.23.tar.xz
if (bytesRead < 0)
- throwFileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtPath(getFilePath())), L"read", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file %x."), L"%x", fmtPath(getFilePath())), L"read");
#endif
if (bytesRead == 0) //"zero indicates end of file"
return bytesReadTotal;
@@ -262,7 +262,7 @@ FileOutput::FileOutput(const Zstring& filepath, AccessFlag access) : //throw Fil
fileHandle = createHandle(FILE_ATTRIBUTE_NORMAL);
if (fileHandle == INVALID_HANDLE_VALUE)
{
- DWORD ec = ::GetLastError(); //copy before directly or indirectly making other system calls!
+ DWORD ec = ::GetLastError(); //copy before directly/indirectly making other system calls!
//CREATE_ALWAYS fails with ERROR_ACCESS_DENIED if the existing file is hidden or "system" http://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
if (ec == ERROR_ACCESS_DENIED && dwCreationDisposition == CREATE_ALWAYS)
@@ -352,10 +352,10 @@ void FileOutput::close() //throw FileError
#ifdef ZEN_WIN
if (!::CloseHandle(fileHandle))
- throwFileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(getFilePath())), L"CloseHandle", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(getFilePath())), L"CloseHandle");
#elif defined ZEN_LINUX || defined ZEN_MAC
if (::close(fileHandle) != 0)
- throwFileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(getFilePath())), L"close", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(getFilePath())), L"close");
#endif
}
@@ -369,7 +369,7 @@ void FileOutput::write(const void* buffer, size_t bytesToWrite) //throw FileErro
static_cast<DWORD>(bytesToWrite), //__in DWORD nNumberOfBytesToWrite,
&bytesWritten, //__out_opt LPDWORD lpNumberOfBytesWritten,
nullptr)) //__inout_opt LPOVERLAPPED lpOverlapped
- throwFileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(getFilePath())), L"WriteFile", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(getFilePath())), L"WriteFile");
if (bytesWritten != bytesToWrite) //must be fulfilled for synchronous writes!
throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(getFilePath())), L"WriteFile: incomplete write."); //user should never see this
@@ -389,7 +389,7 @@ void FileOutput::write(const void* buffer, size_t bytesToWrite) //throw FileErro
if (bytesWritten == 0) //comment in safe-read.c suggests to treat this as an error due to buggy drivers
errno = ENOSPC;
- throwFileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(getFilePath())), L"write", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(getFilePath())), L"write");
}
if (bytesWritten > static_cast<ssize_t>(bytesToWrite)) //better safe than sorry
throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(getFilePath())), L"write: buffer overflow."); //user should never see this
diff --git a/zen/file_traverser.cpp b/zen/file_traverser.cpp
index 3ef94032..facce75c 100644
--- a/zen/file_traverser.cpp
+++ b/zen/file_traverser.cpp
@@ -39,15 +39,15 @@ void zen::traverseFolder(const Zstring& dirPath,
HANDLE hDir = ::FindFirstFile(applyLongPathPrefix(appendSeparator(dirPath) + L'*').c_str(), &findData);
if (hDir == INVALID_HANDLE_VALUE)
{
- const DWORD lastError = ::GetLastError(); //copy before making other system calls!
- if (lastError == ERROR_FILE_NOT_FOUND)
+ const DWORD ec = ::GetLastError(); //copy before directly/indirectly making other system calls!
+ if (ec == ERROR_FILE_NOT_FOUND)
{
//1. directory may not exist *or* 2. it is completely empty: not all directories contain "., .." entries, e.g. a drive's root directory; NetDrive
// -> FindFirstFile() is a nice example of violation of API design principle of single responsibility
if (dirExists(dirPath)) //yes, a race-condition, still the best we can do
return;
}
- throwFileError(replaceCpy(_("Cannot open directory %x."), L"%x", fmtPath(dirPath)), L"FindFirstFile", lastError);
+ throw FileError(replaceCpy(_("Cannot open directory %x."), L"%x", fmtPath(dirPath)), formatSystemError(L"FindFirstFile", ec));
}
ZEN_ON_SCOPE_EXIT(::FindClose(hDir));
@@ -58,37 +58,39 @@ void zen::traverseFolder(const Zstring& dirPath,
firstIteration = false;
else if (!::FindNextFile(hDir, &findData))
{
- const DWORD lastError = ::GetLastError();
- if (lastError == ERROR_NO_MORE_FILES) //not an error situation
+ const DWORD ec = ::GetLastError(); //copy before directly/indirectly making other system calls!
+ if (ec == ERROR_NO_MORE_FILES) //not an error situation
return;
//else we have a problem... report it:
- throwFileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtPath(dirPath)), L"FindNextFile", lastError);
+ throw FileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtPath(dirPath)), formatSystemError(L"FindNextFile", ec));
}
//skip "." and ".."
- const Zchar* const shortName = findData.cFileName;
+ const wchar_t* const itemNameRaw = findData.cFileName;
- if (shortName[0] == 0) throw FileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtPath(dirPath)), L"FindNextFile: Data corruption; item is missing a name.");
- if (shortName[0] == L'.' &&
- (shortName[1] == 0 || (shortName[1] == L'.' && shortName[2] == 0)))
+ if (itemNameRaw[0] == 0)
+ throw FileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtPath(dirPath)), L"FindNextFile: Data corruption; item with empty name.");
+
+ if (itemNameRaw[0] == L'.' &&
+ (itemNameRaw[1] == 0 || (itemNameRaw[1] == L'.' && itemNameRaw[2] == 0)))
continue;
- const Zstring& itempath = appendSeparator(dirPath) + shortName;
+ const Zstring& itemPath = appendSeparator(dirPath) + itemNameRaw;
if (zen::isSymlink(findData)) //check first!
{
if (onLink)
- onLink({ shortName, itempath, filetimeToTimeT(findData.ftLastWriteTime) });
+ onLink({ itemPath, filetimeToTimeT(findData.ftLastWriteTime) });
}
else if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
{
if (onDir)
- onDir({ shortName, itempath });
+ onDir({ itemPath });
}
else //a file
{
if (onFile)
- onFile({ shortName, itempath, get64BitUInt(findData.nFileSizeLow, findData.nFileSizeHigh), filetimeToTimeT(findData.ftLastWriteTime) });
+ onFile({ itemPath, get64BitUInt(findData.nFileSizeLow, findData.nFileSizeHigh), filetimeToTimeT(findData.ftLastWriteTime) });
}
}
@@ -106,32 +108,34 @@ void zen::traverseFolder(const Zstring& dirPath,
DIR* dirObj = ::opendir(dirPath.c_str()); //directory must NOT end with path separator, except "/"
if (!dirObj)
- throwFileError(replaceCpy(_("Cannot open directory %x."), L"%x", fmtPath(dirPath)), L"opendir", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot open directory %x."), L"%x", fmtPath(dirPath)), L"opendir");
ZEN_ON_SCOPE_EXIT(::closedir(dirObj)); //never close nullptr handles! -> crash
for (;;)
{
struct ::dirent* dirEntry = nullptr;
if (::readdir_r(dirObj, reinterpret_cast< ::dirent*>(&buffer[0]), &dirEntry) != 0)
- throwFileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtPath(dirPath)), L"readdir_r", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtPath(dirPath)), L"readdir_r");
//don't retry but restart dir traversal on error! http://blogs.msdn.com/b/oldnewthing/archive/2014/06/12/10533529.aspx
if (!dirEntry) //no more items
return;
//don't return "." and ".."
- const char* shortName = dirEntry->d_name;
+ const char* itemNameRaw = dirEntry->d_name;
+
+ if (itemNameRaw[0] == 0)
+ throw FileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtPath(dirPath)), L"readdir_r: Data corruption; item with empty name.");
- if (shortName[0] == 0) throw FileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtPath(dirPath)), L"readdir_r: Data corruption; item is missing a name.");
- if (shortName[0] == '.' &&
- (shortName[1] == 0 || (shortName[1] == '.' && shortName[2] == 0)))
+ if (itemNameRaw[0] == '.' &&
+ (itemNameRaw[1] == 0 || (itemNameRaw[1] == '.' && itemNameRaw[2] == 0)))
continue;
#ifdef ZEN_MAC
//some file system abstraction layers fail to properly return decomposed UTF8: http://developer.apple.com/library/mac/#qa/qa1173/_index.html
//so we need to do it ourselves; perf: ~600 ns per conversion
//note: it's not sufficient to apply this in z_impl::compareFilenamesNoCase: if UTF8 forms differ, FFS assumes a rename in case sensitivity and
// will try to propagate the rename => this won't work if target drive reports a particular UTF8 form only!
- if (CFStringRef cfStr = osx::createCFString(shortName))
+ if (CFStringRef cfStr = osx::createCFString(itemNameRaw))
{
ZEN_ON_SCOPE_EXIT(::CFRelease(cfStr));
@@ -140,19 +144,19 @@ void zen::traverseFolder(const Zstring& dirPath,
{
bufferUtfDecomposed.resize(lenMax);
if (::CFStringGetFileSystemRepresentation(cfStr, &bufferUtfDecomposed[0], lenMax)) //get decomposed UTF form (verified!) despite ambiguous documentation
- shortName = &bufferUtfDecomposed[0];
+ itemNameRaw = &bufferUtfDecomposed[0];
}
}
//const char* sampleDecomposed = "\x6f\xcc\x81.txt";
//const char* samplePrecomposed = "\xc3\xb3.txt";
#endif
- const Zstring& itempath = appendSeparator(dirPath) + shortName;
+ const Zstring& itemPath = appendSeparator(dirPath) + itemNameRaw;
struct ::stat statData = {};
try
{
- if (::lstat(itempath.c_str(), &statData) != 0) //lstat() does not resolve symlinks
- throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(itempath)), L"lstat", getLastError());
+ if (::lstat(itemPath.c_str(), &statData) != 0) //lstat() does not resolve symlinks
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(itemPath)), L"lstat");
}
catch (const FileError& e)
{
@@ -164,17 +168,17 @@ void zen::traverseFolder(const Zstring& dirPath,
if (S_ISLNK(statData.st_mode)) //on Linux there is no distinction between file and directory symlinks!
{
if (onLink)
- onLink({ shortName, itempath, statData.st_mtime});
+ onLink({ itemPath, statData.st_mtime});
}
else if (S_ISDIR(statData.st_mode)) //a directory
{
if (onDir)
- onDir({ shortName, itempath });
+ onDir({ itemPath });
}
else //a file or named pipe, ect.
{
if (onFile)
- onFile({ shortName, itempath, makeUnsigned(statData.st_size), statData.st_mtime });
+ onFile({ itemPath, makeUnsigned(statData.st_size), statData.st_mtime });
}
/*
It may be a good idea to not check "S_ISREG(statData.st_mode)" explicitly and to not issue an error message on other types to support these scenarios:
diff --git a/zen/file_traverser.h b/zen/file_traverser.h
index 3f8030d3..75c7660c 100644
--- a/zen/file_traverser.h
+++ b/zen/file_traverser.h
@@ -16,7 +16,6 @@ namespace zen
{
struct FileInfo
{
- const Zchar* shortName;
const Zstring& fullPath;
std::uint64_t fileSize; //[bytes]
std::int64_t lastWriteTime; //number of seconds since Jan. 1st 1970 UTC
@@ -24,13 +23,11 @@ struct FileInfo
struct DirInfo
{
- const Zchar* shortName;
const Zstring& fullPath;
};
struct SymlinkInfo
{
- const Zchar* shortName;
const Zstring& fullPath;
std::int64_t lastWriteTime; //number of seconds since Jan. 1st 1970 UTC
};
diff --git a/zen/fixed_list.h b/zen/fixed_list.h
index a1f83eb4..61ce3f16 100644
--- a/zen/fixed_list.h
+++ b/zen/fixed_list.h
@@ -27,10 +27,7 @@ class FixedList
};
public:
- FixedList() :
- firstInsert(nullptr),
- lastInsert(nullptr),
- sz(0) {}
+ FixedList() {}
~FixedList() { clear(); }
@@ -151,9 +148,9 @@ private:
delete oldNode;
}
- Node* firstInsert;
- Node* lastInsert; //point to last insertion; required by efficient emplace_back()
- size_t sz;
+ Node* firstInsert = nullptr;
+ Node* lastInsert = nullptr; //point to last insertion; required by efficient emplace_back()
+ size_t sz = 0;
};
}
diff --git a/zen/i18n.h b/zen/i18n.h
index 6c3a37c4..1a075413 100644
--- a/zen/i18n.h
+++ b/zen/i18n.h
@@ -33,6 +33,7 @@ struct TranslationHandler
{
virtual ~TranslationHandler() {}
+ //C++11: std::wstring should be thread-safe like an int
virtual std::wstring translate(const std::wstring& text) = 0; //simple translation
virtual std::wstring translate(const std::wstring& singular, const std::wstring& plural, std::int64_t n) = 0;
};
diff --git a/zen/long_path_prefix.h b/zen/long_path_prefix.h
index 4b79e051..6f6ebfdc 100644
--- a/zen/long_path_prefix.h
+++ b/zen/long_path_prefix.h
@@ -30,9 +30,9 @@ Zstring ntPathToWin32Path(const Zstring& path); //noexcept
http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx#NT_Namespaces
As used by GetModuleFileNameEx() and symlinks (FSCTL_GET_REPARSE_POINT):
- E.g.:
- \??\C:\folder -> C:\folder
- \SystemRoot -> C:\Windows
+ E.g.:
+ \??\C:\folder -> C:\folder
+ \SystemRoot -> C:\Windows
*/
}
diff --git a/zen/process_priority.cpp b/zen/process_priority.cpp
index 577e33a6..017eaa8b 100644
--- a/zen/process_priority.cpp
+++ b/zen/process_priority.cpp
@@ -41,7 +41,7 @@ struct ScheduleForBackgroundProcessing::Pimpl {};
ScheduleForBackgroundProcessing::ScheduleForBackgroundProcessing()
{
if (!::SetPriorityClass(::GetCurrentProcess(), PROCESS_MODE_BACKGROUND_BEGIN)) //this call lowers CPU priority, too!!
- throwFileError(_("Cannot change process I/O priorities."), L"SetPriorityClass", getLastError());
+ THROW_LAST_FILE_ERROR(_("Cannot change process I/O priorities."), L"SetPriorityClass");
}
@@ -64,32 +64,32 @@ ScheduleForBackgroundProcessing::~ScheduleForBackgroundProcessing() {};
/*
struct ScheduleForBackgroundProcessing
{
- - required functions ioprio_get/ioprio_set are not part of glibc: http://linux.die.net/man/2/ioprio_set
- - and probably never will: http://sourceware.org/bugzilla/show_bug.cgi?id=4464
- - /usr/include/linux/ioprio.h not available on Ubuntu, so we can't use it instead
-
- ScheduleForBackgroundProcessing() : oldIoPrio(getIoPriority(IOPRIO_WHO_PROCESS, ::getpid()))
- {
- if (oldIoPrio != -1)
- setIoPriority(::getpid(), IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0));
- }
- ~ScheduleForBackgroundProcessing()
- {
- if (oldIoPrio != -1)
- setIoPriority(::getpid(), oldIoPrio);
- }
+ - required functions ioprio_get/ioprio_set are not part of glibc: http://linux.die.net/man/2/ioprio_set
+ - and probably never will: http://sourceware.org/bugzilla/show_bug.cgi?id=4464
+ - /usr/include/linux/ioprio.h not available on Ubuntu, so we can't use it instead
+
+ ScheduleForBackgroundProcessing() : oldIoPrio(getIoPriority(IOPRIO_WHO_PROCESS, ::getpid()))
+ {
+ if (oldIoPrio != -1)
+ setIoPriority(::getpid(), IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0));
+ }
+ ~ScheduleForBackgroundProcessing()
+ {
+ if (oldIoPrio != -1)
+ setIoPriority(::getpid(), oldIoPrio);
+ }
private:
- static int getIoPriority(pid_t pid)
- {
- return ::syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, pid);
- }
- static int setIoPriority(pid_t pid, int ioprio)
- {
- return ::syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, pid, ioprio);
- }
-
- const int oldIoPrio;
+ static int getIoPriority(pid_t pid)
+ {
+ return ::syscall(SYS_ioprio_get, IOPRIO_WHO_PROCESS, pid);
+ }
+ static int setIoPriority(pid_t pid, int ioprio)
+ {
+ return ::syscall(SYS_ioprio_set, IOPRIO_WHO_PROCESS, pid, ioprio);
+ }
+
+ const int oldIoPrio;
};
*/
#endif
diff --git a/zen/recycler.cpp b/zen/recycler.cpp
index 75083d57..d49e686c 100644
--- a/zen/recycler.cpp
+++ b/zen/recycler.cpp
@@ -172,18 +172,18 @@ bool zen::recycleOrDelete(const Zstring& itempath) //throw FileError
#ifdef ZEN_WIN
-bool zen::recycleBinExists(const Zstring& dirpath, const std::function<void ()>& onUpdateGui) //throw FileError
+bool zen::recycleBinExists(const Zstring& dirPath, const std::function<void ()>& onUpdateGui) //throw FileError
{
#ifdef ZEN_WIN_VISTA_AND_LATER
- return vista::supportsRecycleBin(dirpath); //throw FileError
+ return vista::supportsRecycleBin(dirPath); //throw FileError
#else
//excessive runtime if recycle bin exists, is full and drive is slow:
- auto ft = runAsync([dirpath]()
+ auto ft = runAsync([dirPath]()
{
SHQUERYRBINFO recInfo = {};
recInfo.cbSize = sizeof(recInfo);
- return ::SHQueryRecycleBin(dirpath.c_str(), //__in_opt LPCTSTR pszRootPath,
+ return ::SHQueryRecycleBin(dirPath.c_str(), //__in_opt LPCTSTR pszRootPath,
&recInfo); //__inout LPSHQUERYRBINFO pSHQueryRBInfo
});
@@ -197,7 +197,7 @@ bool zen::recycleBinExists(const Zstring& dirpath, const std::function<void ()>&
//1. ::SHQueryRecycleBin() is excessive: traverses whole $Recycle.Bin directory tree each time!!!! But it's safe and correct.
//2. we can't simply buffer the ::SHQueryRecycleBin() based on volume serial number:
- // "subst S:\ C:\" => GetVolumeInformation() returns same serial for C:\ and S:\, but S:\ does not support recycle bin!
+ // "subst S:\ C:\" => GetVolumeInformation() returns same serial for C:\ and S:\, but S:\ does not support recycle bin!
//3. we would prefer to use CLSID_RecycleBinManager beginning with Vista... if only this interface were documented!!!
@@ -210,7 +210,7 @@ bool zen::recycleBinExists(const Zstring& dirpath, const std::function<void ()>&
/*
Zstring rootPathPf = appendSeparator(&buffer[0]);
- const bool canUseFastCheckForRecycler = winXpOrLater();
+ const bool canUseFastCheckForRecycler = winXpOrLater();
if (!canUseFastCheckForRecycler) //== "checkForRecycleBin"
return STATUS_REC_UNKNOWN;
diff --git a/zen/recycler.h b/zen/recycler.h
index 7c63cf8a..3df7fda2 100644
--- a/zen/recycler.h
+++ b/zen/recycler.h
@@ -21,7 +21,8 @@ namespace zen
Windows
-------
-Recycler API always available: during runtime either SHFileOperation or IFileOperation (since Vista) will be dynamically selected
+-> Recycler API always available: during runtime either SHFileOperation or IFileOperation (since Vista) will be dynamically selected
+-> COM needs to be initialized before calling any of these functions! CoInitializeEx/CoUninitialize
Linux
-----
@@ -31,15 +32,18 @@ Linker flags: `pkg-config --libs gio-2.0`
Already included in package "gtk+-2.0"!
*/
+
+
//move a file or folder to Recycle Bin (deletes permanently if recycler is not available) -> crappy semantics, but we have no choice thanks to Windows' design
-bool recycleOrDelete(const Zstring& itempath); //throw FileError, return "true" if file/dir was actually deleted
+bool recycleOrDelete(const Zstring& itemPath); //throw FileError, return "true" if file/dir was actually deleted
#ifdef ZEN_WIN
//Win XP: can take a long time if recycle bin is full and drive is slow!!! => buffer result!
-bool recycleBinExists(const Zstring& dirpath, const std::function<void ()>& onUpdateGui); //throw FileError
+//Vista and later: dirPath must exist for a valid check!
+bool recycleBinExists(const Zstring& dirPath, const std::function<void ()>& onUpdateGui); //throw FileError
-void recycleOrDelete(const std::vector<Zstring>& filepaths, //throw FileError, return "true" if file/dir was actually deleted
+void recycleOrDelete(const std::vector<Zstring>& filePaths, //throw FileError, return "true" if file/dir was actually deleted
const std::function<void (const std::wstring& displayPath)>& onRecycleItem); //optional; currentItem may be empty
#endif
}
diff --git a/zen/scope_guard.h b/zen/scope_guard.h
index 5e917853..b5564c9b 100644
--- a/zen/scope_guard.h
+++ b/zen/scope_guard.h
@@ -17,13 +17,13 @@ namespace zen
//Scope Guard
/*
zen::ScopeGuard lockAio = zen::makeGuard([&] { ::CloseHandle(hDir); });
- ...
- lockAio.dismiss();
+ ...
+ lockAio.dismiss();
*/
//Scope Exit
/*
- ZEN_ON_SCOPE_EXIT(::CloseHandle(hDir));
+ ZEN_ON_SCOPE_EXIT(::CloseHandle(hDir));
*/
class ScopeGuardBase
@@ -32,7 +32,7 @@ public:
void dismiss() { dismissed_ = true; }
protected:
- ScopeGuardBase() : dismissed_(false) {}
+ ScopeGuardBase() {}
ScopeGuardBase(ScopeGuardBase&& other) : dismissed_(other.dismissed_) { other.dismiss(); } //take over responsibility
~ScopeGuardBase() {} //[!] protected non-virtual base class destructor
@@ -42,7 +42,7 @@ private:
ScopeGuardBase (const ScopeGuardBase&) = delete;
ScopeGuardBase& operator=(const ScopeGuardBase&) = delete;
- bool dismissed_;
+ bool dismissed_ = false;
};
diff --git a/zen/serialize.h b/zen/serialize.h
index 07d9362c..ff2871b1 100644
--- a/zen/serialize.h
+++ b/zen/serialize.h
@@ -67,7 +67,7 @@ template <class BinContainer> BinContainer loadBinStream(const Zstring& filepath
-----------------------------
struct BinInputStream
{
- size_t read(void* data, size_t len); //return "len" bytes unless end of stream!
+ size_t read(void* data, size_t len); //return "len" bytes unless end of stream!
};
------------------------------
diff --git a/zen/shell_execute.h b/zen/shell_execute.h
index b36bc5ea..2adce179 100644
--- a/zen/shell_execute.h
+++ b/zen/shell_execute.h
@@ -62,12 +62,14 @@ bool shellExecuteImpl(Function fillExecInfo, ExecutionType type)
void shellExecute(const void* /*PCIDLIST_ABSOLUTE*/ shellItemPidl, const std::wstring& displayPath, ExecutionType type) //throw FileError
{
- if (!shellExecuteImpl([&](SHELLEXECUTEINFO& execInfo)
-{
- execInfo.fMask |= SEE_MASK_IDLIST;
- execInfo.lpIDList = const_cast<void*>(shellItemPidl); //lpIDList is documented as PCIDLIST_ABSOLUTE!
- }, type)) //throw FileError
- throwFileError(_("Incorrect command line:") + L"\n" + fmtPath(displayPath), L"ShellExecuteEx", ::GetLastError());
+ auto fillExecInfo = [&](SHELLEXECUTEINFO& execInfo)
+ {
+ execInfo.fMask |= SEE_MASK_IDLIST;
+ execInfo.lpIDList = const_cast<void*>(shellItemPidl); //lpIDList is documented as PCIDLIST_ABSOLUTE!
+ };
+
+ if (!shellExecuteImpl(fillExecInfo , type)) //throw FileError
+ THROW_LAST_FILE_ERROR(_("Incorrect command line:") + L"\n" + fmtPath(displayPath), L"ShellExecuteEx");
}
#endif
@@ -97,12 +99,14 @@ void shellExecute(const Zstring& command, ExecutionType type) //throw FileError
(iter->empty() || std::any_of(iter->begin(), iter->end(), &isWhiteSpace<wchar_t>) ? L"\"" + *iter + L"\"" : *iter);
}
- if (!shellExecuteImpl([&](SHELLEXECUTEINFO& execInfo)
-{
- execInfo.lpFile = filepath.c_str();
+ auto fillExecInfo = [&](SHELLEXECUTEINFO& execInfo)
+ {
+ execInfo.lpFile = filepath.c_str();
execInfo.lpParameters = arguments.c_str();
- }, type))
- throwFileError(_("Incorrect command line:") + L"\nFile: " + fmtPath(filepath) + L"\nArg: " + copyStringTo<std::wstring>(arguments), L"ShellExecuteEx", ::GetLastError());
+ };
+
+ if (!shellExecuteImpl(fillExecInfo, type))
+ THROW_LAST_FILE_ERROR(_("Incorrect command line:") + L"\nFile: " + fmtPath(filepath) + L"\nArg: " + copyStringTo<std::wstring>(arguments), L"ShellExecuteEx");
#elif defined ZEN_LINUX || defined ZEN_MAC
/*
diff --git a/zen/stl_tools.h b/zen/stl_tools.h
index e949c5c9..1e38f1b0 100644
--- a/zen/stl_tools.h
+++ b/zen/stl_tools.h
@@ -13,6 +13,7 @@
#include <memory>
#include <algorithm>
#include "type_tools.h"
+#include "build_info.h"
//enhancements for <algorithm>
namespace zen
@@ -59,12 +60,19 @@ template <class InputIterator1, class InputIterator2>
bool equal(InputIterator1 first1, InputIterator1 last1,
InputIterator2 first2, InputIterator2 last2);
-//until std::make_unique is available in GCC:
-template <class T, class... Args> inline
-std::unique_ptr<T> make_unique(Args&& ... args) { return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); }
-
+size_t hashBytes(const unsigned char* ptr, size_t len);
+//support for custom string classes in std::unordered_set/map
+struct StringHash
+{
+ template <class String>
+ size_t operator()(const String& str) const
+ {
+ const auto* strFirst = strBegin(str);
+ return hashBytes(reinterpret_cast<const unsigned char*>(strFirst), strLength(str) * sizeof(strFirst[0]));
+ }
+};
@@ -199,6 +207,28 @@ bool equal(InputIterator1 first1, InputIterator1 last1,
#if defined _MSC_VER && _MSC_VER <= 1600
static_assert(false, "VS2010 performance bug in std::unordered_set<>: http://drdobbs.com/blogs/cpp/232200410 -> should be fixed in VS11");
#endif
+
+
+inline
+size_t hashBytes(const unsigned char* ptr, size_t len)
+{
+ //http://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function
+#ifdef ZEN_BUILD_32BIT
+ const size_t basis = 2166136261U;
+ const size_t prime = 16777619U;
+#elif defined ZEN_BUILD_64BIT
+ const size_t basis = 14695981039346656037ULL;
+ const size_t prime = 1099511628211ULL;
+#endif
+
+ size_t val = basis;
+ for (size_t i = 0; i < len; ++i)
+ {
+ val ^= static_cast<size_t>(ptr[i]);
+ val *= prime;
+ }
+ return val;
+}
}
#endif //STL_TOOLS_HEADER_84567184321434
diff --git a/zen/string_base.h b/zen/string_base.h
index 1bf8ed68..224797e8 100644
--- a/zen/string_base.h
+++ b/zen/string_base.h
@@ -198,7 +198,7 @@ private:
length (static_cast<std::uint32_t>(len)),
capacity(static_cast<std::uint32_t>(cap)) { static_assert(ATOMIC_INT_LOCK_FREE == 2, ""); } //2: "the types are always lock-free"
- std::atomic<unsigned int> refCount { 1 }; //std:atomic is uninitialized by default!
+ std::atomic<unsigned int> refCount { 1 }; //std:atomic is uninitialized by default!
std::uint32_t length;
std::uint32_t capacity; //allocated size without null-termination
};
@@ -211,9 +211,9 @@ private:
//perf note: interestingly StorageDeepCopy and StorageRefCountThreadSafe show same performance in FFS comparison
-template <class Char, //Character Type
+template <class Char, //Character Type
template <class, class> class SP = StorageRefCountThreadSafe, //Storage Policy
- class AP = AllocatorOptimalSpeed> //Allocator Policy
+ class AP = AllocatorOptimalSpeed> //Allocator Policy
class Zbase : public SP<Char, AP>
{
public:
@@ -222,10 +222,10 @@ public:
Zbase(const Char* source, size_t length);
Zbase(const Zbase& source);
Zbase(Zbase&& tmp) noexcept;
- explicit Zbase(Char source); //dangerous if implicit: Char buffer[]; return buffer[0]; ups... forgot &, but not a compiler error!
-
-//allow explicit construction from different string type, prevent ambiguity via SFINAE
-//template <class S> explicit Zbase(const S& other, typename S::value_type = 0);
+ //explicit Zbase(Char source); //dangerous if implicit: Char buffer[]; return buffer[0]; ups... forgot &, but not a compiler error! //-> non-standard extension!!!
+
+ //allow explicit construction from different string type, prevent ambiguity via SFINAE
+ //template <class S> explicit Zbase(const S& other, typename S::value_type = 0);
~Zbase();
@@ -275,7 +275,7 @@ public:
Zbase& operator+=(const Char* other);
Zbase& operator+=(Char ch);
- static const size_t npos = static_cast<size_t>(-1);
+ static const size_t npos = static_cast<size_t>(-1);
private:
Zbase (int) = delete; //
@@ -307,8 +307,8 @@ template <class Char, template <class, class> class SP, class AP> inline Zbase<C
template <class Char, template <class, class> class SP, class AP> inline Zbase<Char, SP, AP> operator+(Zbase<Char, SP, AP>&& lhs, const Char* rhs) { return std::move(lhs += rhs); } //lhs, is an l-value parameter...
template <class Char, template <class, class> class SP, class AP> inline Zbase<Char, SP, AP> operator+(Zbase<Char, SP, AP>&& lhs, Char rhs) { return std::move(lhs += rhs); } //and not a local variable => no copy elision
-template <class Char, template <class, class> class SP, class AP> inline Zbase<Char, SP, AP> operator+( Char lhs, const Zbase<Char, SP, AP>& rhs) { return Zbase<Char, SP, AP>(lhs) += rhs; }
-template <class Char, template <class, class> class SP, class AP> inline Zbase<Char, SP, AP> operator+(const Char* lhs, const Zbase<Char, SP, AP>& rhs) { return Zbase<Char, SP, AP>(lhs) += rhs; }
+template <class Char, template <class, class> class SP, class AP> inline Zbase<Char, SP, AP> operator+( Char lhs, const Zbase<Char, SP, AP>& rhs) { return Zbase<Char, SP, AP>(&lhs, 1) += rhs; }
+template <class Char, template <class, class> class SP, class AP> inline Zbase<Char, SP, AP> operator+(const Char* lhs, const Zbase<Char, SP, AP>& rhs) { return Zbase<Char, SP, AP>(lhs ) += rhs; }
@@ -333,15 +333,6 @@ Zbase<Char, SP, AP>::Zbase()
template <class Char, template <class, class> class SP, class AP> inline
-Zbase<Char, SP, AP>::Zbase(Char source)
-{
- rawStr = this->create(1);
- rawStr[0] = source;
- rawStr[1] = 0;
-}
-
-
-template <class Char, template <class, class> class SP, class AP> inline
Zbase<Char, SP, AP>::Zbase(const Char* source)
{
const size_t sourceLen = strLength(source);
diff --git a/zen/string_tools.h b/zen/string_tools.h
index 9708464e..8f83b9cd 100644
--- a/zen/string_tools.h
+++ b/zen/string_tools.h
@@ -18,7 +18,7 @@
#include "stl_tools.h"
#include "string_traits.h"
-
+
//enhance arbitray string class with useful non-member functions:
namespace zen
{
@@ -444,9 +444,9 @@ S numberTo(const Num& number, Int2Type<NUM_TYPE_FLOATING_POINT>)
/*
perf: integer to string: (executed 10 mio. times)
- std::stringstream - 14796 ms
- std::sprintf - 3086 ms
- formatInteger - 778 ms
+ std::stringstream - 14796 ms
+ std::sprintf - 3086 ms
+ formatInteger - 778 ms
*/
template <class OutputIterator, class Num> inline
diff --git a/zen/string_traits.h b/zen/string_traits.h
index add53d3a..61fa2625 100644
--- a/zen/string_traits.h
+++ b/zen/string_traits.h
@@ -16,21 +16,21 @@ namespace zen
/*
IsStringLike<>::value:
IsStringLike<const wchar_t*>::value; //equals "true"
- IsStringLike<const int*> ::value; //equals "false"
+ IsStringLike<const int*> ::value; //equals "false"
GetCharType<>::Type:
- GetCharType<std::wstring>::Type //equals wchar_t
- GetCharType<wchar_t[5]> ::Type //equals wchar_t
+ GetCharType<std::wstring>::Type //equals wchar_t
+ GetCharType<wchar_t[5]> ::Type //equals wchar_t
strLength():
- strLength(str); //equals str.length()
- strLength(array); //equals cStringLength(array)
+ strLength(str); //equals str.length()
+ strLength(array); //equals cStringLength(array)
strBegin(): -> not null-terminated! -> may be nullptr if length is 0!
- std::wstring str(L"dummy");
- char array[] = "dummy";
- strBegin(str); //returns str.c_str()
- strBegin(array); //returns array
+ std::wstring str(L"dummy");
+ char array[] = "dummy";
+ strBegin(str); //returns str.c_str()
+ strBegin(array); //returns array
*/
//reference a sub-string for consumption by zen string_tools
diff --git a/zen/symlink_target.h b/zen/symlink_target.h
index c4557559..b5ca8191 100644
--- a/zen/symlink_target.h
+++ b/zen/symlink_target.h
@@ -100,7 +100,7 @@ Zstring getSymlinkRawTargetString_impl(const Zstring& linkPath) //throw FileErro
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, //_In_ DWORD dwFlagsAndAttributes,
nullptr); //_In_opt_ HANDLE hTemplateFile
if (hLink == INVALID_HANDLE_VALUE)
- throwFileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtPath(linkPath)), L"CreateFile", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtPath(linkPath)), L"CreateFile");
ZEN_ON_SCOPE_EXIT(::CloseHandle(hLink));
//respect alignment issues...
@@ -116,7 +116,7 @@ Zstring getSymlinkRawTargetString_impl(const Zstring& linkPath) //throw FileErro
bufferSize, //__in DWORD nOutBufferSize,
&bytesReturned, //__out_opt LPDWORD lpBytesReturned,
nullptr)) //__inout_opt LPOVERLAPPED lpOverlapped
- throwFileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtPath(linkPath)), L"DeviceIoControl, FSCTL_GET_REPARSE_POINT", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtPath(linkPath)), L"DeviceIoControl, FSCTL_GET_REPARSE_POINT");
REPARSE_DATA_BUFFER& reparseData = *reinterpret_cast<REPARSE_DATA_BUFFER*>(&buffer[0]); //REPARSE_DATA_BUFFER needs to be artificially enlarged!
@@ -144,7 +144,7 @@ Zstring getSymlinkRawTargetString_impl(const Zstring& linkPath) //throw FileErro
const ssize_t bytesWritten = ::readlink(linkPath.c_str(), &buffer[0], BUFFER_SIZE);
if (bytesWritten < 0)
- throwFileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtPath(linkPath)), L"readlink", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtPath(linkPath)), L"readlink");
if (bytesWritten >= static_cast<ssize_t>(BUFFER_SIZE)) //detect truncation, not an error for readlink!
throw FileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtPath(linkPath)), L"readlink: buffer truncated.");
@@ -162,7 +162,7 @@ Zstring getResolvedSymlinkPath_impl(const Zstring& linkPath) //throw FileError
const SysDllFun<GetFinalPathNameByHandleWFunc> getFinalPathNameByHandle(L"kernel32.dll", "GetFinalPathNameByHandleW");
if (!getFinalPathNameByHandle)
throw FileError(replaceCpy(_("Cannot determine final path for %x."), L"%x", fmtPath(linkPath)), replaceCpy(_("Cannot find system function %x."), L"%x", L"\"GetFinalPathNameByHandleW\""));
-
+
const HANDLE hFile = ::CreateFile(applyLongPathPrefix(linkPath).c_str(), //_In_ LPCTSTR lpFileName,
0, //_In_ DWORD dwDesiredAccess,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, //_In_ DWORD dwShareMode,
@@ -172,12 +172,12 @@ Zstring getResolvedSymlinkPath_impl(const Zstring& linkPath) //throw FileError
FILE_FLAG_BACKUP_SEMANTICS, //_In_ DWORD dwFlagsAndAttributes,
nullptr); //_In_opt_ HANDLE hTemplateFile
if (hFile == INVALID_HANDLE_VALUE)
- throwFileError(replaceCpy(_("Cannot determine final path for %x."), L"%x", fmtPath(linkPath)), L"CreateFile", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot determine final path for %x."), L"%x", fmtPath(linkPath)), L"CreateFile");
ZEN_ON_SCOPE_EXIT(::CloseHandle(hFile));
const DWORD bufferSize = getFinalPathNameByHandle(hFile, nullptr, 0, 0);
if (bufferSize == 0)
- throwFileError(replaceCpy(_("Cannot determine final path for %x."), L"%x", fmtPath(linkPath)), L"GetFinalPathNameByHandle", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot determine final path for %x."), L"%x", fmtPath(linkPath)), L"GetFinalPathNameByHandle");
std::vector<wchar_t> targetPath(bufferSize);
const DWORD charsWritten = getFinalPathNameByHandle(hFile, //__in HANDLE hFile,
@@ -188,7 +188,7 @@ Zstring getResolvedSymlinkPath_impl(const Zstring& linkPath) //throw FileError
{
const std::wstring errorMsg = replaceCpy(_("Cannot determine final path for %x."), L"%x", fmtPath(linkPath));
if (charsWritten == 0)
- throwFileError(errorMsg, L"GetFinalPathNameByHandle", getLastError());
+ THROW_LAST_FILE_ERROR(errorMsg, L"GetFinalPathNameByHandle");
throw FileError(errorMsg);
}
@@ -197,7 +197,7 @@ Zstring getResolvedSymlinkPath_impl(const Zstring& linkPath) //throw FileError
#elif defined ZEN_LINUX || defined ZEN_MAC
char* targetPath = ::realpath(linkPath.c_str(), nullptr);
if (!targetPath)
- throwFileError(replaceCpy(_("Cannot determine final path for %x."), L"%x", fmtPath(linkPath)), L"realpath", getLastError());
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot determine final path for %x."), L"%x", fmtPath(linkPath)), L"realpath");
ZEN_ON_SCOPE_EXIT(::free(targetPath));
return targetPath;
#endif
@@ -216,13 +216,13 @@ Zstring getResolvedSymlinkPath(const Zstring& linkPath) { return getResolvedSyml
#ifdef ZEN_WIN
/*
Reparse Point Tags
- http://msdn.microsoft.com/en-us/library/windows/desktop/aa365511(v=vs.85).aspx
+ http://msdn.microsoft.com/en-us/library/windows/desktop/aa365511(v=vs.85).aspx
WIN32_FIND_DATA structure
- http://msdn.microsoft.com/en-us/library/windows/desktop/aa365740(v=vs.85).aspx
+ http://msdn.microsoft.com/en-us/library/windows/desktop/aa365740(v=vs.85).aspx
The only surrogate reparse points are;
- IO_REPARSE_TAG_MOUNT_POINT
- IO_REPARSE_TAG_SYMLINK
+ IO_REPARSE_TAG_MOUNT_POINT
+ IO_REPARSE_TAG_SYMLINK
*/
inline
diff --git a/zen/thread.h b/zen/thread.h
index a3b8760b..b10dd342 100644
--- a/zen/thread.h
+++ b/zen/thread.h
@@ -25,7 +25,7 @@ public:
InterruptibleThread& operator=(InterruptibleThread&& tmp) = default;
template <class Function>
- InterruptibleThread(Function f);
+ InterruptibleThread(Function&& f);
bool joinable () const { return stdThread.joinable(); }
void interrupt();
@@ -62,8 +62,8 @@ void interruptibleSleep(const std::chrono::duration<Rep, Period>& relTime); //th
/*
std::async replacement without crappy semantics:
- 1. guaranteed to run asynchronously
- 2. does not follow C++11 [futures.async], Paragraph 5, where std::future waits for thread in destructor
+ 1. guaranteed to run asynchronously
+ 2. does not follow C++11 [futures.async], Paragraph 5, where std::future waits for thread in destructor
Example:
Zstring dirpath = ...
@@ -72,7 +72,7 @@ Example:
//dir exising
*/
template <class Function>
-auto runAsync(Function fun) -> std::future<decltype(fun())>;
+auto runAsync(Function&& fun) -> std::future<decltype(fun())>;
//wait for all with a time limit: return true if *all* results are available!
template<class InputIterator, class Duration>
@@ -90,7 +90,7 @@ public:
GetFirstResult();
template <class Fun>
- void addJob(Fun f); //f must return a std::unique_ptr<T> containing a value if successful
+ void addJob(Fun&& f); //f must return a std::unique_ptr<T> containing a value if successful
template <class Duration>
bool timedWait(const Duration& duration) const; //true: "get()" is ready, false: time elapsed
@@ -139,18 +139,38 @@ private:
//###################### implementation ######################
+namespace impl
+{
template <class Function> inline
-auto runAsync(Function fun) -> std::future<decltype(fun())>
+auto runAsync(Function&& fun, TrueType /*copy-constructible*/) -> std::future<decltype(fun())>
{
typedef decltype(fun()) ResultType;
- std::packaged_task<ResultType()> pt(std::move(fun));
+ //note: std::packaged_task does NOT support move-only function objects!
+ std::packaged_task<ResultType()> pt(std::forward<Function>(fun));
auto fut = pt.get_future();
std::thread(std::move(pt)).detach(); //we have to explicitly detach since C++11: [thread.thread.destr] ~thread() calls std::terminate() if joinable()!!!
return fut;
}
+template <class Function> inline
+auto runAsync(Function&& fun, FalseType /*copy-constructible*/) -> std::future<decltype(fun())>
+{
+ //support move-only function objects!
+ auto sharedFun = std::make_shared<Function>(std::forward<Function>(fun));
+ return runAsync([sharedFun]() { return (*sharedFun)(); }, TrueType());
+}
+}
+
+
+template <class Function> inline
+auto runAsync(Function&& fun) -> std::future<decltype(fun())>
+{
+ return impl::runAsync(std::forward<Function>(fun), StaticBool<std::is_copy_constructible<Function>::value>());
+}
+
+
template<class InputIterator, class Duration> inline
bool wait_for_all_timed(InputIterator first, InputIterator last, const Duration& duration)
{
@@ -166,12 +186,6 @@ template <class T>
class GetFirstResult<T>::AsyncResult
{
public:
- AsyncResult() :
-#ifndef NDEBUG
- returnedResult(false),
-#endif
- jobsFinished(0) {}
-
//context: worker threads
void reportFinished(std::unique_ptr<T>&& result)
{
@@ -208,11 +222,11 @@ private:
bool jobDone(size_t jobsTotal) const { return result_ || (jobsFinished >= jobsTotal); } //call while locked!
#ifndef NDEBUG
- bool returnedResult;
+ bool returnedResult = false;
#endif
std::mutex lockResult;
- size_t jobsFinished; //
+ size_t jobsFinished = 0; //
std::unique_ptr<T> result_; //our condition is: "have result" or "jobsFinished == jobsTotal"
std::condition_variable conditionJobDone;
};
@@ -225,9 +239,9 @@ GetFirstResult<T>::GetFirstResult() : asyncResult_(std::make_shared<AsyncResult>
template <class T>
template <class Fun> inline
-void GetFirstResult<T>::addJob(Fun f) //f must return a std::unique_ptr<T> containing a value on success
+void GetFirstResult<T>::addJob(Fun&& f) //f must return a std::unique_ptr<T> containing a value on success
{
- std::thread t([asyncResult = this->asyncResult_, f = std::move(f)] { asyncResult->reportFinished(f()); });
+ std::thread t([asyncResult = this->asyncResult_, f = std::forward<Fun>(f)] { asyncResult->reportFinished(f()); });
++jobsTotal_;
t.detach(); //we have to be explicit since C++11: [thread.thread.destr] ~thread() calls std::terminate() if joinable()!!!
}
@@ -367,12 +381,12 @@ void interruptibleSleep(const std::chrono::duration<Rep, Period>& relTime) //thr
template <class Function> inline
-InterruptibleThread::InterruptibleThread(Function f) : intStatus_(std::make_shared<InterruptionStatus>())
+InterruptibleThread::InterruptibleThread(Function&& f) : intStatus_(std::make_shared<InterruptionStatus>())
{
std::promise<void> pFinished;
threadCompleted = pFinished.get_future();
- stdThread = std::thread([f = std::move(f),
+ stdThread = std::thread([f = std::forward<Function>(f),
intStatus = this->intStatus_,
pFinished = std::move(pFinished)]() mutable
{
diff --git a/zen/tick_count.h b/zen/tick_count.h
index bedc66a5..b5667c6c 100644
--- a/zen/tick_count.h
+++ b/zen/tick_count.h
@@ -65,8 +65,8 @@ public:
return numeric::dist(lhs.val_.QuadPart, rhs.val_.QuadPart); //std::abs(a - b) can lead to overflow!
#elif defined ZEN_LINUX
//structure timespec documented with members:
- // time_t tv_sec seconds
- // long tv_nsec nanoseconds
+ // time_t tv_sec seconds
+ // long tv_nsec nanoseconds
const int64_t deltaSec = lhs.val_.tv_sec - rhs.val_.tv_sec;
const int64_t deltaNsec = lhs.val_.tv_nsec - rhs.val_.tv_nsec;
return numeric::abs(deltaSec * 1000000000 + deltaNsec);
@@ -114,8 +114,8 @@ int64_t ticksPerSec() //return 0 on error
if (::mach_timebase_info(&tbi) != KERN_SUCCESS)
return 0;
//structure mach_timebase_info_data_t documented with members:
- // uint32_t numer;
- // uint32_t denom;
+ // uint32_t numer;
+ // uint32_t denom;
return static_cast<int64_t>(1000000000) * tbi.denom / tbi.numer;
#endif
}
diff --git a/zen/time.h b/zen/time.h
index df0f3a54..516fc511 100644
--- a/zen/time.h
+++ b/zen/time.h
@@ -154,8 +154,8 @@ struct GetFormat<FormatIsoDateTimeTag> //%Y-%m-%d %H:%M:%S - e.g. 2001-08-23 14:
//strftime() craziness on invalid input:
-// VS 2010: CRASH unless "_invalid_parameter_handler" is set: http://msdn.microsoft.com/en-us/library/ksazx244.aspx
-// GCC: returns 0, apparently no crash. Still, considering some clib maintainer's comments, we should expect the worst!
+// VS 2010: CRASH unless "_invalid_parameter_handler" is set: http://msdn.microsoft.com/en-us/library/ksazx244.aspx
+// GCC: returns 0, apparently no crash. Still, considering some clib maintainer's comments, we should expect the worst!
inline
size_t strftimeWrap_impl(char* buffer, size_t bufferSize, const char* format, const struct std::tm* timeptr)
{
@@ -173,12 +173,12 @@ size_t strftimeWrap_impl(wchar_t* buffer, size_t bufferSize, const wchar_t* form
inline
bool isValid(const struct std::tm& t)
{
- -> not enough! MSCRT has different limits than the C standard which even seem to change with different versions:
- _VALIDATE_RETURN((( timeptr->tm_sec >=0 ) && ( timeptr->tm_sec <= 59 ) ), EINVAL, FALSE)
- _VALIDATE_RETURN(( timeptr->tm_year >= -1900 ) && ( timeptr->tm_year <= 8099 ), EINVAL, FALSE)
- -> also std::mktime does *not* help here at all!
+ -> not enough! MSCRT has different limits than the C standard which even seem to change with different versions:
+ _VALIDATE_RETURN((( timeptr->tm_sec >=0 ) && ( timeptr->tm_sec <= 59 ) ), EINVAL, FALSE)
+ _VALIDATE_RETURN(( timeptr->tm_year >= -1900 ) && ( timeptr->tm_year <= 8099 ), EINVAL, FALSE)
+ -> also std::mktime does *not* help here at all!
- auto inRange = [](int value, int minVal, int maxVal) { return minVal <= value && value <= maxVal; };
+ auto inRange = [](int value, int minVal, int maxVal) { return minVal <= value && value <= maxVal; };
//http://www.cplusplus.com/reference/clibrary/ctime/tm/
return inRange(t.tm_sec , 0, 61) &&
diff --git a/zen/type_traits.h b/zen/type_traits.h
index e03085d9..3ec90f49 100644
--- a/zen/type_traits.h
+++ b/zen/type_traits.h
@@ -60,20 +60,20 @@ template <class T> struct IsArithmetic; //IsInteger or IsFloat
//################# Class Members ########################
/* Detect data or function members of a class by name: ZEN_INIT_DETECT_MEMBER + HasMember_
- Example: 1. ZEN_INIT_DETECT_MEMBER(c_str);
- 2. HasMember_c_str<T>::value -> use as boolean
+ Example: 1. ZEN_INIT_DETECT_MEMBER(c_str);
+ 2. HasMember_c_str<T>::value -> use as boolean
*/
/* Detect data or function members of a class by name *and* type: ZEN_INIT_DETECT_MEMBER2 + HasMember_
- Example: 1. ZEN_INIT_DETECT_MEMBER2(size, size_t (T::*)() const);
- 2. HasMember_size<T>::value -> use as boolean
+ Example: 1. ZEN_INIT_DETECT_MEMBER2(size, size_t (T::*)() const);
+ 2. HasMember_size<T>::value -> use as boolean
*/
/* Detect member type of a class: ZEN_INIT_DETECT_MEMBER_TYPE + HasMemberType_
- Example: 1. ZEN_INIT_DETECT_MEMBER_TYPE(value_type);
- 2. HasMemberType_value_type<T>::value -> use as boolean
+ Example: 1. ZEN_INIT_DETECT_MEMBER_TYPE(value_type);
+ 2. HasMemberType_value_type<T>::value -> use as boolean
*/
@@ -130,29 +130,29 @@ template <class T>
struct IsArithmetic : StaticBool<IsInteger<T>::value || IsFloat<T>::value> {};
//####################################################################
-#define ZEN_INIT_DETECT_MEMBER(NAME) \
+#define ZEN_INIT_DETECT_MEMBER(NAME) \
\
- template<bool isClass, class T> \
- struct HasMemberImpl_##NAME \
- { \
+ template<bool isClass, class T> \
+ struct HasMemberImpl_##NAME \
+ { \
private: \
- typedef char Yes[1]; \
- typedef char No [2]; \
+ typedef char Yes[1]; \
+ typedef char No [2]; \
\
template <typename U, U t> \
- class Helper {}; \
- struct Fallback { int NAME; }; \
+ class Helper {}; \
+ struct Fallback { int NAME; }; \
\
- template <class U> \
- struct Helper2 : public U, public Fallback {}; /*this works only for class types!!!*/ \
+ template <class U> \
+ struct Helper2 : public U, public Fallback {}; /*this works only for class types!!!*/ \
\
- template <class U> static No& hasMember(Helper<int Fallback::*, &Helper2<U>::NAME>*); \
- template <class U> static Yes& hasMember(...); \
- public: \
- enum { value = sizeof(hasMember<T>(nullptr)) == sizeof(Yes) }; \
+ template <class U> static No& hasMember(Helper<int Fallback::*, &Helper2<U>::NAME>*); \
+ template <class U> static Yes& hasMember(...); \
+ public: \
+ enum { value = sizeof(hasMember<T>(nullptr)) == sizeof(Yes) }; \
}; \
\
- template<class T> \
+ template<class T> \
struct HasMemberImpl_##NAME<false, T> : FalseType {}; \
\
template<typename T> \
@@ -160,37 +160,37 @@ struct IsArithmetic : StaticBool<IsInteger<T>::value || IsFloat<T>::value> {};
//####################################################################
-#define ZEN_INIT_DETECT_MEMBER2(NAME, TYPE) \
+#define ZEN_INIT_DETECT_MEMBER2(NAME, TYPE) \
\
- template<typename U> \
- class HasMember_##NAME \
- { \
- typedef char Yes[1]; \
- typedef char No [2]; \
+ template<typename U> \
+ class HasMember_##NAME \
+ { \
+ typedef char Yes[1]; \
+ typedef char No [2]; \
\
template <typename T, T t> class Helper {}; \
\
- template <class T> static Yes& hasMember(Helper<TYPE, &T::NAME>*); \
- template <class T> static No& hasMember(...); \
- public: \
+ template <class T> static Yes& hasMember(Helper<TYPE, &T::NAME>*); \
+ template <class T> static No& hasMember(...); \
+ public: \
enum { value = sizeof(hasMember<U>(nullptr)) == sizeof(Yes) }; \
};
//####################################################################
-#define ZEN_INIT_DETECT_MEMBER_TYPE(TYPENAME) \
+#define ZEN_INIT_DETECT_MEMBER_TYPE(TYPENAME) \
\
- template<typename T> \
- class HasMemberType_##TYPENAME \
- { \
- typedef char Yes[1]; \
- typedef char No [2]; \
+ template<typename T> \
+ class HasMemberType_##TYPENAME \
+ { \
+ typedef char Yes[1]; \
+ typedef char No [2]; \
\
- template <typename U> class Helper {}; \
+ template <typename U> class Helper {}; \
\
template <class U> static Yes& hasMemberType(Helper<typename U::TYPENAME>*); \
- template <class U> static No& hasMemberType(...); \
- public: \
- enum { value = sizeof(hasMemberType<T>(nullptr)) == sizeof(Yes) }; \
+ template <class U> static No& hasMemberType(...); \
+ public: \
+ enum { value = sizeof(hasMemberType<T>(nullptr)) == sizeof(Yes) }; \
};
}
diff --git a/zen/warn_static.h b/zen/warn_static.h
index 1e942031..3f268ec3 100644
--- a/zen/warn_static.h
+++ b/zen/warn_static.h
@@ -19,7 +19,7 @@ Usage:
#define STATIC_WARNING_MAKE_STRINGIZE(NUM) STATIC_WARNING_MAKE_STRINGIZE_SUB(NUM)
#define warn_static(TXT) \
- __pragma(message (__FILE__ "(" STATIC_WARNING_MAKE_STRINGIZE(__LINE__) "): Warning: " ## TXT))
+ __pragma(message(__FILE__ "(" STATIC_WARNING_MAKE_STRINGIZE(__LINE__) "): Warning: " ## TXT))
#elif defined __GNUC__
#define STATIC_WARNING_CONCAT_SUB(X, Y) X ## Y
diff --git a/zen/zstring.cpp b/zen/zstring.cpp
index e2a756e6..3b29e664 100644
--- a/zen/zstring.cpp
+++ b/zen/zstring.cpp
@@ -21,8 +21,8 @@ using namespace zen;
/*
Perf test: compare strings 10 mio times; 64 bit build
-----------------------------------------------------
- string a = "Fjk84$%kgfj$%T\\\\Gffg\\gsdgf\\fgsx----------d-"
- string b = "fjK84$%kgfj$%T\\\\gfFg\\gsdgf\\fgSy----------dfdf"
+ string a = "Fjk84$%kgfj$%T\\\\Gffg\\gsdgf\\fgsx----------d-"
+ string b = "fjK84$%kgfj$%T\\\\gfFg\\gsdgf\\fgSy----------dfdf"
Windows (UTF16 wchar_t)
4 ns | wcscmp
@@ -125,8 +125,7 @@ Zstring makeUpperCopy(const Zstring& str)
if (len == 0) //LCMapString does not allow input sizes of 0!
return str;
- Zstring output;
- output.resize(len);
+ Zstring output = str;
//LOCALE_INVARIANT is NOT available with Windows 2000 -> ok
bgstack15