diff options
Diffstat (limited to 'zen')
-rw-r--r-- | zen/dir_watcher.cpp | 16 | ||||
-rw-r--r-- | zen/dll.h | 121 | ||||
-rw-r--r-- | zen/dst_hack.cpp | 16 | ||||
-rw-r--r-- | zen/file_error.h | 9 | ||||
-rw-r--r-- | zen/file_handling.cpp | 115 | ||||
-rw-r--r-- | zen/file_io.cpp | 14 | ||||
-rw-r--r-- | zen/file_traverser.cpp | 26 | ||||
-rw-r--r-- | zen/long_path_prefix.h | 46 | ||||
-rw-r--r-- | zen/notify_removal.cpp | 17 | ||||
-rw-r--r-- | zen/osx_string.h | 82 | ||||
-rw-r--r-- | zen/osx_throw_exception.h | 56 | ||||
-rw-r--r-- | zen/privilege.cpp | 138 | ||||
-rw-r--r-- | zen/privilege.h | 18 | ||||
-rw-r--r-- | zen/process_priority.cpp | 6 | ||||
-rw-r--r-- | zen/recycler.cpp | 14 | ||||
-rw-r--r-- | zen/shell_execute.h | 3 | ||||
-rw-r--r-- | zen/string_tools.h | 16 | ||||
-rw-r--r-- | zen/string_traits.h | 6 | ||||
-rw-r--r-- | zen/symlink_target.h | 33 | ||||
-rw-r--r-- | zen/sys_error.h | 8 | ||||
-rw-r--r-- | zen/thread.h | 16 |
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 |