diff options
author | Daniel Wilhelm <shieldwed@outlook.com> | 2018-12-16 08:01:40 +0000 |
---|---|---|
committer | Daniel Wilhelm <shieldwed@outlook.com> | 2018-12-16 08:01:40 +0000 |
commit | 00c412ab7731cb1dfb505485bcbdb87076a046b9 (patch) | |
tree | 597a84bf090173bfc5f406e9009263875218707d /zen | |
parent | Merge branch '10.6' into 'master' (diff) | |
parent | 10.7 (diff) | |
download | FreeFileSync-00c412ab7731cb1dfb505485bcbdb87076a046b9.tar.gz FreeFileSync-00c412ab7731cb1dfb505485bcbdb87076a046b9.tar.bz2 FreeFileSync-00c412ab7731cb1dfb505485bcbdb87076a046b9.zip |
Merge branch '10.7' into 'master'10.7
10.7
See merge request opensource-tracking/FreeFileSync!4
Diffstat (limited to 'zen')
-rwxr-xr-x | zen/file_access.cpp | 28 | ||||
-rwxr-xr-x | zen/thread.h | 22 | ||||
-rwxr-xr-x | zen/zstring.h | 13 |
3 files changed, 32 insertions, 31 deletions
diff --git a/zen/file_access.cpp b/zen/file_access.cpp index 82c78760..ea19b6c7 100755 --- a/zen/file_access.cpp +++ b/zen/file_access.cpp @@ -311,8 +311,8 @@ void renameFile_sub(const Zstring& pathSource, const Zstring& pathTarget) //thro { //rename() will never fail with EEXIST, but always (atomically) overwrite! //=> equivalent to SetFileInformationByHandle() + FILE_RENAME_INFO::ReplaceIfExists or ::MoveFileEx + MOVEFILE_REPLACE_EXISTING - //=> Linux: renameat2() with RENAME_NOREPLACE -> still new, probably buggy - //=> OS X: no solution + //Linux: renameat2() with RENAME_NOREPLACE -> still new, probably buggy + //macOS: no solution auto throwException = [&](int ec) { @@ -326,18 +326,19 @@ void renameFile_sub(const Zstring& pathSource, const Zstring& pathTarget) //thro throw FileError(errorMsg, errorDescr); }; - if (!equalFilePath(pathSource, pathTarget)) //exception for OS X: changing file name case is not an "already exists" situation! - { - const bool alreadyExists = [&] - { - try { /*ItemType type = */getItemType(pathTarget); return true; } /*throw FileError*/ - catch (FileError&) { return false; } - }(); + struct ::stat infoSrc = {}; + if (::lstat(pathSource.c_str(), &infoSrc) != 0) + THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(pathSource)), L"stat"); - if (alreadyExists) - throwException(EEXIST); - //else: nothing exists or other error (hopefully ::rename will also fail!) - } + struct ::stat infoTrg = {}; + if (::lstat(pathTarget.c_str(), &infoTrg) == 0) + { + if (infoSrc.st_dev != infoTrg.st_dev || + infoSrc.st_ino != infoTrg.st_ino) + throwException(EEXIST); //that's what we're really here for + //else: continue with a rename in case + } + //else: not existing or access error (hopefully ::rename will also fail!) if (::rename(pathSource.c_str(), pathTarget.c_str()) != 0) throwException(errno); @@ -397,6 +398,7 @@ void setWriteTimeNative(const Zstring& itemPath, const struct ::timespec& modTim struct ::timespec newTimes[2] = {}; newTimes[0].tv_sec = ::time(nullptr); //access time; using UTIME_OMIT for tv_nsec would trigger even more bugs: https://freefilesync.org/forum/viewtopic.php?t=1701 newTimes[1] = modTime; //modification time + //test: even modTime == 0 is correctly applied (no NOOP!) test2: same behavior for "utime()" if (procSl == ProcSymlink::FOLLOW) { diff --git a/zen/thread.h b/zen/thread.h index 809bc771..8a9adc87 100755 --- a/zen/thread.h +++ b/zen/thread.h @@ -124,7 +124,7 @@ public: template <class Function> auto access(Function fun) //-> decltype(fun(std::declval<T&>())) { - std::lock_guard<std::mutex> dummy(lockValue_); + std::lock_guard dummy(lockValue_); return fun(value_); } @@ -164,7 +164,7 @@ public: void run(Function&& wi /*should throw ThreadInterruption when needed*/, bool insertFront = false) { { - std::lock_guard<std::mutex> dummy(workLoad_->lock); + std::lock_guard dummy(workLoad_->lock); if (insertFront) workLoad_->tasks.push_front(std::move(wi)); @@ -194,7 +194,7 @@ public: //non-blocking wait()-alternative: context of controlling thread: void notifyWhenDone(const std::function<void()>& onCompletion /*noexcept! runs on worker thread!*/) { - std::lock_guard<std::mutex> dummy(workLoad_->lock); + std::lock_guard dummy(workLoad_->lock); if (workLoad_->tasksPending == 0) onCompletion(); @@ -217,7 +217,7 @@ private: { setCurrentThreadName(threadName.c_str()); - std::unique_lock<std::mutex> dummy(wl->lock); + std::unique_lock dummy(wl->lock); for (;;) { interruptibleWait(wl->conditionNewTask, dummy, [&tasks = wl->tasks] { return !tasks.empty(); }); //throw ThreadInterruption @@ -328,7 +328,7 @@ public: void reportFinished(std::optional<T>&& result) { { - std::lock_guard<std::mutex> dummy(lockResult_); + std::lock_guard dummy(lockResult_); ++jobsFinished_; if (!result_) result_ = std::move(result); @@ -340,13 +340,13 @@ public: template <class Duration> bool waitForResult(size_t jobsTotal, const Duration& duration) { - std::unique_lock<std::mutex> dummy(lockResult_); + std::unique_lock dummy(lockResult_); return conditionJobDone_.wait_for(dummy, duration, [&] { return this->jobDone(jobsTotal); }); } std::optional<T> getResult(size_t jobsTotal) { - std::unique_lock<std::mutex> dummy(lockResult_); + std::unique_lock dummy(lockResult_); conditionJobDone_.wait(dummy, [&] { return this->jobDone(jobsTotal); }); return std::move(result_); @@ -399,12 +399,12 @@ public: interrupted_ = true; { - std::lock_guard<std::mutex> dummy(lockSleep_); //needed! makes sure the following signal is not lost! + std::lock_guard dummy(lockSleep_); //needed! makes sure the following signal is not lost! //usually we'd make "interrupted" non-atomic, but this is already given due to interruptibleWait() handling } conditionSleepInterruption_.notify_all(); - std::lock_guard<std::mutex> dummy(lockConditionPtr_); + std::lock_guard dummy(lockConditionPtr_); if (activeCondition_) activeCondition_->notify_all(); //signal may get lost! //alternative design locking the cv's mutex here could be dangerous: potential for dead lock! @@ -436,7 +436,7 @@ public: template <class Rep, class Period> void interruptibleSleep(const std::chrono::duration<Rep, Period>& relTime) //throw ThreadInterruption { - std::unique_lock<std::mutex> lock(lockSleep_); + std::unique_lock lock(lockSleep_); if (conditionSleepInterruption_.wait_for(lock, relTime, [this] { return static_cast<bool>(this->interrupted_); })) throw ThreadInterruption(); } @@ -444,7 +444,7 @@ public: private: void setConditionVar(std::condition_variable* cv) { - std::lock_guard<std::mutex> dummy(lockConditionPtr_); + std::lock_guard dummy(lockConditionPtr_); activeCondition_ = cv; } diff --git a/zen/zstring.h b/zen/zstring.h index 9fecdce3..a511e4e0 100755 --- a/zen/zstring.h +++ b/zen/zstring.h @@ -32,11 +32,14 @@ Zstring makeUpperCopy(const Zstring& str); //Windows, Linux: precomposed //macOS: decomposed Zstring getUnicodeNormalForm(const Zstring& str); - -Zstring replaceCpyAsciiNoCase(const Zstring& str, const Zstring& oldTerm, const Zstring& newTerm); +// "In fact, Unicode declares that there is an equivalence relationship between decomposed and composed sequences, +// and conformant software should not treat canonically equivalent sequences, whether composed or decomposed or something inbetween, as different." +// http://www.win.tue.nl/~aeb/linux/uc/nfc_vs_nfd.html struct LessUnicodeNormal { bool operator()(const Zstring& lhs, const Zstring& rhs) const { return getUnicodeNormalForm(lhs) < getUnicodeNormalForm(rhs);} }; +Zstring replaceCpyAsciiNoCase(const Zstring& str, const Zstring& oldTerm, const Zstring& newTerm); + //------------------------------------------------------------------------------------------ inline bool equalNoCase(const Zstring& lhs, const Zstring& rhs) { return makeUpperCopy(lhs) == makeUpperCopy(rhs); } @@ -53,7 +56,7 @@ inline bool operator<(const ZstringNoCase& lhs, const ZstringNoCase& rhs) { retu //Compare *local* file paths: // Windows: igore case // Linux: byte-wise comparison -// macOS: igore case + Unicode normalization forms +// macOS: ignore case + Unicode normalization forms int compareNativePath(const Zstring& lhs, const Zstring& rhs); inline bool equalNativePath(const Zstring& lhs, const Zstring& rhs) { return compareNativePath(lhs, rhs) == 0; } @@ -66,10 +69,6 @@ int compareNatural(const Zstring& lhs, const Zstring& rhs); struct LessNaturalSort { bool operator()(const Zstring& lhs, const Zstring rhs) const { return compareNatural(lhs, rhs) < 0; } }; //------------------------------------------------------------------------------------------ -warn_static("get rid:") -inline bool equalFilePath(const Zstring& lhs, const Zstring& rhs) { return compareNativePath(lhs, rhs) == 0; } -//------------------------------------------------------------------------------------------ - inline |