summaryrefslogtreecommitdiff
path: root/zen
diff options
context:
space:
mode:
Diffstat (limited to 'zen')
-rw-r--r--zen/dir_watcher.cpp16
-rw-r--r--zen/dll.h121
-rw-r--r--zen/dst_hack.cpp16
-rw-r--r--zen/file_error.h9
-rw-r--r--zen/file_handling.cpp115
-rw-r--r--zen/file_io.cpp14
-rw-r--r--zen/file_traverser.cpp26
-rw-r--r--zen/long_path_prefix.h46
-rw-r--r--zen/notify_removal.cpp17
-rw-r--r--zen/osx_string.h82
-rw-r--r--zen/osx_throw_exception.h56
-rw-r--r--zen/privilege.cpp138
-rw-r--r--zen/privilege.h18
-rw-r--r--zen/process_priority.cpp6
-rw-r--r--zen/recycler.cpp14
-rw-r--r--zen/shell_execute.h3
-rw-r--r--zen/string_tools.h16
-rw-r--r--zen/string_traits.h6
-rw-r--r--zen/symlink_target.h33
-rw-r--r--zen/sys_error.h8
-rw-r--r--zen/thread.h16
21 files changed, 196 insertions, 580 deletions
diff --git a/zen/dir_watcher.cpp b/zen/dir_watcher.cpp
index 8ba9eb19..258a1c35 100644
--- a/zen/dir_watcher.cpp
+++ b/zen/dir_watcher.cpp
@@ -156,7 +156,7 @@ public:
FILE_FLAG_OVERLAPPED, //_In_ DWORD dwFlagsAndAttributes,
nullptr); //_In_opt_ HANDLE hTemplateFile
if (hDir == INVALID_HANDLE_VALUE)
- throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(directory)), formatSystemError(L"CreateFile", getLastError()));
+ throwFileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(directory)), L"CreateFile", getLastError());
//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 lastError = ::GetLastError(); //copy before making other system calls!
+ const DWORD lastError = ::GetLastError(); //copy before directly or indirectly making other system calls!
return shared_->reportError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(dirnamePf)), formatSystemError(L"CreateEvent", lastError), lastError);
}
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 lastError = ::GetLastError(); //copy before making other system calls!
+ const DWORD lastError = ::GetLastError(); //copy before directly or indirectly making other system calls!
return shared_->reportError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(dirnamePf)), formatSystemError(L"ReadDirectoryChangesW", lastError), lastError);
}
@@ -236,7 +236,7 @@ public:
&bytesWritten, //__out LPDWORD lpNumberOfBytesTransferred,
false)) //__in BOOL bWait
{
- const DWORD lastError = ::GetLastError(); //copy before making other system calls!
+ const DWORD lastError = ::GetLastError(); //copy before directly or indirectly making other system calls!
if (lastError != ERROR_IO_INCOMPLETE)
return shared_->reportError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(dirnamePf)), formatSystemError(L"GetOverlappedResult", lastError), lastError);
@@ -420,7 +420,7 @@ DirWatcher::DirWatcher(const Zstring& directory) : //throw FileError
pimpl_->baseDirname = directory;
pimpl_->notifDescr = ::inotify_init();
if (pimpl_->notifDescr == -1)
- throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(directory)), formatSystemError(L"inotify_init", getLastError()));
+ throwFileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(directory)), L"inotify_init", getLastError());
zen::ScopeGuard guardDescr = zen::makeGuard([&] { ::close(pimpl_->notifDescr); });
@@ -432,7 +432,7 @@ DirWatcher::DirWatcher(const Zstring& directory) : //throw FileError
initSuccess = ::fcntl(pimpl_->notifDescr, F_SETFL, flags | O_NONBLOCK) != -1;
}
if (!initSuccess)
- throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(directory)), formatSystemError(L"fcntl", getLastError()));
+ throwFileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(directory)), L"fcntl", getLastError());
//add watches
for (const Zstring& subdir : fullDirList)
@@ -449,7 +449,7 @@ DirWatcher::DirWatcher(const Zstring& directory) : //throw FileError
IN_MOVED_TO |
IN_MOVE_SELF);
if (wd == -1)
- throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(subdir)), formatSystemError(L"inotify_add_watch", getLastError()));
+ throwFileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(subdir)), L"inotify_add_watch", getLastError());
pimpl_->watchDescrs.insert(std::make_pair(wd, appendSeparator(subdir)));
}
@@ -481,7 +481,7 @@ std::vector<DirWatcher::Entry> DirWatcher::getChanges(const std::function<void()
if (errno == EAGAIN) //this error is ignored in all inotify wrappers I found
return std::vector<Entry>();
- throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(pimpl_->baseDirname)), formatSystemError(L"read", getLastError()));
+ throwFileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(pimpl_->baseDirname)), L"read", getLastError());
}
std::vector<Entry> output;
diff --git a/zen/dll.h b/zen/dll.h
deleted file mode 100644
index e1f3f0ad..00000000
--- a/zen/dll.h
+++ /dev/null
@@ -1,121 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
-// **************************************************************************
-
-#ifndef DLLLOADER_H_INCLUDED
-#define DLLLOADER_H_INCLUDED
-
-#include <memory>
-#ifdef ZEN_WIN
-#include <string>
-#include "scope_guard.h"
-#include "win.h" //includes "windows.h"
-
-#elif defined ZEN_LINUX || defined ZEN_MAC
-#include <dlfcn.h>
-#endif
-
-namespace zen
-{
-/*
-Manage DLL function and library ownership
- - thread safety: like built-in type
- - full value semantics
-
- Usage:
- typedef BOOL (WINAPI* FunType_IsWow64Process)(HANDLE hProcess, PBOOL Wow64Process);
- const zen::SysDllFun<FunType_IsWow64Process> isWow64Process(L"kernel32.dll", "IsWow64Process");
- if (isWow64Process) ... use function ptr ...
-
- Usage 2:
- #define DEF_DLL_FUN(name) DllFun<dll_ns::FunType_##name> name(dll_ns::getDllName(), dll_ns::funName_##name);
- DEF_DLL_FUN(funname1); DEF_DLL_FUN(funname2); DEF_DLL_FUN(funname3);
-*/
-
-template <class Func>
-class DllFun
-{
-public:
- DllFun() : fun(nullptr) {}
-
-#ifdef ZEN_WIN
- DllFun(const wchar_t* libraryName, const char* functionName) :
- hLibRef(::LoadLibrary(libraryName), ::FreeLibrary),
- fun(hLibRef ? reinterpret_cast<Func>(::GetProcAddress(static_cast<HMODULE>(hLibRef.get()), functionName)) : nullptr) {}
-#elif defined ZEN_LINUX || defined ZEN_MAC
- DllFun(const char* libraryName, const char* functionName) :
- hLibRef(::dlopen(libraryName, RTLD_LAZY), ::dlclose),
- fun(hLibRef ? reinterpret_cast<Func>(::dlsym(hLibRef.get(), functionName)) : nullptr) {}
-#endif
- operator Func() const { return fun; }
-
-private:
- std::shared_ptr<void> hLibRef; //we would prefer decltype(*HMODULE()) if only it would work...
- Func fun;
-};
-
-
-#ifdef ZEN_WIN
-//if the dll is already part of the process space, e.g. "kernel32.dll" or "shell32.dll", we can use a faster variant:
-//NOTE: since the lifetime of the referenced library is *not* controlled, this is safe to use only for permanently loaded libraries like these!
-template <class Func>
-class SysDllFun
-{
-public:
- SysDllFun() : fun(nullptr) {}
-
- SysDllFun(const wchar_t* systemLibrary, const char* functionName)
- {
- HMODULE mod = ::GetModuleHandle(systemLibrary);
- fun = mod ? reinterpret_cast<Func>(::GetProcAddress(mod, functionName)) : nullptr;
- }
-
- operator Func() const { return fun; }
-
-private:
- Func fun;
-};
-
-/*
-extract binary resources from .exe/.dll:
-
--- resource.h --
-#define MY_BINARY_RESOURCE 1337
-
--- resource.rc --
-MY_BINARY_RESOURCE RCDATA "filename.dat"
-*/
-std::string getResourceStream(const std::wstring& libraryName, size_t resourceId);
-#endif
-
-
-
-
-
-
-
-
-
-
-//--------------- implementation---------------------------------------------------
-#ifdef ZEN_WIN
-inline
-std::string getResourceStream(const wchar_t* libraryName, size_t resourceId)
-{
- if (HMODULE module = ::LoadLibrary(libraryName))
- {
- ZEN_ON_SCOPE_EXIT(::FreeLibrary(module));
-
- if (HRSRC res = ::FindResource(module, MAKEINTRESOURCE(resourceId), RT_RCDATA))
- if (HGLOBAL resHandle = ::LoadResource(module, res))
- if (const char* stream = static_cast<const char*>(::LockResource(resHandle)))
- return std::string(stream, static_cast<size_t>(::SizeofResource(module, res))); //size is 0 on error
- }
- return std::string();
-}
-#endif
-}
-
-#endif // DLLLOADER_H_INCLUDED
diff --git a/zen/dst_hack.cpp b/zen/dst_hack.cpp
index 887b9b63..95fbe732 100644
--- a/zen/dst_hack.cpp
+++ b/zen/dst_hack.cpp
@@ -166,10 +166,10 @@ FILETIME utcToLocal(const FILETIME& utcTime) //throw std::runtime_error
&utcTime, //__in const FILETIME *lpFileTime,
&localTime)) //__out LPFILETIME lpLocalFileTime
{
- const std::wstring errorMsg = _("Conversion error:") + L" FILETIME -> local FILETIME: " + L"(" +
- L"High: " + numberTo<std::wstring>(utcTime.dwHighDateTime) + L" " +
- L"Low: " + numberTo<std::wstring>(utcTime.dwLowDateTime) + L") " + L"\n\n" + formatSystemError(L"FileTimeToLocalFileTime", getLastError());
- throw std::runtime_error(utfCvrtTo<std::string>(errorMsg));
+ const DWORD lastError = ::GetLastError(); //copy before directly or indirectly making other system calls!
+ throw std::runtime_error(utfCvrtTo<std::string>(_("Conversion error:") + L" FILETIME -> local FILETIME: " + L"(" +
+ L"High: " + numberTo<std::wstring>(utcTime.dwHighDateTime) + L" " +
+ L"Low: " + numberTo<std::wstring>(utcTime.dwLowDateTime) + L") " + L"\n\n" + formatSystemError(L"FileTimeToLocalFileTime", lastError)));
}
return localTime;
}
@@ -184,10 +184,10 @@ FILETIME localToUtc(const FILETIME& localTime) //throw std::runtime_error
&localTime, //__in const FILETIME *lpLocalFileTime,
&utcTime)) //__out LPFILETIME lpFileTime
{
- const std::wstring errorMsg = _("Conversion error:") + L" local FILETIME -> FILETIME: " + L"(" +
- L"High: " + numberTo<std::wstring>(localTime.dwHighDateTime) + L" " +
- L"Low: " + numberTo<std::wstring>(localTime.dwLowDateTime) + L") " + L"\n\n" + formatSystemError(L"LocalFileTimeToFileTime", getLastError());
- throw std::runtime_error(utfCvrtTo<std::string>(errorMsg));
+ const DWORD lastError = ::GetLastError(); //copy before directly or indirectly making other system calls!
+ throw std::runtime_error(utfCvrtTo<std::string>(_("Conversion error:") + L" local FILETIME -> FILETIME: " + L"(" +
+ L"High: " + numberTo<std::wstring>(localTime.dwHighDateTime) + L" " +
+ L"Low: " + numberTo<std::wstring>(localTime.dwLowDateTime) + L") " + L"\n\n" + formatSystemError(L"LocalFileTimeToFileTime", lastError)));
}
return utcTime;
}
diff --git a/zen/file_error.h b/zen/file_error.h
index 5d655239..cb5e3a7b 100644
--- a/zen/file_error.h
+++ b/zen/file_error.h
@@ -36,6 +36,15 @@ 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!!!)
+inline
+void throwFileError(const std::wstring& msg, const std::wstring& functionName, const ErrorCode ec) //throw FileError
+{
+ throw FileError(msg, formatSystemError(functionName, ec));
+}
+
+
//----------- facilitate usage of std::wstring for error messages --------------------
//allow implicit UTF8 conversion: since std::wstring models a GUI string, convenience is more important than performance
diff --git a/zen/file_handling.cpp b/zen/file_handling.cpp
index 87ffee62..0b544ed5 100644
--- a/zen/file_handling.cpp
+++ b/zen/file_handling.cpp
@@ -106,7 +106,7 @@ bool zen::somethingExists(const Zstring& objname)
const DWORD attr = ::GetFileAttributes(applyLongPathPrefix(objname).c_str());
if (attr != INVALID_FILE_ATTRIBUTES)
return true;
- const ErrorCode lastError = getLastError();
+ const DWORD lastError = ::GetLastError();
//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"
@@ -165,7 +165,7 @@ UInt64 zen::getFilesize(const Zstring& filename) //throw FileError
{
const HANDLE searchHandle = ::FindFirstFile(applyLongPathPrefix(filename).c_str(), &fileInfo);
if (searchHandle == INVALID_HANDLE_VALUE)
- throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)), formatSystemError(L"FindFirstFile", getLastError()));
+ throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)), L"FindFirstFile", getLastError());
::FindClose(searchHandle);
}
// WIN32_FILE_ATTRIBUTE_DATA sourceAttr = {};
@@ -186,12 +186,12 @@ UInt64 zen::getFilesize(const Zstring& filename) //throw FileError
FILE_FLAG_BACKUP_SEMANTICS, /*needed to open a directory*/ //_In_ DWORD dwFlagsAndAttributes,
nullptr); //_In_opt_ HANDLE hTemplateFile
if (hFile == INVALID_HANDLE_VALUE)
- throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)), formatSystemError(L"CreateFile", getLastError()));
+ throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)), L"CreateFile", getLastError());
ZEN_ON_SCOPE_EXIT(::CloseHandle(hFile));
BY_HANDLE_FILE_INFORMATION fileInfoHnd = {};
if (!::GetFileInformationByHandle(hFile, &fileInfoHnd))
- throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)), formatSystemError(L"GetFileInformationByHandle", getLastError()));
+ throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)), L"GetFileInformationByHandle", getLastError());
return UInt64(fileInfoHnd.nFileSizeLow, fileInfoHnd.nFileSizeHigh);
}
@@ -199,7 +199,7 @@ UInt64 zen::getFilesize(const Zstring& filename) //throw FileError
#elif defined ZEN_LINUX || defined ZEN_MAC
struct ::stat fileInfo = {};
if (::stat(filename.c_str(), &fileInfo) != 0)
- throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)), formatSystemError(L"stat", getLastError()));
+ throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)), L"stat", getLastError());
return UInt64(fileInfo.st_size);
#endif
@@ -214,14 +214,14 @@ UInt64 zen::getFreeDiskSpace(const Zstring& path) //throw FileError
&bytesFree, //__out_opt PULARGE_INTEGER lpFreeBytesAvailable,
nullptr, //__out_opt PULARGE_INTEGER lpTotalNumberOfBytes,
nullptr)) //__out_opt PULARGE_INTEGER lpTotalNumberOfFreeBytes
- throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(path)), formatSystemError(L"GetDiskFreeSpaceEx", getLastError()));
+ throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(path)), L"GetDiskFreeSpaceEx", getLastError());
return UInt64(bytesFree.LowPart, bytesFree.HighPart);
#elif defined ZEN_LINUX || defined ZEN_MAC
struct statfs info = {};
if (::statfs(path.c_str(), &info) != 0)
- throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(path)), formatSystemError(L"statfs", getLastError()));
+ throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(path)), L"statfs", getLastError());
return UInt64(info.f_bsize) * info.f_bavail;
#endif
@@ -292,7 +292,7 @@ void renameFile_sub(const Zstring& oldName, const Zstring& newName) //throw File
newNameFmt.c_str(), //__in_opt LPCTSTR lpNewFileName,
0)) //__in DWORD dwFlags
{
- DWORD lastError = ::GetLastError();
+ DWORD lastError = ::GetLastError(); //copy before directly or 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
{
@@ -323,7 +323,8 @@ void renameFile_sub(const Zstring& oldName, const Zstring& newName) //throw File
const std::wstring errorMsg = replaceCpy(replaceCpy(_("Cannot move file %x to %y."), L"%x", L"\n" + fmtFileName(oldName)), L"%y", L"\n" + fmtFileName(newName));
std::wstring errorDescr = formatSystemError(L"MoveFileEx", lastError);
- if (lastError == ERROR_SHARING_VIOLATION || //-> enhance error message!
+ //try to enhance error message:
+ if (lastError == ERROR_SHARING_VIOLATION ||
lastError == ERROR_LOCK_VIOLATION)
{
const Zstring procList = getLockingProcessNames(oldName); //throw()
@@ -343,7 +344,7 @@ void renameFile_sub(const Zstring& oldName, const Zstring& newName) //throw File
#elif defined ZEN_LINUX || defined ZEN_MAC
if (::rename(oldName.c_str(), newName.c_str()) != 0)
{
- const int lastError = errno; //copy before making other system calls!
+ const int lastError = errno; //copy before directly or indirectly making other system calls!
const std::wstring errorMsg = replaceCpy(replaceCpy(_("Cannot move file %x to %y."), L"%x", L"\n" + fmtFileName(oldName)), L"%y", L"\n" + fmtFileName(newName));
const std::wstring errorDescr = formatSystemError(L"rename", lastError);
@@ -549,7 +550,7 @@ void removeDirectoryImpl(const Zstring& directory, //throw FileError
const wchar_t functionName[] = L"unlink";
if (::unlink(directory.c_str()) != 0)
#endif
- throw FileError(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtFileName(directory)), formatSystemError(functionName, getLastError()));
+ throwFileError(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtFileName(directory)), functionName, getLastError());
}
else
{
@@ -583,7 +584,7 @@ void removeDirectoryImpl(const Zstring& directory, //throw FileError
const wchar_t functionName[] = L"rmdir";
if (::rmdir(directory.c_str()) != 0)
#endif
- throw FileError(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtFileName(directory)), formatSystemError(functionName, getLastError()));
+ throwFileError(replaceCpy(_("Cannot delete directory %x."), L"%x", fmtFileName(directory)), functionName, getLastError());
//may spuriously fail with ERROR_DIR_NOT_EMPTY(145) even though all child items have
//successfully been *marked* for deletion, but some application still has a handle open!
//e.g. Open "C:\Test\Dir1\Dir2" (filled with lots of files) in Explorer, then delete "C:\Test\Dir1" via ::RemoveDirectory() => Error 145
@@ -631,12 +632,12 @@ void setFileTimeRaw(const Zstring& filename, const FILETIME& creationTime, const
{
const DWORD tmpAttr = ::GetFileAttributes(applyLongPathPrefix(filename).c_str());
if (tmpAttr == INVALID_FILE_ATTRIBUTES)
- throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)), formatSystemError(L"GetFileAttributes", getLastError()));
+ throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)), L"GetFileAttributes", getLastError());
if (tmpAttr & FILE_ATTRIBUTE_READONLY)
{
if (!::SetFileAttributes(applyLongPathPrefix(filename).c_str(), FILE_ATTRIBUTE_NORMAL))
- throw FileError(replaceCpy(_("Cannot write file attributes of %x."), L"%x", fmtFileName(filename)), formatSystemError(L"SetFileAttributes", getLastError()));
+ throwFileError(replaceCpy(_("Cannot write file attributes of %x."), L"%x", fmtFileName(filename)), L"SetFileAttributes", getLastError());
attribs = tmpAttr; //reapplied on scope exit
return true;
@@ -680,13 +681,13 @@ void setFileTimeRaw(const Zstring& filename, const FILETIME& creationTime, const
hFile = openFile(false);
if (hFile == INVALID_HANDLE_VALUE)
{
- const ErrorCode lastError = getLastError(); //copy before making other system calls!
+ const DWORD lastError = ::GetLastError(); //copy before directly or indirectly making other system calls!
if (lastError == ERROR_ACCESS_DENIED)
if (removeReadonly()) //throw FileError
continue;
//3. after these herculean stunts we give up...
- throw FileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filename)), formatSystemError(L"CreateFile", lastError));
+ throwFileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filename)), L"CreateFile", lastError);
}
}
break;
@@ -701,7 +702,7 @@ void setFileTimeRaw(const Zstring& filename, const FILETIME& creationTime, const
nullptr, //__in_opt const FILETIME *lpLastAccessTime,
&lastWriteTime)) //__in_opt const FILETIME *lpLastWriteTime
{
- ErrorCode lastError = getLastError(); //copy before making other system calls!
+ ErrorCode lastError = getLastError(); //copy before directly or 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)
@@ -718,7 +719,7 @@ void setFileTimeRaw(const Zstring& filename, const FILETIME& creationTime, const
FileBasicInfo, //__in FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
&basicInfo, //__in LPVOID lpFileInformation,
sizeof(basicInfo))) //__in DWORD dwBufferSize
- throw FileError(replaceCpy(_("Cannot write file attributes of %x."), L"%x", fmtFileName(filename)), formatSystemError(L"SetFileInformationByHandle", getLastError()));
+ throwFileError(replaceCpy(_("Cannot write file attributes of %x."), L"%x", fmtFileName(filename)), L"SetFileInformationByHandle", getLastError());
};
auto toLargeInteger = [](const FILETIME& ft) -> LARGE_INTEGER
@@ -757,7 +758,6 @@ void setFileTimeRaw(const Zstring& filename, const FILETIME& creationTime, const
}
std::wstring errorMsg = replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filename));
- const std::wstring errorDescr = formatSystemError(L"SetFileTime", lastError);
//add more meaningful message: FAT accepts only a subset of the NTFS date range
if (lastError == ERROR_INVALID_PARAMETER &&
@@ -806,7 +806,7 @@ void setFileTimeRaw(const Zstring& filename, const FILETIME& creationTime, const
}
if (lastError != ERROR_SUCCESS)
- throw FileError(errorMsg, errorDescr);
+ throwFileError(errorMsg, L"SetFileTime", lastError);
}
}
#ifndef NDEBUG //verify written data: mainly required to check consistency of DST hack
@@ -873,19 +873,21 @@ void zen::setFileTime(const Zstring& filename, const Int64& modTime, ProcSymlink
// newTimes[1].tv_sec = to<time_t>(modTime); //modification time (seconds)
//
// if (::utimensat(AT_FDCWD, filename.c_str(), newTimes, procSl == SYMLINK_DIRECT ? AT_SYMLINK_NOFOLLOW : 0) != 0)
- // throw FileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filename)), formatSystemError(L"utimensat", getLastError()));
+ // throwFileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filename)), L"utimensat", getLastError());
//=> fallback to "retarded-idiot version"! -- DarkByte
+ //OS X: utime() is obsoleted by utimes()! utimensat() not yet implemented
+
struct ::timeval newTimes[2] = {};
- newTimes[0].tv_sec = ::time(nullptr); //access time (seconds)
+ newTimes[0].tv_sec = ::time(nullptr); //access time (seconds)
newTimes[1].tv_sec = to<time_t>(modTime); //modification time (seconds)
const int rv = procSl == ProcSymlink::FOLLOW ?
- :: utimes(filename.c_str(), newTimes) : //utimensat() not yet implemented on OS X
+ :: utimes(filename.c_str(), newTimes) :
::lutimes(filename.c_str(), newTimes);
if (rv != 0)
- throw FileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filename)), formatSystemError(L"utimes", getLastError()));
+ throwFileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filename)), L"utimes", getLastError());
#endif
}
@@ -898,7 +900,7 @@ bool zen::supportsPermissions(const Zstring& dirname) //throw FileError
if (!::GetVolumePathName(dirname.c_str(), //__in LPCTSTR lpszFileName,
&buffer[0], //__out LPTSTR lpszVolumePathName,
bufferSize)) //__in DWORD cchBufferLength
- throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(dirname)), formatSystemError(L"GetVolumePathName", getLastError()));
+ throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(dirname)), L"GetVolumePathName", getLastError());
DWORD fsFlags = 0;
if (!::GetVolumeInformation(&buffer[0], //__in_opt LPCTSTR lpRootPathName,
@@ -909,7 +911,7 @@ bool zen::supportsPermissions(const Zstring& dirname) //throw FileError
&fsFlags, //__out_opt LPDWORD lpFileSystemFlags,
nullptr, //__out LPTSTR lpFileSystemNameBuffer,
0)) //__in DWORD nFileSystemNameSize
- throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(dirname)), formatSystemError(L"GetVolumeInformation", getLastError()));
+ throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(dirname)), L"GetVolumeInformation", getLastError());
return (fsFlags & FILE_PERSISTENT_ACLS) != 0;
@@ -935,7 +937,7 @@ void copySecurityContext(const Zstring& source, const Zstring& target, ProcSymli
errno == EOPNOTSUPP) //extended attributes are not supported by the filesystem
return;
- throw FileError(replaceCpy(_("Cannot read security context of %x."), L"%x", fmtFileName(source)), formatSystemError(L"getfilecon", getLastError()));
+ throwFileError(replaceCpy(_("Cannot read security context of %x."), L"%x", fmtFileName(source)), L"getfilecon", getLastError());
}
ZEN_ON_SCOPE_EXIT(::freecon(contextSource));
@@ -963,7 +965,7 @@ void copySecurityContext(const Zstring& source, const Zstring& target, ProcSymli
::setfilecon(target.c_str(), contextSource) :
::lsetfilecon(target.c_str(), contextSource);
if (rv3 < 0)
- throw FileError(replaceCpy(_("Cannot write security context of %x."), L"%x", fmtFileName(target)), formatSystemError(L"setfilecon", getLastError()));
+ throwFileError(replaceCpy(_("Cannot write security context of %x."), L"%x", fmtFileName(target)), L"setfilecon", getLastError());
}
#endif //HAVE_SELINUX
@@ -1014,7 +1016,7 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, ProcSym
if (bytesNeeded > buffer.size())
buffer.resize(bytesNeeded);
else
- throw FileError(replaceCpy(_("Cannot read permissions of %x."), L"%x", fmtFileName(sourceResolved)), formatSystemError(L"GetFileSecurity", getLastError()));
+ throwFileError(replaceCpy(_("Cannot read permissions of %x."), L"%x", fmtFileName(sourceResolved)), L"GetFileSecurity", getLastError());
}
SECURITY_DESCRIPTOR& secDescr = reinterpret_cast<SECURITY_DESCRIPTOR&>(buffer[0]);
@@ -1038,7 +1040,7 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, ProcSym
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION, //__in SECURITY_INFORMATION SecurityInformation,
&secDescr)) //__in PSECURITY_DESCRIPTOR pSecurityDescriptor
- throw FileError(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtFileName(targetResolved)), formatSystemError(L"SetFileSecurity", getLastError()));
+ throwFileError(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtFileName(targetResolved)), L"SetFileSecurity", getLastError());
/*
PSECURITY_DESCRIPTOR buffer = nullptr;
@@ -1130,24 +1132,24 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, ProcSym
if (procSl == ProcSymlink::FOLLOW)
{
if (::stat(source.c_str(), &fileInfo) != 0)
- throw FileError(replaceCpy(_("Cannot read permissions of %x."), L"%x", fmtFileName(source)), formatSystemError(L"stat", getLastError()));
+ throwFileError(replaceCpy(_("Cannot read permissions of %x."), L"%x", fmtFileName(source)), L"stat", getLastError());
if (::chown(target.c_str(), fileInfo.st_uid, fileInfo.st_gid) != 0) // may require admin rights!
- throw FileError(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtFileName(target)), formatSystemError(L"chown", getLastError()));
+ throwFileError(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtFileName(target)), L"chown", getLastError());
if (::chmod(target.c_str(), fileInfo.st_mode) != 0)
- throw FileError(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtFileName(target)), formatSystemError(L"chmod", getLastError()));
+ throwFileError(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtFileName(target)), L"chmod", getLastError());
}
else
{
if (::lstat(source.c_str(), &fileInfo) != 0)
- throw FileError(replaceCpy(_("Cannot read permissions of %x."), L"%x", fmtFileName(source)), formatSystemError(L"lstat", getLastError()));
+ throwFileError(replaceCpy(_("Cannot read permissions of %x."), L"%x", fmtFileName(source)), L"lstat", getLastError());
if (::lchown(target.c_str(), fileInfo.st_uid, fileInfo.st_gid) != 0) // may require admin rights!
- throw FileError(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtFileName(target)), formatSystemError(L"lchown", getLastError()));
+ throwFileError(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtFileName(target)), L"lchown", getLastError());
if (!symlinkExists(target) && ::chmod(target.c_str(), fileInfo.st_mode) != 0) //setting access permissions doesn't make sense for symlinks on Linux: there is no lchmod()
- throw FileError(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtFileName(target)), formatSystemError(L"chmod", getLastError()));
+ throwFileError(replaceCpy(_("Cannot write permissions of %x."), L"%x", fmtFileName(target)), L"chmod", getLastError());
}
#endif
}
@@ -1251,7 +1253,7 @@ void zen::makeDirectoryPlain(const Zstring& directory, //throw FileError, ErrorT
if (!::CreateDirectory(applyLongPathPrefixCreateDir(directory).c_str(), //__in LPCTSTR lpPathName,
nullptr)) //__in_opt LPSECURITY_ATTRIBUTES lpSecurityAttributes
{
- ErrorCode lastError = getLastError();
+ DWORD lastError = ::GetLastError(); //copy before directly or indirectly making other system calls!
//handle issues with already existing short 8.3 file names on Windows
if (lastError == ERROR_ALREADY_EXISTS)
@@ -1263,7 +1265,7 @@ void zen::makeDirectoryPlain(const Zstring& directory, //throw FileError, ErrorT
if (::CreateDirectory(applyLongPathPrefixCreateDir(directory).c_str(), nullptr))
lastError = ERROR_SUCCESS;
else
- lastError = getLastError();
+ lastError = ::GetLastError();
}
if (lastError != ERROR_SUCCESS)
@@ -1282,7 +1284,7 @@ void zen::makeDirectoryPlain(const Zstring& directory, //throw FileError, ErrorT
#elif defined ZEN_LINUX || defined ZEN_MAC
if (::mkdir(directory.c_str(), 0755) != 0) //mode: drwxr-xr-x
{
- const ErrorCode lastError = getLastError();
+ const int lastError = errno; //copy before directly or indirectly making other system calls!
const std::wstring errorMsg = replaceCpy(_("Cannot create directory %x."), L"%x", fmtFileName(directory));
const std::wstring errorDescr = formatSystemError(L"mkdir", lastError);
@@ -1397,7 +1399,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
- throw FileError(replaceCpy(_("Cannot create symbolic link %x."), L"%x", fmtFileName(targetLink)), formatSystemError(functionName, getLastError()));
+ throwFileError(replaceCpy(_("Cannot create symbolic link %x."), L"%x", fmtFileName(targetLink)), functionName, getLastError());
//allow only consistent objects to be created -> don't place before ::symlink, targetLink may already exist
zen::ScopeGuard guardNewLink = zen::makeGuard([&]
@@ -1420,14 +1422,14 @@ 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
- throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(sourceLink)), formatSystemError(L"GetFileAttributesEx", getLastError()));
+ throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(sourceLink)), L"GetFileAttributesEx", getLastError());
setFileTimeRaw(targetLink, sourceAttr.ftCreationTime, sourceAttr.ftLastWriteTime, ProcSymlink::DIRECT); //throw FileError
#elif defined ZEN_LINUX || defined ZEN_MAC
struct ::stat srcInfo = {};
if (::lstat(sourceLink.c_str(), &srcInfo) != 0)
- throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(sourceLink)), formatSystemError(L"lstat", getLastError()));
+ throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(sourceLink)), L"lstat", getLastError());
setFileTime(targetLink, Int64(srcInfo.st_mtime), ProcSymlink::DIRECT); //throw FileError
#endif
@@ -1567,7 +1569,7 @@ void copyFileWindowsSparse(const Zstring& sourceFile,
nullptr); //_In_opt_ HANDLE hTemplateFile
if (hFileSource == INVALID_HANDLE_VALUE)
{
- const DWORD lastError = ::GetLastError();
+ const DWORD lastError = ::GetLastError(); //copy before directly or indirectly making other system calls!
const std::wstring errorMsg = replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(sourceFile));
std::wstring errorDescr = formatSystemError(L"CreateFile", lastError);
@@ -1589,7 +1591,7 @@ void copyFileWindowsSparse(const Zstring& sourceFile,
//----------------------------------------------------------------------
BY_HANDLE_FILE_INFORMATION fileInfoSource = {};
if (!::GetFileInformationByHandle(hFileSource, &fileInfoSource))
- throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(sourceFile)), formatSystemError(L"GetFileInformationByHandle", getLastError()));
+ throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(sourceFile)), L"GetFileInformationByHandle", getLastError());
//----------------------------------------------------------------------
const DWORD validAttribs = FILE_ATTRIBUTE_NORMAL | //"This attribute is valid only if used alone."
@@ -1615,7 +1617,7 @@ void copyFileWindowsSparse(const Zstring& sourceFile,
nullptr); //_In_opt_ HANDLE hTemplateFile
if (hFileTarget == INVALID_HANDLE_VALUE)
{
- const ErrorCode lastError = getLastError(); //copy before making other system calls!
+ const DWORD lastError = ::GetLastError(); //copy before directly or indirectly making other system calls!
const std::wstring errorMsg = replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(targetFile));
const std::wstring errorDescr = formatSystemError(L"CreateFile", lastError);
@@ -1634,7 +1636,7 @@ void copyFileWindowsSparse(const Zstring& sourceFile,
//----------------------------------------------------------------------
BY_HANDLE_FILE_INFORMATION fileInfoTarget = {};
if (!::GetFileInformationByHandle(hFileTarget, &fileInfoTarget))
- throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(targetFile)), formatSystemError(L"GetFileInformationByHandle", getLastError()));
+ throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(targetFile)), L"GetFileInformationByHandle", getLastError());
//return up-to-date file attributes
if (newAttrib)
@@ -1683,8 +1685,7 @@ void copyFileWindowsSparse(const Zstring& sourceFile,
0, //OutBufferSize
&bytesReturned, //number of bytes returned
nullptr)) //OVERLAPPED structure
- throw FileError(replaceCpy(_("Cannot write file attributes of %x."), L"%x", fmtFileName(targetFile)),
- formatSystemError(L"DeviceIoControl, FSCTL_SET_SPARSE", getLastError()));
+ throwFileError(replaceCpy(_("Cannot write file attributes of %x."), L"%x", fmtFileName(targetFile)), L"DeviceIoControl, FSCTL_SET_SPARSE", getLastError());
}
//----------------------------------------------------------------------
@@ -1711,7 +1712,7 @@ void copyFileWindowsSparse(const Zstring& sourceFile,
false, //__in BOOL bAbort,
false, //__in BOOL bProcessSecurity,
&contextRead)) //__out LPVOID *lpContext
- throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(sourceFile)), formatSystemError(L"BackupRead", getLastError())); //better use fine-granular error messages "reading/writing"!
+ throwFileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(sourceFile)), L"BackupRead", getLastError()); //better use fine-granular error messages "reading/writing"!
if (bytesRead > BUFFER_SIZE)
throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(sourceFile)), L"buffer overflow"); //user should never see this
@@ -1727,7 +1728,7 @@ void copyFileWindowsSparse(const Zstring& sourceFile,
false, //__in BOOL bAbort,
false, //__in BOOL bProcessSecurity,
&contextWrite)) //__out LPVOID *lpContext
- throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(targetFile)), formatSystemError(L"BackupWrite", getLastError()));
+ throwFileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(targetFile)), L"BackupWrite", getLastError());
if (bytesWritten != bytesRead)
throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(targetFile)), L"incomplete write"); //user should never see this
@@ -1755,7 +1756,7 @@ void copyFileWindowsSparse(const Zstring& sourceFile,
&fileInfoSource.ftCreationTime,
nullptr,
&fileInfoSource.ftLastWriteTime))
- throw FileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(targetFile)), formatSystemError(L"SetFileTime", getLastError()));
+ throwFileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(targetFile)), L"SetFileTime", getLastError());
guardTarget.dismiss();
@@ -1891,13 +1892,15 @@ DWORD CALLBACK copyCallbackInternal(LARGE_INTEGER totalFileSize,
//#################### return source file attributes ################################
if (!::GetFileInformationByHandle(hSourceFile, &cbd.fileInfoSrc))
{
- cbd.errorHandler.reportError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(cbd.sourceFile_)), formatSystemError(L"GetFileInformationByHandle", getLastError()));
+ const DWORD lastError = ::GetLastError(); //copy before directly or indirectly making other system calls!
+ cbd.errorHandler.reportError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(cbd.sourceFile_)), formatSystemError(L"GetFileInformationByHandle", lastError));
return PROGRESS_CANCEL;
}
if (!::GetFileInformationByHandle(hDestinationFile, &cbd.fileInfoTrg))
{
- cbd.errorHandler.reportError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(cbd.targetFile_)), formatSystemError(L"GetFileInformationByHandle", getLastError()));
+ const DWORD lastError = ::GetLastError(); //copy before directly or indirectly making other system calls!
+ cbd.errorHandler.reportError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(cbd.targetFile_)), formatSystemError(L"GetFileInformationByHandle", lastError));
return PROGRESS_CANCEL;
}
@@ -1995,7 +1998,7 @@ void copyFileWindowsDefault(const Zstring& sourceFile,
cbd.errorHandler.evaluateErrors(); //throw ?, process errors in callback first!
if (!success)
{
- const DWORD lastError = ::GetLastError();
+ const DWORD lastError = ::GetLastError(); //copy before directly or indirectly making other system calls!
//don't suppress "lastError == ERROR_REQUEST_ABORTED": a user aborted operation IS an error condition!
@@ -2144,7 +2147,7 @@ void copyFileLinuxMac(const Zstring& sourceFile,
struct ::stat sourceInfo = {};
if (::fstat(fileIn.getDescriptor(), &sourceInfo) != 0) //read file attributes from source
- throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(sourceFile)), formatSystemError(L"fstat", getLastError()));
+ throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(sourceFile)), L"fstat", getLastError());
zen::ScopeGuard guardTarget = zen::makeGuard([&] { try { removeFile(targetFile); } catch (FileError&) {} }); //transactional behavior: place guard before lifetime of FileOutput
try
@@ -2171,7 +2174,7 @@ void copyFileLinuxMac(const Zstring& sourceFile,
//read and return file statistics
struct ::stat targetInfo = {};
if (::fstat(fileOut.getDescriptor(), &targetInfo) != 0)
- throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(targetFile)), formatSystemError(L"fstat", getLastError()));
+ throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(targetFile)), L"fstat", getLastError());
if (newAttrib)
{
diff --git a/zen/file_io.cpp b/zen/file_io.cpp
index 5eab476a..82b1def5 100644
--- a/zen/file_io.cpp
+++ b/zen/file_io.cpp
@@ -162,7 +162,7 @@ size_t FileInput::read(void* buffer, size_t bytesToRead) //returns actual number
const size_t bytesRead = ::fread(buffer, 1, bytesToRead, fileHandle);
if (::ferror(fileHandle) != 0) //checks status of stream, not fread()!
#endif
- throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(getFilename())), formatSystemError(functionName, getLastError()));
+ throwFileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(getFilename())), functionName, getLastError());
#ifdef ZEN_WIN
if (bytesRead < bytesToRead) //verify only!
@@ -214,7 +214,7 @@ FileOutput::FileOutput(const Zstring& filename, AccessFlag access) : //throw Fil
fileHandle = getHandle(FILE_ATTRIBUTE_NORMAL);
if (fileHandle == INVALID_HANDLE_VALUE)
{
- DWORD lastError = ::GetLastError(); //copy before making other system calls!
+ DWORD lastError = ::GetLastError(); //copy before directly or 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 (lastError == ERROR_ACCESS_DENIED &&
@@ -260,7 +260,7 @@ FileOutput::FileOutput(const Zstring& filename, AccessFlag access) : //throw Fil
access == ACC_OVERWRITE ? "w,type=record,noseek" : "wx,type=record,noseek");
if (!fileHandle)
{
- const ErrorCode lastError = getLastError(); //copy before making other system calls!
+ const int lastError = errno; //copy before directly or indirectly making other system calls!
const std::wstring errorMsg = replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(getFilename()));
const std::wstring errorDescr = formatSystemError(L"fopen", lastError);
@@ -301,7 +301,7 @@ void FileOutput::write(const void* buffer, size_t bytesToWrite) //throw FileErro
const size_t bytesWritten = ::fwrite(buffer, 1, bytesToWrite, fileHandle);
if (::ferror(fileHandle) != 0) //checks status of stream, not fwrite()!
#endif
- throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(getFilename())), formatSystemError(functionName, getLastError()));
+ throwFileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(getFilename())), functionName, getLastError());
if (bytesWritten != bytesToWrite) //must be fulfilled for synchronous writes!
throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(getFilename())), L"Incomplete write."); //user should never see this
@@ -317,7 +317,7 @@ FileInputUnbuffered::FileInputUnbuffered(const Zstring& filename) : FileInputBas
fdFile = ::open(filename.c_str(), O_RDONLY);
if (fdFile == -1) //don't check "< 0" -> docu seems to allow "-2" to be a valid file handle
- throw FileError(replaceCpy(_("Cannot open file %x."), L"%x", fmtFileName(filename)), formatSystemError(L"open", getLastError()));
+ throwFileError(replaceCpy(_("Cannot open file %x."), L"%x", fmtFileName(filename)), L"open", getLastError());
}
@@ -337,7 +337,7 @@ size_t FileInputUnbuffered::read(void* buffer, size_t bytesToRead) //throw FileE
while (bytesRead < 0 && errno == EINTR);
if (bytesRead < 0)
- throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(getFilename())), formatSystemError(L"read", getLastError()));
+ throwFileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(getFilename())), L"read", getLastError());
else if (bytesRead == 0) //"zero indicates end of file"
setEof();
else if (bytesRead > static_cast<ssize_t>(bytesToRead)) //better safe than sorry
@@ -391,7 +391,7 @@ void FileOutputUnbuffered::write(const void* buffer, size_t bytesToWrite) //thro
if (bytesWritten == 0) //comment in safe-read.c suggests to treat this as an error due to buggy drivers
errno = ENOSPC;
- throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(getFilename())), formatSystemError(L"write", getLastError()));
+ throwFileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(getFilename())), L"write", getLastError());
}
if (bytesWritten > static_cast<ssize_t>(bytesToWrite)) //better safe than sorry
throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(getFilename())), L"buffer overflow"); //user should never see this
diff --git a/zen/file_traverser.cpp b/zen/file_traverser.cpp
index 4fe521a6..65d95f4a 100644
--- a/zen/file_traverser.cpp
+++ b/zen/file_traverser.cpp
@@ -90,12 +90,12 @@ void getInfoFromFileSymlink(const Zstring& linkName, zen::TraverseCallback::File
//needed to open a directory -> keep it even if we expect to open a file! See comment below
nullptr); //_In_opt_ HANDLE hTemplateFile
if (hFile == INVALID_HANDLE_VALUE)
- throw FileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkName)), formatSystemError(L"CreateFile", getLastError()));
+ throwFileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkName)), L"CreateFile", getLastError());
ZEN_ON_SCOPE_EXIT(::CloseHandle(hFile));
BY_HANDLE_FILE_INFORMATION fileInfo = {};
if (!::GetFileInformationByHandle(hFile, &fileInfo))
- throw FileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkName)), formatSystemError(L"GetFileInformationByHandle", getLastError()));
+ throwFileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkName)), L"GetFileInformationByHandle", getLastError());
//a file symlink may incorrectly point to a directory, but both CreateFile() and GetFileInformationByHandle() will succeed and return garbage!
//- if we did not use FILE_FLAG_BACKUP_SEMANTICS above, CreateFile() would error out with an even less helpful ERROR_ACCESS_DENIED!
@@ -195,7 +195,7 @@ struct Win32Traverser
//no noticable performance difference compared to FindFirstFileEx with FindExInfoBasic, FIND_FIRST_EX_CASE_SENSITIVE and/or FIND_FIRST_EX_LARGE_FETCH
if (hnd.searchHandle == INVALID_HANDLE_VALUE)
{
- const ErrorCode lastError = getLastError(); //copy before making other system calls!
+ const DWORD lastError = ::GetLastError(); //copy before making other system calls!
hnd.haveData = false;
if (lastError == ERROR_FILE_NOT_FOUND)
{
@@ -204,7 +204,7 @@ struct Win32Traverser
if (dirExists(dirname)) //yes, a race-condition, still the best we can do
return;
}
- throw FileError(replaceCpy(_("Cannot open directory %x."), L"%x", fmtFileName(dirname)), formatSystemError(L"FindFirstFile", lastError));
+ throwFileError(replaceCpy(_("Cannot open directory %x."), L"%x", fmtFileName(dirname)), L"FindFirstFile", lastError);
}
}
@@ -224,11 +224,11 @@ struct Win32Traverser
if (!::FindNextFile(hnd.searchHandle, &fileInfo))
{
- const ErrorCode lastError = getLastError(); //copy before making other system calls!
+ const DWORD lastError = ::GetLastError(); //copy before making other system calls!
if (lastError == ERROR_NO_MORE_FILES) //not an error situation
return false;
//else we have a problem... report it:
- throw FileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtFileName(dirname)), formatSystemError(L"FindNextFile", lastError));
+ throwFileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtFileName(dirname)), L"FindNextFile", lastError);
}
return true;
}
@@ -267,7 +267,7 @@ struct FilePlusTraverser
{
hnd.searchHandle = ::openDir(applyLongPathPrefix(dirname).c_str());
if (hnd.searchHandle == nullptr)
- throw FileError(replaceCpy(_("Cannot open directory %x."), L"%x", fmtFileName(dirname)), formatSystemError(L"openDir", getLastError()));
+ throwFileError(replaceCpy(_("Cannot open directory %x."), L"%x", fmtFileName(dirname)), L"openDir", getLastError());
}
static void destroy(DirHandle hnd) { ::closeDir(hnd.searchHandle); } //throw()
@@ -276,7 +276,7 @@ struct FilePlusTraverser
{
if (!::readDir(hnd.searchHandle, fileInfo))
{
- const DWORD lastError = ::GetLastError();
+ const DWORD lastError = ::GetLastError(); //copy before directly or indirectly making other system calls!
if (lastError == ERROR_NO_MORE_FILES) //not an error situation
return false;
@@ -289,7 +289,7 @@ struct FilePlusTraverser
//fallback should apply to whole directory sub-tree! => client needs to handle duplicate file notifications!
//else we have a problem... report it:
- throw FileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtFileName(dirname)), formatSystemError(L"readDir", lastError));
+ throwFileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtFileName(dirname)), L"readDir", lastError);
}
return true;
@@ -547,7 +547,7 @@ private:
{
dirObj = ::opendir(dirname.c_str()); //directory must NOT end with path separator, except "/"
if (!dirObj)
- throw FileError(replaceCpy(_("Cannot open directory %x."), L"%x", fmtFileName(dirname)), formatSystemError(L"opendir", getLastError()));
+ throwFileError(replaceCpy(_("Cannot open directory %x."), L"%x", fmtFileName(dirname)), L"opendir", getLastError());
}, sink))
return; //ignored error
ZEN_ON_SCOPE_EXIT(::closedir(dirObj)); //never close nullptr handles! -> crash
@@ -558,7 +558,7 @@ private:
tryReportingDirError([&]
{
if (::readdir_r(dirObj, reinterpret_cast< ::dirent*>(&buffer[0]), &dirEntry) != 0)
- throw FileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtFileName(dirname)), formatSystemError(L"readdir_r", getLastError()));
+ throwFileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtFileName(dirname)), L"readdir_r", getLastError());
}, sink);
if (!dirEntry) //no more items or ignored error
return;
@@ -594,7 +594,7 @@ private:
if (!tryReportingItemError([&]
{
if (::lstat(fullName.c_str(), &statData) != 0) //lstat() does not resolve symlinks
- throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(fullName)), formatSystemError(L"lstat", getLastError()));
+ throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(fullName)), L"lstat", getLastError());
}, sink, shortName))
continue; //ignore error: skip file
@@ -612,7 +612,7 @@ private:
bool validLink = tryReportingItemError([&]
{
if (::stat(fullName.c_str(), &statDataTrg) != 0)
- throw FileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(fullName)), formatSystemError(L"stat", getLastError()));
+ throwFileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(fullName)), L"stat", getLastError());
}, sink, shortName);
if (validLink)
diff --git a/zen/long_path_prefix.h b/zen/long_path_prefix.h
index ae09c5f5..0669cf88 100644
--- a/zen/long_path_prefix.h
+++ b/zen/long_path_prefix.h
@@ -18,10 +18,21 @@ namespace zen
2. if path is smaller than MAX_PATH nothing is changed! caveat: FindFirstFile() "Prepending the string "\\?\" does not allow access to the root directory."
3. path may already contain \\?\-prefix
*/
-Zstring applyLongPathPrefix(const Zstring& path); //throw()
-Zstring applyLongPathPrefixCreateDir(const Zstring& path); //throw() -> special rule for ::CreateDirectory()/::CreateDirectoryEx(): MAX_PATH - 12(=^ 8.3 filename) is threshold
+Zstring applyLongPathPrefix(const Zstring& path); //noexcept
+Zstring applyLongPathPrefixCreateDir(const Zstring& path); //noexcept -> special rule for ::CreateDirectory()/::CreateDirectoryEx(): MAX_PATH - 12(=^ 8.3 filename) is threshold
-Zstring removeLongPathPrefix(const Zstring& path); //throw()
+Zstring removeLongPathPrefix(const Zstring& path); //noexcept
+
+
+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
+*/
}
@@ -84,7 +95,7 @@ Zstring zen::applyLongPathPrefix(const Zstring& path)
inline
-Zstring zen::applyLongPathPrefixCreateDir(const Zstring& path) //throw()
+Zstring zen::applyLongPathPrefixCreateDir(const Zstring& path) //noexcept
{
//special rule for ::CreateDirectoryEx(): MAX_PATH - 12(=^ 8.3 filename) is threshold
return applyLongPathPrefixImpl<MAX_PATH - 12> (path);
@@ -92,7 +103,7 @@ Zstring zen::applyLongPathPrefixCreateDir(const Zstring& path) //throw()
inline
-Zstring zen::removeLongPathPrefix(const Zstring& path) //throw()
+Zstring zen::removeLongPathPrefix(const Zstring& path) //noexcept
{
if (zen::startsWith(path, LONG_PATH_PREFIX))
{
@@ -104,4 +115,29 @@ Zstring zen::removeLongPathPrefix(const Zstring& path) //throw()
return path; //fallback
}
+
+inline
+Zstring zen::ntPathToWin32Path(const Zstring& path) //noexcept
+{
+ if (startsWith(path, L"\\??\\"))
+ return Zstring(path.c_str() + 4, path.length() - 4);
+
+ if (startsWith(path, L"\\SystemRoot\\"))
+ {
+ DWORD bufSize = ::GetEnvironmentVariable(L"SystemRoot", nullptr, 0);
+ if (bufSize > 0)
+ {
+ std::vector<wchar_t> buf(bufSize);
+ DWORD charsWritten = ::GetEnvironmentVariable(L"SystemRoot", //_In_opt_ LPCTSTR lpName,
+ &buf[0], //_Out_opt_ LPTSTR lpBuffer,
+ bufSize); //_In_ DWORD nSize
+
+ if (charsWritten != 0 && charsWritten < bufSize)
+ return replaceCpy(path, L"\\SystemRoot\\", appendSeparator(Zstring(&buf[0], charsWritten)), false);
+ }
+ }
+
+ return path;
+}
+
#endif //LONGPATHPREFIX_H_INCLUDED
diff --git a/zen/notify_removal.cpp b/zen/notify_removal.cpp
index 678675b5..c66eb3c1 100644
--- a/zen/notify_removal.cpp
+++ b/zen/notify_removal.cpp
@@ -75,7 +75,7 @@ MessageProvider::MessageProvider() :
windowHandle(nullptr)
{
if (!hMainModule)
- throw FileError(_("Unable to register to receive system messages."), formatSystemError(L"GetModuleHandle", getLastError()));
+ throwFileError(_("Unable to register to receive system messages."), L"GetModuleHandle", getLastError());
//register the main window class
WNDCLASS wc = {};
@@ -84,7 +84,7 @@ MessageProvider::MessageProvider() :
wc.lpszClassName = dummyWindowName;
if (::RegisterClass(&wc) == 0)
- throw FileError(_("Unable to register to receive system messages."), formatSystemError(L"RegisterClass", getLastError()));
+ throwFileError(_("Unable to register to receive system messages."), L"RegisterClass", getLastError());
ScopeGuard guardClass = makeGuard([&] { ::UnregisterClass(dummyWindowName, hMainModule); });
@@ -101,14 +101,17 @@ MessageProvider::MessageProvider() :
hMainModule, //HINSTANCE hInstance,
nullptr); //LPVOID lpParam
if (!windowHandle)
- throw FileError(_("Unable to register to receive system messages."), formatSystemError(L"CreateWindow", getLastError()));
+ throwFileError(_("Unable to register to receive system messages."), L"CreateWindow", getLastError());
//store this-pointer for topWndProc() to use: do this AFTER CreateWindow() to avoid processing messages while this constructor is running!!!
//unlike: http://blogs.msdn.com/b/oldnewthing/archive/2014/02/03/10496248.aspx
::SetLastError(ERROR_SUCCESS); //[!] required for proper error handling, see MSDN, SetWindowLongPtr
if (::SetWindowLongPtr(windowHandle, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this)) == 0)
- if (::GetLastError() != ERROR_SUCCESS)
- throw FileError(_("Unable to register to receive system messages."), formatSystemError(L"SetWindowLongPtr", getLastError()));
+ {
+ const DWORD lastError = ::GetLastError(); //copy before directly or indirectly making other system calls!
+ if (lastError != ERROR_SUCCESS)
+ throwFileError(_("Unable to register to receive system messages."), L"SetWindowLongPtr", lastError);
+ }
guardClass.dismiss();
}
@@ -152,11 +155,11 @@ public:
DEVICE_NOTIFY_WINDOW_HANDLE); //__in DWORD Flags
if (!hNotification)
{
- const DWORD lastError = ::GetLastError();
+ const DWORD lastError = ::GetLastError(); //copy before directly or indirectly making other system calls!
if (lastError != ERROR_CALL_NOT_IMPLEMENTED && //fail on SAMBA share: this shouldn't be a showstopper!
lastError != ERROR_SERVICE_SPECIFIC_ERROR && //neither should be fail for "Pogoplug" mapped network drives
lastError != ERROR_INVALID_DATA) //this seems to happen for a NetDrive-mapped FTP server
- throw zen::FileError(_("Unable to register to receive system messages."), formatSystemError(L"RegisterDeviceNotification", lastError));
+ throwFileError(_("Unable to register to receive system messages."), L"RegisterDeviceNotification", lastError);
}
guardProvider.dismiss();
diff --git a/zen/osx_string.h b/zen/osx_string.h
deleted file mode 100644
index ba83ca27..00000000
--- a/zen/osx_string.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
-// **************************************************************************
-
-#ifndef OSX_STRING_1873641732143214324
-#define OSX_STRING_1873641732143214324
-
-#include <CoreFoundation/CoreFoundation.h> //CFString
-#include "zstring.h"
-
-namespace osx
-{
-Zstring cfStringToZstring(const CFStringRef& cfStr);
-
-CFStringRef createCFString (const char* utf8Str); //returns nullptr on error
-CFMutableStringRef createMutableCFString(const char* utf8Str); //pass ownership! => ZEN_ON_SCOPE_EXIT(::CFRelease(str));
-
-
-
-
-
-
-
-
-
-
-
-
-
-//################# implementation #####################
-inline
-Zstring cfStringToZstring(const CFStringRef& cfStr)
-{
- if (cfStr)
- {
- //perf: try to get away cheap:
- if (const char* utf8Str = ::CFStringGetCStringPtr(cfStr, kCFStringEncodingUTF8))
- return utf8Str;
-
- CFIndex length = ::CFStringGetLength(cfStr);
- if (length > 0)
- {
- CFIndex bufferSize = ::CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8);
- Zstring buffer;
- buffer.resize(bufferSize);
-
- if (::CFStringGetCString(cfStr, &*buffer.begin(), bufferSize, kCFStringEncodingUTF8))
- {
- buffer.resize(zen::strLength(buffer.c_str())); //caveat: memory consumption of returned string!
- return buffer;
- }
- }
- }
- return Zstring();
-}
-
-
-inline
-CFStringRef createCFString(const char* utf8Str)
-{
- //don't bother with CFStringCreateWithBytes: it's slightly slower, despite passing length info
- return ::CFStringCreateWithCString(nullptr, //CFAllocatorRef alloc,
- utf8Str, //const char *cStr,
- kCFStringEncodingUTF8); //CFStringEncoding encoding
-}
-
-
-inline
-CFMutableStringRef createMutableCFString(const char* utf8Str)
-{
- if (CFMutableStringRef strRef = ::CFStringCreateMutable(NULL, 0))
- {
- ::CFStringAppendCString(strRef, utf8Str, kCFStringEncodingUTF8);
- return strRef;
- }
- return nullptr;
-}
-}
-
-#endif //OSX_STRING_1873641732143214324
diff --git a/zen/osx_throw_exception.h b/zen/osx_throw_exception.h
deleted file mode 100644
index 07e3af3e..00000000
--- a/zen/osx_throw_exception.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
-// **************************************************************************
-
-#ifndef OSX_EXCEPTION_89274305834255
-#define OSX_EXCEPTION_89274305834255
-
-#import <Cocoa/Cocoa.h>
-#include "sys_error.h"
-#include "utf.h"
-
-namespace osx
-{
-//for use in Objective C implementation files only!
-void throwSysError(NSException* e); //throw SysError
-
-#define ZEN_OSX_ASSERT(obj) ZEN_OSX_ASSERT_IMPL(obj, #obj) //throw SysError
-/*
-Example: ZEN_OSX_ASSERT(obj);
-
-Equivalent to:
- if (!obj)
- throw zen::SysError(L"Assertion failed: \"obj\".");
-*/
-
-
-
-
-
-
-//######################## implmentation ############################
-inline
-void throwSysError(NSException* e) //throw SysError
-{
- std::string msg;
- if (const char* name = [[e name ] cStringUsingEncoding:NSUTF8StringEncoding]) //"const char*" NOT owned by us!
- msg += name;
- if (const char* descr = [[e reason] cStringUsingEncoding:NSUTF8StringEncoding])
- {
- msg += "\n";
- msg += descr;
- }
- throw zen::SysError(zen::utfCvrtTo<std::wstring>(msg));
- /*
- e.g.
- NSInvalidArgumentException
- *** +[NSString stringWithCString:encoding:]: NULL cString
- */
-}
-}
-
-#define ZEN_OSX_ASSERT_IMPL(obj, txt) if (!(obj)) throw zen::SysError(std::wstring(L"Assertion failed: \"") + L ## txt + L"\".");
-
-#endif //OSX_EXCEPTION_89274305834255
diff --git a/zen/privilege.cpp b/zen/privilege.cpp
deleted file mode 100644
index 90612756..00000000
--- a/zen/privilege.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-#include "privilege.h"
-#include <map>
-#include <mutex>
-#include "zstring.h"
-#include "scope_guard.h"
-#include "win_ver.h"
-
-using namespace zen;
-
-
-namespace
-{
-bool privilegeIsActive(LPCTSTR privilege) //throw FileError
-{
- HANDLE hToken = nullptr;
- if (!::OpenProcessToken(::GetCurrentProcess(), //__in HANDLE ProcessHandle,
- TOKEN_QUERY, //__in DWORD DesiredAccess,
- &hToken)) //__out PHANDLE TokenHandle
- throw FileError(replaceCpy(_("Cannot set privilege %x."), L"%x", std::wstring(L"\"") + privilege + L"\""), formatSystemError(L"OpenProcessToken", getLastError()));
- ZEN_ON_SCOPE_EXIT(::CloseHandle(hToken));
-
- LUID luid = {};
- if (!::LookupPrivilegeValue(nullptr, //__in_opt LPCTSTR lpSystemName,
- privilege, //__in LPCTSTR lpName,
- &luid )) //__out PLUID lpLuid
- throw FileError(replaceCpy(_("Cannot set privilege %x."), L"%x", std::wstring(L"\"") + privilege + L"\""), formatSystemError(L"LookupPrivilegeValue", getLastError()));
-
- PRIVILEGE_SET priv = {};
- priv.PrivilegeCount = 1;
- priv.Control = PRIVILEGE_SET_ALL_NECESSARY;
- priv.Privilege[0].Luid = luid;
- priv.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
-
- BOOL alreadyGranted = FALSE;
- if (!::PrivilegeCheck(hToken, //__in HANDLE ClientToken,
- &priv, //__inout PPRIVILEGE_SET RequiredPrivileges,
- &alreadyGranted)) //__out LPBOOL pfResult
- throw FileError(replaceCpy(_("Cannot set privilege %x."), L"%x", std::wstring(L"\"") + privilege + L"\""), formatSystemError(L"PrivilegeCheck", getLastError()));
-
- return alreadyGranted != FALSE;
-}
-
-
-void setPrivilege(LPCTSTR privilege, bool enable) //throw FileError
-{
- HANDLE hToken = nullptr;
- if (!::OpenProcessToken(::GetCurrentProcess(), //__in HANDLE ProcessHandle,
- TOKEN_ADJUST_PRIVILEGES, //__in DWORD DesiredAccess,
- &hToken)) //__out PHANDLE TokenHandle
- throw FileError(replaceCpy(_("Cannot set privilege %x."), L"%x", std::wstring(L"\"") + privilege + L"\""), formatSystemError(L"OpenProcessToken", getLastError()));
- ZEN_ON_SCOPE_EXIT(::CloseHandle(hToken));
-
- LUID luid = {};
- if (!::LookupPrivilegeValue(nullptr, //__in_opt LPCTSTR lpSystemName,
- privilege, //__in LPCTSTR lpName,
- &luid )) //__out PLUID lpLuid
- throw FileError(replaceCpy(_("Cannot set privilege %x."), L"%x", std::wstring(L"\"") + privilege + L"\""), formatSystemError(L"LookupPrivilegeValue", getLastError()));
-
- TOKEN_PRIVILEGES tp = {};
- tp.PrivilegeCount = 1;
- tp.Privileges[0].Luid = luid;
- tp.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0;
-
- if (!::AdjustTokenPrivileges(hToken, //__in HANDLE TokenHandle,
- false, //__in BOOL DisableAllPrivileges,
- &tp, //__in_opt PTOKEN_PRIVILEGES NewState,
- 0, //__in DWORD BufferLength,
- nullptr, //__out_opt PTOKEN_PRIVILEGES PreviousState,
- nullptr)) //__out_opt PDWORD ReturnLength
- throw FileError(replaceCpy(_("Cannot set privilege %x."), L"%x", std::wstring(L"\"") + privilege + L"\""), formatSystemError(L"AdjustTokenPrivileges", getLastError()));
-
- ErrorCode lastError = getLastError();
- if (lastError == ERROR_NOT_ALL_ASSIGNED) //check although previous function returned with success!
- {
-#ifdef __MINGW32__ //Shobjidl.h
-#define ERROR_ELEVATION_REQUIRED 740L
-#endif
- if (vistaOrLater()) //replace this useless error code with what it *really* means!
- lastError = ERROR_ELEVATION_REQUIRED;
-
- throw FileError(replaceCpy(_("Cannot set privilege %x."), L"%x", std::wstring(L"\"") + privilege + L"\""), formatSystemError(L"AdjustTokenPrivileges", lastError));
- }
-}
-
-
-class Privileges
-{
-public:
- static Privileges& getInstance()
- {
- static Privileges inst;
- return inst;
- }
-
- void ensureActive(LPCTSTR privilege) //throw FileError
- {
- if (activePrivileges.find(privilege) != activePrivileges.end())
- return; //privilege already active
-
- if (privilegeIsActive(privilege)) //privilege was already active before starting this tool
- activePrivileges.insert(std::make_pair(privilege, false));
- else
- {
- setPrivilege(privilege, true);
- activePrivileges.insert(std::make_pair(privilege, true));
- }
- }
-
-private:
- Privileges() {}
- Privileges(Privileges&);
- Privileges& operator=(const Privileges&);
-
- ~Privileges() //clean up: deactivate all privileges that have been activated by this application
- {
- for (const auto& priv : activePrivileges)
- if (priv.second)
- {
- try
- {
- setPrivilege(priv.first.c_str(), false); //throw FileError
- }
- catch (FileError&) {}
- }
- }
-
- std::map<Zstring, bool> activePrivileges; //bool: enabled by this application
-};
-
-std::mutex lockPrivileges;
-}
-
-
-void zen::activatePrivilege(LPCTSTR privilege) //throw FileError
-{
- std::lock_guard<std::mutex> dummy(lockPrivileges);
- Privileges::getInstance().ensureActive(privilege);
-}
diff --git a/zen/privilege.h b/zen/privilege.h
deleted file mode 100644
index 70d5b7f1..00000000
--- a/zen/privilege.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// **************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: http://www.gnu.org/licenses/gpl.html *
-// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
-// **************************************************************************
-
-#ifndef PRIVILEGE_H_INCLUDED
-#define PRIVILEGE_H_INCLUDED
-
-#include "file_error.h"
-#include "win.h" //includes "windows.h"
-
-namespace zen
-{
-void activatePrivilege(LPCTSTR privilege); //throw FileError; thread-safe!!!
-}
-
-#endif // PRIVILEGE_H_INCLUDED
diff --git a/zen/process_priority.cpp b/zen/process_priority.cpp
index 3ac2f068..a50fbd75 100644
--- a/zen/process_priority.cpp
+++ b/zen/process_priority.cpp
@@ -49,7 +49,7 @@ struct ScheduleForBackgroundProcessing::Pimpl {};
ScheduleForBackgroundProcessing::ScheduleForBackgroundProcessing()
{
if (!::SetPriorityClass(::GetCurrentProcess(), PROCESS_MODE_BACKGROUND_BEGIN)) //this call lowers CPU priority, too!!
- throw FileError(_("Cannot change process I/O priorities."), formatSystemError(L"SetPriorityClass", getLastError()));
+ throwFileError(_("Cannot change process I/O priorities."), L"SetPriorityClass", getLastError());
}
@@ -136,10 +136,10 @@ ScheduleForBackgroundProcessing::ScheduleForBackgroundProcessing() : pimpl(make_
{
pimpl->oldIoPrio = ::getiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS);
if (pimpl->oldIoPrio == -1)
- throw FileError(_("Cannot change process I/O priorities."), formatSystemError(L"getiopolicy_np", getLastError()));
+ throwFileError(_("Cannot change process I/O priorities."), L"getiopolicy_np", getLastError());
if (::setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE) != 0)
- throw FileError(_("Cannot change process I/O priorities."), formatSystemError(L"setiopolicy_np", getLastError()));
+ throwFileError(_("Cannot change process I/O priorities."), L"setiopolicy_np", getLastError());
}
diff --git a/zen/recycler.cpp b/zen/recycler.cpp
index b9245259..0e4e4be0 100644
--- a/zen/recycler.cpp
+++ b/zen/recycler.cpp
@@ -85,10 +85,10 @@ void zen::recycleOrDelete(const std::vector<Zstring>& filenames, const std::func
if (vistaOrLater()) //new recycle bin usage: available since Vista
{
using namespace fileop;
- const DllFun<FunType_moveToRecycleBin> moveToRecycler(getDllName(), funName_moveToRecycleBin);
- const DllFun<FunType_getLastError> getLastError (getDllName(), funName_getLastError);
+ const DllFun<FunType_moveToRecycleBin > moveToRecycler (getDllName(), funName_moveToRecycleBin);
+ const DllFun<FunType_getLastErrorMessage> getLastErrorMessage(getDllName(), funName_getLastErrorMessage);
- if (!moveToRecycler || !getLastError)
+ if (!moveToRecycler || !getLastErrorMessage)
throw FileError(replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", fmtFileName(filenames[0])),
replaceCpy(_("Cannot load file %x."), L"%x", fmtFileName(getDllName())));
@@ -110,7 +110,7 @@ void zen::recycleOrDelete(const std::vector<Zstring>& filenames, const std::func
if (filenames.size() > 1)
filenameFmt += L", ..."; //give at least some hint that there are multiple files, and the error need not be related to the first one
- throw FileError(replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", filenameFmt), getLastError()); //already includes details about locking errors!
+ throw FileError(replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", filenameFmt), getLastErrorMessage()); //already includes details about locking errors!
}
}
else //regular recycle bin usage: available since XP
@@ -242,15 +242,15 @@ bool zen::recycleBinExists(const Zstring& pathName, const std::function<void ()>
{
using namespace fileop;
const DllFun<FunType_getRecycleBinStatus> getRecycleBinStatus(getDllName(), funName_getRecycleBinStatus);
- const DllFun<FunType_getLastError> getLastError (getDllName(), funName_getLastError);
+ const DllFun<FunType_getLastErrorMessage> getLastErrorMessage(getDllName(), funName_getLastErrorMessage);
- if (!getRecycleBinStatus || !getLastError)
+ if (!getRecycleBinStatus || !getLastErrorMessage)
throw FileError(replaceCpy(_("Checking recycle bin failed for folder %x."), L"%x", fmtFileName(pathName)),
replaceCpy(_("Cannot load file %x."), L"%x", fmtFileName(getDllName())));
bool hasRecycler = false;
if (!getRecycleBinStatus(pathName.c_str(), hasRecycler))
- throw FileError(replaceCpy(_("Checking recycle bin failed for folder %x."), L"%x", fmtFileName(pathName)), getLastError());
+ throw FileError(replaceCpy(_("Checking recycle bin failed for folder %x."), L"%x", fmtFileName(pathName)), getLastErrorMessage());
return hasRecycler;
}
diff --git a/zen/shell_execute.h b/zen/shell_execute.h
index 14a6a40e..78526b70 100644
--- a/zen/shell_execute.h
+++ b/zen/shell_execute.h
@@ -68,8 +68,7 @@ void shellExecute2(const Zstring& command, ExecutionType type) //throw FileError
execInfo.nShow = SW_SHOWNORMAL;
if (!::ShellExecuteEx(&execInfo)) //__inout LPSHELLEXECUTEINFO lpExecInfo
- throw FileError(_("Incorrect command line:") + L"\nFile: " + filename + L"\nArg: " + arguments,
- formatSystemError(L"ShellExecuteEx", getLastError()));
+ throwFileError(_("Incorrect command line:") + L"\nFile: " + filename + L"\nArg: " + arguments, L"ShellExecuteEx", ::GetLastError());
if (execInfo.hProcess)
{
diff --git a/zen/string_tools.h b/zen/string_tools.h
index 1dd5905d..a0b02d14 100644
--- a/zen/string_tools.h
+++ b/zen/string_tools.h
@@ -65,20 +65,6 @@ template <class T, class S> T copyStringTo(const S& str);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
//---------------------- implementation ----------------------
template <> inline
bool isWhiteSpace(char ch)
@@ -584,7 +570,7 @@ Num extractInteger(const S& str, bool& hasMinusSign) //very fast conversion to i
}
else
{
- //rest of string should contain whitespace only, it's NOT a bug if there is some!
+ //rest of string should contain whitespace only, it's NOT a bug if there is something else!
//assert(std::all_of(iter, last, &isWhiteSpace<CharType>)); -> this is NO assert situation
break;
}
diff --git a/zen/string_traits.h b/zen/string_traits.h
index 887752c0..f192e045 100644
--- a/zen/string_traits.h
+++ b/zen/string_traits.h
@@ -162,7 +162,7 @@ struct GetCharType : ResultType<typename implementation::StringTraits<T>::CharTy
namespace implementation
{
template <class C> inline
-size_t cStringLength(const C* str) //strlen()
+size_t cStringLength(const C* str) //naive implementation seems somewhat faster than "optimized" strlen/wcslen!
{
assert_static((IsSameType<C, char>::value || IsSameType<C, wchar_t>::value));
size_t len = 0;
@@ -195,8 +195,8 @@ size_t strLength(const S& str, typename EnableIf<implementation::StringTraits<S>
inline size_t strLength(const char* str) { return implementation::cStringLength(str); }
inline size_t strLength(const wchar_t* str) { return implementation::cStringLength(str); }
-inline size_t strLength(char) { return 1; }
-inline size_t strLength(wchar_t) { return 1; }
+inline size_t strLength(char) { return 1; }
+inline size_t strLength(wchar_t) { return 1; }
inline size_t strLength(const StringRef<char >& ref) { return ref.length(); }
inline size_t strLength(const StringRef<wchar_t>& ref) { return ref.length(); }
}
diff --git a/zen/symlink_target.h b/zen/symlink_target.h
index 4c4c3745..13226f1f 100644
--- a/zen/symlink_target.h
+++ b/zen/symlink_target.h
@@ -101,7 +101,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)
- throw FileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkPath)), formatSystemError(L"CreateFile", getLastError()));
+ throwFileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkPath)), L"CreateFile", getLastError());
ZEN_ON_SCOPE_EXIT(::CloseHandle(hLink));
//respect alignment issues...
@@ -117,7 +117,7 @@ Zstring getSymlinkRawTargetString_impl(const Zstring& linkPath) //throw FileErro
bufferSize, //__in DWORD nOutBufferSize,
&bytesReturned, //__out_opt LPDWORD lpBytesReturned,
nullptr)) //__inout_opt LPOVERLAPPED lpOverlapped
- throw FileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkPath)), formatSystemError(L"DeviceIoControl, FSCTL_GET_REPARSE_POINT", getLastError()));
+ throwFileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkPath)), L"DeviceIoControl, FSCTL_GET_REPARSE_POINT", getLastError());
REPARSE_DATA_BUFFER& reparseData = *reinterpret_cast<REPARSE_DATA_BUFFER*>(&buffer[0]); //REPARSE_DATA_BUFFER needs to be artificially enlarged!
@@ -135,25 +135,20 @@ Zstring getSymlinkRawTargetString_impl(const Zstring& linkPath) //throw FileErro
else
throw FileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkPath)), L"Not a symbolic link or junction.");
- //absolute symlinks and junctions technically start with \??\ while relative ones do not
- if (startsWith(output, Zstr("\\??\\")))
- output = Zstring(output.c_str() + 4, output.length() - 4);
-
- return output;
+ //absolute symlinks and junctions use NT namespace naming convention while relative ones do not:
+ //http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx#NT_Namespaces
+ return ntPathToWin32Path(output);
#elif defined ZEN_LINUX || defined ZEN_MAC
const size_t BUFFER_SIZE = 10000;
std::vector<char> buffer(BUFFER_SIZE);
const ssize_t bytesWritten = ::readlink(linkPath.c_str(), &buffer[0], BUFFER_SIZE);
- if (bytesWritten < 0 || bytesWritten >= static_cast<ssize_t>(BUFFER_SIZE)) //detect truncation!
- {
- ErrorCode lastError = getLastError();
- const std::wstring errorMsg = replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkPath));
- if (bytesWritten < 0)
- throw FileError(errorMsg, formatSystemError(L"readlink", lastError));
- throw FileError(errorMsg);
- }
+ if (bytesWritten < 0)
+ throwFileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkPath)), L"readlink", getLastError());
+ if (bytesWritten >= static_cast<ssize_t>(BUFFER_SIZE)) //detect truncation!
+ throw FileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkPath)));
+
return Zstring(&buffer[0], bytesWritten); //readlink does not append 0-termination!
#endif
}
@@ -172,7 +167,7 @@ Zstring getResolvedFilePath_impl(const Zstring& linkPath) //throw FileError
FILE_FLAG_BACKUP_SEMANTICS, //_In_ DWORD dwFlagsAndAttributes,
nullptr); //_In_opt_ HANDLE hTemplateFile
if (hDir == INVALID_HANDLE_VALUE)
- throw FileError(replaceCpy(_("Cannot determine final path for %x."), L"%x", fmtFileName(linkPath)), formatSystemError(L"CreateFile", getLastError()));
+ throwFileError(replaceCpy(_("Cannot determine final path for %x."), L"%x", fmtFileName(linkPath)), L"CreateFile", getLastError());
ZEN_ON_SCOPE_EXIT(::CloseHandle(hDir));
//GetFinalPathNameByHandle() is not available before Vista!
@@ -184,7 +179,7 @@ Zstring getResolvedFilePath_impl(const Zstring& linkPath) //throw FileError
const DWORD bufferSize = getFinalPathNameByHandle(hDir, nullptr, 0, 0);
if (bufferSize == 0)
- throw FileError(replaceCpy(_("Cannot determine final path for %x."), L"%x", fmtFileName(linkPath)), formatSystemError(L"GetFinalPathNameByHandle", getLastError()));
+ throwFileError(replaceCpy(_("Cannot determine final path for %x."), L"%x", fmtFileName(linkPath)), L"GetFinalPathNameByHandle", getLastError());
std::vector<wchar_t> targetPath(bufferSize);
const DWORD charsWritten = getFinalPathNameByHandle(hDir, //__in HANDLE hFile,
@@ -195,7 +190,7 @@ Zstring getResolvedFilePath_impl(const Zstring& linkPath) //throw FileError
{
const std::wstring errorMsg = replaceCpy(_("Cannot determine final path for %x."), L"%x", fmtFileName(linkPath));
if (charsWritten == 0)
- throw FileError(errorMsg, formatSystemError(L"GetFinalPathNameByHandle", getLastError()));
+ throwFileError(errorMsg, L"GetFinalPathNameByHandle", getLastError());
throw FileError(errorMsg);
}
@@ -204,7 +199,7 @@ Zstring getResolvedFilePath_impl(const Zstring& linkPath) //throw FileError
#elif defined ZEN_LINUX || defined ZEN_MAC
char* targetPath = ::realpath(linkPath.c_str(), nullptr);
if (!targetPath)
- throw FileError(replaceCpy(_("Cannot determine final path for %x."), L"%x", fmtFileName(linkPath)), formatSystemError(L"realpath", getLastError()));
+ throwFileError(replaceCpy(_("Cannot determine final path for %x."), L"%x", fmtFileName(linkPath)), L"realpath", getLastError());
ZEN_ON_SCOPE_EXIT(::free(targetPath));
return targetPath;
#endif
diff --git a/zen/sys_error.h b/zen/sys_error.h
index dc60c77f..8afab138 100644
--- a/zen/sys_error.h
+++ b/zen/sys_error.h
@@ -4,8 +4,8 @@
// * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved *
// **************************************************************************
-#ifndef LAST_ERROR_H_3284791347018951324534
-#define LAST_ERROR_H_3284791347018951324534
+#ifndef SYS_ERROR_H_3284791347018951324534
+#define SYS_ERROR_H_3284791347018951324534
#include <string>
#include "utf.h"
@@ -67,7 +67,7 @@ ErrorCode getLastError()
}
-std::wstring formatSystemError(const std::wstring& functionName, long long lastError); //not implemented! intentional overload ambiguity to catch usage errors with HRESULT!
+std::wstring formatSystemError(const std::wstring& functionName, long long lastError) = delete; //not implemented! intentional overload ambiguity to catch usage errors with HRESULT!
inline
@@ -110,4 +110,4 @@ std::wstring formatSystemError(const std::wstring& functionName, ErrorCode lastE
}
}
-#endif //LAST_ERROR_H_3284791347018951324534
+#endif //SYS_ERROR_H_3284791347018951324534
diff --git a/zen/thread.h b/zen/thread.h
index 15ebb3c3..d74eaa5b 100644
--- a/zen/thread.h
+++ b/zen/thread.h
@@ -73,8 +73,8 @@ public:
private:
class AsyncResult;
- std::shared_ptr<AsyncResult> result;
- size_t jobsTotal;
+ std::shared_ptr<AsyncResult> asyncResult;
+ size_t jobsTotal_;
};
@@ -178,27 +178,27 @@ private:
template <class T> inline
-GetFirstResult<T>::GetFirstResult() : result(std::make_shared<AsyncResult>()), jobsTotal(0) {}
+GetFirstResult<T>::GetFirstResult() : asyncResult(std::make_shared<AsyncResult>()), jobsTotal_(0) {}
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
{
- auto result2 = result; //capture member variable, not "this"!
- boost::thread t([result2, f] { result2->reportFinished(f()); });
- ++jobsTotal;
+ auto asyncResult2 = asyncResult; //capture member variable, not "this"!
+ boost::thread t([asyncResult2, f] { asyncResult2->reportFinished(f()); });
+ ++jobsTotal_;
t.detach(); //we have to be explicit since C++11: [thread.thread.destr] ~thread() calls std::terminate() if joinable()!!!
}
template <class T>
template <class Duration> inline
-bool GetFirstResult<T>::timedWait(const Duration& duration) const { return result->waitForResult(jobsTotal, duration); }
+bool GetFirstResult<T>::timedWait(const Duration& duration) const { return asyncResult->waitForResult(jobsTotal_, duration); }
template <class T> inline
-std::unique_ptr<T> GetFirstResult<T>::get() const { return result->getResult(jobsTotal); }
+std::unique_ptr<T> GetFirstResult<T>::get() const { return asyncResult->getResult(jobsTotal_); }
}
#endif //BOOST_THREAD_WRAP_H_78963234
bgstack15