diff options
Diffstat (limited to 'zen')
-rw-r--r-- | zen/async_task.h | 4 | ||||
-rw-r--r-- | zen/dir_watcher.cpp | 84 | ||||
-rw-r--r-- | zen/dir_watcher.h | 8 | ||||
-rw-r--r-- | zen/dst_hack.cpp | 65 | ||||
-rw-r--r-- | zen/file_error.h | 4 | ||||
-rw-r--r-- | zen/file_handling.cpp | 275 | ||||
-rw-r--r-- | zen/file_handling.h | 27 | ||||
-rw-r--r-- | zen/file_id_def.h | 20 | ||||
-rw-r--r-- | zen/file_io.cpp | 62 | ||||
-rw-r--r-- | zen/file_io.h | 22 | ||||
-rw-r--r-- | zen/file_traverser.cpp | 443 | ||||
-rw-r--r-- | zen/file_traverser.h | 25 | ||||
-rw-r--r-- | zen/fixed_list.h | 4 | ||||
-rw-r--r-- | zen/format_unit.cpp | 28 | ||||
-rw-r--r-- | zen/format_unit.h | 10 | ||||
-rw-r--r-- | zen/int64.h | 222 | ||||
-rw-r--r-- | zen/long_path_prefix.h | 6 | ||||
-rw-r--r-- | zen/notify_removal.cpp | 8 | ||||
-rw-r--r-- | zen/process_priority.cpp | 7 | ||||
-rw-r--r-- | zen/recycler.cpp | 72 | ||||
-rw-r--r-- | zen/recycler.h | 7 | ||||
-rw-r--r-- | zen/serialize.h | 16 | ||||
-rw-r--r-- | zen/shell_execute.h | 8 | ||||
-rw-r--r-- | zen/symlink_target.h | 1 | ||||
-rw-r--r-- | zen/thread.h | 4 | ||||
-rw-r--r-- | zen/win_ver.h | 2 | ||||
-rw-r--r-- | zen/xml_io.cpp | 20 | ||||
-rw-r--r-- | zen/xml_io.h | 9 | ||||
-rw-r--r-- | zen/zstring.cpp | 7 | ||||
-rw-r--r-- | zen/zstring.h | 7 |
30 files changed, 661 insertions, 816 deletions
diff --git a/zen/async_task.h b/zen/async_task.h index c5e5857a..f9bea890 100644 --- a/zen/async_task.h +++ b/zen/async_task.h @@ -9,8 +9,8 @@ #include <list> #include <functional> -#include <zen/thread.h> -#include <zen/scope_guard.h> +#include "thread.h" +#include "scope_guard.h" //#include "type_tools.h" namespace zen diff --git a/zen/dir_watcher.cpp b/zen/dir_watcher.cpp index 258a1c35..3751e5dd 100644 --- a/zen/dir_watcher.cpp +++ b/zen/dir_watcher.cpp @@ -22,7 +22,7 @@ #elif defined ZEN_MAC #include <CoreServices/CoreServices.h> -#include <zen/osx_string.h> +#include "osx_string.h" #endif using namespace zen; @@ -35,7 +35,7 @@ class SharedData { public: //context of worker thread - void addChanges(const char* buffer, DWORD bytesWritten, const Zstring& dirname) //throw () + void addChanges(const char* buffer, DWORD bytesWritten, const Zstring& dirpath) //throw () { boost::lock_guard<boost::mutex> dummy(lockAccess); @@ -48,7 +48,7 @@ public: { const FILE_NOTIFY_INFORMATION& notifyInfo = reinterpret_cast<const FILE_NOTIFY_INFORMATION&>(*bufPos); - const Zstring fullname = dirname + Zstring(notifyInfo.FileName, notifyInfo.FileNameLength / sizeof(WCHAR)); + const Zstring fullpath = dirpath + Zstring(notifyInfo.FileName, notifyInfo.FileNameLength / sizeof(WCHAR)); [&] { @@ -57,7 +57,7 @@ public: if (notifyInfo.Action == FILE_ACTION_MODIFIED) { //note: this check will not work if top watched directory has been renamed - const DWORD ret = ::GetFileAttributes(applyLongPathPrefix(fullname).c_str()); + const DWORD ret = ::GetFileAttributes(applyLongPathPrefix(fullpath).c_str()); if (ret != INVALID_FILE_ATTRIBUTES && (ret & FILE_ATTRIBUTE_DIRECTORY)) //returns true for (dir-)symlinks also return; } @@ -67,14 +67,14 @@ public: { case FILE_ACTION_ADDED: case FILE_ACTION_RENAMED_NEW_NAME: //harmonize with "move" which is notified as "create + delete" - changedFiles.push_back(DirWatcher::Entry(DirWatcher::ACTION_CREATE, fullname)); + changedFiles.push_back(DirWatcher::Entry(DirWatcher::ACTION_CREATE, fullpath)); break; case FILE_ACTION_REMOVED: case FILE_ACTION_RENAMED_OLD_NAME: - changedFiles.push_back(DirWatcher::Entry(DirWatcher::ACTION_DELETE, fullname)); + changedFiles.push_back(DirWatcher::Entry(DirWatcher::ACTION_DELETE, fullpath)); break; case FILE_ACTION_MODIFIED: - changedFiles.push_back(DirWatcher::Entry(DirWatcher::ACTION_UPDATE, fullname)); + changedFiles.push_back(DirWatcher::Entry(DirWatcher::ACTION_UPDATE, fullpath)); break; } }(); @@ -87,10 +87,10 @@ public: } ////context of main thread - //void addChange(const Zstring& dirname) //throw () + //void addChange(const Zstring& dirpath) //throw () //{ // boost::lock_guard<boost::mutex> dummy(lockAccess); - // changedFiles.insert(dirname); + // changedFiles.insert(dirpath); //} @@ -144,10 +144,10 @@ public: ReadChangesAsync(const Zstring& directory, //make sure to not leak-in thread-unsafe types! const std::shared_ptr<SharedData>& shared) : shared_(shared), - dirnamePf(appendSeparator(directory)), + dirpathPf(appendSeparator(directory)), hDir(INVALID_HANDLE_VALUE) { - hDir = ::CreateFile(applyLongPathPrefix(dirnamePf).c_str(), //_In_ LPCTSTR lpFileName, + hDir = ::CreateFile(applyLongPathPrefix(dirpathPf).c_str(), //_In_ LPCTSTR lpFileName, FILE_LIST_DIRECTORY, //_In_ DWORD dwDesiredAccess, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, //_In_ DWORD dwShareMode, nullptr, //_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, @@ -165,7 +165,7 @@ public: hDir(INVALID_HANDLE_VALUE) { shared_ = std::move(other.shared_); - dirnamePf = std::move(other.dirnamePf); + dirpathPf = std::move(other.dirpathPf); std::swap(hDir, other.hDir); } @@ -194,7 +194,7 @@ public: if (overlapped.hEvent == nullptr) { 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); + return shared_->reportError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(dirpathPf)), formatSystemError(L"CreateEvent", lastError), lastError); } ZEN_ON_SCOPE_EXIT(::CloseHandle(overlapped.hEvent)); @@ -214,7 +214,7 @@ public: nullptr)) // __in_opt LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine { 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); + return shared_->reportError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(dirpathPf)), formatSystemError(L"ReadDirectoryChangesW", lastError), lastError); } //async I/O is a resource that needs to be guarded since it will write to local variable "buffer"! @@ -238,7 +238,7 @@ public: { 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); + return shared_->reportError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(dirpathPf)), formatSystemError(L"GetOverlappedResult", lastError), lastError); //execute asynchronous procedure calls (APC) queued on this thread ::SleepEx(50, // __in DWORD dwMilliseconds, @@ -248,7 +248,7 @@ public: } guardAio.dismiss(); - shared_->addChanges(&buffer[0], bytesWritten, dirnamePf); //throw () + shared_->addChanges(&buffer[0], bytesWritten, dirpathPf); //throw () } } catch (boost::thread_interrupted&) @@ -260,13 +260,13 @@ public: HANDLE getDirHandle() const { return hDir; } //for reading/monitoring purposes only, don't abuse (e.g. close handle)! private: - ReadChangesAsync(const ReadChangesAsync&); - ReadChangesAsync& operator=(const ReadChangesAsync&); + ReadChangesAsync (const ReadChangesAsync&) = delete; + ReadChangesAsync& operator=(const ReadChangesAsync&) = delete; //shared between main and worker: std::shared_ptr<SharedData> shared_; //worker thread only: - Zstring dirnamePf; //thread safe! + Zstring dirpathPf; //thread safe! HANDLE hDir; }; @@ -314,7 +314,7 @@ struct DirWatcher::Pimpl boost::thread worker; std::shared_ptr<SharedData> shared; - Zstring dirname; + Zstring dirpath; std::unique_ptr<HandleVolumeRemoval> volRemoval; }; @@ -323,7 +323,7 @@ DirWatcher::DirWatcher(const Zstring& directory) : //throw FileError pimpl_(new Pimpl) { pimpl_->shared = std::make_shared<SharedData>(); - pimpl_->dirname = directory; + pimpl_->dirpath = directory; ReadChangesAsync reader(directory, pimpl_->shared); //throw FileError pimpl_->volRemoval.reset(new HandleVolumeRemoval(reader.getDirHandle(), pimpl_->worker)); //throw FileError @@ -360,7 +360,7 @@ std::vector<DirWatcher::Entry> DirWatcher::getChanges(const std::function<void() boost::thread::sleep(boost::get_system_time() + boost::posix_time::milliseconds(50)); } - output.push_back(Entry(ACTION_DELETE, pimpl_->dirname)); //report removal as change to main directory + output.push_back(Entry(ACTION_DELETE, pimpl_->dirpath)); //report removal as change to main directory } else //the normal case... pimpl_->shared->fetchChanges(output); //throw FileError @@ -376,11 +376,11 @@ class DirsOnlyTraverser : public zen::TraverseCallback public: DirsOnlyTraverser(std::vector<Zstring>& dirs) : dirs_(dirs) {} - virtual void onFile (const Zchar* shortName, const Zstring& fullName, const FileInfo& details) {} - virtual HandleLink onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details) { return LINK_SKIP; } - virtual TraverseCallback* onDir(const Zchar* shortName, const Zstring& fullName) + virtual void onFile (const Zchar* shortName, const Zstring& filepath, const FileInfo& details) {} + virtual HandleLink onSymlink(const Zchar* shortName, const Zstring& linkpath, const SymlinkInfo& details) { return LINK_SKIP; } + virtual TraverseCallback* onDir(const Zchar* shortName, const Zstring& dirpath) { - dirs_.push_back(fullName); + dirs_.push_back(dirpath); return this; } virtual HandleError reportDirError (const std::wstring& msg, size_t retryNumber) { throw FileError(msg); } @@ -396,7 +396,7 @@ struct DirWatcher::Pimpl { Pimpl() : notifDescr() {} - Zstring baseDirname; + Zstring basedirpath; int notifDescr; std::map<int, Zstring> watchDescrs; //watch descriptor and (sub-)directory name (postfixed with separator) -> owned by "notifDescr" }; @@ -406,18 +406,18 @@ DirWatcher::DirWatcher(const Zstring& directory) : //throw FileError pimpl_(new Pimpl) { //get all subdirectories - Zstring dirname = directory; - if (endsWith(dirname, FILE_NAME_SEPARATOR)) - dirname.resize(dirname.size() - 1); + Zstring dirpathFmt = directory; + if (endsWith(dirpathFmt, FILE_NAME_SEPARATOR)) + dirpathFmt.resize(dirpathFmt.size() - 1); - std::vector<Zstring> fullDirList { dirname }; + std::vector<Zstring> fullDirList { dirpathFmt }; { DirsOnlyTraverser traverser(fullDirList); //throw FileError - zen::traverseFolder(dirname, traverser); //don't traverse into symlinks (analog to windows build) + zen::traverseFolder(dirpathFmt, traverser); //don't traverse into symlinks (analog to windows build) } //init - pimpl_->baseDirname = directory; + pimpl_->basedirpath = directory; pimpl_->notifDescr = ::inotify_init(); if (pimpl_->notifDescr == -1) throwFileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(directory)), L"inotify_init", getLastError()); @@ -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>(); - throwFileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(pimpl_->baseDirname)), L"read", getLastError()); + throwFileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(pimpl_->basedirpath)), L"read", getLastError()); } std::vector<Entry> output; @@ -573,18 +573,18 @@ struct DirWatcher::Pimpl DirWatcher::DirWatcher(const Zstring& directory) : pimpl_(new Pimpl) { - CFStringRef dirnameCf = osx::createCFString(directory.c_str()); //returns nullptr on error - if (!dirnameCf) + CFStringRef dirpathCf = osx::createCFString(directory.c_str()); //returns nullptr on error + if (!dirpathCf) throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(directory)), L"Function call failed: createCFString"); //no error code documented! - ZEN_ON_SCOPE_EXIT(::CFRelease(dirnameCf)); + ZEN_ON_SCOPE_EXIT(::CFRelease(dirpathCf)); - CFArrayRef dirnameCfArray = ::CFArrayCreate(nullptr, //CFAllocatorRef allocator, - reinterpret_cast<const void**>(&dirnameCf), //const void** values, + CFArrayRef dirpathCfArray = ::CFArrayCreate(nullptr, //CFAllocatorRef allocator, + reinterpret_cast<const void**>(&dirpathCf), //const void** values, 1, //CFIndex numValues, nullptr); //const CFArrayCallBacks* callBacks - if (!dirnameCfArray) + if (!dirpathCfArray) throw FileError(replaceCpy(_("Cannot monitor directory %x."), L"%x", fmtFileName(directory)), L"Function call failed: CFArrayCreate"); //no error code documented! - ZEN_ON_SCOPE_EXIT(::CFRelease(dirnameCfArray)); + ZEN_ON_SCOPE_EXIT(::CFRelease(dirpathCfArray)); FSEventStreamContext context = {}; context.info = &pimpl_->changedFiles; @@ -592,7 +592,7 @@ DirWatcher::DirWatcher(const Zstring& directory) : pimpl_->eventStream = ::FSEventStreamCreate(nullptr, //CFAllocatorRef allocator, &eventCallback, //FSEventStreamCallback callback, &context, //FSEventStreamContext* context, - dirnameCfArray, //CFArrayRef pathsToWatch, + dirpathCfArray, //CFArrayRef pathsToWatch, kFSEventStreamEventIdSinceNow, //FSEventStreamEventId sinceWhen, 0, //CFTimeInterval latency, in seconds kFSEventStreamCreateFlagWatchRoot | diff --git a/zen/dir_watcher.h b/zen/dir_watcher.h index bc9714a0..99131470 100644 --- a/zen/dir_watcher.h +++ b/zen/dir_watcher.h @@ -49,18 +49,18 @@ public: struct Entry { Entry() : action_(ACTION_CREATE) {} - Entry(ActionType action, const Zstring& filename) : action_(action), filename_(filename) {} + Entry(ActionType action, const Zstring& filepath) : action_(action), filepath_(filepath) {} ActionType action_; - Zstring filename_; + Zstring filepath_; }; //extract accumulated changes since last call std::vector<Entry> getChanges(const std::function<void()>& processGuiMessages); //throw FileError private: - DirWatcher(const DirWatcher&); - DirWatcher& operator=(const DirWatcher&); + DirWatcher (const DirWatcher&) = delete; + DirWatcher& operator=(const DirWatcher&) = delete; struct Pimpl; std::unique_ptr<Pimpl> pimpl_; diff --git a/zen/dst_hack.cpp b/zen/dst_hack.cpp index 95fbe732..52d45679 100644 --- a/zen/dst_hack.cpp +++ b/zen/dst_hack.cpp @@ -14,16 +14,16 @@ using namespace zen; namespace { //fast ::GetVolumePathName() clone: let's hope it's not too simple (doesn't honor mount points) -Zstring getVolumeName(const Zstring& filename) +Zstring getVolumeName(const Zstring& filepath) { //this call is expensive: ~1.5 ms! - // if (!::GetVolumePathName(filename.c_str(), //__in LPCTSTR lpszFileName, + // if (!::GetVolumePathName(filepath.c_str(), //__in LPCTSTR lpszFileName, // fsName, //__out LPTSTR lpszVolumePathName, // BUFFER_SIZE)) //__in DWORD cchBufferLength // ... // Zstring volumePath = appendSeparator(fsName); - const Zstring nameFmt = appendSeparator(removeLongPathPrefix(filename)); //throw() + const Zstring nameFmt = appendSeparator(removeLongPathPrefix(filepath)); //throw() if (startsWith(nameFmt, Zstr("\\\\"))) //UNC path: "\\ComputerName\SharedFolder\" { @@ -50,9 +50,9 @@ Zstring getVolumeName(const Zstring& filename) } -bool dst::isFatDrive(const Zstring& fileName) //throw() +bool dst::isFatDrive(const Zstring& filepath) //throw() { - const Zstring volumePath = getVolumeName(fileName); + const Zstring volumePath = getVolumeName(filepath); if (volumePath.empty()) return false; @@ -123,37 +123,34 @@ Requires Windows Vista! namespace { -//convert UInt64 and Int64 to FILETIME +//convert std::uint64_t and std::int64_t to FILETIME inline -FILETIME toFiletime(Int64 number) +FILETIME toFiletime(std::uint64_t number) { - const UInt64 unsig = to<UInt64>(number); + ULARGE_INTEGER cvt = {}; + cvt.QuadPart = number; - FILETIME output = {}; - output.dwLowDateTime = unsig.getLo(); - output.dwHighDateTime = unsig.getHi(); + const FILETIME output = { cvt.LowPart, cvt.HighPart }; return output; } -FILETIME toFiletime(UInt64 number) +inline +FILETIME toFiletime(std::int64_t number) { - FILETIME output = {}; - output.dwLowDateTime = number.getLo(); - output.dwHighDateTime = number.getHi(); - return output; + return toFiletime(static_cast<std::uint64_t>(number)); } inline -UInt64 toUInt64(const FILETIME& fileTime) +std::uint64_t toUInt64(const FILETIME& fileTime) { - return UInt64(fileTime.dwLowDateTime, fileTime.dwHighDateTime); + return get64BitUInt(fileTime.dwLowDateTime, fileTime.dwHighDateTime); } inline -Int64 toInt64(const FILETIME& fileTime) +std::int64_t toInt64(const FILETIME& fileTime) { - return to<Int64>(UInt64(fileTime.dwLowDateTime, fileTime.dwHighDateTime)); + return get64BitUInt(fileTime.dwLowDateTime, fileTime.dwHighDateTime); //convert unsigned to signed in return } @@ -216,7 +213,7 @@ const size_t WRITE_TIME_HASH_BITS = CREATE_TIME_INFO_BITS - INDICATOR_EXISTING_B template <size_t precision> inline -FILETIME encodeRawInformation(UInt64 rawInfo) +FILETIME encodeRawInformation(std::uint64_t rawInfo) { rawInfo *= precision; rawInfo += toUInt64(FAT_MIN_TIME); @@ -227,13 +224,13 @@ FILETIME encodeRawInformation(UInt64 rawInfo) template <size_t precision> inline -UInt64 extractRawInformation(const FILETIME& createTime) +std::uint64_t extractRawInformation(const FILETIME& createTime) { assert(toUInt64(FAT_MIN_TIME) <= toUInt64(createTime)); assert(toUInt64(createTime) <= toUInt64(FAT_MAX_TIME)); //FAT create time ranges from 1980 - 2107 (2^7 years) with 1/100 seconds precision - UInt64 rawInfo = toUInt64(createTime); + std::uint64_t rawInfo = toUInt64(createTime); rawInfo -= toUInt64(FAT_MIN_TIME); rawInfo /= precision; //reduce precision (FILETIME has unit 10^-7 s) @@ -245,9 +242,9 @@ UInt64 extractRawInformation(const FILETIME& createTime) //convert write time to it's minimal representation (no restriction to FAT range "1980 - 2107") inline -UInt64 extractRawWriteTime(const FILETIME& writeTime) +std::uint64_t extractRawWriteTime(const FILETIME& writeTime) { - UInt64 rawInfo = toUInt64(writeTime); + std::uint64_t rawInfo = toUInt64(writeTime); assert(rawInfo % PRECISION_WRITE_TIME == 0U); rawInfo /= PRECISION_WRITE_TIME; //reduce precision (FILETIME has unit 10^-7 s) return rawInfo; @@ -258,7 +255,7 @@ UInt64 extractRawWriteTime(const FILETIME& writeTime) inline FILETIME roundToFatWriteTime(const FILETIME& writeTime) { - UInt64 rawData = toUInt64(writeTime); + std::uint64_t rawData = toUInt64(writeTime); if (rawData % PRECISION_WRITE_TIME != 0U) rawData += PRECISION_WRITE_TIME; @@ -277,7 +274,7 @@ std::bitset<UTC_LOCAL_OFFSET_BITS> getUtcLocalShift() const FILETIME localTime = utcToLocal(utcTime); - const int timeShiftSec = to<int>((toInt64(localTime) - toInt64(utcTime)) / 10000000); //time shift in seconds + const int timeShiftSec = static_cast<int>((toInt64(localTime) - toInt64(utcTime)) / 10000000); //time shift in seconds const int timeShiftQuarter = timeShiftSec / (60 * 15); //time shift in quarter-hours @@ -311,7 +308,7 @@ int convertUtcLocalShift(std::bitset<UTC_LOCAL_OFFSET_BITS> rawShift) } -bool dst::fatHasUtcEncoded(const RawTime& rawTime) //"createTimeRaw" as retrieved by ::FindFirstFile() and ::GetFileAttributesEx(); throw (std::runtime_error) +bool dst::fatHasUtcEncoded(const RawTime& rawTime) //"createTimeRaw" as retrieved by ::FindFirstFile() and ::GetFileAttributesEx(); throw std::runtime_error { if (toUInt64(rawTime.createTimeRaw) < toUInt64(FAT_MIN_TIME) || toUInt64(FAT_MAX_TIME) < toUInt64(rawTime.createTimeRaw)) @@ -320,7 +317,7 @@ bool dst::fatHasUtcEncoded(const RawTime& rawTime) //"createTimeRaw" as retrieve return false; } - const UInt64 rawInfo = extractRawInformation<PRECISION_CREATE_TIME>(utcToLocal(rawTime.createTimeRaw)); + const std::uint64_t rawInfo = extractRawInformation<PRECISION_CREATE_TIME>(utcToLocal(rawTime.createTimeRaw)); assert_static(WRITE_TIME_HASH_BITS == 30); return (extractRawWriteTime(utcToLocal(rawTime.writeTimeRaw)) & 0x3FFFFFFFU) == (rawInfo & 0x3FFFFFFFU) && //ensure write time wasn't changed externally @@ -335,7 +332,7 @@ dst::RawTime dst::fatEncodeUtcTime(const FILETIME& writeTimeRealUtc) //throw std //create time lets us store 40 bit of information //indicator that utc time is encoded -> hopefully results in a date long way in the future; but even if this bit is accidentally set, we still have the hash! - UInt64 data = 1U; + std::uint64_t data = 1U; const std::bitset<UTC_LOCAL_OFFSET_BITS> utcShift = getUtcLocalShift(); data <<= UTC_LOCAL_OFFSET_BITS; @@ -358,14 +355,14 @@ FILETIME dst::fatDecodeUtcTime(const RawTime& rawTime) //return real UTC time; t if (!fatHasUtcEncoded(rawTime)) return rawTime.writeTimeRaw; - const UInt64 rawInfo = extractRawInformation<PRECISION_CREATE_TIME>(utcToLocal(rawTime.createTimeRaw)); + const std::uint64_t rawInfo = extractRawInformation<PRECISION_CREATE_TIME>(utcToLocal(rawTime.createTimeRaw)); - const std::bitset<UTC_LOCAL_OFFSET_BITS> rawShift(to<int>((rawInfo >> WRITE_TIME_HASH_BITS) & 0x7FU)); //static_cast<int>: a shame MSC... "unsigned long" should be supported instead! + const std::bitset<UTC_LOCAL_OFFSET_BITS> rawShift(static_cast<int>((rawInfo >> WRITE_TIME_HASH_BITS) & 0x7FU)); //static_cast<int>: a shame MSC... "unsigned long long" should be supported instead! assert_static(UTC_LOCAL_OFFSET_BITS == 7); - const int timeShiftSec = convertUtcLocalShift(rawShift); + const std::int64_t timeShiftSec = convertUtcLocalShift(rawShift); const FILETIME writeTimeLocal = utcToLocal(rawTime.writeTimeRaw); - const Int64 realUTC = toInt64(writeTimeLocal) - Int64(timeShiftSec) * 10000000; + const std::int64_t realUTC = toInt64(writeTimeLocal) - timeShiftSec * 10000000; return toFiletime(realUTC); } diff --git a/zen/file_error.h b/zen/file_error.h index cb5e3a7b..73cfa17a 100644 --- a/zen/file_error.h +++ b/zen/file_error.h @@ -55,11 +55,11 @@ std::wstring operator+(const std::wstring& lhs, const Zstring& rhs) { return std inline -std::wstring fmtFileName(const Zstring& filename) +std::wstring fmtFileName(const Zstring& filepath) { std::wstring output; output += L'\"'; - output += utfCvrtTo<std::wstring>(filename); + output += utfCvrtTo<std::wstring>(filepath); output += L'\"'; return output; } diff --git a/zen/file_handling.cpp b/zen/file_handling.cpp index cecebff1..b4622a9c 100644 --- a/zen/file_handling.cpp +++ b/zen/file_handling.cpp @@ -8,13 +8,13 @@ #include <map> #include <algorithm> #include <stdexcept> +#include "int64.h" #include "file_traverser.h" #include "scope_guard.h" #include "symlink_target.h" #include "file_io.h" #include "assert_static.h" #include "file_id_def.h" -//#include <boost/thread/tss.hpp> #ifdef ZEN_WIN #include <Aclapi.h> @@ -35,7 +35,6 @@ #elif defined ZEN_MAC #include <sys/mount.h> //statfs -//#include <utime.h> #endif #if defined ZEN_LINUX || defined ZEN_MAC @@ -46,34 +45,34 @@ using namespace zen; -bool zen::fileExists(const Zstring& filename) +bool zen::fileExists(const Zstring& filepath) { //symbolic links (broken or not) are also treated as existing files! #ifdef ZEN_WIN - const DWORD attr = ::GetFileAttributes(applyLongPathPrefix(filename).c_str()); + const DWORD attr = ::GetFileAttributes(applyLongPathPrefix(filepath).c_str()); if (attr != INVALID_FILE_ATTRIBUTES) return (attr & FILE_ATTRIBUTE_DIRECTORY) == 0; //returns true for (file-)symlinks also #elif defined ZEN_LINUX || defined ZEN_MAC struct ::stat fileInfo = {}; - if (::stat(filename.c_str(), &fileInfo) == 0) //follow symlinks! + if (::stat(filepath.c_str(), &fileInfo) == 0) //follow symlinks! return S_ISREG(fileInfo.st_mode); #endif return false; } -bool zen::dirExists(const Zstring& dirname) +bool zen::dirExists(const Zstring& dirpath) { //symbolic links (broken or not) are also treated as existing directories! #ifdef ZEN_WIN - const DWORD attr = ::GetFileAttributes(applyLongPathPrefix(dirname).c_str()); + const DWORD attr = ::GetFileAttributes(applyLongPathPrefix(dirpath).c_str()); if (attr != INVALID_FILE_ATTRIBUTES) return (attr & FILE_ATTRIBUTE_DIRECTORY) != 0; //returns true for (dir-)symlinks also #elif defined ZEN_LINUX || defined ZEN_MAC struct ::stat dirInfo = {}; - if (::stat(dirname.c_str(), &dirInfo) == 0) //follow symlinks! + if (::stat(dirpath.c_str(), &dirInfo) == 0) //follow symlinks! return S_ISDIR(dirInfo.st_mode); #endif return false; @@ -137,7 +136,7 @@ namespace { #ifdef ZEN_WIN //(try to) enhance error messages by showing which processes lock the file -Zstring getLockingProcessNames(const Zstring& filename) //throw(), empty string if none found or error occurred +Zstring getLockingProcessNames(const Zstring& filepath) //throw(), empty string if none found or error occurred { if (vistaOrLater()) { @@ -146,7 +145,7 @@ Zstring getLockingProcessNames(const Zstring& filename) //throw(), empty string const DllFun<FunType_freeString> freeString (getDllName(), funName_freeString); if (getLockingProcesses && freeString) - if (const wchar_t* procList = getLockingProcesses(filename.c_str())) + if (const wchar_t* procList = getLockingProcesses(filepath.c_str())) { ZEN_ON_SCOPE_EXIT(freeString(procList)); return procList; @@ -158,14 +157,14 @@ Zstring getLockingProcessNames(const Zstring& filename) //throw(), empty string } -UInt64 zen::getFilesize(const Zstring& filename) //throw FileError +std::uint64_t zen::getFilesize(const Zstring& filepath) //throw FileError { #ifdef ZEN_WIN WIN32_FIND_DATA fileInfo = {}; { - const HANDLE searchHandle = ::FindFirstFile(applyLongPathPrefix(filename).c_str(), &fileInfo); + const HANDLE searchHandle = ::FindFirstFile(applyLongPathPrefix(filepath).c_str(), &fileInfo); if (searchHandle == INVALID_HANDLE_VALUE) - throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)), L"FindFirstFile", getLastError()); + throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filepath)), L"FindFirstFile", getLastError()); ::FindClose(searchHandle); } // WIN32_FILE_ATTRIBUTE_DATA sourceAttr = {}; @@ -174,11 +173,11 @@ UInt64 zen::getFilesize(const Zstring& filename) //throw FileError // &sourceAttr)) //__out LPVOID lpFileInformation if (!isSymlink(fileInfo)) - return UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh); + return get64BitUInt(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh); else { //open handle to target of symbolic link - const HANDLE hFile = ::CreateFile(applyLongPathPrefix(filename).c_str(), //_In_ LPCTSTR lpFileName, + const HANDLE hFile = ::CreateFile(applyLongPathPrefix(filepath).c_str(), //_In_ LPCTSTR lpFileName, 0, //_In_ DWORD dwDesiredAccess, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, //_In_ DWORD dwShareMode, nullptr, //_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, @@ -186,27 +185,27 @@ 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) - throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)), L"CreateFile", getLastError()); + throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filepath)), L"CreateFile", getLastError()); ZEN_ON_SCOPE_EXIT(::CloseHandle(hFile)); BY_HANDLE_FILE_INFORMATION fileInfoHnd = {}; if (!::GetFileInformationByHandle(hFile, &fileInfoHnd)) - throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)), L"GetFileInformationByHandle", getLastError()); + throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filepath)), L"GetFileInformationByHandle", getLastError()); - return UInt64(fileInfoHnd.nFileSizeLow, fileInfoHnd.nFileSizeHigh); + return get64BitUInt(fileInfoHnd.nFileSizeLow, fileInfoHnd.nFileSizeHigh); } #elif defined ZEN_LINUX || defined ZEN_MAC struct ::stat fileInfo = {}; - if (::stat(filename.c_str(), &fileInfo) != 0) - throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)), L"stat", getLastError()); + if (::stat(filepath.c_str(), &fileInfo) != 0) + throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filepath)), L"stat", getLastError()); - return UInt64(fileInfo.st_size); + return fileInfo.st_size; #endif } -UInt64 zen::getFreeDiskSpace(const Zstring& path) //throw FileError +std::uint64_t zen::getFreeDiskSpace(const Zstring& path) //throw FileError { #ifdef ZEN_WIN ULARGE_INTEGER bytesFree = {}; @@ -216,52 +215,52 @@ UInt64 zen::getFreeDiskSpace(const Zstring& path) //throw FileError nullptr)) //__out_opt PULARGE_INTEGER lpTotalNumberOfFreeBytes throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(path)), L"GetDiskFreeSpaceEx", getLastError()); - return UInt64(bytesFree.LowPart, bytesFree.HighPart); + return get64BitUInt(bytesFree.LowPart, bytesFree.HighPart); #elif defined ZEN_LINUX || defined ZEN_MAC struct statfs info = {}; if (::statfs(path.c_str(), &info) != 0) throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(path)), L"statfs", getLastError()); - return UInt64(info.f_bsize) * info.f_bavail; + return static_cast<std::uint64_t>(info.f_bsize) * info.f_bavail; #endif } -bool zen::removeFile(const Zstring& filename) //throw FileError +bool zen::removeFile(const Zstring& filepath) //throw FileError { #ifdef ZEN_WIN const wchar_t functionName[] = L"DeleteFile"; - const Zstring& filenameFmt = applyLongPathPrefix(filename); - if (!::DeleteFile(filenameFmt.c_str())) + const Zstring& filepathFmt = applyLongPathPrefix(filepath); + if (!::DeleteFile(filepathFmt.c_str())) #elif defined ZEN_LINUX || defined ZEN_MAC const wchar_t functionName[] = L"unlink"; - if (::unlink(filename.c_str()) != 0) + if (::unlink(filepath.c_str()) != 0) #endif { ErrorCode lastError = getLastError(); #ifdef ZEN_WIN if (lastError == ERROR_ACCESS_DENIED) //function fails if file is read-only { - ::SetFileAttributes(filenameFmt.c_str(), FILE_ATTRIBUTE_NORMAL); //(try to) normalize file attributes + ::SetFileAttributes(filepathFmt.c_str(), FILE_ATTRIBUTE_NORMAL); //(try to) normalize file attributes - if (::DeleteFile(filenameFmt.c_str())) //now try again... + if (::DeleteFile(filepathFmt.c_str())) //now try again... return true; lastError = ::GetLastError(); } #endif - if (!somethingExists(filename)) //warning: changes global error code!! + if (!somethingExists(filepath)) //warning: changes global error code!! return false; //neither file nor any other object (e.g. broken symlink) with that name existing - caveat: what if "access is denied"!?!??!?!? //begin of "regular" error reporting - const std::wstring errorMsg = replaceCpy(_("Cannot delete file %x."), L"%x", fmtFileName(filename)); + const std::wstring errorMsg = replaceCpy(_("Cannot delete file %x."), L"%x", fmtFileName(filepath)); std::wstring errorDescr = formatSystemError(functionName, lastError); #ifdef ZEN_WIN if (lastError == ERROR_SHARING_VIOLATION || //-> enhance error message! lastError == ERROR_LOCK_VIOLATION) { - const Zstring procList = getLockingProcessNames(filename); //throw() + const Zstring procList = getLockingProcessNames(filepath); //throw() if (!procList.empty()) errorDescr = _("The file is locked by another process:") + L"\n" + procList; } @@ -364,17 +363,17 @@ void renameFile_sub(const Zstring& oldName, const Zstring& newName) //throw File ::GetShortPathName() ::GetLongPathName() */ template <typename Function> -Zstring getFilenameFmt(const Zstring& filename, Function fun) //throw(); returns empty string on error +Zstring getFilenameFmt(const Zstring& filepath, Function fun) //throw(); returns empty string on error { - const Zstring filenameFmt = applyLongPathPrefix(filename); + const Zstring filepathFmt = applyLongPathPrefix(filepath); - const DWORD bufferSize = fun(filenameFmt.c_str(), nullptr, 0); + const DWORD bufferSize = fun(filepathFmt.c_str(), nullptr, 0); if (bufferSize == 0) return Zstring(); std::vector<wchar_t> buffer(bufferSize); - const DWORD charsWritten = fun(filenameFmt.c_str(), //__in LPCTSTR lpszShortPath, + const DWORD charsWritten = fun(filepathFmt.c_str(), //__in LPCTSTR lpszShortPath, &buffer[0], //__out LPTSTR lpszLongPath, bufferSize); //__in DWORD cchBuffer if (charsWritten == 0 || charsWritten >= bufferSize) @@ -384,18 +383,18 @@ Zstring getFilenameFmt(const Zstring& filename, Function fun) //throw(); returns } -Zstring findUnused8Dot3Name(const Zstring& filename) //find a unique 8.3 short name +Zstring findUnused8Dot3Name(const Zstring& filepath) //find a unique 8.3 short name { - const Zstring pathPrefix = contains(filename, FILE_NAME_SEPARATOR) ? - (beforeLast(filename, FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR) : Zstring(); + const Zstring pathPrefix = contains(filepath, FILE_NAME_SEPARATOR) ? + (beforeLast(filepath, FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR) : Zstring(); - Zstring extension = afterLast(afterLast(filename, FILE_NAME_SEPARATOR), Zchar('.')); //extension needn't contain reasonable data + Zstring extension = afterLast(afterLast(filepath, FILE_NAME_SEPARATOR), Zchar('.')); //extension needn't contain reasonable data if (extension.empty()) extension = Zstr("FFS"); else if (extension.length() > 3) extension.resize(3); - for (int index = 0; index < 100000000; ++index) //filename must be representable by <= 8 characters + for (int index = 0; index < 100000000; ++index) //filepath must be representable by <= 8 characters { const Zstring output = pathPrefix + numberTo<Zstring>(index) + Zchar('.') + extension; if (!somethingExists(output)) //ensure uniqueness @@ -405,24 +404,24 @@ Zstring findUnused8Dot3Name(const Zstring& filename) //find a unique 8.3 short n } -bool have8dot3NameClash(const Zstring& filename) +bool have8dot3NameClash(const Zstring& filepath) { - if (!contains(filename, FILE_NAME_SEPARATOR)) + if (!contains(filepath, FILE_NAME_SEPARATOR)) return false; - if (somethingExists(filename)) //name OR directory! + if (somethingExists(filepath)) //name OR directory! { - const Zstring origName = afterLast(filename, FILE_NAME_SEPARATOR); //returns the whole string if ch not found - const Zstring shortName = afterLast(getFilenameFmt(filename, ::GetShortPathName), FILE_NAME_SEPARATOR); //throw() returns empty string on error - const Zstring longName = afterLast(getFilenameFmt(filename, ::GetLongPathName ), FILE_NAME_SEPARATOR); // + const Zstring origName = afterLast(filepath, FILE_NAME_SEPARATOR); //returns the whole string if ch not found + const Zstring shortName = afterLast(getFilenameFmt(filepath, ::GetShortPathName), FILE_NAME_SEPARATOR); //throw() returns empty string on error + const Zstring longName = afterLast(getFilenameFmt(filepath, ::GetLongPathName ), FILE_NAME_SEPARATOR); // if (!shortName.empty() && !longName .empty() && EqualFilename()(origName, shortName) && !EqualFilename()(shortName, longName)) { - //for filename short and long file name are equal and another unrelated file happens to have the same short name - //e.g. filename == "TESTWE~1", but another file is existing named "TestWeb" with short name ""TESTWE~1" + //for filepath short and long file name are equal and another unrelated file happens to have the same short name + //e.g. filepath == "TESTWE~1", but another file is existing named "TestWeb" with short name ""TESTWE~1" return true; } } @@ -432,14 +431,14 @@ bool have8dot3NameClash(const Zstring& filename) class Fix8Dot3NameClash //throw FileError { public: - Fix8Dot3NameClash(const Zstring& filename) + Fix8Dot3NameClash(const Zstring& filepath) { - const Zstring longName = afterLast(getFilenameFmt(filename, ::GetLongPathName), FILE_NAME_SEPARATOR); //throw() returns empty string on error + const Zstring longName = afterLast(getFilenameFmt(filepath, ::GetLongPathName), FILE_NAME_SEPARATOR); //throw() returns empty string on error - unrelatedFile = beforeLast(filename, FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + longName; + unrelatedFile = beforeLast(filepath, FILE_NAME_SEPARATOR) + FILE_NAME_SEPARATOR + longName; //find another name in short format: this ensures the actual short name WILL be renamed as well! - unrelatedFileParked = findUnused8Dot3Name(filename); + unrelatedFileParked = findUnused8Dot3Name(filepath); //move already existing short name out of the way for now renameFile_sub(unrelatedFile, unrelatedFileParked); //throw FileError, ErrorDifferentVolume @@ -476,7 +475,7 @@ void zen::renameFile(const Zstring& oldName, const Zstring& newName) //throw Fil //try to handle issues with already existing short 8.3 file names on Windows if (have8dot3NameClash(newName)) { - Fix8Dot3NameClash dummy(newName); //throw FileError; move clashing filename to the side + Fix8Dot3NameClash dummy(newName); //throw FileError; move clashing filepath to the side //now try again... renameFile_sub(oldName, newName); //throw FileError return; @@ -496,29 +495,29 @@ public: files_(files), dirs_(dirs) {} - virtual void onFile(const Zchar* shortName, const Zstring& fullName, const FileInfo& details) + virtual void onFile(const Zchar* shortName, const Zstring& filepath, const FileInfo& details) { - files_.push_back(fullName); + files_.push_back(filepath); } - virtual HandleLink onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details) + virtual HandleLink onSymlink(const Zchar* shortName, const Zstring& linkpath, const SymlinkInfo& details) { - if (dirExists(fullName)) //dir symlink + if (dirExists(linkpath)) //dir symlink dirs_.push_back(shortName); else //file symlink, broken symlink files_.push_back(shortName); return LINK_SKIP; } - virtual TraverseCallback* onDir(const Zchar* shortName, const Zstring& fullName) + virtual TraverseCallback* onDir(const Zchar* shortName, const Zstring& dirpath) { - dirs_.push_back(fullName); + dirs_.push_back(dirpath); return nullptr; //DON'T traverse into subdirs; removeDirectory works recursively! } virtual HandleError reportDirError (const std::wstring& msg, size_t retryNumber) { throw FileError(msg); } virtual HandleError reportItemError(const std::wstring& msg, size_t retryNumber, const Zchar* shortName) { throw FileError(msg); } private: - CollectFilesFlat(const CollectFilesFlat&); - CollectFilesFlat& operator=(const CollectFilesFlat&); + CollectFilesFlat (const CollectFilesFlat&) = delete; + CollectFilesFlat& operator=(const CollectFilesFlat&) = delete; std::vector<Zstring>& files_; std::vector<Zstring>& dirs_; @@ -526,8 +525,8 @@ private: void removeDirectoryImpl(const Zstring& directory, //throw FileError - const std::function<void (const Zstring& filename)>& onBeforeFileDeletion, - const std::function<void (const Zstring& dirname)>& onBeforeDirDeletion) + const std::function<void (const Zstring& filepath)>& onBeforeFileDeletion, + const std::function<void (const Zstring& dirpath)>& onBeforeDirDeletion) { assert(somethingExists(directory)); //[!] @@ -563,15 +562,15 @@ void removeDirectoryImpl(const Zstring& directory, //throw FileError } //delete directories recursively - for (const Zstring& dirname : dirList) - removeDirectoryImpl(dirname, onBeforeFileDeletion, onBeforeDirDeletion); //throw FileError; call recursively to correctly handle symbolic links + for (const Zstring& dirpath : dirList) + removeDirectoryImpl(dirpath, onBeforeFileDeletion, onBeforeDirDeletion); //throw FileError; call recursively to correctly handle symbolic links //delete files - for (const Zstring& filename : fileList) + for (const Zstring& filepath : fileList) { if (onBeforeFileDeletion) - onBeforeFileDeletion(filename); //call once per file - removeFile(filename); //throw FileError + onBeforeFileDeletion(filepath); //call once per file + removeFile(filepath); //throw FileError } //parent directory is deleted last @@ -594,7 +593,7 @@ void removeDirectoryImpl(const Zstring& directory, //throw FileError #ifdef ZEN_WIN -void setFileTimeRaw(const Zstring& filename, const FILETIME& creationTime, const FILETIME& lastWriteTime, ProcSymlink procSl) //throw FileError +void setFileTimeRaw(const Zstring& filepath, const FILETIME& creationTime, const FILETIME& lastWriteTime, ProcSymlink procSl) //throw FileError { { //extra scope for debug check below @@ -623,21 +622,21 @@ void setFileTimeRaw(const Zstring& filename, const FILETIME& creationTime, const DWORD attribs = INVALID_FILE_ATTRIBUTES; ZEN_ON_SCOPE_EXIT( if (attribs != INVALID_FILE_ATTRIBUTES) - ::SetFileAttributes(applyLongPathPrefix(filename).c_str(), attribs); + ::SetFileAttributes(applyLongPathPrefix(filepath).c_str(), attribs); ); auto removeReadonly = [&]() -> bool //throw FileError; may need to remove the readonly-attribute (e.g. on FAT usb drives) { if (attribs == INVALID_FILE_ATTRIBUTES) { - const DWORD tmpAttr = ::GetFileAttributes(applyLongPathPrefix(filename).c_str()); + const DWORD tmpAttr = ::GetFileAttributes(applyLongPathPrefix(filepath).c_str()); if (tmpAttr == INVALID_FILE_ATTRIBUTES) - throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filename)), L"GetFileAttributes", getLastError()); + throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(filepath)), L"GetFileAttributes", getLastError()); if (tmpAttr & FILE_ATTRIBUTE_READONLY) { - if (!::SetFileAttributes(applyLongPathPrefix(filename).c_str(), FILE_ATTRIBUTE_NORMAL)) - throwFileError(replaceCpy(_("Cannot write file attributes of %x."), L"%x", fmtFileName(filename)), L"SetFileAttributes", getLastError()); + if (!::SetFileAttributes(applyLongPathPrefix(filepath).c_str(), FILE_ATTRIBUTE_NORMAL)) + throwFileError(replaceCpy(_("Cannot write file attributes of %x."), L"%x", fmtFileName(filepath)), L"SetFileAttributes", getLastError()); attribs = tmpAttr; //reapplied on scope exit return true; @@ -648,7 +647,7 @@ void setFileTimeRaw(const Zstring& filename, const FILETIME& creationTime, const auto openFile = [&](bool conservativeApproach) { - return ::CreateFile(applyLongPathPrefix(filename).c_str(), //_In_ LPCTSTR lpFileName, + return ::CreateFile(applyLongPathPrefix(filepath).c_str(), //_In_ LPCTSTR lpFileName, (conservativeApproach ? //some NAS seem to have issues with FILE_WRITE_ATTRIBUTES, even worse, they may fail silently! //http://sourceforge.net/tracker/?func=detail&atid=1093081&aid=3536680&group_id=234430 @@ -687,7 +686,7 @@ void setFileTimeRaw(const Zstring& filename, const FILETIME& creationTime, const continue; //3. after these herculean stunts we give up... - throwFileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filename)), L"CreateFile", lastError); + throwFileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filepath)), L"CreateFile", lastError); } } break; @@ -719,7 +718,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 - throwFileError(replaceCpy(_("Cannot write file attributes of %x."), L"%x", fmtFileName(filename)), L"SetFileInformationByHandle", getLastError()); + throwFileError(replaceCpy(_("Cannot write file attributes of %x."), L"%x", fmtFileName(filepath)), L"SetFileInformationByHandle", getLastError()); }; auto toLargeInteger = [](const FILETIME& ft) -> LARGE_INTEGER @@ -757,11 +756,11 @@ void setFileTimeRaw(const Zstring& filename, const FILETIME& creationTime, const } } - std::wstring errorMsg = replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filename)); + std::wstring errorMsg = replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filepath)); //add more meaningful message: FAT accepts only a subset of the NTFS date range if (lastError == ERROR_INVALID_PARAMETER && - dst::isFatDrive(filename)) + dst::isFatDrive(filepath)) { //we need a low-level reliable routine to format a potentially invalid date => don't use strftime!!! auto fmtDate = [](const FILETIME& ft) -> Zstring @@ -813,7 +812,7 @@ void setFileTimeRaw(const Zstring& filename, const FILETIME& creationTime, const FILETIME creationTimeDbg = {}; FILETIME lastWriteTimeDbg = {}; - HANDLE hFile = ::CreateFile(applyLongPathPrefix(filename).c_str(), //_In_ LPCTSTR lpFileName, + HANDLE hFile = ::CreateFile(applyLongPathPrefix(filepath).c_str(), //_In_ LPCTSTR lpFileName, FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, //_In_ DWORD dwDesiredAccess, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, //_In_ DWORD dwShareMode, nullptr, //_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, @@ -829,8 +828,8 @@ void setFileTimeRaw(const Zstring& filename, const FILETIME& creationTime, const nullptr, &lastWriteTimeDbg)); - assert(::CompareFileTime(&creationTimeDbg, &creationTime) == 0); - assert(::CompareFileTime(&lastWriteTimeDbg, &lastWriteTime) == 0); + assert(std::abs(filetimeToTimeT(creationTimeDbg ) - filetimeToTimeT(creationTime )) <= 2); //respect 2 second FAT/FAT32 precision + assert(std::abs(filetimeToTimeT(lastWriteTimeDbg) - filetimeToTimeT(lastWriteTime)) <= 2); // #endif } #endif @@ -838,8 +837,8 @@ void setFileTimeRaw(const Zstring& filename, const FILETIME& creationTime, const void zen::removeDirectory(const Zstring& directory, //throw FileError - const std::function<void (const Zstring& filename)>& onBeforeFileDeletion, - const std::function<void (const Zstring& dirname)>& onBeforeDirDeletion) + const std::function<void (const Zstring& filepath)>& onBeforeFileDeletion, + const std::function<void (const Zstring& dirpath)>& onBeforeDirDeletion) { //no error situation if directory is not existing! manual deletion relies on it! if (!somethingExists(directory)) @@ -848,22 +847,25 @@ void zen::removeDirectory(const Zstring& directory, //throw FileError } -void zen::setFileTime(const Zstring& filename, const Int64& modTime, ProcSymlink procSl) //throw FileError +void zen::setFileTime(const Zstring& filepath, std::int64_t modTime, ProcSymlink procSl) //throw FileError { #ifdef ZEN_WIN FILETIME creationTime = {}; - FILETIME lastWriteTime = toFileTime(modTime); + FILETIME lastWriteTime = timetToFileTime(modTime); //####################################### DST hack ########################################### - if (dst::isFatDrive(filename)) //throw(); hacky: does not consider symlinks pointing to FAT! + warn_static("let's tentatively disable the DST hack:") +#if 0 + if (dst::isFatDrive(filepath)) //throw(); hacky: does not consider symlinks pointing to FAT! { const dst::RawTime encodedTime = dst::fatEncodeUtcTime(lastWriteTime); //throw std::runtime_error creationTime = encodedTime.createTimeRaw; lastWriteTime = encodedTime.writeTimeRaw; } +#endif //####################################### DST hack ########################################### - setFileTimeRaw(filename, creationTime, lastWriteTime, procSl); //throw FileError + setFileTimeRaw(filepath, creationTime, lastWriteTime, procSl); //throw FileError #elif defined ZEN_LINUX || defined ZEN_MAC //sigh, we can't use utimensat on NTFS volumes on Ubuntu: silent failure!!! what morons are programming this shit??? @@ -872,35 +874,35 @@ void zen::setFileTime(const Zstring& filename, const Int64& modTime, ProcSymlink // newTimes[0].tv_nsec = UTIME_OMIT; //omit access time // 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) - // throwFileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filename)), L"utimensat", getLastError()); + // if (::utimensat(AT_FDCWD, filepath.c_str(), newTimes, procSl == SYMLINK_DIRECT ? AT_SYMLINK_NOFOLLOW : 0) != 0) + // throwFileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filepath)), 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[1].tv_sec = to<time_t>(modTime); //modification time (seconds) + newTimes[0].tv_sec = ::time(nullptr); //access time (seconds) + newTimes[1].tv_sec = modTime; //modification time (seconds) const int rv = procSl == ProcSymlink::FOLLOW ? - :: utimes(filename.c_str(), newTimes) : - ::lutimes(filename.c_str(), newTimes); + :: utimes(filepath.c_str(), newTimes) : + ::lutimes(filepath.c_str(), newTimes); if (rv != 0) - throwFileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filename)), L"utimes", getLastError()); + throwFileError(replaceCpy(_("Cannot write modification time of %x."), L"%x", fmtFileName(filepath)), L"utimes", getLastError()); #endif } -bool zen::supportsPermissions(const Zstring& dirname) //throw FileError +bool zen::supportsPermissions(const Zstring& dirpath) //throw FileError { #ifdef ZEN_WIN const DWORD bufferSize = MAX_PATH + 1; std::vector<wchar_t> buffer(bufferSize); - if (!::GetVolumePathName(dirname.c_str(), //__in LPCTSTR lpszFileName, + if (!::GetVolumePathName(dirpath.c_str(), //__in LPCTSTR lpszFileName, &buffer[0], //__out LPTSTR lpszVolumePathName, bufferSize)) //__in DWORD cchBufferLength - throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(dirname)), L"GetVolumePathName", getLastError()); + throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(dirpath)), L"GetVolumePathName", getLastError()); DWORD fsFlags = 0; if (!::GetVolumeInformation(&buffer[0], //__in_opt LPCTSTR lpRootPathName, @@ -911,7 +913,7 @@ bool zen::supportsPermissions(const Zstring& dirname) //throw FileError &fsFlags, //__out_opt LPDWORD lpFileSystemFlags, nullptr, //__out LPTSTR lpFileSystemNameBuffer, 0)) //__in DWORD nFileSystemNameSize - throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(dirname)), L"GetVolumeInformation", getLastError()); + throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(dirpath)), L"GetVolumeInformation", getLastError()); return (fsFlags & FILE_PERSISTENT_ACLS) != 0; @@ -1431,7 +1433,7 @@ void zen::copySymlink(const Zstring& sourceLink, const Zstring& targetLink, bool if (::lstat(sourceLink.c_str(), &srcInfo) != 0) 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 + setFileTime(targetLink, srcInfo.st_mtime, ProcSymlink::DIRECT); //throw FileError #endif if (copyFilePermissions) @@ -1545,7 +1547,7 @@ bool canCopyAsSparse(const Zstring& sourceFile, const Zstring& targetFile) //thr //precondition: canCopyAsSparse() must return "true"! void copyFileWindowsSparse(const Zstring& sourceFile, const Zstring& targetFile, - const std::function<void(Int64 bytesDelta)>& onUpdateCopyStatus, + const std::function<void(std::int64_t bytesDelta)>& onUpdateCopyStatus, InSyncAttributes* newAttrib) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked { assert(canCopyAsSparse(sourceFile, targetFile)); @@ -1641,10 +1643,10 @@ void copyFileWindowsSparse(const Zstring& sourceFile, //return up-to-date file attributes if (newAttrib) { - newAttrib->fileSize = UInt64(fileInfoSource.nFileSizeLow, fileInfoSource.nFileSizeHigh); - newAttrib->modificationTime = toTimeT(fileInfoSource.ftLastWriteTime); //no DST hack (yet) - newAttrib->sourceFileId = extractFileID(fileInfoSource); - newAttrib->targetFileId = extractFileID(fileInfoTarget); + newAttrib->fileSize = get64BitUInt(fileInfoSource.nFileSizeLow, fileInfoSource.nFileSizeHigh); + newAttrib->modificationTime = filetimeToTimeT(fileInfoSource.ftLastWriteTime); //no DST hack (yet) + newAttrib->sourceFileId = extractFileId(fileInfoSource); + newAttrib->targetFileId = extractFileId(fileInfoTarget); } //#################### copy NTFS compressed attribute ######################### @@ -1737,7 +1739,7 @@ void copyFileWindowsSparse(const Zstring& sourceFile, //invoke callback method to update progress indicators if (onUpdateCopyStatus) - onUpdateCopyStatus(Int64(bytesRead)); //throw X! + onUpdateCopyStatus(bytesRead); //throw X! if (bytesRead > 0) someBytesWritten = true; @@ -1747,7 +1749,7 @@ void copyFileWindowsSparse(const Zstring& sourceFile, //DST hack not required, since both source and target volumes cannot be FAT! //::BackupRead() silently fails reading encrypted files -> double check! - if (!someBytesWritten && UInt64(fileInfoSource.nFileSizeLow, fileInfoSource.nFileSizeHigh) != 0U) + if (!someBytesWritten && get64BitUInt(fileInfoSource.nFileSizeLow, fileInfoSource.nFileSizeHigh) != 0U) //note: there is no guaranteed ordering relation beween bytes transferred and file size! Consider ADS (>) and compressed/sparse files (<)! throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtFileName(sourceFile)), L"unknown error"); //user should never see this -> this method is called only if "canCopyAsSparse()" @@ -1804,7 +1806,7 @@ public: //call context: copyCallbackInternal() void reportErrorShouldCopyAsSparse() { shouldCopyAsSparse = true; } - void reportUserException(const std::function<void(Int64 bytesDelta)>& onUpdateCopyStatus) { exceptionInUserCallback = onUpdateCopyStatus; } + void reportUserException(const std::function<void(std::int64_t bytesDelta)>& onUpdateCopyStatus) { exceptionInUserCallback = onUpdateCopyStatus; } void reportError(const std::wstring& msg, const std::wstring& description) { errorMsg = std::make_pair(msg, description); } @@ -1827,30 +1829,31 @@ public: private: bool shouldCopyAsSparse; // std::pair<std::wstring, std::wstring> errorMsg; //these are exclusive! - std::function<void(Int64 bytesDelta)> exceptionInUserCallback; // -> optional + std::function<void(std::int64_t bytesDelta)> exceptionInUserCallback; // -> optional }; struct CallbackData { - CallbackData(const std::function<void(Int64 bytesDelta)>& onUpdateCopyStatus, + CallbackData(const std::function<void(std::int64_t bytesDelta)>& onUpdateCopyStatus, const Zstring& sourceFile, const Zstring& targetFile) : sourceFile_(sourceFile), targetFile_(targetFile), onUpdateCopyStatus_(onUpdateCopyStatus), fileInfoSrc(), - fileInfoTrg() {} + fileInfoTrg(), + bytesReported() {} const Zstring& sourceFile_; const Zstring& targetFile_; - const std::function<void(Int64 bytesDelta)>& onUpdateCopyStatus_; + const std::function<void(std::int64_t bytesDelta)>& onUpdateCopyStatus_; ErrorHandling errorHandler; BY_HANDLE_FILE_INFORMATION fileInfoSrc; //modified by CopyFileEx() at beginning BY_HANDLE_FILE_INFORMATION fileInfoTrg; // - Int64 bytesReported; //used internally to calculate bytes transferred delta + std::int64_t bytesReported; //used internally to calculate bytes transferred delta }; @@ -1962,7 +1965,7 @@ const bool supportNonEncryptedDestination = winXpOrLater(); //encrypted destinat void copyFileWindowsDefault(const Zstring& sourceFile, const Zstring& targetFile, - const std::function<void(Int64 bytesDelta)>& onUpdateCopyStatus, + const std::function<void(std::int64_t bytesDelta)>& onUpdateCopyStatus, InSyncAttributes* newAttrib) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked, ErrorShouldCopyAsSparse { //try to get backup read and write privileges: who knows, maybe this helps solve some obscure "access denied" errors @@ -2039,10 +2042,10 @@ void copyFileWindowsDefault(const Zstring& sourceFile, //trying to copy > 4GB file to FAT/FAT32 volume gives obscure ERROR_INVALID_PARAMETER (FAT can indeed handle files up to 4 Gig, tested!) if (lastError == ERROR_INVALID_PARAMETER && dst::isFatDrive(targetFile) && - getFilesize(sourceFile) >= 4U * UInt64(1024U * 1024 * 1024)) //throw FileError + getFilesize(sourceFile) >= 4U * std::uint64_t(1024U * 1024 * 1024)) //throw FileError errorDescr += L"\nFAT volumes cannot store files larger than 4 gigabyte."; - //note: ERROR_INVALID_PARAMETER can also occur when copying to a SharePoint server or MS SkyDrive and the target filename is of a restricted type. + //note: ERROR_INVALID_PARAMETER can also occur when copying to a SharePoint server or MS SkyDrive and the target filepath is of a restricted type. } catch (FileError&) {} @@ -2051,16 +2054,18 @@ void copyFileWindowsDefault(const Zstring& sourceFile, if (newAttrib) { - newAttrib->fileSize = UInt64(cbd.fileInfoSrc.nFileSizeLow, cbd.fileInfoSrc.nFileSizeHigh); + newAttrib->fileSize = get64BitUInt(cbd.fileInfoSrc.nFileSizeLow, cbd.fileInfoSrc.nFileSizeHigh); //newAttrib->modificationTime = -> set further below - newAttrib->sourceFileId = extractFileID(cbd.fileInfoSrc); - newAttrib->targetFileId = extractFileID(cbd.fileInfoTrg); + newAttrib->sourceFileId = extractFileId(cbd.fileInfoSrc); + newAttrib->targetFileId = extractFileId(cbd.fileInfoTrg); } { FILETIME creationtime = cbd.fileInfoSrc.ftCreationTime; FILETIME lastWriteTimeRaw = cbd.fileInfoSrc.ftLastWriteTime; //####################################### DST hack ########################################### + warn_static("let's tentatively disable the DST hack:") +#if 0 if (dst::isFatDrive(sourceFile)) //throw(); hacky: does not consider symlinks pointing to FAT! { const dst::RawTime rawTime(creationtime, lastWriteTimeRaw); @@ -2070,10 +2075,11 @@ void copyFileWindowsDefault(const Zstring& sourceFile, ::GetSystemTimeAsFileTime(&creationtime); //real creation time information is not available... } } +#endif //####################################### DST hack ########################################### if (newAttrib) - newAttrib->modificationTime = toTimeT(lastWriteTimeRaw); + newAttrib->modificationTime = filetimeToTimeT(lastWriteTimeRaw); //caveat: - ::CopyFileEx() silently *ignores* failure to set modification time!!! => we always need to set it again but with proper error checking! // - perf-loss on USB sticks with many small files of about 30%! @@ -2081,12 +2087,15 @@ void copyFileWindowsDefault(const Zstring& sourceFile, FILETIME lastWriteTimeOut = lastWriteTimeRaw; //####################################### DST hack ########################################### + warn_static("let's tentatively disable the DST hack:") +#if 0 if (dst::isFatDrive(targetFile)) //throw(); target cannot be a symlink in this context! { const dst::RawTime encodedTime = dst::fatEncodeUtcTime(lastWriteTimeRaw); //throw std::runtime_error creationTimeOut = encodedTime.createTimeRaw; lastWriteTimeOut = encodedTime.writeTimeRaw; } +#endif //####################################### DST hack ########################################### setFileTimeRaw(targetFile, creationTimeOut, lastWriteTimeOut, ProcSymlink::FOLLOW); //throw FileError @@ -2098,7 +2107,7 @@ void copyFileWindowsDefault(const Zstring& sourceFile, //another layer to support copying sparse files inline -void copyFileWindowsSelectRoutine(const Zstring& sourceFile, const Zstring& targetFile, const std::function<void(Int64 bytesDelta)>& onUpdateCopyStatus, InSyncAttributes* sourceAttr) +void copyFileWindowsSelectRoutine(const Zstring& sourceFile, const Zstring& targetFile, const std::function<void(std::int64_t bytesDelta)>& onUpdateCopyStatus, InSyncAttributes* sourceAttr) { try { @@ -2115,7 +2124,7 @@ void copyFileWindowsSelectRoutine(const Zstring& sourceFile, const Zstring& targ inline void copyFileWindows(const Zstring& sourceFile, const Zstring& targetFile, - const std::function<void(Int64 bytesDelta)>& onUpdateCopyStatus, + const std::function<void(std::int64_t bytesDelta)>& onUpdateCopyStatus, InSyncAttributes* sourceAttr) { try @@ -2127,8 +2136,8 @@ void copyFileWindows(const Zstring& sourceFile, //try to handle issues with already existing short 8.3 file names on Windows if (have8dot3NameClash(targetFile)) { - Fix8Dot3NameClash dummy(targetFile); //throw FileError; move clashing filename to the side - copyFileWindowsSelectRoutine(sourceFile, targetFile, onUpdateCopyStatus, sourceAttr); //throw FileError; the short filename name clash is solved, this should work now + Fix8Dot3NameClash dummy(targetFile); //throw FileError; move clashing filepath to the side + copyFileWindowsSelectRoutine(sourceFile, targetFile, onUpdateCopyStatus, sourceAttr); //throw FileError; the short filepath name clash is solved, this should work now return; } throw; @@ -2139,7 +2148,7 @@ void copyFileWindows(const Zstring& sourceFile, #elif defined ZEN_LINUX || defined ZEN_MAC void copyFileLinuxMac(const Zstring& sourceFile, const Zstring& targetFile, - const std::function<void(Int64 bytesDelta)>& onUpdateCopyStatus, + const std::function<void(std::int64_t bytesDelta)>& onUpdateCopyStatus, InSyncAttributes* newAttrib) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting { //open sourceFile for reading @@ -2165,7 +2174,7 @@ void copyFileLinuxMac(const Zstring& sourceFile, //invoke callback method to update progress indicators if (onUpdateCopyStatus) - onUpdateCopyStatus(Int64(bytesRead)); //throw X! + onUpdateCopyStatus(bytesRead); //throw X! } while (!fileIn.eof()); @@ -2178,10 +2187,10 @@ void copyFileLinuxMac(const Zstring& sourceFile, if (newAttrib) { - newAttrib->fileSize = UInt64(sourceInfo.st_size); + newAttrib->fileSize = sourceInfo.st_size; newAttrib->modificationTime = sourceInfo.st_mtime; - newAttrib->sourceFileId = extractFileID(sourceInfo); - newAttrib->targetFileId = extractFileID(targetInfo); + newAttrib->sourceFileId = extractFileId(sourceInfo); + newAttrib->targetFileId = extractFileId(targetInfo); } } } @@ -2220,7 +2229,7 @@ copyFileWindowsDefault(::CopyFileEx) copyFileWindowsSparse(::BackupRead/::Backu inline void copyFileSelectOs(const Zstring& sourceFile, const Zstring& targetFile, - const std::function<void(Int64 bytesDelta)>& onUpdateCopyStatus, + const std::function<void(std::int64_t bytesDelta)>& onUpdateCopyStatus, InSyncAttributes* sourceAttr) { #ifdef ZEN_WIN @@ -2238,7 +2247,7 @@ void zen::copyFile(const Zstring& sourceFile, //throw FileError, ErrorTargetPath bool copyFilePermissions, bool transactionalCopy, const std::function<void()>& onDeleteTargetFile, - const std::function<void(Int64 bytesDelta)>& onUpdateCopyStatus, + const std::function<void(std::int64_t bytesDelta)>& onUpdateCopyStatus, InSyncAttributes* sourceAttr) { if (transactionalCopy) diff --git a/zen/file_handling.h b/zen/file_handling.h index c3ce1d83..b58f6c07 100644 --- a/zen/file_handling.h +++ b/zen/file_handling.h @@ -11,12 +11,11 @@ #include "zstring.h" #include "file_error.h" #include "file_id_def.h" -#include "int64.h" namespace zen { -bool fileExists (const Zstring& filename); //noexcept; check whether file or file-symlink exists -bool dirExists (const Zstring& dirname ); //noexcept; check whether directory or dir-symlink exists +bool fileExists (const Zstring& filepath); //noexcept; check whether file or file-symlink exists +bool dirExists (const Zstring& dirpath ); //noexcept; check whether directory or dir-symlink exists bool symlinkExists (const Zstring& linkname); //noexcept; check whether a symbolic link exists bool somethingExists(const Zstring& objname ); //noexcept; check whether any object with this name exists @@ -26,21 +25,21 @@ enum class ProcSymlink FOLLOW }; -void setFileTime(const Zstring& filename, const Int64& modificationTime, ProcSymlink procSl); //throw FileError +void setFileTime(const Zstring& filepath, std::int64_t modificationTime, ProcSymlink procSl); //throw FileError //symlink handling: always evaluate target -UInt64 getFilesize(const Zstring& filename); //throw FileError -UInt64 getFreeDiskSpace(const Zstring& path); //throw FileError +std::uint64_t getFilesize(const Zstring& filepath); //throw FileError +std::uint64_t getFreeDiskSpace(const Zstring& path); //throw FileError -bool removeFile(const Zstring& filename); //throw FileError; return "false" if file is not existing +bool removeFile(const Zstring& filepath); //throw FileError; return "false" if file is not existing void removeDirectory(const Zstring& directory, //throw FileError - const std::function<void (const Zstring& filename)>& onBeforeFileDeletion = nullptr, //optional; - const std::function<void (const Zstring& dirname)>& onBeforeDirDeletion = nullptr); //one call for each *existing* object! + const std::function<void (const Zstring& filepath)>& onBeforeFileDeletion = nullptr, //optional; + const std::function<void (const Zstring& dirpath)>& onBeforeDirDeletion = nullptr); //one call for each *existing* object! //rename file or directory: no copying!!! void renameFile(const Zstring& oldName, const Zstring& newName); //throw FileError, ErrorDifferentVolume, ErrorTargetExisting -bool supportsPermissions(const Zstring& dirname); //throw FileError, dereferences symlinks +bool supportsPermissions(const Zstring& dirpath); //throw FileError, dereferences symlinks //if parent directory not existing: create recursively: void makeDirectory(const Zstring& directory, bool failIfExists = false); //throw FileError, ErrorTargetExisting @@ -52,8 +51,8 @@ void makeDirectoryPlain(const Zstring& directory, const Zstring& templateDir, bo struct InSyncAttributes { - UInt64 fileSize; - Int64 modificationTime; //time_t UTC compatible + std::uint64_t fileSize; + std::int64_t modificationTime; //time_t UTC compatible FileId sourceFileId; FileId targetFileId; }; @@ -64,11 +63,11 @@ void copyFile(const Zstring& sourceFile, //throw FileError, ErrorTargetPathMissi bool transactionalCopy, //if target is existing user needs to implement deletion: copyFile() NEVER overwrites target if already existing! //if transactionalCopy == true, full read access on source had been proven at this point, so it's safe to delete it. - const std::function<void()>& onDeleteTargetFile, //may be nullptr; throw X! + const std::function<void()>& onDeleteTargetFile, //may be nullptr; may throw! //Linux: unconditionally //Windows: first exception is swallowed, updateCopyStatus() is then called again where it should throw again and the exception will propagate as expected //accummulated delta != file size! consider ADS, sparse, compressed files - const std::function<void(Int64 bytesDelta)>& onUpdateCopyStatus, //may be nullptr; throw X! + const std::function<void(std::int64_t bytesDelta)>& onUpdateCopyStatus, //may be nullptr; may throw! InSyncAttributes* newAttrib = nullptr); //return current attributes at the time of copy diff --git a/zen/file_id_def.h b/zen/file_id_def.h index 0608aacd..daadd391 100644 --- a/zen/file_id_def.h +++ b/zen/file_id_def.h @@ -27,21 +27,21 @@ typedef ULONGLONG FileIndex; typedef std::pair<DeviceId, FileIndex> FileId; inline -FileId extractFileID(const BY_HANDLE_FILE_INFORMATION& fileInfo) +FileId extractFileId(const BY_HANDLE_FILE_INFORMATION& fileInfo) { - ULARGE_INTEGER uint = {}; - uint.HighPart = fileInfo.nFileIndexHigh; - uint.LowPart = fileInfo.nFileIndexLow; + ULARGE_INTEGER fileIndex = {}; + fileIndex.HighPart = fileInfo.nFileIndexHigh; + fileIndex.LowPart = fileInfo.nFileIndexLow; - return fileInfo.dwVolumeSerialNumber != 0 && uint.QuadPart != 0 ? - FileId(fileInfo.dwVolumeSerialNumber, uint.QuadPart) : FileId(); + return fileInfo.dwVolumeSerialNumber != 0 && fileIndex.QuadPart != 0 ? + FileId(fileInfo.dwVolumeSerialNumber, fileIndex.QuadPart) : FileId(); } inline -FileId extractFileID(DWORD dwVolumeSerialNumber, ULARGE_INTEGER fileId) +FileId extractFileId(DWORD volumeSerialNumber, ULONGLONG fileIndex) { - return dwVolumeSerialNumber != 0 && fileId.QuadPart != 0 ? - FileId(dwVolumeSerialNumber, fileId.QuadPart) : FileId(); + return volumeSerialNumber != 0 && fileIndex != 0 ? + FileId(volumeSerialNumber, fileIndex) : FileId(); } assert_static(sizeof(FileId().first ) == sizeof(BY_HANDLE_FILE_INFORMATION().dwVolumeSerialNumber)); @@ -58,7 +58,7 @@ typedef decltype(impl::StatDummy::st_ino) FileIndex; typedef std::pair<DeviceId, FileIndex> FileId; inline -FileId extractFileID(const struct ::stat& fileInfo) +FileId extractFileId(const struct ::stat& fileInfo) { return fileInfo.st_dev != 0 && fileInfo.st_ino != 0 ? FileId(fileInfo.st_dev, fileInfo.st_ino) : FileId(); diff --git a/zen/file_io.cpp b/zen/file_io.cpp index 82b1def5..e11a1201 100644 --- a/zen/file_io.cpp +++ b/zen/file_io.cpp @@ -24,7 +24,7 @@ namespace { #ifdef ZEN_WIN //(try to) enhance error messages by showing which processes lock the file -Zstring getLockingProcessNames(const Zstring& filename) //throw(), empty string if none found or error occurred +Zstring getLockingProcessNames(const Zstring& filepath) //throw(), empty string if none found or error occurred { if (vistaOrLater()) { @@ -33,7 +33,7 @@ Zstring getLockingProcessNames(const Zstring& filename) //throw(), empty string const DllFun<FunType_freeString> freeString (getDllName(), funName_freeString); if (getLockingProcesses && freeString) - if (const wchar_t* procList = getLockingProcesses(filename.c_str())) + if (const wchar_t* procList = getLockingProcesses(filepath.c_str())) { ZEN_ON_SCOPE_EXIT(freeString(procList)); return procList; @@ -43,11 +43,11 @@ Zstring getLockingProcessNames(const Zstring& filename) //throw(), empty string } #elif defined ZEN_LINUX || defined ZEN_MAC -//"filename" could be a named pipe which *blocks* forever during "open()"! https://sourceforge.net/p/freefilesync/bugs/221/ -void checkForUnsupportedType(const Zstring& filename) //throw FileError +//"filepath" could be a named pipe which *blocks* forever during "open()"! https://sourceforge.net/p/freefilesync/bugs/221/ +void checkForUnsupportedType(const Zstring& filepath) //throw FileError { struct ::stat fileInfo = {}; - if (::stat(filename.c_str(), &fileInfo) != 0) //follows symlinks + if (::stat(filepath.c_str(), &fileInfo) != 0) //follows symlinks return; //let the caller handle errors like "not existing" if (!S_ISREG(fileInfo.st_mode) && @@ -64,21 +64,21 @@ void checkForUnsupportedType(const Zstring& filename) //throw FileError const std::wstring numFmt = printNumber<std::wstring>(L"0%06o", m & S_IFMT); return name ? numFmt + L", " + name : numFmt; }; - throw FileError(replaceCpy(_("Type of item %x is not supported:"), L"%x", fmtFileName(filename)) + L" " + getTypeName(fileInfo.st_mode)); + throw FileError(replaceCpy(_("Type of item %x is not supported:"), L"%x", fmtFileName(filepath)) + L" " + getTypeName(fileInfo.st_mode)); } } #endif } -FileInput::FileInput(FileHandle handle, const Zstring& filename) : FileInputBase(filename), fileHandle(handle) {} +FileInput::FileInput(FileHandle handle, const Zstring& filepath) : FileInputBase(filepath), fileHandle(handle) {} -FileInput::FileInput(const Zstring& filename) : FileInputBase(filename) //throw FileError +FileInput::FileInput(const Zstring& filepath) : FileInputBase(filepath) //throw FileError { #ifdef ZEN_WIN const wchar_t functionName[] = L"CreateFile"; - fileHandle = ::CreateFile(applyLongPathPrefix(filename).c_str(), //_In_ LPCTSTR lpFileName, + fileHandle = ::CreateFile(applyLongPathPrefix(filepath).c_str(), //_In_ LPCTSTR lpFileName, GENERIC_READ, //_In_ DWORD dwDesiredAccess, FILE_SHARE_READ | FILE_SHARE_DELETE, //_In_ DWORD dwShareMode, nullptr, //_In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes, @@ -111,21 +111,21 @@ FileInput::FileInput(const Zstring& filename) : FileInputBase(filename) //throw nullptr); //_In_opt_ HANDLE hTemplateFile if (fileHandle == INVALID_HANDLE_VALUE) #elif defined ZEN_LINUX || defined ZEN_MAC - checkForUnsupportedType(filename); //throw FileError; reading a named pipe would block forever! + checkForUnsupportedType(filepath); //throw FileError; reading a named pipe would block forever! const wchar_t functionName[] = L"fopen"; - fileHandle = ::fopen(filename.c_str(), "r,type=record,noseek"); //utilize UTF-8 filename + fileHandle = ::fopen(filepath.c_str(), "r,type=record,noseek"); //utilize UTF-8 filepath if (!fileHandle) #endif { const ErrorCode lastError = getLastError(); //copy before making other system calls! - const std::wstring errorMsg = replaceCpy(_("Cannot open file %x."), L"%x", fmtFileName(filename)); + const std::wstring errorMsg = replaceCpy(_("Cannot open file %x."), L"%x", fmtFileName(filepath)); std::wstring errorDescr = formatSystemError(functionName, lastError); #ifdef ZEN_WIN if (lastError == ERROR_SHARING_VIOLATION || //-> enhance error message! lastError == ERROR_LOCK_VIOLATION) { - const Zstring procList = getLockingProcessNames(filename); //throw() + const Zstring procList = getLockingProcessNames(filepath); //throw() if (!procList.empty()) errorDescr = _("The file is locked by another process:") + L"\n" + procList; } @@ -184,18 +184,18 @@ size_t FileInput::read(void* buffer, size_t bytesToRead) //returns actual number } -FileOutput::FileOutput(FileHandle handle, const Zstring& filename) : FileOutputBase(filename), fileHandle(handle) {} +FileOutput::FileOutput(FileHandle handle, const Zstring& filepath) : FileOutputBase(filepath), fileHandle(handle) {} -FileOutput::FileOutput(const Zstring& filename, AccessFlag access) : //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting - FileOutputBase(filename) +FileOutput::FileOutput(const Zstring& filepath, AccessFlag access) : //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting + FileOutputBase(filepath) { #ifdef ZEN_WIN const DWORD dwCreationDisposition = access == FileOutput::ACC_OVERWRITE ? CREATE_ALWAYS : CREATE_NEW; auto getHandle = [&](DWORD dwFlagsAndAttributes) { - return ::CreateFile(applyLongPathPrefix(filename).c_str(), //_In_ LPCTSTR lpFileName, + return ::CreateFile(applyLongPathPrefix(filepath).c_str(), //_In_ LPCTSTR lpFileName, GENERIC_READ | GENERIC_WRITE, //_In_ DWORD dwDesiredAccess, /* http://msdn.microsoft.com/en-us/library/aa363858(v=vs.85).aspx quote: When an application creates a file across a network, it is better @@ -220,7 +220,7 @@ FileOutput::FileOutput(const Zstring& filename, AccessFlag access) : //throw Fil if (lastError == ERROR_ACCESS_DENIED && dwCreationDisposition == CREATE_ALWAYS) { - const DWORD attrib = ::GetFileAttributes(applyLongPathPrefix(filename).c_str()); + const DWORD attrib = ::GetFileAttributes(applyLongPathPrefix(filepath).c_str()); if (attrib != INVALID_FILE_ATTRIBUTES) { fileHandle = getHandle(attrib); //retry: alas this may still fail for hidden file, e.g. accessing shared folder in XP as Virtual Box guest! @@ -231,13 +231,13 @@ FileOutput::FileOutput(const Zstring& filename, AccessFlag access) : //throw Fil //begin of "regular" error reporting if (fileHandle == INVALID_HANDLE_VALUE) { - const std::wstring errorMsg = replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(filename)); + const std::wstring errorMsg = replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(filepath)); std::wstring errorDescr = formatSystemError(L"CreateFile", lastError); if (lastError == ERROR_SHARING_VIOLATION || //-> enhance error message! lastError == ERROR_LOCK_VIOLATION) { - const Zstring procList = getLockingProcessNames(filename); //throw() + const Zstring procList = getLockingProcessNames(filepath); //throw() if (!procList.empty()) errorDescr = _("The file is locked by another process:") + L"\n" + procList; } @@ -254,8 +254,8 @@ FileOutput::FileOutput(const Zstring& filename, AccessFlag access) : //throw Fil } #elif defined ZEN_LINUX || defined ZEN_MAC - checkForUnsupportedType(filename); //throw FileError; writing a named pipe would block forever! - fileHandle = ::fopen(filename.c_str(), + checkForUnsupportedType(filepath); //throw FileError; writing a named pipe would block forever! + fileHandle = ::fopen(filepath.c_str(), //GNU extension: https://www.securecoding.cert.org/confluence/display/cplusplus/FIO03-CPP.+Do+not+make+assumptions+about+fopen()+and+file+creation access == ACC_OVERWRITE ? "w,type=record,noseek" : "wx,type=record,noseek"); if (!fileHandle) @@ -311,13 +311,13 @@ void FileOutput::write(const void* buffer, size_t bytesToWrite) //throw FileErro #if defined ZEN_LINUX || defined ZEN_MAC //Compare copy_reg() in copy.c: ftp://ftp.gnu.org/gnu/coreutils/coreutils-5.0.tar.gz -FileInputUnbuffered::FileInputUnbuffered(const Zstring& filename) : FileInputBase(filename) //throw FileError +FileInputUnbuffered::FileInputUnbuffered(const Zstring& filepath) : FileInputBase(filepath) //throw FileError { - checkForUnsupportedType(filename); //throw FileError; reading a named pipe would block forever! + checkForUnsupportedType(filepath); //throw FileError; reading a named pipe would block forever! - fdFile = ::open(filename.c_str(), O_RDONLY); + fdFile = ::open(filepath.c_str(), O_RDONLY); if (fdFile == -1) //don't check "< 0" -> docu seems to allow "-2" to be a valid file handle - throwFileError(replaceCpy(_("Cannot open file %x."), L"%x", fmtFileName(filename)), L"open", getLastError()); + throwFileError(replaceCpy(_("Cannot open file %x."), L"%x", fmtFileName(filepath)), L"open", getLastError()); } @@ -348,16 +348,16 @@ size_t FileInputUnbuffered::read(void* buffer, size_t bytesToRead) //throw FileE } -FileOutputUnbuffered::FileOutputUnbuffered(const Zstring& filename, mode_t mode) : FileOutputBase(filename) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting +FileOutputUnbuffered::FileOutputUnbuffered(const Zstring& filepath, mode_t mode) : FileOutputBase(filepath) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting { - //checkForUnsupportedType(filename); -> not needed, open() + O_EXCL shoul fail fast + //checkForUnsupportedType(filepath); -> not needed, open() + O_EXCL shoul fail fast //overwrite is: O_CREAT | O_WRONLY | O_TRUNC - fdFile = ::open(filename.c_str(), O_CREAT | O_WRONLY | O_EXCL, mode & (S_IRWXU | S_IRWXG | S_IRWXO)); + fdFile = ::open(filepath.c_str(), O_CREAT | O_WRONLY | O_EXCL, mode & (S_IRWXU | S_IRWXG | S_IRWXO)); if (fdFile == -1) { const int lastError = errno; //copy before making other system calls! - const std::wstring errorMsg = replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(filename)); + const std::wstring errorMsg = replaceCpy(_("Cannot write file %x."), L"%x", fmtFileName(filepath)); const std::wstring errorDescr = formatSystemError(L"open", lastError); if (lastError == EEXIST) @@ -370,7 +370,7 @@ FileOutputUnbuffered::FileOutputUnbuffered(const Zstring& filename, mode_t mode) } } -FileOutputUnbuffered::FileOutputUnbuffered(int fd, const Zstring& filename) : FileOutputBase(filename), fdFile(fd) {} +FileOutputUnbuffered::FileOutputUnbuffered(int fd, const Zstring& filepath) : FileOutputBase(filepath), fdFile(fd) {} FileOutputUnbuffered::~FileOutputUnbuffered() { ::close(fdFile); } diff --git a/zen/file_io.h b/zen/file_io.h index 2e9e828e..5ae6eb1c 100644 --- a/zen/file_io.h +++ b/zen/file_io.h @@ -37,11 +37,11 @@ typedef FILE* FileHandle; class FileInput : public FileInputBase { public: - FileInput(const Zstring& filename); //throw FileError - FileInput(FileHandle handle, const Zstring& filename); //takes ownership! + FileInput(const Zstring& filepath); //throw FileError + FileInput(FileHandle handle, const Zstring& filepath); //takes ownership! ~FileInput(); - virtual size_t read(void* buffer, size_t bytesToRead); //throw FileError; returns actual number of bytes read + virtual size_t read(void* buffer, size_t bytesToRead) override; //throw FileError; returns actual number of bytes read //expected to fill buffer completely unless "end of file" private: @@ -52,11 +52,11 @@ private: class FileOutput : public FileOutputBase { public: - FileOutput(const Zstring& filename, AccessFlag access); //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting - FileOutput(FileHandle handle, const Zstring& filename); //takes ownership! + FileOutput(const Zstring& filepath, AccessFlag access); //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting + FileOutput(FileHandle handle, const Zstring& filepath); //takes ownership! ~FileOutput(); - virtual void write(const void* buffer, size_t bytesToWrite); //throw FileError + virtual void write(const void* buffer, size_t bytesToWrite) override; //throw FileError private: FileHandle fileHandle; @@ -66,11 +66,11 @@ private: class FileInputUnbuffered : public FileInputBase { public: - FileInputUnbuffered(const Zstring& filename); //throw FileError + FileInputUnbuffered(const Zstring& filepath); //throw FileError ~FileInputUnbuffered(); //considering safe-read.c it seems buffer size should be a multiple of 8192 - virtual size_t read(void* buffer, size_t bytesToRead); //throw FileError; returns actual number of bytes read + virtual size_t read(void* buffer, size_t bytesToRead) override; //throw FileError; returns actual number of bytes read //do NOT rely on partially filled buffer meaning EOF! int getDescriptor() { return fdFile;} @@ -83,11 +83,11 @@ class FileOutputUnbuffered : public FileOutputBase { public: //creates a new file (no overwrite allowed!) - FileOutputUnbuffered(const Zstring& filename, mode_t mode); //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting - FileOutputUnbuffered(int fd, const Zstring& filename); //takes ownership! + FileOutputUnbuffered(const Zstring& filepath, mode_t mode); //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting + FileOutputUnbuffered(int fd, const Zstring& filepath); //takes ownership! ~FileOutputUnbuffered(); - virtual void write(const void* buffer, size_t bytesToWrite); //throw FileError + virtual void write(const void* buffer, size_t bytesToWrite) override; //throw FileError int getDescriptor() { return fdFile;} private: diff --git a/zen/file_traverser.cpp b/zen/file_traverser.cpp index 65d95f4a..d8f2d0cf 100644 --- a/zen/file_traverser.cpp +++ b/zen/file_traverser.cpp @@ -8,9 +8,10 @@ #include "sys_error.h" #include "assert_static.h" #include "symlink_target.h" +#include "int64.h" #ifdef ZEN_WIN -#include <zen/win_ver.h> +#include "win_ver.h" #include "long_path_prefix.h" #include "dst_hack.h" #include "file_handling.h" //remove this huge dependency when getting rid of DST hack!! until then we need "setFileTime" @@ -18,7 +19,7 @@ #include "FindFilePlus/find_file_plus.h" #elif defined ZEN_MAC -#include <zen/osx_string.h> +#include "osx_string.h" #endif #if defined ZEN_LINUX || defined ZEN_MAC @@ -29,7 +30,7 @@ using namespace zen; - + namespace { //implement "retry" in a generic way: @@ -78,7 +79,7 @@ bool tryReportingItemError(Command cmd, zen::TraverseCallback& callback, const Z #ifdef ZEN_WIN -void getInfoFromFileSymlink(const Zstring& linkName, zen::TraverseCallback::FileInfo& output) //throw FileError +TraverseCallback::FileInfo getInfoFromFileSymlink(const Zstring& linkName) //throw FileError { //open handle to target of symbolic link HANDLE hFile = ::CreateFile(zen::applyLongPathPrefix(linkName).c_str(), //_In_ LPCTSTR lpFileName, @@ -104,11 +105,12 @@ void getInfoFromFileSymlink(const Zstring& linkName, zen::TraverseCallback::File if (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) throw FileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(linkName)), formatSystemError(L"GetFileInformationByHandle", static_cast<DWORD>(ERROR_FILE_INVALID))); - //write output - output.fileSize = UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh); - output.lastWriteTime = toTimeT(fileInfo.ftLastWriteTime); - output.id = extractFileID(fileInfo); //consider detection of moved files: allow for duplicate file ids, renaming affects symlink, not target, ... + TraverseCallback::FileInfo output; + output.fileSize = get64BitUInt(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh); + output.lastWriteTime = filetimeToTimeT(fileInfo.ftLastWriteTime); + output.id = extractFileId(fileInfo); //consider detection of moved files: allow for duplicate file ids, renaming affects symlink, not target, ... //output.symlinkInfo -> not filled here + return output; } @@ -154,17 +156,17 @@ struct TraverserPolicy //see "policy based design" typedef ... DirHandle; typedef ... FindData; -static void create(const Zstring& directory, DirHandle& hnd); //throw FileError - *no* concession to FindFirstFile(): open handle only, *no* return of data! +static DirHandle create(const Zstring& directory); //throw FileError - don't follow FindFirstFile() design: open handle only, *no* return of data! static void destroy(DirHandle hnd); //throw() static bool getEntry(DirHandle hnd, const Zstring& directory, FindData& fileInfo) //throw FileError, NeedFallbackToWin32Traverser -> fallback to FindFirstFile()/FindNextFile() //FindData "member" functions -static void extractFileInfo (const FindData& fileInfo, DWORD volumeSerial, TraverseCallback::FileInfo& output); //volumeSerial may be 0 if not available! -static Int64 getModTime (const FindData& fileInfo); +static TraverseCallback::FileInfo extractFileInfo(const FindData& fileInfo, DWORD volumeSerial); //volumeSerial may be 0 if not available! +static std::int64_t getModTime (const FindData& fileInfo); static const FILETIME& getModTimeRaw (const FindData& fileInfo); //yet another concession to DST hack static const FILETIME& getCreateTimeRaw(const FindData& fileInfo); // -static const wchar_t* getShortName (const FindData& fileInfo); +static const wchar_t* getItemName (const FindData& fileInfo); static bool isDirectory (const FindData& fileInfo); static bool isSymlink (const FindData& fileInfo); } @@ -177,40 +179,41 @@ struct Win32Traverser { struct DirHandle { - DirHandle() : searchHandle(nullptr), haveData(true), data() {} + DirHandle(HANDLE hnd, const WIN32_FIND_DATA& d) : searchHandle(hnd), haveData(true), data(d) {} + explicit DirHandle(HANDLE hnd) : searchHandle(hnd), haveData(false) {} HANDLE searchHandle; - bool haveData; WIN32_FIND_DATA data; }; typedef WIN32_FIND_DATA FindData; - static void create(const Zstring& dirname, DirHandle& hnd) //throw FileError + static DirHandle create(const Zstring& dirpath) //throw FileError { - const Zstring& dirnamePf = appendSeparator(dirname); + const Zstring& dirpathPf = appendSeparator(dirpath); - hnd.searchHandle = ::FindFirstFile(applyLongPathPrefix(dirnamePf + L'*').c_str(), &hnd.data); + WIN32_FIND_DATA fileData = {}; + HANDLE hnd = ::FindFirstFile(applyLongPathPrefix(dirpathPf + L'*').c_str(), &fileData); //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) + if (hnd == INVALID_HANDLE_VALUE) { const DWORD lastError = ::GetLastError(); //copy before making other system calls! - hnd.haveData = false; if (lastError == ERROR_FILE_NOT_FOUND) { //1. directory may not exist *or* 2. it is completely empty: not all directories contain "., .." entries, e.g. a drive's root directory; NetDrive // -> FindFirstFile() is a nice example of violation of API design principle of single responsibility - if (dirExists(dirname)) //yes, a race-condition, still the best we can do - return; + if (dirExists(dirpath)) //yes, a race-condition, still the best we can do + return DirHandle(hnd); } - throwFileError(replaceCpy(_("Cannot open directory %x."), L"%x", fmtFileName(dirname)), L"FindFirstFile", lastError); + throwFileError(replaceCpy(_("Cannot open directory %x."), L"%x", fmtFileName(dirpath)), L"FindFirstFile", lastError); } + return DirHandle(hnd, fileData); } static void destroy(const DirHandle& hnd) { ::FindClose(hnd.searchHandle); } //throw() - static bool getEntry(DirHandle& hnd, const Zstring& dirname, FindData& fileInfo) //throw FileError + static bool getEntry(DirHandle& hnd, const Zstring& dirpath, FindData& fileInfo) //throw FileError { if (hnd.searchHandle == INVALID_HANDLE_VALUE) //handle special case of "truly empty directories" return false; @@ -228,22 +231,25 @@ struct Win32Traverser if (lastError == ERROR_NO_MORE_FILES) //not an error situation return false; //else we have a problem... report it: - throwFileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtFileName(dirname)), L"FindNextFile", lastError); + throwFileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtFileName(dirpath)), L"FindNextFile", lastError); } return true; } - static void extractFileInfo(const FindData& fileInfo, DWORD volumeSerial, TraverseCallback::FileInfo& output) + static TraverseCallback::FileInfo extractFileInfo(const FindData& fileInfo, DWORD volumeSerial) { - output.fileSize = UInt64(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh); + TraverseCallback::FileInfo output; + output.fileSize = get64BitUInt(fileInfo.nFileSizeLow, fileInfo.nFileSizeHigh); output.lastWriteTime = getModTime(fileInfo); - output.id = FileId(); + //output.id = FileId(); + //output.symlinkInfo = nullptr; + return output; } - static Int64 getModTime (const FindData& fileInfo) { return toTimeT(fileInfo.ftLastWriteTime); } + static std::int64_t getModTime (const FindData& fileInfo) { return filetimeToTimeT(fileInfo.ftLastWriteTime); } static const FILETIME& getModTimeRaw (const FindData& fileInfo) { return fileInfo.ftLastWriteTime; } static const FILETIME& getCreateTimeRaw(const FindData& fileInfo) { return fileInfo.ftCreationTime; } - static const wchar_t* getShortName (const FindData& fileInfo) { return fileInfo.cFileName; } + static const wchar_t* getItemName (const FindData& fileInfo) { return fileInfo.cFileName; } static bool isDirectory (const FindData& fileInfo) { return (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; } static bool isSymlink (const FindData& fileInfo) { return zen::isSymlink(fileInfo); } //[!] keep namespace }; @@ -256,23 +262,25 @@ struct FilePlusTraverser { struct DirHandle { - DirHandle() : searchHandle(nullptr) {} + explicit DirHandle(findplus::FindHandle hnd) : searchHandle(hnd) {} findplus::FindHandle searchHandle; }; typedef findplus::FileInformation FindData; - static void create(const Zstring& dirname, DirHandle& hnd) //throw FileError + static DirHandle create(const Zstring& dirpath) //throw FileError { - hnd.searchHandle = ::openDir(applyLongPathPrefix(dirname).c_str()); - if (hnd.searchHandle == nullptr) - throwFileError(replaceCpy(_("Cannot open directory %x."), L"%x", fmtFileName(dirname)), L"openDir", getLastError()); + const findplus::FindHandle hnd = ::openDir(applyLongPathPrefix(dirpath).c_str()); + if (!hnd) + throwFileError(replaceCpy(_("Cannot open directory %x."), L"%x", fmtFileName(dirpath)), L"openDir", getLastError()); + + return DirHandle(hnd); } static void destroy(DirHandle hnd) { ::closeDir(hnd.searchHandle); } //throw() - static bool getEntry(DirHandle hnd, const Zstring& dirname, FindData& fileInfo) //throw FileError, NeedFallbackToWin32Traverser + static bool getEntry(DirHandle hnd, const Zstring& dirpath, FindData& fileInfo) //throw FileError, NeedFallbackToWin32Traverser { if (!::readDir(hnd.searchHandle, fileInfo)) { @@ -289,23 +297,26 @@ struct FilePlusTraverser //fallback should apply to whole directory sub-tree! => client needs to handle duplicate file notifications! //else we have a problem... report it: - throwFileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtFileName(dirname)), L"readDir", lastError); + throwFileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtFileName(dirpath)), L"readDir", lastError); } return true; } - static void extractFileInfo(const FindData& fileInfo, DWORD volumeSerial, TraverseCallback::FileInfo& output) + static TraverseCallback::FileInfo extractFileInfo(const FindData& fileInfo, DWORD volumeSerial) { - output.fileSize = fileInfo.fileSize.QuadPart; + TraverseCallback::FileInfo output; + output.fileSize = fileInfo.fileSize; output.lastWriteTime = getModTime(fileInfo); - output.id = extractFileID(volumeSerial, fileInfo.fileId); + output.id = extractFileId(volumeSerial, fileInfo.fileId); + //output.symlinkInfo = nullptr; + return output; } - static Int64 getModTime (const FindData& fileInfo) { return toTimeT(fileInfo.lastWriteTime); } + static std::int64_t getModTime (const FindData& fileInfo) { return filetimeToTimeT(fileInfo.lastWriteTime); } static const FILETIME& getModTimeRaw (const FindData& fileInfo) { return fileInfo.lastWriteTime; } static const FILETIME& getCreateTimeRaw(const FindData& fileInfo) { return fileInfo.creationTime; } - static const wchar_t* getShortName (const FindData& fileInfo) { return fileInfo.shortName; } + static const wchar_t* getItemName (const FindData& fileInfo) { return fileInfo.shortName; } static bool isDirectory (const FindData& fileInfo) { return (fileInfo.fileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; } static bool isSymlink (const FindData& fileInfo) { return zen::isSymlink(fileInfo.fileAttributes, fileInfo.reparseTag); } //[!] keep namespace }; @@ -320,139 +331,15 @@ public: } private: - DirTraverser(const Zstring& baseDirectory, TraverseCallback& sink, DstHackCallback* dstCallback) : - needDstHack(dstCallback ? dst::isFatDrive(baseDirectory) : false) - { - try //traversing certain folders with restricted permissions requires this privilege! (but copying these files may still fail) - { - activatePrivilege(SE_BACKUP_NAME); //throw FileError - } - catch (FileError&) {} //don't cause issues in user mode - - if (::openDir && ::readDir && ::closeDir) - { - try - { - traverse<FilePlusTraverser>(baseDirectory, sink, retrieveVolumeSerial(baseDirectory)); //throw NeedFallbackToWin32Traverser; retrieveVolumeSerial returns 0 on error - } - catch (NeedFallbackToWin32Traverser&) { traverse<Win32Traverser>(baseDirectory, sink, 0); } - } - else //fallback - traverse<Win32Traverser>(baseDirectory, sink, 0); - - //apply daylight saving time hack AFTER file traversing, to give separate feedback to user - if (needDstHack) - if (dstCallback) //bound if "needDstHack == true" - applyDstHack(*dstCallback); - } - - DirTraverser(const DirTraverser&); - DirTraverser& operator=(const DirTraverser&); + DirTraverser(const Zstring& baseDirectory, TraverseCallback& sink, DstHackCallback* dstCallback); + DirTraverser (const DirTraverser&) = delete; + DirTraverser& operator=(const DirTraverser&) = delete; template <class Trav> - void traverse(const Zstring& dirname, zen::TraverseCallback& sink, DWORD volumeSerial /*may be 0!*/) //throw NeedFallbackToWin32Traverser - { - //no need to check for endless recursion: Windows seems to have an internal path limit of about 700 chars - - typename Trav::DirHandle searchHandle; - - if (!tryReportingDirError([&] { Trav::create(dirname, searchHandle); /*throw FileError*/ }, sink)) - return; //ignored error - ZEN_ON_SCOPE_EXIT(Trav::destroy(searchHandle)); - - typename Trav::FindData findData = {}; - - for (;;) - { - bool gotEntry = false; - tryReportingDirError([&] - { - gotEntry = Trav::getEntry(searchHandle, dirname, findData); //throw FileError, NeedFallbackToWin32Traverser - }, sink); - if (!gotEntry) //no more items or ignored error - return; - - //skip "." and ".." - const Zchar* const shortName = Trav::getShortName(findData); - if (shortName[0] == L'.' && - (shortName[1] == 0 || (shortName[1] == L'.' && shortName[2] == 0))) - continue; - - const Zstring& fullName = appendSeparator(dirname) + shortName; - - if (Trav::isSymlink(findData)) //check first! - { - TraverseCallback::SymlinkInfo linkInfo; - linkInfo.lastWriteTime = Trav::getModTime (findData); - - switch (sink.onSymlink(shortName, fullName, linkInfo)) - { - case TraverseCallback::LINK_FOLLOW: - if (Trav::isDirectory(findData)) - { - if (TraverseCallback* trav = sink.onDir(shortName, fullName)) - { - ZEN_ON_SCOPE_EXIT(sink.releaseDirTraverser(trav)); - try - { - traverse<Trav>(fullName, *trav, retrieveVolumeSerial(fullName)); //throw NeedFallbackToWin32Traverser; symlink may link to different volume => redetermine volume serial! - } - catch (NeedFallbackToWin32Traverser&) { traverse<Win32Traverser>(fullName, *trav, 0); } - } - } - else //a file - { - TraverseCallback::FileInfo targetInfo; - const bool validLink = tryReportingItemError([&] //try to resolve symlink (and report error on failure!!!) - { - getInfoFromFileSymlink(fullName, targetInfo); //throw FileError - targetInfo.symlinkInfo = &linkInfo; - }, sink, shortName); - - if (validLink) - sink.onFile(shortName, fullName, targetInfo); - // else //broken symlink -> ignore: it's client's responsibility to handle error! - } - break; - - case TraverseCallback::LINK_SKIP: - break; - } - } - else if (Trav::isDirectory(findData)) - { - if (TraverseCallback* trav = sink.onDir(shortName, fullName)) - { - ZEN_ON_SCOPE_EXIT(sink.releaseDirTraverser(trav)); - try - { - traverse<Trav>(fullName, *trav, volumeSerial); //throw NeedFallbackToWin32Traverser - } - catch (NeedFallbackToWin32Traverser&) { traverse<Win32Traverser>(fullName, *trav, 0); } - } - } - else //a file - { - TraverseCallback::FileInfo fileInfo; - Trav::extractFileInfo(findData, volumeSerial, fileInfo); - - //####################################### DST hack ########################################### - if (needDstHack) - { - const dst::RawTime rawTime(Trav::getCreateTimeRaw(findData), Trav::getModTimeRaw(findData)); - - if (dst::fatHasUtcEncoded(rawTime)) //throw std::runtime_error - fileInfo.lastWriteTime = toTimeT(dst::fatDecodeUtcTime(rawTime)); //return real UTC time; throw std::runtime_error - else - markForDstHack.push_back(std::make_pair(fullName, toTimeT(rawTime.writeTimeRaw))); - } - //####################################### DST hack ########################################### - - sink.onFile(shortName, fullName, fileInfo); - } - } - } + void traverse(const Zstring& dirpath, TraverseCallback& sink, DWORD volumeSerial); + template <class Trav> + void traverseWithException(const Zstring& dirpath, TraverseCallback& sink, DWORD volumeSerial /*may be 0!*/); //throw FileError, NeedFallbackToWin32Traverser //####################################### DST hack ########################################### void applyDstHack(zen::DstHackCallback& dstCallback) @@ -482,7 +369,7 @@ private: //even at this point it's not sure whether data was written correctly, again cloud storages tend to lie about success status if (filesToValidate-- > 0) { - const dst::RawTime encodedTime = dst::fatEncodeUtcTime(toFileTime(it->second)); //throw std::runtime_error + const dst::RawTime encodedTime = dst::fatEncodeUtcTime(timetToFileTime(it->second)); //throw std::runtime_error //dst hack: verify data written; attention: this check may fail for "sync.ffs_lock" WIN32_FILE_ATTRIBUTE_DATA debugeAttr = {}; @@ -502,11 +389,144 @@ private: } const bool needDstHack; - typedef std::vector<std::pair<Zstring, Int64>> FilenameTimeList; + typedef std::vector<std::pair<Zstring, std::int64_t>> FilenameTimeList; FilenameTimeList markForDstHack; //####################################### DST hack ########################################### }; + +template <> inline +void DirTraverser::traverse<Win32Traverser>(const Zstring& dirpath, TraverseCallback& sink, DWORD volumeSerial) +{ + tryReportingDirError([&] + { + traverseWithException<Win32Traverser>(dirpath, sink, 0); //throw FileError + }, sink); +} + + +template <> inline +void DirTraverser::traverse<FilePlusTraverser>(const Zstring& dirpath, TraverseCallback& sink, DWORD volumeSerial) +{ + try + { + tryReportingDirError([&] + { + traverseWithException<FilePlusTraverser>(dirpath, sink, volumeSerial); //throw FileError, NeedFallbackToWin32Traverser + }, sink); + } + catch (NeedFallbackToWin32Traverser&) { traverse<Win32Traverser>(dirpath, sink, 0); } +} + + +inline +DirTraverser::DirTraverser(const Zstring& baseDirectory, TraverseCallback& sink, DstHackCallback* dstCallback) : + needDstHack(dstCallback ? dst::isFatDrive(baseDirectory) : false) +{ + try //traversing certain folders with restricted permissions requires this privilege! (but copying these files may still fail) + { + activatePrivilege(SE_BACKUP_NAME); //throw FileError + } + catch (FileError&) {} //don't cause issues in user mode + + if (::openDir && ::readDir && ::closeDir) + traverse<FilePlusTraverser>(baseDirectory, sink, retrieveVolumeSerial(baseDirectory)); //retrieveVolumeSerial returns 0 on error + else //fallback + traverse<Win32Traverser>(baseDirectory, sink, 0); + + //apply daylight saving time hack AFTER file traversing, to give separate feedback to user + if (needDstHack) + if (dstCallback) //bound if "needDstHack == true" + applyDstHack(*dstCallback); +} + + +template <class Trav> +void DirTraverser::traverseWithException(const Zstring& dirpath, TraverseCallback& sink, DWORD volumeSerial /*may be 0!*/) //throw FileError, NeedFallbackToWin32Traverser +{ + //no need to check for endless recursion: Windows seems to have an internal path limit of about 700 chars + + typename Trav::DirHandle searchHandle = Trav::create(dirpath); //throw FileError + ZEN_ON_SCOPE_EXIT(Trav::destroy(searchHandle)); + + typename Trav::FindData findData = {}; + + while (Trav::getEntry(searchHandle, dirpath, findData)) //throw FileError, NeedFallbackToWin32Traverser + //don't retry but restart dir traversal on error! http://blogs.msdn.com/b/oldnewthing/archive/2014/06/12/10533529.aspx + { + //skip "." and ".." + const Zchar* const shortName = Trav::getItemName(findData); + if (shortName[0] == L'.' && + (shortName[1] == 0 || (shortName[1] == L'.' && shortName[2] == 0))) + continue; + + const Zstring& itempath = appendSeparator(dirpath) + shortName; + + if (Trav::isSymlink(findData)) //check first! + { + TraverseCallback::SymlinkInfo linkInfo; + linkInfo.lastWriteTime = Trav::getModTime (findData); + + switch (sink.onSymlink(shortName, itempath, linkInfo)) + { + case TraverseCallback::LINK_FOLLOW: + if (Trav::isDirectory(findData)) + { + if (TraverseCallback* trav = sink.onDir(shortName, itempath)) + { + ZEN_ON_SCOPE_EXIT(sink.releaseDirTraverser(trav)); + traverse<Trav>(itempath, *trav, retrieveVolumeSerial(itempath)); //symlink may link to different volume => redetermine volume serial! + } + } + else //a file + { + TraverseCallback::FileInfo targetInfo; + const bool validLink = tryReportingItemError([&] //try to resolve symlink (and report error on failure!!!) + { + targetInfo = getInfoFromFileSymlink(itempath); //throw FileError + targetInfo.symlinkInfo = &linkInfo; + }, sink, shortName); + + if (validLink) + sink.onFile(shortName, itempath, targetInfo); + // else //broken symlink -> ignore: it's client's responsibility to handle error! + } + break; + + case TraverseCallback::LINK_SKIP: + break; + } + } + else if (Trav::isDirectory(findData)) + { + if (TraverseCallback* trav = sink.onDir(shortName, itempath)) + { + ZEN_ON_SCOPE_EXIT(sink.releaseDirTraverser(trav)); + traverse<Trav>(itempath, *trav, volumeSerial); + } + } + else //a file + { + TraverseCallback::FileInfo fileInfo = Trav::extractFileInfo(findData, volumeSerial); + + //####################################### DST hack ########################################### + if (needDstHack) + { + const dst::RawTime rawTime(Trav::getCreateTimeRaw(findData), Trav::getModTimeRaw(findData)); + + if (dst::fatHasUtcEncoded(rawTime)) //throw std::runtime_error + fileInfo.lastWriteTime = filetimeToTimeT(dst::fatDecodeUtcTime(rawTime)); //return real UTC time; throw std::runtime_error + else + markForDstHack.push_back(std::make_pair(itempath, filetimeToTimeT(rawTime.writeTimeRaw))); + } + //####################################### DST hack ########################################### + + sink.onFile(shortName, itempath, fileInfo); + } + } +} + + #elif defined ZEN_LINUX || defined ZEN_MAC class DirTraverser { @@ -535,32 +555,34 @@ private: traverse(directoryFormatted, sink); } - DirTraverser(const DirTraverser&); - DirTraverser& operator=(const DirTraverser&); + DirTraverser (const DirTraverser&) = delete; + DirTraverser& operator=(const DirTraverser&) = delete; - void traverse(const Zstring& dirname, zen::TraverseCallback& sink) + void traverse(const Zstring& dirpath, TraverseCallback& sink) { - //no need to check for endless recursion: Linux has a fixed limit on the number of symbolic links in a path + tryReportingDirError([&] + { + traverseWithException(dirpath, sink); //throw FileError + }, sink); + } - DIR* dirObj = nullptr; - if (!tryReportingDirError([&] + void traverseWithException(const Zstring& dirpath, TraverseCallback& sink) //throw FileError { - dirObj = ::opendir(dirname.c_str()); //directory must NOT end with path separator, except "/" - if (!dirObj) - throwFileError(replaceCpy(_("Cannot open directory %x."), L"%x", fmtFileName(dirname)), L"opendir", getLastError()); - }, sink)) - return; //ignored error + //no need to check for endless recursion: Linux has a fixed limit on the number of symbolic links in a path + + DIR* dirObj = ::opendir(dirpath.c_str()); //directory must NOT end with path separator, except "/" + if (!dirObj) + throwFileError(replaceCpy(_("Cannot open directory %x."), L"%x", fmtFileName(dirpath)), L"opendir", getLastError()); ZEN_ON_SCOPE_EXIT(::closedir(dirObj)); //never close nullptr handles! -> crash for (;;) { struct ::dirent* dirEntry = nullptr; - tryReportingDirError([&] - { - if (::readdir_r(dirObj, reinterpret_cast< ::dirent*>(&buffer[0]), &dirEntry) != 0) - throwFileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtFileName(dirname)), L"readdir_r", getLastError()); - }, sink); - if (!dirEntry) //no more items or ignored error + if (::readdir_r(dirObj, reinterpret_cast< ::dirent*>(&buffer[0]), &dirEntry) != 0) + throwFileError(replaceCpy(_("Cannot enumerate directory %x."), L"%x", fmtFileName(dirpath)), L"readdir_r", getLastError()); + //don't retry but restart dir traversal on error! http://blogs.msdn.com/b/oldnewthing/archive/2014/06/12/10533529.aspx + + if (!dirEntry) //no more items return; //don't return "." and ".." @@ -588,13 +610,13 @@ private: //const char* sampleDecomposed = "\x6f\xcc\x81.txt"; //const char* samplePrecomposed = "\xc3\xb3.txt"; #endif - const Zstring& fullName = appendSeparator(dirname) + shortName; + const Zstring& itempath = appendSeparator(dirpath) + shortName; struct ::stat statData = {}; if (!tryReportingItemError([&] { - if (::lstat(fullName.c_str(), &statData) != 0) //lstat() does not resolve symlinks - throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(fullName)), L"lstat", getLastError()); + if (::lstat(itempath.c_str(), &statData) != 0) //lstat() does not resolve symlinks + throwFileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(itempath)), L"lstat", getLastError()); }, sink, shortName)) continue; //ignore error: skip file @@ -603,7 +625,7 @@ private: TraverseCallback::SymlinkInfo linkInfo; linkInfo.lastWriteTime = statData.st_mtime; //UTC time (ANSI C format); unit: 1 second - switch (sink.onSymlink(shortName, fullName, linkInfo)) + switch (sink.onSymlink(shortName, itempath, linkInfo)) { case TraverseCallback::LINK_FOLLOW: { @@ -611,28 +633,28 @@ private: struct ::stat statDataTrg = {}; bool validLink = tryReportingItemError([&] { - if (::stat(fullName.c_str(), &statDataTrg) != 0) - throwFileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(fullName)), L"stat", getLastError()); + if (::stat(itempath.c_str(), &statDataTrg) != 0) + throwFileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtFileName(itempath)), L"stat", getLastError()); }, sink, shortName); if (validLink) { if (S_ISDIR(statDataTrg.st_mode)) //a directory { - if (TraverseCallback* trav = sink.onDir(shortName, fullName)) + if (TraverseCallback* trav = sink.onDir(shortName, itempath)) { ZEN_ON_SCOPE_EXIT(sink.releaseDirTraverser(trav)); - traverse(fullName, *trav); + traverse(itempath, *trav); } } else //a file or named pipe, ect. { TraverseCallback::FileInfo fileInfo; - fileInfo.fileSize = zen::UInt64(statDataTrg.st_size); + fileInfo.fileSize = statDataTrg.st_size; fileInfo.lastWriteTime = statDataTrg.st_mtime; //UTC time (time_t format); unit: 1 second - fileInfo.id = extractFileID(statDataTrg); + fileInfo.id = extractFileId(statDataTrg); fileInfo.symlinkInfo = &linkInfo; - sink.onFile(shortName, fullName, fileInfo); + sink.onFile(shortName, itempath, fileInfo); } } // else //broken symlink -> ignore: it's client's responsibility to handle error! @@ -645,20 +667,20 @@ private: } else if (S_ISDIR(statData.st_mode)) //a directory { - if (TraverseCallback* trav = sink.onDir(shortName, fullName)) + if (TraverseCallback* trav = sink.onDir(shortName, itempath)) { ZEN_ON_SCOPE_EXIT(sink.releaseDirTraverser(trav)); - traverse(fullName, *trav); + traverse(itempath, *trav); } } else //a file or named pipe, ect. { TraverseCallback::FileInfo fileInfo; - fileInfo.fileSize = zen::UInt64(statData.st_size); + fileInfo.fileSize = statData.st_size; fileInfo.lastWriteTime = statData.st_mtime; //UTC time (time_t format); unit: 1 second - fileInfo.id = extractFileID(statData); + fileInfo.id = extractFileId(statData); - sink.onFile(shortName, fullName, fileInfo); + sink.onFile(shortName, itempath, fileInfo); } /* It may be a good idea to not check "S_ISREG(statData.st_mode)" explicitly and to not issue an error message on other types to support these scenarios: @@ -679,7 +701,12 @@ private: } -void zen::traverseFolder(const Zstring& dirname, TraverseCallback& sink, DstHackCallback* dstCallback) +void zen::traverseFolder(const Zstring& dirpath, TraverseCallback& sink, DstHackCallback* dstCallback) { - DirTraverser::execute(dirname, sink, dstCallback); + warn_static("let's tentatively disable the DST hack:") + DirTraverser::execute(dirpath, sink, nullptr); + return; +#if 0 + DirTraverser::execute(dirpath, sink, dstCallback); +#endif } diff --git a/zen/file_traverser.h b/zen/file_traverser.h index db93a688..f240d8c7 100644 --- a/zen/file_traverser.h +++ b/zen/file_traverser.h @@ -7,8 +7,8 @@ #ifndef FILETRAVERSER_H_INCLUDED #define FILETRAVERSER_H_INCLUDED +#include <cstdint> #include "zstring.h" -#include "int64.h" #include "file_id_def.h" //advanced file traverser returning metadata and hierarchical information on files and directories @@ -21,14 +21,17 @@ struct TraverseCallback struct SymlinkInfo { - Int64 lastWriteTime; //number of seconds since Jan. 1st 1970 UTC + SymlinkInfo() : lastWriteTime() {} + + std::int64_t lastWriteTime; //number of seconds since Jan. 1st 1970 UTC }; struct FileInfo { - FileInfo() : symlinkInfo() {} - UInt64 fileSize; //unit: bytes! - Int64 lastWriteTime; //number of seconds since Jan. 1st 1970 UTC + FileInfo() : fileSize(), lastWriteTime(), symlinkInfo() {} + + std::uint64_t fileSize; //unit: bytes! + std::int64_t lastWriteTime; //number of seconds since Jan. 1st 1970 UTC FileId id; //optional: initial if not supported! const SymlinkInfo* symlinkInfo; //only filled if file is a followed symlink }; @@ -45,13 +48,13 @@ struct TraverseCallback ON_ERROR_IGNORE }; - virtual void onFile (const Zchar* shortName, const Zstring& fullName, const FileInfo& details) = 0; - virtual HandleLink onSymlink(const Zchar* shortName, const Zstring& fullName, const SymlinkInfo& details) = 0; - virtual TraverseCallback* onDir (const Zchar* shortName, const Zstring& fullName) = 0; + virtual void onFile (const Zchar* shortName, const Zstring& filepath, const FileInfo& details) = 0; + virtual HandleLink onSymlink(const Zchar* shortName, const Zstring& linkpath, const SymlinkInfo& details) = 0; + virtual TraverseCallback* onDir (const Zchar* shortName, const Zstring& dirpath) = 0; //nullptr: ignore directory, non-nullptr: traverse into using the (new) callback => implement releaseDirTraverser() if necessary! virtual void releaseDirTraverser(TraverseCallback* trav) {} - virtual HandleError reportDirError (const std::wstring& msg, size_t retryNumber) = 0; //failed directory traversal -> consider directory data as incomplete! + virtual HandleError reportDirError (const std::wstring& msg, size_t retryNumber) = 0; //failed directory traversal -> consider directory data at current level as incomplete! virtual HandleError reportItemError(const std::wstring& msg, size_t retryNumber, const Zchar* shortName) = 0; //failed to get data for single file/dir/symlink only! }; @@ -60,7 +63,7 @@ struct TraverseCallback struct DstHackCallback { virtual ~DstHackCallback() {} - virtual void requestUiRefresh(const Zstring& filename) = 0; //applying DST hack imposes significant one-time performance drawback => callback to inform user + virtual void requestUiRefresh(const Zstring& filepath) = 0; //applying DST hack imposes significant one-time performance drawback => callback to inform user }; #elif defined ZEN_LINUX || defined ZEN_MAC struct DstHackCallback; //DST hack not required on Unix @@ -69,7 +72,7 @@ struct DstHackCallback; //DST hack not required on Unix //custom traverser with detail information about files //- client needs to handle duplicate file reports! (FilePlusTraverser fallback, retrying to read directory contents, ...) //- directory may end with PATH_SEPARATOR -void traverseFolder(const Zstring& dirname, //throw() +void traverseFolder(const Zstring& dirpath, //throw() TraverseCallback& sink, DstHackCallback* dstCallback = nullptr); //apply DST hack if callback is supplied } diff --git a/zen/fixed_list.h b/zen/fixed_list.h index 7e35f012..63ef3f2f 100644 --- a/zen/fixed_list.h +++ b/zen/fixed_list.h @@ -129,8 +129,8 @@ public: size_t size() const { return sz; } private: - FixedList(const FixedList&); - FixedList& operator=(const FixedList&); + FixedList (const FixedList&) = delete; + FixedList& operator=(const FixedList&) = delete; void pushNode(Node* newNode) //throw() { diff --git a/zen/format_unit.cpp b/zen/format_unit.cpp index bcf318d9..e251dc3c 100644 --- a/zen/format_unit.cpp +++ b/zen/format_unit.cpp @@ -5,20 +5,21 @@ // ************************************************************************** #include "format_unit.h" -#include <zen/basic_math.h> -#include <zen/i18n.h> -#include <zen/time.h> +#include "basic_math.h" +#include "i18n.h" +#include "time.h" +#include "int64.h" #include <cwchar> //swprintf #include <ctime> #include <cstdio> #ifdef ZEN_WIN -#include <zen/win.h> //includes "windows.h" -#include <zen/win_ver.h> +#include "win.h" //includes "windows.h" +#include "win_ver.h" #elif defined ZEN_LINUX || defined ZEN_MAC -#include <clocale> //thousands separator -#include <zen/utf.h> // +#include <clocale> //thousands separator +#include "utf.h" // #endif using namespace zen; @@ -35,14 +36,15 @@ std::wstring zen::formatThreeDigitPrecision(double value) } -std::wstring zen::filesizeToShortString(Int64 size) +std::wstring zen::filesizeToShortString(std::int64_t size) { //if (size < 0) return _("Error"); -> really? if (numeric::abs(size) <= 999) - return _P("1 byte", "%x bytes", to<int>(size)); + return _P("1 byte", "%x bytes", static_cast<int>(size)); + + double sizeInUnit = static_cast<double>(size); - double sizeInUnit = to<double>(size); auto formatUnit = [&](const std::wstring& unitTxt) { return replaceCpy(unitTxt, L"%x", formatThreeDigitPrecision(sizeInUnit)); }; sizeInUnit /= 1024; @@ -282,12 +284,12 @@ const bool useNewLocalTimeCalculation = zen::vistaOrLater(); #endif -std::wstring zen::utcToLocalTimeString(Int64 utcTime) +std::wstring zen::utcToLocalTimeString(std::int64_t utcTime) { auto errorMsg = [&] { return _("Error") + L" (time_t: " + numberTo<std::wstring>(utcTime) + L")"; }; #ifdef ZEN_WIN - FILETIME lastWriteTimeUtc = toFileTime(utcTime); //convert ansi C time to FILETIME + FILETIME lastWriteTimeUtc = timetToFileTime(utcTime); //convert ansi C time to FILETIME SYSTEMTIME systemTimeLocal = {}; @@ -325,7 +327,7 @@ std::wstring zen::utcToLocalTimeString(Int64 utcTime) loc.second = systemTimeLocal.wSecond; #elif defined ZEN_LINUX || defined ZEN_MAC - zen::TimeComp loc = zen::localTime(to<time_t>(utcTime)); + zen::TimeComp loc = zen::localTime(utcTime); #endif std::wstring dateString = formatTime<std::wstring>(L"%x %X", loc); diff --git a/zen/format_unit.h b/zen/format_unit.h index e3e2d107..237b9f04 100644 --- a/zen/format_unit.h +++ b/zen/format_unit.h @@ -8,15 +8,15 @@ #define FMT_UNIT_8702184019487324 #include <string> -#include <zen/int64.h> -#include <zen/string_tools.h> +#include <cstdint> +#include "string_tools.h" namespace zen { -std::wstring filesizeToShortString(Int64 filesize); +std::wstring filesizeToShortString(std::int64_t filesize); std::wstring remainingTimeToString(double timeInSec); std::wstring fractionToString(double fraction); //within [0, 1] -std::wstring utcToLocalTimeString(Int64 utcTime); //like Windows Explorer would... +std::wstring utcToLocalTimeString(std::int64_t utcTime); //like Windows Explorer would... std::wstring formatThreeDigitPrecision(double value); //= *at least* three digits @@ -44,7 +44,7 @@ std::wstring includeNumberSeparator(const std::wstring& number); template <class NumberType> inline std::wstring toGuiString(NumberType number) { - //assert_static(IsInteger<NumberType>::value); -> doesn't work for UInt64 + assert_static(IsInteger<NumberType>::value); return ffs_Impl::includeNumberSeparator(zen::numberTo<std::wstring>(number)); } } diff --git a/zen/int64.h b/zen/int64.h index f658e034..4183c8da 100644 --- a/zen/int64.h +++ b/zen/int64.h @@ -7,251 +7,65 @@ #ifndef FFS_LARGE_64_BIT_INTEGER_H_INCLUDED #define FFS_LARGE_64_BIT_INTEGER_H_INCLUDED -#include <cassert> -#include <limits> #include <cstdint> -#include <cstdint> -#include <ostream> -#include "assert_static.h" -#include "type_tools.h" #ifdef ZEN_WIN #include "win.h" #endif -/* -zen::Int64/zen::UInt64: wrapper classes around std::int64_t/std::uint64_t - - - default initialization with 0 - - debug runtime overflow/underflow checks - - safe and explicit semantics: no unsafe type conversions - - safe conversion to and from Windows 64-bit integers - - specializes std::numeric_limits - - support stream operator<< and operator>> -*/ - namespace zen { -template <class T, class U> inline -void checkRange(U value) -{ - //caveat: std::numeric_limits<T>::min returns minimum positive(!) number for T = double, while behaving correctly for integer types... sigh - assert(double(std::numeric_limits<T>::lowest()) <= double(value) && //new with C++11! - double(std::numeric_limits<T>::max() ) >= double(value)); -} - -class Int64 -{ -public: - //safe implicit conversions - Int64() : value(0) {} - Int64(const Int64& rhs) : value(rhs.value) {} - template <class T> - Int64(T rhs, typename EnableIf<IsSignedInt<T>::value&& sizeof(T) <= sizeof(std::int64_t)>::Type* = nullptr) : - value(static_cast<std::int64_t>(rhs)) {} - - //unsafe explicit but checked conversion for all other integer types - template <class T> explicit Int64(T rhs, typename EnableIf<!(IsSignedInt<T>::value&& sizeof(T) <= sizeof(std::int64_t))>::Type* = nullptr) : - value(static_cast<std::int64_t>(rhs)) { checkRange<std::int64_t>(rhs); } - - Int64& operator=(const Int64& rhs) { value = rhs.value; return *this; } - #ifdef ZEN_WIN - Int64(DWORD low, LONG high) +inline + std::int64_t get64BitInt(DWORD low, LONG high) { - assert_static(sizeof(low) + sizeof(high) == sizeof(value)); + static_assert(sizeof(low) + sizeof(high) == sizeof(std::int64_t), ""); LARGE_INTEGER cvt = {}; cvt.LowPart = low; cvt.HighPart = high; - value = cvt.QuadPart; - } - LONG getHi() const - { - LARGE_INTEGER cvt = {}; - cvt.QuadPart = value; - return cvt.HighPart; + return cvt.QuadPart; } - DWORD getLo() const - { - LARGE_INTEGER cvt = {}; - cvt.QuadPart = value; - return cvt.LowPart; - } -#endif - - Int64& operator+=(const Int64& rhs) { checkRange<std::int64_t>(double(value) + rhs.value); value += rhs.value; return *this; } - Int64& operator-=(const Int64& rhs) { checkRange<std::int64_t>(double(value) - rhs.value); value -= rhs.value; return *this; } - Int64& operator*=(const Int64& rhs) { checkRange<std::int64_t>(double(value) * rhs.value); value *= rhs.value; return *this; } - Int64& operator/=(const Int64& rhs) { assert(rhs.value != 0); value /= rhs.value; return *this; } - Int64& operator%=(const Int64& rhs) { assert(rhs.value != 0); value %= rhs.value; return *this; } - Int64& operator&=(const Int64& rhs) { value &= rhs.value; return *this;} - Int64& operator|=(const Int64& rhs) { value |= rhs.value; return *this;} - Int64& operator<<=(int rhs) { assert(rhs < 0 || (value << rhs) >> rhs == value); value <<= rhs; return *this; } - Int64& operator>>=(int rhs) { assert(rhs > 0 || (value >> rhs) << rhs == value); value >>= rhs; return *this; } - Int64 operator-() const { return -value; } - - inline friend bool operator==(const Int64& lhs, const Int64& rhs) { return lhs.value == rhs.value; } - inline friend bool operator!=(const Int64& lhs, const Int64& rhs) { return lhs.value != rhs.value; } - inline friend bool operator< (const Int64& lhs, const Int64& rhs) { return lhs.value < rhs.value; } - inline friend bool operator> (const Int64& lhs, const Int64& rhs) { return lhs.value > rhs.value; } - inline friend bool operator<=(const Int64& lhs, const Int64& rhs) { return lhs.value <= rhs.value; } - inline friend bool operator>=(const Int64& lhs, const Int64& rhs) { return lhs.value >= rhs.value; } - - //checked conversion to arbitrary target integer type - template <class T> inline friend T to(Int64 number) { checkRange<T>(number.value); return static_cast<T>(number.value); } - template <class T> inline friend std::basic_istream<T>& operator>>(std::basic_istream<T>& lhs, Int64& rhs) { lhs >> rhs.value; return lhs; } - template <class T> inline friend std::basic_ostream<T>& operator<<(std::basic_ostream<T>& lhs, const Int64& rhs) { lhs << rhs.value; return lhs; } +std::int64_t get64BitInt(std::uint64_t low, std::int64_t high) = delete; -private: - std::int64_t value; -}; -inline Int64 operator+ (const Int64& lhs, const Int64& rhs) { return Int64(lhs) += rhs; } -inline Int64 operator- (const Int64& lhs, const Int64& rhs) { return Int64(lhs) -= rhs; } -inline Int64 operator* (const Int64& lhs, const Int64& rhs) { return Int64(lhs) *= rhs; } -inline Int64 operator/ (const Int64& lhs, const Int64& rhs) { return Int64(lhs) /= rhs; } -inline Int64 operator% (const Int64& lhs, const Int64& rhs) { return Int64(lhs) %= rhs; } -inline Int64 operator& (const Int64& lhs, const Int64& rhs) { return Int64(lhs) &= rhs; } -inline Int64 operator| (const Int64& lhs, const Int64& rhs) { return Int64(lhs) |= rhs; } -inline Int64 operator<<(const Int64& lhs, int rhs) { return Int64(lhs) <<= rhs; } -inline Int64 operator>>(const Int64& lhs, int rhs) { return Int64(lhs) >>= rhs; } - - -class UInt64 -{ -public: - //safe implicit conversions - UInt64() : value(0) {} - UInt64(const UInt64& rhs) : value(rhs.value) {} - template <class T> - UInt64(T rhs, typename EnableIf<IsUnsignedInt<T>::value&& sizeof(T) <= sizeof(std::uint64_t)>::Type* = nullptr) : - value(static_cast<std::uint64_t>(rhs)) {} - - //unsafe explicit but checked conversion for all other integer types - template <class T> explicit UInt64(T rhs, typename EnableIf<!(IsUnsignedInt<T>::value&& sizeof(T) <= sizeof(std::uint64_t))>::Type* = nullptr) : - value(static_cast<std::uint64_t>(rhs)) { checkRange<std::uint64_t>(rhs); } - - UInt64& operator=(const UInt64& rhs) { value = rhs.value; return *this; } - -#ifdef ZEN_WIN - UInt64(DWORD low, DWORD high) +inline +std::uint64_t get64BitUInt(DWORD low, DWORD high) { - assert_static(sizeof(low) + sizeof(high) == sizeof(value)); + static_assert(sizeof(low) + sizeof(high) == sizeof(std::uint64_t), ""); ULARGE_INTEGER cvt = {}; cvt.LowPart = low; cvt.HighPart = high; - value = cvt.QuadPart; - } - DWORD getHi() const - { - ULARGE_INTEGER cvt = {}; - cvt.QuadPart = value; - return cvt.HighPart; - } - DWORD getLo() const - { - ULARGE_INTEGER cvt = {}; - cvt.QuadPart = value; - return cvt.LowPart; + return cvt.QuadPart; } -#endif - - UInt64& operator+=(const UInt64& rhs) { checkRange<std::uint64_t>(double(value) + rhs.value); value += rhs.value; return *this; } - UInt64& operator-=(const UInt64& rhs) { checkRange<std::uint64_t>(double(value) - rhs.value); value -= rhs.value; return *this; } - UInt64& operator*=(const UInt64& rhs) { checkRange<std::uint64_t>(double(value) * rhs.value); value *= rhs.value; return *this; } - UInt64& operator/=(const UInt64& rhs) { assert(rhs.value != 0); value /= rhs.value; return *this; } - UInt64& operator%=(const UInt64& rhs) { assert(rhs.value != 0); value %= rhs.value; return *this; } - UInt64& operator&=(const UInt64& rhs) { value &= rhs.value; return *this;} - UInt64& operator|=(const UInt64& rhs) { value |= rhs.value; return *this;} - UInt64& operator<<=(int rhs) { assert(rhs < 0 || (value << rhs) >> rhs == value); value <<= rhs; return *this; } - UInt64& operator>>=(int rhs) { assert(rhs > 0 || (value >> rhs) << rhs == value); value >>= rhs; return *this; } - - inline friend bool operator==(const UInt64& lhs, const UInt64& rhs) { return lhs.value == rhs.value; } - inline friend bool operator!=(const UInt64& lhs, const UInt64& rhs) { return lhs.value != rhs.value; } - inline friend bool operator< (const UInt64& lhs, const UInt64& rhs) { return lhs.value < rhs.value; } - inline friend bool operator> (const UInt64& lhs, const UInt64& rhs) { return lhs.value > rhs.value; } - inline friend bool operator<=(const UInt64& lhs, const UInt64& rhs) { return lhs.value <= rhs.value; } - inline friend bool operator>=(const UInt64& lhs, const UInt64& rhs) { return lhs.value >= rhs.value; } - - //checked conversion to arbitrary target integer type - template <class T> friend T to(UInt64 number); - - template <class T> inline friend std::basic_istream<T>& operator>>(std::basic_istream<T>& lhs, UInt64& rhs) { lhs >> rhs.value; return lhs; } - template <class T> inline friend std::basic_ostream<T>& operator<<(std::basic_ostream<T>& lhs, const UInt64& rhs) { lhs << rhs.value; return lhs; } - -private: - std::uint64_t value; -}; - -template <class T> inline T to(UInt64 number) { checkRange<T>(number.value); return static_cast<T>(number.value); } //Clang 3.2 doesn't properly handle inline-friends defined in class definition -inline UInt64 operator+ (const UInt64& lhs, const UInt64& rhs) { return UInt64(lhs) += rhs; } -inline UInt64 operator- (const UInt64& lhs, const UInt64& rhs) { return UInt64(lhs) -= rhs; } -inline UInt64 operator* (const UInt64& lhs, const UInt64& rhs) { return UInt64(lhs) *= rhs; } -inline UInt64 operator/ (const UInt64& lhs, const UInt64& rhs) { return UInt64(lhs) /= rhs; } -inline UInt64 operator% (const UInt64& lhs, const UInt64& rhs) { return UInt64(lhs) %= rhs; } -inline UInt64 operator& (const UInt64& lhs, const UInt64& rhs) { return UInt64(lhs) &= rhs; } -inline UInt64 operator| (const UInt64& lhs, const UInt64& rhs) { return UInt64(lhs) |= rhs; } -inline UInt64 operator<<(const UInt64& lhs, int rhs) { return UInt64(lhs) <<= rhs; } -inline UInt64 operator>>(const UInt64& lhs, int rhs) { return UInt64(lhs) >>= rhs; } +std::int64_t get64BitUInt(std::uint64_t low, std::uint64_t high) = delete; -template <> inline UInt64 to(Int64 number) { checkRange<std::uint64_t>(number.value); return UInt64(number.value); } -template <> inline Int64 to(UInt64 number) { checkRange<std:: int64_t>(number.value); return Int64(number.value); } - -#ifdef ZEN_WIN //convert FILETIME (number of 100-nanosecond intervals since January 1, 1601 UTC) // to time_t (number of seconds since Jan. 1st 1970 UTC) // //FAT32 time is preserved exactly: FAT32 -> toTimeT -> tofiletime -> FAT32 inline -Int64 toTimeT(const FILETIME& ft) +std::int64_t filetimeToTimeT(const FILETIME& ft) { - return to<Int64>(UInt64(ft.dwLowDateTime, ft.dwHighDateTime) / 10000000U) - Int64(3054539008UL, 2); + return static_cast<std::int64_t>(get64BitUInt(ft.dwLowDateTime, ft.dwHighDateTime) / 10000000U) - get64BitInt(3054539008UL, 2); //caveat: signed/unsigned arithmetics! //timeshift between ansi C time and FILETIME in seconds == 11644473600s } inline -FILETIME toFileTime(const Int64& utcTime) -{ - const UInt64 fileTimeLong = to<UInt64>(utcTime + Int64(3054539008UL, 2)) * 10000000U; - const FILETIME output = { fileTimeLong.getLo(), fileTimeLong.getHi() }; +FILETIME timetToFileTime(std::int64_t utcTime) +{ + ULARGE_INTEGER cvt = {}; + cvt.QuadPart = (utcTime + get64BitInt(3054539008UL, 2)) * 10000000U; //caveat: signed/unsigned arithmetics! + + const FILETIME output = { cvt.LowPart, cvt.HighPart }; return output; } #endif } -//specialize numeric limits -namespace std -{ -assert_static(std::numeric_limits<std:: int64_t>::is_specialized); -assert_static(std::numeric_limits<std::uint64_t>::is_specialized); - -template <> class numeric_limits<zen::Int64> : public numeric_limits<std::int64_t> -{ -public: - static zen::Int64 min() throw() { return numeric_limits<std::int64_t>::min(); } - static zen::Int64 max() throw() { return numeric_limits<std::int64_t>::max(); } -}; - -template <> class numeric_limits<zen::UInt64> : public numeric_limits<std::uint64_t> -{ -public: - static zen::UInt64 min() throw() { return numeric_limits<std::uint64_t>::min(); } - static zen::UInt64 max() throw() { return numeric_limits<std::uint64_t>::max(); } -}; -} - -/* -//specialize zen type trait -namespace zen -> we cannot mix signed/unsigned in general arithmetic operations -> we'll use the ostream-approach -{ -template <> struct IsUnsignedInt<UInt64> : StaticBool<true> {}; -template <> struct IsSignedInt <Int64> : StaticBool<true> {}; -} -*/ #endif //FFS_LARGE_64_BIT_INTEGER_H_INCLUDED diff --git a/zen/long_path_prefix.h b/zen/long_path_prefix.h index 0669cf88..824c7084 100644 --- a/zen/long_path_prefix.h +++ b/zen/long_path_prefix.h @@ -12,14 +12,14 @@ namespace zen { -//handle filenames longer-equal 260 (== MAX_PATH) characters by applying \\?\-prefix; see: http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath +//handle filepaths longer-equal 260 (== MAX_PATH) characters by applying \\?\-prefix; see: http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath /* 1. path must be absolute 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); //noexcept -Zstring applyLongPathPrefixCreateDir(const Zstring& path); //noexcept -> special rule for ::CreateDirectory()/::CreateDirectoryEx(): MAX_PATH - 12(=^ 8.3 filename) is threshold +Zstring applyLongPathPrefixCreateDir(const Zstring& path); //noexcept -> special rule for ::CreateDirectory()/::CreateDirectoryEx(): MAX_PATH - 12(=^ 8.3 filepath) is threshold Zstring removeLongPathPrefix(const Zstring& path); //noexcept @@ -97,7 +97,7 @@ Zstring zen::applyLongPathPrefix(const Zstring& path) inline Zstring zen::applyLongPathPrefixCreateDir(const Zstring& path) //noexcept { - //special rule for ::CreateDirectoryEx(): MAX_PATH - 12(=^ 8.3 filename) is threshold + //special rule for ::CreateDirectoryEx(): MAX_PATH - 12(=^ 8.3 filepath) is threshold return applyLongPathPrefixImpl<MAX_PATH - 12> (path); } diff --git a/zen/notify_removal.cpp b/zen/notify_removal.cpp index c66eb3c1..3de375f2 100644 --- a/zen/notify_removal.cpp +++ b/zen/notify_removal.cpp @@ -35,8 +35,8 @@ public: private: MessageProvider(); ~MessageProvider(); - MessageProvider(const MessageProvider&); - MessageProvider& operator=(const MessageProvider&); + MessageProvider (const MessageProvider&) = delete; + MessageProvider& operator=(const MessageProvider&) = delete; static const wchar_t dummyWindowName[]; @@ -173,8 +173,8 @@ public: } private: - Pimpl(Pimpl&); - Pimpl& operator=(Pimpl&); + Pimpl (const Pimpl&) = delete; + Pimpl& operator=(const Pimpl&) = delete; virtual void onMessage(UINT message, WPARAM wParam, LPARAM lParam) //throw()! { diff --git a/zen/process_priority.cpp b/zen/process_priority.cpp index a50fbd75..d2f6dc26 100644 --- a/zen/process_priority.cpp +++ b/zen/process_priority.cpp @@ -5,18 +5,17 @@ // ************************************************************************** #include "process_priority.h" -#include <zen/sys_error.h> -#include <zen/i18n.h> +#include "sys_error.h" +#include "i18n.h" #ifdef ZEN_WIN #include "win.h" //includes "windows.h" #elif defined ZEN_LINUX -//#include <sys/syscall.h> #elif defined ZEN_MAC #include <sys/resource.h> //getiopolicy_np -#include <IOKit/pwr_mgt/IOPMLib.h> //keep in .cpp file to not pollute global namespace! e.g. with UInt64 +#include <IOKit/pwr_mgt/IOPMLib.h> //keep in .cpp file to not pollute global namespace! #endif using namespace zen; diff --git a/zen/recycler.cpp b/zen/recycler.cpp index 0e4e4be0..41ea6002 100644 --- a/zen/recycler.cpp +++ b/zen/recycler.cpp @@ -5,7 +5,7 @@ // ************************************************************************** #include "recycler.h" -#include <zen/file_handling.h> +#include "file_handling.h" #ifdef ZEN_WIN #include "thread.h" @@ -16,9 +16,9 @@ #include "IFileOperation/file_op.h" #elif defined ZEN_LINUX -#include <zen/scope_guard.h> #include <sys/stat.h> #include <gio/gio.h> +#include "scope_guard.h" #elif defined ZEN_MAC #include <CoreServices/CoreServices.h> @@ -54,14 +54,14 @@ struct CallbackData }; -bool onRecyclerCallback(const wchar_t* filename, void* sink) +bool onRecyclerCallback(const wchar_t* itempath, void* sink) { CallbackData& cbd = *static_cast<CallbackData*>(sink); //sink is NOT optional here if (cbd.notifyDeletionStatus_) try { - cbd.notifyDeletionStatus_(filename); //throw ? + cbd.notifyDeletionStatus_(itempath); //throw ? } catch (...) { @@ -73,11 +73,11 @@ bool onRecyclerCallback(const wchar_t* filename, void* sink) } -void zen::recycleOrDelete(const std::vector<Zstring>& filenames, const std::function<void (const Zstring& currentItem)>& notifyDeletionStatus) +void zen::recycleOrDelete(const std::vector<Zstring>& itempaths, const std::function<void (const Zstring& currentItem)>& notifyDeletionStatus) { - if (filenames.empty()) + if (itempaths.empty()) return; - //::SetFileAttributes(applyLongPathPrefix(filename).c_str(), FILE_ATTRIBUTE_NORMAL); + //::SetFileAttributes(applyLongPathPrefix(itempath).c_str(), FILE_ATTRIBUTE_NORMAL); //warning: moving long file paths to recycler does not work! //both ::SHFileOperation() and ::IFileOperation() cannot delete a folder named "System Volume Information" with normal attributes but shamelessly report success //both ::SHFileOperation() and ::IFileOperation() can't handle \\?\-prefix! @@ -89,11 +89,11 @@ void zen::recycleOrDelete(const std::vector<Zstring>& filenames, const std::func const DllFun<FunType_getLastErrorMessage> getLastErrorMessage(getDllName(), funName_getLastErrorMessage); if (!moveToRecycler || !getLastErrorMessage) - throw FileError(replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", fmtFileName(filenames[0])), + throw FileError(replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", fmtFileName(itempaths[0])), replaceCpy(_("Cannot load file %x."), L"%x", fmtFileName(getDllName()))); std::vector<const wchar_t*> cNames; - for (auto it = filenames.begin(); it != filenames.end(); ++it) //CAUTION: do not create temporary strings here!! + for (auto it = itempaths.begin(); it != itempaths.end(); ++it) //CAUTION: do not create temporary strings here!! cNames.push_back(it->c_str()); CallbackData cbd(notifyDeletionStatus); @@ -106,26 +106,26 @@ void zen::recycleOrDelete(const std::vector<Zstring>& filenames, const std::func assert(false); } - std::wstring filenameFmt = fmtFileName(filenames[0]); //probably not the correct file name for file lists larger than 1! - 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 + std::wstring itempathFmt = fmtFileName(itempaths[0]); //probably not the correct file name for file lists larger than 1! + if (itempaths.size() > 1) + itempathFmt += 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), getLastErrorMessage()); //already includes details about locking errors! + throw FileError(replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", itempathFmt), getLastErrorMessage()); //already includes details about locking errors! } } else //regular recycle bin usage: available since XP { - Zstring filenamesDoubleNull; - for (const Zstring& filename : filenames) + Zstring itempathsDoubleNull; + for (const Zstring& itempath : itempaths) { - filenamesDoubleNull += filename; - filenamesDoubleNull += L'\0'; + itempathsDoubleNull += itempath; + itempathsDoubleNull += L'\0'; } SHFILEOPSTRUCT fileOp = {}; fileOp.hwnd = nullptr; fileOp.wFunc = FO_DELETE; - fileOp.pFrom = filenamesDoubleNull.c_str(); + fileOp.pFrom = itempathsDoubleNull.c_str(); fileOp.pTo = nullptr; fileOp.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_SILENT | FOF_NOERRORUI; fileOp.fAnyOperationsAborted = false; @@ -135,25 +135,25 @@ void zen::recycleOrDelete(const std::vector<Zstring>& filenames, const std::func //"You should use fully-qualified path names with this function. Using it with relative path names is not thread safe." if (::SHFileOperation(&fileOp) != 0 || fileOp.fAnyOperationsAborted) { - throw FileError(replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", fmtFileName(filenames[0]))); //probably not the correct file name for file list larger than 1! + throw FileError(replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", fmtFileName(itempaths[0]))); //probably not the correct file name for file list larger than 1! } } } #endif -bool zen::recycleOrDelete(const Zstring& filename) //throw FileError +bool zen::recycleOrDelete(const Zstring& itempath) //throw FileError { - if (!somethingExists(filename)) //[!] do not optimize away, OS X needs this for reliable detection of "recycle bin missing" + if (!somethingExists(itempath)) //[!] do not optimize away, OS X needs this for reliable detection of "recycle bin missing" return false; //neither file nor any other object with that name existing: no error situation, manual deletion relies on it! #ifdef ZEN_WIN - std::vector<Zstring> filenames; - filenames.push_back(filename); - recycleOrDelete(filenames, nullptr); //throw FileError + std::vector<Zstring> itempaths; + itempaths.push_back(itempath); + recycleOrDelete(itempaths, nullptr); //throw FileError #elif defined ZEN_LINUX - GFile* file = ::g_file_new_for_path(filename.c_str()); //never fails according to docu + GFile* file = ::g_file_new_for_path(itempath.c_str()); //never fails according to docu ZEN_ON_SCOPE_EXIT(g_object_unref(file);) GError* error = nullptr; @@ -161,7 +161,7 @@ bool zen::recycleOrDelete(const Zstring& filename) //throw FileError if (!::g_file_trash(file, nullptr, &error)) { - const std::wstring errorMsg = replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", fmtFileName(filename)); + const std::wstring errorMsg = replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", fmtFileName(itempath)); if (!error) throw FileError(errorMsg, L"Unknown error."); //user should never see this @@ -170,13 +170,13 @@ bool zen::recycleOrDelete(const Zstring& filename) //throw FileError if (error->code == G_IO_ERROR_NOT_SUPPORTED) { struct ::stat fileInfo = {}; - if (::lstat(filename.c_str(), &fileInfo) != 0) + if (::lstat(itempath.c_str(), &fileInfo) != 0) return false; if (S_ISLNK(fileInfo.st_mode) || S_ISREG(fileInfo.st_mode)) - removeFile(filename); //throw FileError + removeFile(itempath); //throw FileError else if (S_ISDIR(fileInfo.st_mode)) - removeDirectory(filename); //throw FileError + removeDirectory(itempath); //throw FileError return true; } @@ -188,11 +188,11 @@ bool zen::recycleOrDelete(const Zstring& filename) //throw FileError //we cannot use FSPathMoveObjectToTrashSync directly since it follows symlinks! assert_static(sizeof(Zchar) == sizeof(char)); - const UInt8* filenameUtf8 = reinterpret_cast<const UInt8*>(filename.c_str()); + const UInt8* itempathUtf8 = reinterpret_cast<const UInt8*>(itempath.c_str()); auto throwFileError = [&](OSStatus oss) { - const std::wstring errorMsg = replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", fmtFileName(filename)); + const std::wstring errorMsg = replaceCpy(_("Unable to move %x to the recycle bin."), L"%x", fmtFileName(itempath)); std::wstring errorDescr = L"OSStatus Code " + numberTo<std::wstring>(oss); if (const char* description = ::GetMacOSStatusCommentString(oss)) //found no documentation for proper use of GetMacOSStatusCommentString @@ -201,7 +201,7 @@ bool zen::recycleOrDelete(const Zstring& filename) //throw FileError }; FSRef objectRef = {}; //= POD structure not a pointer type! - OSStatus rv = ::FSPathMakeRefWithOptions(filenameUtf8, //const UInt8 *path, + OSStatus rv = ::FSPathMakeRefWithOptions(itempathUtf8, //const UInt8 *path, kFSPathMakeRefDoNotFollowLeafSymlink, //OptionBits options, &objectRef, //FSRef *ref, nullptr); //Boolean *isDirectory @@ -218,13 +218,13 @@ bool zen::recycleOrDelete(const Zstring& filename) //throw FileError if (rv2 == -120) //=="Directory not found or incomplete pathname." but should really be "recycle bin directory not found"! { struct ::stat fileInfo = {}; - if (::lstat(filename.c_str(), &fileInfo) != 0) + if (::lstat(itempath.c_str(), &fileInfo) != 0) return false; if (S_ISLNK(fileInfo.st_mode) || S_ISREG(fileInfo.st_mode)) - removeFile(filename); //throw FileError + removeFile(itempath); //throw FileError else if (S_ISDIR(fileInfo.st_mode)) - removeDirectory(filename); //throw FileError + removeDirectory(itempath); //throw FileError return true; } @@ -352,7 +352,7 @@ We really need access to a similar function to check whether a directory support The following function looks perfect, alas it is restricted to local files and to the implementation of GIO only: - gboolean _g_local_file_has_trash_dir(const char* dirname, dev_t dir_dev); + gboolean _g_local_file_has_trash_dir(const char* dirpath, dev_t dir_dev); See: http://www.netmite.com/android/mydroid/2.0/external/bluetooth/glib/gio/glocalfileinfo.h Just checking for "G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH" is not correct, since we find in diff --git a/zen/recycler.h b/zen/recycler.h index 255f11ef..e900dfa3 100644 --- a/zen/recycler.h +++ b/zen/recycler.h @@ -9,8 +9,7 @@ #include <vector> #include <functional> -#include <zen/file_error.h> -#include <zen/zstring.h> +#include "file_error.h" namespace zen { @@ -32,14 +31,14 @@ Already included in package "gtk+-2.0"! */ //move a file or folder to Recycle Bin (deletes permanently if recycler is not available) -> crappy semantics, but we have no choice thanks to Windows' design -bool recycleOrDelete(const Zstring& filename); //throw FileError, return "true" if file/dir was actually deleted +bool recycleOrDelete(const Zstring& itempath); //throw FileError, return "true" if file/dir was actually deleted #ifdef ZEN_WIN //can take a long time if recycle bin is full and drive is slow!!! => buffer volume ids! bool recycleBinExists(const Zstring& pathName, const std::function<void ()>& onUpdateGui); //throw FileError -void recycleOrDelete(const std::vector<Zstring>& filenames, //throw FileError, return "true" if file/dir was actually deleted +void recycleOrDelete(const std::vector<Zstring>& filepaths, //throw FileError, return "true" if file/dir was actually deleted //may throw: first exception is swallowed, updateStatus() is then called again where it should throw again and the exception will propagate as expected const std::function<void (const Zstring& currentItem)>& notifyDeletionStatus); //optional; currentItem may be empty #endif diff --git a/zen/serialize.h b/zen/serialize.h index 9a14e6af..64df0329 100644 --- a/zen/serialize.h +++ b/zen/serialize.h @@ -8,8 +8,8 @@ #define SERIALIZE_H_INCLUDED_83940578357 #include <cstdint> -#include <zen/string_base.h> -#include <zen/file_io.h> +#include "string_base.h" +#include "file_io.h" namespace zen { @@ -54,8 +54,8 @@ private: //---------------------------------------------------------------------- //functions based on binary container abstraction -template <class BinContainer> void saveBinStream(const Zstring& filename, const BinContainer& cont); //throw FileError -template <class BinContainer> BinContainer loadBinStream(const Zstring& filename); //throw FileError +template <class BinContainer> void saveBinStream(const Zstring& filepath, const BinContainer& cont); //throw FileError +template <class BinContainer> BinContainer loadBinStream(const Zstring& filepath); //throw FileError /* @@ -135,22 +135,22 @@ template < class BinInputStream> void readArray (BinInputStream& stre //-----------------------implementation------------------------------- template <class BinContainer> inline -void saveBinStream(const Zstring& filename, const BinContainer& cont) //throw FileError +void saveBinStream(const Zstring& filepath, const BinContainer& cont) //throw FileError { assert_static(sizeof(typename BinContainer::value_type) == 1); //expect: bytes (until further) - FileOutput fileOut(filename, zen::FileOutput::ACC_OVERWRITE); //throw FileError + FileOutput fileOut(filepath, zen::FileOutput::ACC_OVERWRITE); //throw FileError if (!cont.empty()) fileOut.write(&*cont.begin(), cont.size()); //throw FileError } template <class BinContainer> inline -BinContainer loadBinStream(const Zstring& filename) //throw FileError +BinContainer loadBinStream(const Zstring& filepath) //throw FileError { assert_static(sizeof(typename BinContainer::value_type) == 1); //expect: bytes (until further) - FileInput fileIn(filename); //throw FileError + FileInput fileIn(filepath); //throw FileError BinContainer contOut; const size_t blockSize = 128 * 1024; diff --git a/zen/shell_execute.h b/zen/shell_execute.h index 78526b70..9f99315a 100644 --- a/zen/shell_execute.h +++ b/zen/shell_execute.h @@ -46,11 +46,11 @@ void shellExecute2(const Zstring& command, ExecutionType type) //throw FileError std::copy(tmp, tmp + argc, std::back_inserter(argv)); } - Zstring filename; + Zstring filepath; Zstring arguments; if (!argv.empty()) { - filename = argv[0]; + filepath = argv[0]; for (auto iter = argv.begin() + 1; iter != argv.end(); ++iter) arguments += (iter != argv.begin() ? L" " : L"") + (iter->empty() || std::any_of(iter->begin(), iter->end(), &isWhiteSpace<wchar_t>) ? L"\"" + *iter + L"\"" : *iter); @@ -63,12 +63,12 @@ void shellExecute2(const Zstring& command, ExecutionType type) //throw FileError execInfo.fMask = type == EXEC_TYPE_SYNC ? (SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT) : 0; //don't use SEE_MASK_ASYNCOK -> returns successful despite errors! execInfo.fMask |= SEE_MASK_UNICODE | SEE_MASK_FLAG_NO_UI; //::ShellExecuteEx() shows a non-blocking pop-up dialog on errors -> we want a blocking one execInfo.lpVerb = nullptr; - execInfo.lpFile = filename.c_str(); + execInfo.lpFile = filepath.c_str(); execInfo.lpParameters = arguments.c_str(); execInfo.nShow = SW_SHOWNORMAL; if (!::ShellExecuteEx(&execInfo)) //__inout LPSHELLEXECUTEINFO lpExecInfo - throwFileError(_("Incorrect command line:") + L"\nFile: " + filename + L"\nArg: " + arguments, L"ShellExecuteEx", ::GetLastError()); + throwFileError(_("Incorrect command line:") + L"\nFile: " + filepath + L"\nArg: " + arguments, L"ShellExecuteEx", ::GetLastError()); if (execInfo.hProcess) { diff --git a/zen/symlink_target.h b/zen/symlink_target.h index 13226f1f..21833492 100644 --- a/zen/symlink_target.h +++ b/zen/symlink_target.h @@ -12,7 +12,6 @@ #ifdef ZEN_WIN #include "win.h" //includes "windows.h" -//#include <WinIoCtl.h> #include "privilege.h" #include "long_path_prefix.h" #include "dll.h" diff --git a/zen/thread.h b/zen/thread.h index d74eaa5b..8c72e43f 100644 --- a/zen/thread.h +++ b/zen/thread.h @@ -43,8 +43,8 @@ std::async replacement without crappy semantics: 2. does not follow C++11 [futures.async], Paragraph 5, where std::future waits for thread in destructor Example: - Zstring dirname = ... - auto ft = zen::async([=](){ return zen::dirExists(dirname); }); + Zstring dirpath = ... + auto ft = zen::async([=](){ return zen::dirExists(dirpath); }); if (ft.timed_wait(boost::posix_time::milliseconds(200)) && ft.get()) //dir exising */ diff --git a/zen/win_ver.h b/zen/win_ver.h index 766c0ee9..e123737d 100644 --- a/zen/win_ver.h +++ b/zen/win_ver.h @@ -8,7 +8,7 @@ #define WINDOWS_VERSION_HEADER_238470348254325 #include <cstdint> -#include <zen/win.h> //includes "windows.h" +#include "win.h" //includes "windows.h" namespace zen { diff --git a/zen/xml_io.cpp b/zen/xml_io.cpp index a8236300..485d78bb 100644 --- a/zen/xml_io.cpp +++ b/zen/xml_io.cpp @@ -12,13 +12,13 @@ using namespace zen; -XmlDoc zen::loadXmlDocument(const Zstring& filename) //throw FileError +XmlDoc zen::loadXmlDocument(const Zstring& filepath) //throw FileError { //can't simply use zen::loadBinStream() due to the short-circuit xml-validation below! std::string stream; - FileInput inputFile(filename); //throw FileError + FileInput inputFile(filepath); //throw FileError { //quick test whether input is an XML: avoid loading large binary files up front! const std::string xmlBegin = "<?xml version="; @@ -29,7 +29,7 @@ XmlDoc zen::loadXmlDocument(const Zstring& filename) //throw FileError if (!startsWith(stream, xmlBegin) && !startsWith(stream, BYTE_ORDER_MARK_UTF8 + xmlBegin)) //allow BOM! - throw FileError(replaceCpy(_("File %x does not contain a valid configuration."), L"%x", fmtFileName(filename))); + throw FileError(replaceCpy(_("File %x does not contain a valid configuration."), L"%x", fmtFileName(filepath))); } const size_t blockSize = 128 * 1024; @@ -51,32 +51,32 @@ XmlDoc zen::loadXmlDocument(const Zstring& filename) //throw FileError { throw FileError( replaceCpy(replaceCpy(replaceCpy(_("Error parsing file %x, row %y, column %z."), - L"%x", fmtFileName(filename)), + L"%x", fmtFileName(filepath)), L"%y", numberTo<std::wstring>(e.row + 1)), L"%z", numberTo<std::wstring>(e.col + 1))); } } -void zen::saveXmlDocument(const XmlDoc& doc, const Zstring& filename) //throw FileError +void zen::saveXmlDocument(const XmlDoc& doc, const Zstring& filepath) //throw FileError { std::string stream = serialize(doc); //noexcept //only update xml file if there are real changes try { - if (getFilesize(filename) == stream.size()) //throw FileError - if (loadBinStream<std::string>(filename) == stream) //throw FileError + if (getFilesize(filepath) == stream.size()) //throw FileError + if (loadBinStream<std::string>(filepath) == stream) //throw FileError return; } catch (FileError&) {} - FileOutput outputFile(filename, FileOutput::ACC_OVERWRITE); //throw FileError + FileOutput outputFile(filepath, FileOutput::ACC_OVERWRITE); //throw FileError outputFile.write(stream.c_str(), stream.length()); // } -void zen::checkForMappingErrors(const XmlIn& xmlInput, const Zstring& filename) //throw FileError +void zen::checkForMappingErrors(const XmlIn& xmlInput, const Zstring& filepath) //throw FileError { if (xmlInput.errorsOccured()) { @@ -84,6 +84,6 @@ void zen::checkForMappingErrors(const XmlIn& xmlInput, const Zstring& filename) for (const std::wstring& elem : xmlInput.getErrorsAs<std::wstring>()) msg += L"\n" + elem; - throw FileError(replaceCpy(_("Configuration file %x loaded partially only."), L"%x", fmtFileName(filename)) + L"\n\n" + msg); + throw FileError(replaceCpy(_("Configuration file %x loaded partially only."), L"%x", fmtFileName(filepath)) + L"\n\n" + msg); } } diff --git a/zen/xml_io.h b/zen/xml_io.h index b53a5ef4..e3e47f59 100644 --- a/zen/xml_io.h +++ b/zen/xml_io.h @@ -8,8 +8,7 @@ #define XMLBASE_H_INCLUDED #include <zenxml/xml.h> -#include <zen/zstring.h> -#include <zen/file_error.h> +#include "file_error.h" //combine zen::Xml and zen file i/o //-> loadXmlDocument vs loadStream: @@ -18,10 +17,10 @@ namespace zen { -XmlDoc loadXmlDocument(const Zstring& filename); //throw FileError -void checkForMappingErrors(const XmlIn& xmlInput, const Zstring& filename); //throw FileError +XmlDoc loadXmlDocument(const Zstring& filepath); //throw FileError +void checkForMappingErrors(const XmlIn& xmlInput, const Zstring& filepath); //throw FileError -void saveXmlDocument(const XmlDoc& doc, const Zstring& filename); //throw FileError +void saveXmlDocument(const XmlDoc& doc, const Zstring& filepath); //throw FileError } #endif // XMLBASE_H_INCLUDED diff --git a/zen/zstring.cpp b/zen/zstring.cpp index 3e579b1e..f1858efc 100644 --- a/zen/zstring.cpp +++ b/zen/zstring.cpp @@ -12,7 +12,6 @@ #include "win_ver.h" #elif defined ZEN_MAC -//#include <zen/scope_guard.h> #include <ctype.h> //toupper() #endif @@ -75,8 +74,8 @@ private: } } - LeakChecker(const LeakChecker&); - LeakChecker& operator=(const LeakChecker&); + LeakChecker (const LeakChecker&) = delete; + LeakChecker& operator=(const LeakChecker&) = delete; static std::string rawMemToString(const void* ptr, size_t size) { @@ -165,7 +164,7 @@ int z_impl::compareFilenamesNoCase(const wchar_t* lhs, const wchar_t* rhs, size_ else //fallback { //do NOT use "CompareString"; this function is NOT accurate (even with LOCALE_INVARIANT and SORT_STRINGSORT): for example "weiß" == "weiss"!!! - //the only reliable way to compare filenames (with XP) is to call "CharUpper" or "LCMapString": + //the only reliable way to compare filepaths (with XP) is to call "CharUpper" or "LCMapString": auto copyToUpperCase = [](const wchar_t* strIn, wchar_t* strOut, size_t len) { diff --git a/zen/zstring.h b/zen/zstring.h index f103faf7..2152954d 100644 --- a/zen/zstring.h +++ b/zen/zstring.h @@ -8,10 +8,9 @@ #define ZSTRING_H_INCLUDED #include "string_base.h" + #ifdef ZEN_LINUX #include <cstring> //strcmp -#elif defined ZEN_MAC -//#include <strings.h> //strcasecmp #endif @@ -66,7 +65,7 @@ typedef zen::Zbase<Zchar, zen::StorageRefCountThreadSafe, AllocatorFreeStoreChec -//Compare filenames: Windows does NOT distinguish between upper/lower-case, while Linux DOES +//Compare filepaths: Windows does NOT distinguish between upper/lower-case, while Linux DOES template <template <class, class> class SP, class AP> int cmpFileName(const zen::Zbase<Zchar, SP, AP>& lhs, const zen::Zbase<Zchar, SP, AP>& rhs); @@ -114,7 +113,7 @@ int cmpFileName(const zen::Zbase<Zchar, SP, AP>& lhs, const zen::Zbase<Zchar, SP #if defined ZEN_WIN || defined ZEN_MAC return z_impl::compareFilenamesNoCase(lhs.data(), rhs.data(), lhs.length(), rhs.length()); #elif defined ZEN_LINUX - return std::strcmp(lhs.c_str(), rhs.c_str()); //POSIX filenames don't have embedded 0 + return std::strcmp(lhs.c_str(), rhs.c_str()); //POSIX filepaths don't have embedded 0 //#elif defined ZEN_MAC // return ::strcasecmp(lhs.c_str(), rhs.c_str()); //locale-dependent! #endif |