summaryrefslogtreecommitdiff
path: root/zen
diff options
context:
space:
mode:
authorDaniel Wilhelm <shieldwed@outlook.com>2018-12-16 08:01:40 +0000
committerDaniel Wilhelm <shieldwed@outlook.com>2018-12-16 08:01:40 +0000
commit00c412ab7731cb1dfb505485bcbdb87076a046b9 (patch)
tree597a84bf090173bfc5f406e9009263875218707d /zen
parentMerge branch '10.6' into 'master' (diff)
parent10.7 (diff)
downloadFreeFileSync-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-xzen/file_access.cpp28
-rwxr-xr-xzen/thread.h22
-rwxr-xr-xzen/zstring.h13
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
bgstack15