summaryrefslogtreecommitdiff
path: root/zen
diff options
context:
space:
mode:
authorB Stack <bgstack15@gmail.com>2021-03-03 01:18:05 +0000
committerB Stack <bgstack15@gmail.com>2021-03-03 01:18:05 +0000
commit320f1ae680d73da35a0cfe4846eb687d8616bcac (patch)
tree6fb17404841b30822a2d9204e3e0932e55f05ebb /zen
parentMerge branch '11.6' into 'master' (diff)
parentadd upstream 11.7 (diff)
downloadFreeFileSync-320f1ae680d73da35a0cfe4846eb687d8616bcac.tar.gz
FreeFileSync-320f1ae680d73da35a0cfe4846eb687d8616bcac.tar.bz2
FreeFileSync-320f1ae680d73da35a0cfe4846eb687d8616bcac.zip
Merge branch '11.7' into 'master'11.7
add upstream 11.7 See merge request opensource-tracking/FreeFileSync!31
Diffstat (limited to 'zen')
-rw-r--r--zen/basic_math.h22
-rw-r--r--zen/dir_watcher.cpp15
-rw-r--r--zen/error_log.h2
-rw-r--r--zen/file_access.cpp98
-rw-r--r--zen/file_access.h34
-rw-r--r--zen/file_id_def.h46
-rw-r--r--zen/file_io.cpp29
-rw-r--r--zen/file_io.h23
-rw-r--r--zen/file_traverser.cpp8
-rw-r--r--zen/format_unit.cpp8
-rw-r--r--zen/http.cpp12
-rw-r--r--zen/http.h6
-rw-r--r--zen/json.h2
-rw-r--r--zen/open_ssl.cpp132
-rw-r--r--zen/perf.h23
-rw-r--r--zen/process_exec.cpp8
-rw-r--r--zen/resolve_path.cpp9
-rw-r--r--zen/ring_buffer.h8
-rw-r--r--zen/serialize.h14
-rw-r--r--zen/stl_tools.h12
-rw-r--r--zen/string_tools.h16
-rw-r--r--zen/string_traits.h11
-rw-r--r--zen/symlink_target.h4
-rw-r--r--zen/sys_info.cpp48
-rw-r--r--zen/sys_info.h1
-rw-r--r--zen/thread.cpp2
-rw-r--r--zen/thread.h37
-rw-r--r--zen/time.h2
-rw-r--r--zen/type_traits.h60
29 files changed, 313 insertions, 379 deletions
diff --git a/zen/basic_math.h b/zen/basic_math.h
index a4feb83e..944a0f53 100644
--- a/zen/basic_math.h
+++ b/zen/basic_math.h
@@ -111,14 +111,14 @@ std::pair<InputIterator, InputIterator> minMaxElement(InputIterator first, Input
}
}
}
- return { lowest, largest };
+ return {lowest, largest};
}
template <class InputIterator> inline
std::pair<InputIterator, InputIterator> minMaxElement(InputIterator first, InputIterator last)
{
- return minMaxElement(first, last, std::less<typename std::iterator_traits<InputIterator>::value_type>());
+ return minMaxElement(first, last, std::less());
}
*/
@@ -152,10 +152,10 @@ template <class N, class D> inline
auto intDivRound(N num, D den)
{
using namespace zen;
- static_assert(IsInteger<N>::value && IsInteger<D>::value);
- static_assert(IsSignedInt<N>::value == IsSignedInt<D>::value); //until further
+ static_assert(IsIntegerV<N>&& IsIntegerV<D>);
+ static_assert(IsSignedIntV<N> == IsSignedIntV<D>); //until further
assert(den != 0);
- if constexpr (IsSignedInt<N>::value)
+ if constexpr (IsSignedIntV<N>)
{
if ((num < 0) != (den < 0))
return (num - den / 2) / den;
@@ -168,10 +168,10 @@ template <class N, class D> inline
auto intDivCeil(N num, D den)
{
using namespace zen;
- static_assert(IsInteger<N>::value && IsInteger<D>::value);
- static_assert(IsSignedInt<N>::value == IsSignedInt<D>::value); //until further
+ static_assert(IsIntegerV<N>&& IsIntegerV<D>);
+ static_assert(IsSignedIntV<N> == IsSignedIntV<D>); //until further
assert(den != 0);
- if constexpr (IsSignedInt<N>::value)
+ if constexpr (IsSignedIntV<N>)
{
if ((num < 0) != (den < 0))
return num / den;
@@ -187,10 +187,10 @@ template <class N, class D> inline
auto intDivFloor(N num, D den)
{
using namespace zen;
- static_assert(IsInteger<N>::value && IsInteger<D>::value);
- static_assert(IsSignedInt<N>::value == IsSignedInt<D>::value); //until further
+ static_assert(IsIntegerV<N>&& IsIntegerV<D>);
+ static_assert(IsSignedIntV<N> == IsSignedIntV<D>); //until further
assert(den != 0);
- if constexpr (IsSignedInt<N>::value)
+ if constexpr (IsSignedIntV<N>)
{
if ((num < 0) != (den < 0))
{
diff --git a/zen/dir_watcher.cpp b/zen/dir_watcher.cpp
index dc416b34..191ffd64 100644
--- a/zen/dir_watcher.cpp
+++ b/zen/dir_watcher.cpp
@@ -9,7 +9,6 @@
#include <set>
#include "thread.h"
#include "scope_guard.h"
-//#include "basic_math.h"
#include <map>
#include <sys/inotify.h>
@@ -34,7 +33,7 @@ DirWatcher::DirWatcher(const Zstring& dirPath) : //throw FileError
pimpl_(std::make_unique<Impl>())
{
//get all subdirectories
- std::vector<Zstring> fullFolderList { baseDirPath_ };
+ std::vector<Zstring> fullFolderList {baseDirPath_};
{
std::function<void (const Zstring& path)> traverse;
@@ -102,7 +101,7 @@ DirWatcher::~DirWatcher()
std::vector<DirWatcher::Change> DirWatcher::fetchChanges(const std::function<void()>& requestUiUpdate, std::chrono::milliseconds cbInterval) //throw FileError
{
- std::vector<std::byte> buffer(512 * (sizeof(struct ::inotify_event) + NAME_MAX + 1));
+ std::vector<std::byte> buffer(512 * (sizeof(inotify_event) + NAME_MAX + 1));
ssize_t bytesRead = 0;
do
@@ -125,7 +124,7 @@ std::vector<DirWatcher::Change> DirWatcher::fetchChanges(const std::function<voi
ssize_t bytePos = 0;
while (bytePos < bytesRead)
{
- struct ::inotify_event& evt = reinterpret_cast<struct ::inotify_event&>(buffer[bytePos]);
+ inotify_event& evt = reinterpret_cast<inotify_event&>(buffer[bytePos]);
if (evt.len != 0) //exclude case: deletion of "self", already reported by parent directory watch
{
@@ -138,18 +137,18 @@ std::vector<DirWatcher::Change> DirWatcher::fetchChanges(const std::function<voi
if ((evt.mask & IN_CREATE) ||
(evt.mask & IN_MOVED_TO))
- output.push_back({ ChangeType::create, itemPath });
+ output.push_back({ChangeType::create, itemPath});
else if ((evt.mask & IN_MODIFY) ||
(evt.mask & IN_CLOSE_WRITE))
- output.push_back({ ChangeType::update, itemPath });
+ output.push_back({ChangeType::update, itemPath});
else if ((evt.mask & IN_DELETE ) ||
(evt.mask & IN_DELETE_SELF) ||
(evt.mask & IN_MOVE_SELF ) ||
(evt.mask & IN_MOVED_FROM))
- output.push_back({ ChangeType::remove, itemPath });
+ output.push_back({ChangeType::remove, itemPath});
}
}
- bytePos += sizeof(struct ::inotify_event) + evt.len;
+ bytePos += sizeof(inotify_event) + evt.len;
}
return output;
diff --git a/zen/error_log.h b/zen/error_log.h
index 6d9f80ae..a24dfe5a 100644
--- a/zen/error_log.h
+++ b/zen/error_log.h
@@ -68,7 +68,7 @@ private:
inline
void ErrorLog::logMsg(const std::wstring& msg, MessageType type)
{
- entries_.push_back({ std::time(nullptr), type, utfTo<Zstringc>(msg) });
+ entries_.push_back({std::time(nullptr), type, utfTo<Zstringc>(msg)});
}
diff --git a/zen/file_access.cpp b/zen/file_access.cpp
index 4c9af652..fb770f19 100644
--- a/zen/file_access.cpp
+++ b/zen/file_access.cpp
@@ -12,7 +12,6 @@
#include "file_traverser.h"
#include "scope_guard.h"
#include "symlink_target.h"
-#include "file_id_def.h"
#include "file_io.h"
#include "crc.h"
#include "guid.h"
@@ -45,7 +44,7 @@ std::optional<PathComponents> zen::parsePathComponents(const Zstring& itemPath)
Zstring relPath(it + 1, itemPathFmt.end());
trim(relPath, true, true, [](Zchar c) { return c == FILE_NAME_SEPARATOR; });
- return PathComponents({ rootPath, relPath });
+ return PathComponents({rootPath, relPath});
}
return {};
};
@@ -100,7 +99,7 @@ std::optional<Zstring> zen::getParentFolderPath(const Zstring& itemPath)
ItemType zen::getItemType(const Zstring& itemPath) //throw FileError
{
- struct ::stat itemInfo = {};
+ struct stat itemInfo = {};
if (::lstat(itemPath.c_str(), &itemInfo) != 0)
THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(itemPath)), "lstat");
@@ -153,7 +152,7 @@ std::optional<ItemType> zen::itemStillExists(const Zstring& itemPath) //throw Fi
bool zen::fileAvailable(const Zstring& filePath) //noexcept
{
//symbolic links (broken or not) are also treated as existing files!
- struct ::stat fileInfo = {};
+ struct stat fileInfo = {};
if (::stat(filePath.c_str(), &fileInfo) == 0) //follow symlinks!
return S_ISREG(fileInfo.st_mode);
return false;
@@ -163,7 +162,7 @@ bool zen::fileAvailable(const Zstring& filePath) //noexcept
bool zen::dirAvailable(const Zstring& dirPath) //noexcept
{
//symbolic links (broken or not) are also treated as existing directories!
- struct ::stat dirInfo = {};
+ struct stat dirInfo = {};
if (::stat(dirPath.c_str(), &dirInfo) == 0) //follow symlinks!
return S_ISDIR(dirInfo.st_mode);
return false;
@@ -177,29 +176,22 @@ namespace
int64_t zen::getFreeDiskSpace(const Zstring& path) //throw FileError, returns < 0 if not available
{
- struct ::statfs info = {};
- if (::statfs(path.c_str(), &info) != 0)
+ struct statfs info = {};
+ if (::statfs(path.c_str(), &info) != 0) //follows symlinks!
THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot determine free disk space for %x."), L"%x", fmtPath(path)), "statfs");
+ //Linux: "Fields that are undefined for a particular file system are set to 0."
+ //macOS: "Fields that are undefined for a particular file system are set to -1." - mkay :>
+ if (makeSigned(info.f_bsize) <= 0 ||
+ makeSigned(info.f_bavail) <= 0)
+ return -1;
return static_cast<int64_t>(info.f_bsize) * info.f_bavail;
}
-VolumeId zen::getVolumeId(const Zstring& itemPath) //throw FileError
-{
- struct ::stat fileInfo = {};
- if (::stat(itemPath.c_str(), &fileInfo) != 0)
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(itemPath)), "stat");
-
- warn_static("NOT STABLE!")
-
- return fileInfo.st_dev;
-}
-
-
uint64_t zen::getFileSize(const Zstring& filePath) //throw FileError
{
- struct ::stat fileInfo = {};
+ struct stat fileInfo = {};
if (::stat(filePath.c_str(), &fileInfo) != 0)
THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(filePath)), "stat");
@@ -207,6 +199,8 @@ uint64_t zen::getFileSize(const Zstring& filePath) //throw FileError
}
+
+
Zstring zen::getTempFolderPath() //throw FileError
{
if (const char* tempPath = ::getenv("TMPDIR")) //no extended error reporting
@@ -336,15 +330,15 @@ void moveAndRenameFileSub(const Zstring& pathFrom, const Zstring& pathTo, bool r
//macOS: no solution https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man2/rename.2.html
if (!replaceExisting)
{
- struct ::stat infoSrc = {};
- if (::lstat(pathFrom.c_str(), &infoSrc) != 0)
+ struct stat sourceInfo = {};
+ if (::lstat(pathFrom.c_str(), &sourceInfo) != 0)
THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(pathFrom)), "stat");
- struct ::stat infoTrg = {};
- if (::lstat(pathTo.c_str(), &infoTrg) == 0)
+ struct stat targetInfo = {};
+ if (::lstat(pathTo.c_str(), &targetInfo) == 0)
{
- if (infoSrc.st_dev != infoTrg.st_dev ||
- infoSrc.st_ino != infoTrg.st_ino)
+ if (sourceInfo.st_dev != targetInfo.st_dev ||
+ sourceInfo.st_ino != targetInfo.st_ino)
throwException(EEXIST); //that's what we're really here for
//else: continue with a rename in case
//caveat: if we have a hardlink referenced by two different paths, the source one will be unlinked => fine, but not exactly a "rename"...
@@ -376,7 +370,7 @@ void zen::moveAndRenameItem(const Zstring& pathFrom, const Zstring& pathTo, bool
namespace
{
-void setWriteTimeNative(const Zstring& itemPath, const struct ::timespec& modTime, ProcSymlink procSl) //throw FileError
+void setWriteTimeNative(const Zstring& itemPath, const timespec& modTime, ProcSymlink procSl) //throw FileError
{
/*
[2013-05-01] sigh, we can't use utimensat() on NTFS volumes on Ubuntu: silent failure!!! what morons are programming this shit???
@@ -388,12 +382,12 @@ void setWriteTimeNative(const Zstring& itemPath, const struct ::timespec& modTim
=> let's give utimensat another chance:
using open()/futimens() for regular files and utimensat(AT_SYMLINK_NOFOLLOW) for symlinks is consistent with "cp" and "touch"!
*/
- struct ::timespec newTimes[2] = {};
+ 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)
+ if (procSl == ProcSymlink::follow)
{
//hell knows why files on gvfs-mounted Samba shares fail to open(O_WRONLY) returning EOPNOTSUPP:
//https://freefilesync.org/forum/viewtopic.php?t=2803 => utimensat() works (but not for gvfs SFTP)
@@ -422,10 +416,8 @@ void setWriteTimeNative(const Zstring& itemPath, const struct ::timespec& modTim
void zen::setFileTime(const Zstring& filePath, time_t modTime, ProcSymlink procSl) //throw FileError
{
- struct ::timespec writeTime = {};
- writeTime.tv_sec = modTime;
- setWriteTimeNative(filePath, writeTime, procSl); //throw FileError
-
+ setWriteTimeNative(filePath, timetToNativeFileTime(modTime),
+ procSl); //throw FileError
}
@@ -442,7 +434,7 @@ namespace
void copySecurityContext(const Zstring& source, const Zstring& target, ProcSymlink procSl) //throw FileError
{
security_context_t contextSource = nullptr;
- const int rv = procSl == ProcSymlink::FOLLOW ?
+ const int rv = procSl == ProcSymlink::follow ?
::getfilecon (source.c_str(), &contextSource) :
::lgetfilecon(source.c_str(), &contextSource);
if (rv < 0)
@@ -457,7 +449,7 @@ void copySecurityContext(const Zstring& source, const Zstring& target, ProcSymli
{
security_context_t contextTarget = nullptr;
- const int rv2 = procSl == ProcSymlink::FOLLOW ?
+ const int rv2 = procSl == ProcSymlink::follow ?
::getfilecon(target.c_str(), &contextTarget) :
::lgetfilecon(target.c_str(), &contextTarget);
if (rv2 < 0)
@@ -475,7 +467,7 @@ void copySecurityContext(const Zstring& source, const Zstring& target, ProcSymli
}
}
- const int rv3 = procSl == ProcSymlink::FOLLOW ?
+ const int rv3 = procSl == ProcSymlink::follow ?
::setfilecon(target.c_str(), contextSource) :
::lsetfilecon(target.c_str(), contextSource);
if (rv3 < 0)
@@ -493,8 +485,8 @@ void zen::copyItemPermissions(const Zstring& sourcePath, const Zstring& targetPa
copySecurityContext(sourcePath, targetPath, procSl); //throw FileError
#endif
- struct ::stat fileInfo = {};
- if (procSl == ProcSymlink::FOLLOW)
+ struct stat fileInfo = {};
+ if (procSl == ProcSymlink::follow)
{
if (::stat(sourcePath.c_str(), &fileInfo) != 0)
THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read permissions of %x."), L"%x", fmtPath(sourcePath)), "stat");
@@ -614,22 +606,22 @@ void zen::copySymlink(const Zstring& sourcePath, const Zstring& targetPath) //th
catch (FileError&) {});
//file times: essential for syncing a symlink: enforce this! (don't just try!)
- struct ::stat sourceInfo = {};
+ struct stat sourceInfo = {};
if (::lstat(sourcePath.c_str(), &sourceInfo) != 0)
THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(sourcePath)), "lstat");
- setWriteTimeNative(targetPath, sourceInfo.st_mtim, ProcSymlink::DIRECT); //throw FileError
+ setWriteTimeNative(targetPath, sourceInfo.st_mtim, ProcSymlink::direct); //throw FileError
}
FileCopyResult zen::copyNewFile(const Zstring& sourceFile, const Zstring& targetFile, //throw FileError, ErrorTargetExisting, (ErrorFileLocked), X
- const IOCallback& notifyUnbufferedIO /*throw X*/)
+ const IoCallback& notifyUnbufferedIO /*throw X*/)
{
int64_t totalUnbufferedIO = 0;
FileInput fileIn(sourceFile, IOCallbackDivider(notifyUnbufferedIO, totalUnbufferedIO)); //throw FileError, (ErrorFileLocked -> Windows-only)
- struct ::stat sourceInfo = {};
+ struct stat sourceInfo = {};
if (::fstat(fileIn.getHandle(), &sourceInfo) != 0)
THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(sourceFile)), "fstat");
@@ -637,7 +629,7 @@ FileCopyResult zen::copyNewFile(const Zstring& sourceFile, const Zstring& target
//it seems we don't need S_IWUSR, not even for the setFileTime() below! (tested with source file having different user/group!)
//=> need copyItemPermissions() only for "chown" and umask-agnostic permissions
- const int fdTarget = ::open(targetFile.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode);
+ const int fdTarget = ::open(targetFile.c_str(), O_CREAT | O_EXCL | O_WRONLY | O_CLOEXEC, mode);
if (fdTarget == -1)
{
const int ec = errno; //copy before making other system calls!
@@ -659,7 +651,7 @@ FileCopyResult zen::copyNewFile(const Zstring& sourceFile, const Zstring& target
//flush intermediate buffers before fiddling with the raw file handle
fileOut.flushBuffers(); //throw FileError, X
- struct ::stat targetInfo = {};
+ struct stat targetInfo = {};
if (::fstat(fileOut.getHandle(), &targetInfo) != 0)
THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(targetFile)), "fstat");
@@ -673,12 +665,12 @@ FileCopyResult zen::copyNewFile(const Zstring& sourceFile, const Zstring& target
std::optional<FileError> errorModTime;
try
{
- //we cannot set the target file times (::futimes) while the file descriptor is still open after a write operation:
- //this triggers bugs on samba shares where the modification time is set to current time instead.
- //Linux: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=340236
- // http://comments.gmane.org/gmane.linux.file-systems.cifs/2854
- //OS X: https://freefilesync.org/forum/viewtopic.php?t=356
- setWriteTimeNative(targetFile, sourceInfo.st_mtim, ProcSymlink::FOLLOW); //throw FileError
+ /* we cannot set the target file times (::futimes) while the file descriptor is still open after a write operation:
+ this triggers bugs on Samba shares where the modification time is set to current time instead.
+ Linux: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=340236
+ http://comments.gmane.org/gmane.linux.file-systems.cifs/2854
+ macOS: https://freefilesync.org/forum/viewtopic.php?t=356 */
+ setWriteTimeNative(targetFile, sourceInfo.st_mtim, ProcSymlink::follow); //throw FileError
}
catch (const FileError& e)
{
@@ -687,9 +679,9 @@ FileCopyResult zen::copyNewFile(const Zstring& sourceFile, const Zstring& target
FileCopyResult result;
result.fileSize = sourceInfo.st_size;
- result.modTime = sourceInfo.st_mtim.tv_sec; //
- result.sourceFileId = generateFileId(sourceInfo);
- result.targetFileId = generateFileId(targetInfo);
+ result.sourceModTime = sourceInfo.st_mtim;
+ result.sourceFileIdx = sourceInfo.st_ino;
+ result.targetFileIdx = targetInfo.st_ino;
result.errorModTime = errorModTime;
return result;
}
diff --git a/zen/file_access.h b/zen/file_access.h
index a3fa56d7..f3ea6c00 100644
--- a/zen/file_access.h
+++ b/zen/file_access.h
@@ -10,9 +10,8 @@
#include <functional>
#include "zstring.h"
#include "file_error.h"
-#include "file_id_def.h"
-#include "serialize.h"
-
+#include "serialize.h" //IoCallback
+ #include <sys/stat.h>
namespace zen
{
@@ -31,6 +30,21 @@ std::optional<Zstring> getParentFolderPath(const Zstring& itemPath);
bool fileAvailable(const Zstring& filePath); //noexcept
bool dirAvailable (const Zstring& dirPath ); //
+//FAT/FAT32: "Why does the timestamp of a file *increase* by up to 2 seconds when I copy it to a USB thumb drive?"
+const int FAT_FILE_TIME_PRECISION_SEC = 2; //https://devblogs.microsoft.com/oldnewthing/?p=83
+//https://web.archive.org/web/20141127143832/http://support.microsoft.com/kb/127830
+
+using FileIndex = ino_t;
+using FileTimeNative = timespec;
+
+inline time_t nativeFileTimeToTimeT(const timespec& ft) { return ft.tv_sec; } //follow Windows Explorer and always round down!
+inline timespec timetToNativeFileTime(time_t utcTime)
+{
+ timespec natTime = {};
+ natTime.tv_sec = utcTime;
+ return natTime;
+}
+
enum class ItemType
{
file,
@@ -47,14 +61,13 @@ std::optional<ItemType> itemStillExists(const Zstring& itemPath); //throw FileEr
enum class ProcSymlink
{
- DIRECT,
- FOLLOW
+ direct,
+ follow
};
void setFileTime(const Zstring& filePath, time_t modTime, ProcSymlink procSl); //throw FileError
//symlink handling: follow
int64_t getFreeDiskSpace(const Zstring& path); //throw FileError, returns < 0 if not available
-VolumeId getVolumeId(const Zstring& itemPath); //throw FileError
uint64_t getFileSize(const Zstring& filePath); //throw FileError
//get per-user directory designated for temporary files:
@@ -87,16 +100,15 @@ void copySymlink(const Zstring& sourcePath, const Zstring& targetPath); //throw
struct FileCopyResult
{
uint64_t fileSize = 0;
- time_t modTime = 0; //number of seconds since Jan. 1st 1970 UTC
- FileId sourceFileId;
- FileId targetFileId;
+ FileTimeNative sourceModTime = {};
+ FileIndex sourceFileIdx = 0;
+ FileIndex targetFileIdx = 0;
std::optional<FileError> errorModTime; //failure to set modification time
};
FileCopyResult copyNewFile(const Zstring& sourceFile, const Zstring& targetFile, //throw FileError, ErrorTargetExisting, ErrorFileLocked, X
//accummulated delta != file size! consider ADS, sparse, compressed files
- const IOCallback& notifyUnbufferedIO /*throw X*/);
-
+ const IoCallback& notifyUnbufferedIO /*throw X*/);
}
#endif //FILE_ACCESS_H_8017341345614857
diff --git a/zen/file_id_def.h b/zen/file_id_def.h
deleted file mode 100644
index d2d104d5..00000000
--- a/zen/file_id_def.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// *****************************************************************************
-// * This file is part of the FreeFileSync project. It is distributed under *
-// * GNU General Public License: https://www.gnu.org/licenses/gpl-3.0 *
-// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved *
-// *****************************************************************************
-
-#ifndef FILE_ID_DEF_H_013287632486321493
-#define FILE_ID_DEF_H_013287632486321493
-
- #include <sys/stat.h>
-
-
-namespace zen
-{
-namespace impl { typedef struct ::stat StatDummy; } //sigh...
-
-using VolumeId = decltype(impl::StatDummy::st_dev);
-using FileIndex = decltype(impl::StatDummy::st_ino);
-
-
-struct FileId //always available on Linux, and *generally* available on Windows)
-{
- FileId() {}
- FileId(VolumeId volId, FileIndex fIdx) : volumeId(volId), fileIndex(fIdx)
- {
- if (volId == 0 || fIdx == 0)
- {
- volumeId = 0;
- fileIndex = 0;
- }
- }
- VolumeId volumeId = 0;
- FileIndex fileIndex = 0;
-
- bool operator==(const FileId&) const = default;
-};
-
-
-inline
-FileId generateFileId(const struct ::stat& fileInfo)
-{
- return FileId(fileInfo.st_dev, fileInfo.st_ino);
-}
-}
-
-#endif //FILE_ID_DEF_H_013287632486321493
diff --git a/zen/file_io.cpp b/zen/file_io.cpp
index e081335d..f575a366 100644
--- a/zen/file_io.cpp
+++ b/zen/file_io.cpp
@@ -41,7 +41,7 @@ namespace
FileBase::FileHandle openHandleForRead(const Zstring& filePath) //throw FileError, ErrorFileLocked
{
//caveat: check for file types that block during open(): character device, block device, named pipe
- struct ::stat fileInfo = {};
+ struct stat fileInfo = {};
if (::stat(filePath.c_str(), &fileInfo) == 0) //follows symlinks
{
if (!S_ISREG(fileInfo.st_mode) &&
@@ -74,11 +74,11 @@ FileBase::FileHandle openHandleForRead(const Zstring& filePath) //throw FileErro
}
-FileInput::FileInput(FileHandle handle, const Zstring& filePath, const IOCallback& notifyUnbufferedIO) :
+FileInput::FileInput(FileHandle handle, const Zstring& filePath, const IoCallback& notifyUnbufferedIO) :
FileBase(handle, filePath), notifyUnbufferedIO_(notifyUnbufferedIO) {}
-FileInput::FileInput(const Zstring& filePath, const IOCallback& notifyUnbufferedIO) :
+FileInput::FileInput(const Zstring& filePath, const IoCallback& notifyUnbufferedIO) :
FileBase(openHandleForRead(filePath), filePath), //throw FileError, ErrorFileLocked
notifyUnbufferedIO_(notifyUnbufferedIO)
{
@@ -166,8 +166,13 @@ FileBase::FileHandle openHandleForWrite(const Zstring& filePath) //throw FileErr
{
//checkForUnsupportedType(filePath); -> not needed, open() + O_WRONLY should fail fast
- const int fdFile = ::open(filePath.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC | /*access == FileOutput::ACC_OVERWRITE ? O_TRUNC : */ O_EXCL,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); //0666 => umask will be applied implicitly!
+ const mode_t lockFileMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; //0666 => umask will be applied implicitly!
+
+ //O_EXCL contains a race condition on NFS file systems: https://linux.die.net/man/2/open
+ const int fdFile = ::open(filePath.c_str(), //const char* pathname
+ O_CREAT | //int flags
+ /*access == FileOutput::ACC_OVERWRITE ? O_TRUNC : */ O_EXCL | O_WRONLY | O_CLOEXEC,
+ lockFileMode); //mode_t mode
if (fdFile == -1)
{
const int ec = errno; //copy before making other system calls!
@@ -185,13 +190,13 @@ FileBase::FileHandle openHandleForWrite(const Zstring& filePath) //throw FileErr
}
-FileOutput::FileOutput(FileHandle handle, const Zstring& filePath, const IOCallback& notifyUnbufferedIO) :
+FileOutput::FileOutput(FileHandle handle, const Zstring& filePath, const IoCallback& notifyUnbufferedIO) :
FileBase(handle, filePath), notifyUnbufferedIO_(notifyUnbufferedIO)
{
}
-FileOutput::FileOutput(const Zstring& filePath, const IOCallback& notifyUnbufferedIO) :
+FileOutput::FileOutput(const Zstring& filePath, const IoCallback& notifyUnbufferedIO) :
FileBase(openHandleForWrite(filePath), filePath), notifyUnbufferedIO_(notifyUnbufferedIO) {} //throw FileError, ErrorTargetExisting
@@ -298,8 +303,8 @@ void FileOutput::reserveSpace(uint64_t expectedSize) //throw FileError
//don't use ::posix_fallocate which uses horribly inefficient fallback if FS doesn't support it (EOPNOTSUPP) and changes files size!
//FALLOC_FL_KEEP_SIZE => allocate only, file size is NOT changed!
- if (::fallocate(getHandle(), //int fd,
- FALLOC_FL_KEEP_SIZE, //int mode,
+ if (::fallocate(getHandle(), //int fd
+ FALLOC_FL_KEEP_SIZE, //int mode
0, //off_t offset
expectedSize) != 0) //off_t len
if (errno != EOPNOTSUPP) //possible, unlike with posix_fallocate()
@@ -308,19 +313,19 @@ void FileOutput::reserveSpace(uint64_t expectedSize) //throw FileError
}
-std::string zen::getFileContent(const Zstring& filePath, const IOCallback& notifyUnbufferedIO /*throw X*/) //throw FileError, X
+std::string zen::getFileContent(const Zstring& filePath, const IoCallback& notifyUnbufferedIO /*throw X*/) //throw FileError, X
{
FileInput streamIn(filePath, notifyUnbufferedIO); //throw FileError, ErrorFileLocked
return bufferedLoad<std::string>(streamIn); //throw FileError, X
}
-void zen::setFileContent(const Zstring& filePath, const std::string& byteStream, const IOCallback& notifyUnbufferedIO /*throw X*/) //throw FileError, X
+void zen::setFileContent(const Zstring& filePath, const std::string& byteStream, const IoCallback& notifyUnbufferedIO /*throw X*/) //throw FileError, X
{
TempFileOutput fileOut(filePath, notifyUnbufferedIO); //throw FileError
if (!byteStream.empty())
{
- //preallocate disk space + reduce fragmentation
+ //preallocate disk space & reduce fragmentation
fileOut.reserveSpace(byteStream.size()); //throw FileError
fileOut.write(&byteStream[0], byteStream.size()); //throw FileError, X
}
diff --git a/zen/file_io.h b/zen/file_io.h
index a7385241..3d1dfee7 100644
--- a/zen/file_io.h
+++ b/zen/file_io.h
@@ -32,8 +32,7 @@ public:
FileHandle getHandle() { return hFile_; }
//Windows: use 64kB ?? https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/cc938632%28v=technet.10%29
- //Linux: use st_blksize?
- //macOS: use f_iosize?
+ //macOS, Linux: use st_blksize?
static size_t getBlockSize() { return 128 * 1024; };
const Zstring& getFilePath() const { return filePath_; }
@@ -57,15 +56,15 @@ private:
class FileInput : public FileBase
{
public:
- FileInput( const Zstring& filePath, const IOCallback& notifyUnbufferedIO /*throw X*/); //throw FileError, ErrorFileLocked
- FileInput(FileHandle handle, const Zstring& filePath, const IOCallback& notifyUnbufferedIO /*throw X*/); //takes ownership!
+ FileInput( const Zstring& filePath, const IoCallback& notifyUnbufferedIO /*throw X*/); //throw FileError, ErrorFileLocked
+ FileInput(FileHandle handle, const Zstring& filePath, const IoCallback& notifyUnbufferedIO /*throw X*/); //takes ownership!
size_t read(void* buffer, size_t bytesToRead); //throw FileError, ErrorFileLocked, X; return "bytesToRead" bytes unless end of stream!
private:
size_t tryRead(void* buffer, size_t bytesToRead); //throw FileError, ErrorFileLocked; may return short, only 0 means EOF! => CONTRACT: bytesToRead > 0!
- const IOCallback notifyUnbufferedIO_; //throw X
+ const IoCallback notifyUnbufferedIO_; //throw X
std::vector<std::byte> memBuf_ = std::vector<std::byte>(getBlockSize());
size_t bufPos_ = 0;
@@ -76,8 +75,8 @@ private:
class FileOutput : public FileBase
{
public:
- FileOutput( const Zstring& filePath, const IOCallback& notifyUnbufferedIO /*throw X*/); //throw FileError, ErrorTargetExisting
- FileOutput(FileHandle handle, const Zstring& filePath, const IOCallback& notifyUnbufferedIO /*throw X*/); //takes ownership!
+ FileOutput( const Zstring& filePath, const IoCallback& notifyUnbufferedIO /*throw X*/); //throw FileError, ErrorTargetExisting
+ FileOutput(FileHandle handle, const Zstring& filePath, const IoCallback& notifyUnbufferedIO /*throw X*/); //takes ownership!
~FileOutput();
void reserveSpace(uint64_t expectedSize); //throw FileError
@@ -91,7 +90,7 @@ public:
private:
size_t tryWrite(const void* buffer, size_t bytesToWrite); //throw FileError; may return short! CONTRACT: bytesToWrite > 0
- IOCallback notifyUnbufferedIO_; //throw X
+ IoCallback notifyUnbufferedIO_; //throw X
std::vector<std::byte> memBuf_ = std::vector<std::byte>(getBlockSize());
size_t bufPos_ = 0;
size_t bufPosEnd_ = 0;
@@ -102,7 +101,7 @@ private:
class TempFileOutput
{
public:
- TempFileOutput( const Zstring& filePath, const IOCallback& notifyUnbufferedIO /*throw X*/) : //throw FileError
+ TempFileOutput( const Zstring& filePath, const IoCallback& notifyUnbufferedIO /*throw X*/) : //throw FileError
filePath_(filePath),
tmpFile_(tmpFilePath_, notifyUnbufferedIO) {} //throw FileError, (ErrorTargetExisting)
@@ -110,7 +109,7 @@ public:
void write(const void* buffer, size_t bytesToWrite) { tmpFile_.write(buffer, bytesToWrite); } //throw FileError, X
- FileOutput& refTempFile() { return tmpFile_; }
+ FileOutput& refTempFile() { return tmpFile_; }
void commit() //throw FileError, X
{
@@ -133,10 +132,10 @@ private:
};
-[[nodiscard]] std::string getFileContent(const Zstring& filePath, const IOCallback& notifyUnbufferedIO /*throw X*/); //throw FileError, X
+[[nodiscard]] std::string getFileContent(const Zstring& filePath, const IoCallback& notifyUnbufferedIO /*throw X*/); //throw FileError, X
//overwrites if existing + transactional! :)
-void setFileContent(const Zstring& filePath, const std::string& bytes, const IOCallback& notifyUnbufferedIO /*throw X*/); //throw FileError, X
+void setFileContent(const Zstring& filePath, const std::string& bytes, const IoCallback& notifyUnbufferedIO /*throw X*/); //throw FileError, X
}
#endif //FILE_IO_H_89578342758342572345
diff --git a/zen/file_traverser.cpp b/zen/file_traverser.cpp
index aa48cb85..f1b5519b 100644
--- a/zen/file_traverser.cpp
+++ b/zen/file_traverser.cpp
@@ -31,7 +31,7 @@ void zen::traverseFolder(const Zstring& dirPath,
for (;;)
{
errno = 0;
- const struct ::dirent* dirEntry = ::readdir(folder); //don't use readdir_r(), see comment in native.cpp
+ const dirent* dirEntry = ::readdir(folder); //don't use readdir_r(), see comment in native.cpp
if (!dirEntry)
{
if (errno == 0) //errno left unchanged => no more items
@@ -54,7 +54,7 @@ void zen::traverseFolder(const Zstring& dirPath,
const Zstring& itemPath = appendSeparator(dirPath) + itemName;
- struct ::stat statData = {};
+ struct stat statData = {};
try
{
if (::lstat(itemPath.c_str(), &statData) != 0) //lstat() does not resolve symlinks
@@ -75,12 +75,12 @@ void zen::traverseFolder(const Zstring& dirPath,
else if (S_ISDIR(statData.st_mode)) //a directory
{
if (onFolder)
- onFolder({ itemName, itemPath });
+ onFolder({itemName, itemPath});
}
else //a file or named pipe, etc.
{
if (onFile)
- onFile({ itemName, itemPath, makeUnsigned(statData.st_size), statData.st_mtime });
+ onFile({itemName, itemPath, makeUnsigned(statData.st_size), statData.st_mtime});
}
/* 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:
diff --git a/zen/format_unit.cpp b/zen/format_unit.cpp
index 28943de7..b2d1b59a 100644
--- a/zen/format_unit.cpp
+++ b/zen/format_unit.cpp
@@ -128,9 +128,9 @@ std::wstring roundToBlock(double timeInHigh,
std::wstring zen::formatRemainingTime(double timeInSec)
{
- const int steps10[] = { 1, 2, 5, 10 };
- const int steps24[] = { 1, 2, 3, 4, 6, 8, 12, 24 };
- const int steps60[] = { 1, 2, 5, 10, 15, 20, 30, 60 };
+ const int steps10[] = {1, 2, 5, 10};
+ const int steps24[] = {1, 2, 3, 4, 6, 8, 12, 24};
+ const int steps60[] = {1, 2, 5, 10, 15, 20, 30, 60};
//determine preferred unit
double timeInUnit = timeInSec;
@@ -178,7 +178,7 @@ std::wstring zen::formatUtcToLocalTime(time_t utcTime)
{
auto errorMsg = [&] { return _("Error") + L" (time_t: " + numberTo<std::wstring>(utcTime) + L')'; };
- TimeComp loc = getLocalTime(utcTime);
+ const TimeComp& loc = getLocalTime(utcTime);
std::wstring dateString = utfTo<std::wstring>(formatTime(Zstr("%x %X"), loc));
return !dateString.empty() ? dateString : errorMsg();
diff --git a/zen/http.cpp b/zen/http.cpp
index 5d389719..f8fb24a3 100644
--- a/zen/http.cpp
+++ b/zen/http.cpp
@@ -23,7 +23,7 @@ public:
bool disableGetCache /*not relevant for POST (= never cached)*/,
const Zstring& userAgent,
const Zstring* caCertFilePath /*optional: enable certificate validation*/,
- const IOCallback& notifyUnbufferedIO) : //throw SysError, X
+ const IoCallback& notifyUnbufferedIO) : //throw SysError, X
notifyUnbufferedIO_(notifyUnbufferedIO)
{
ZEN_ON_SCOPE_FAIL(cleanup(); /*destructor call would lead to member double clean-up!!!*/);
@@ -214,7 +214,7 @@ private:
int64_t contentRemaining_ = -1; //consider "Content-Length" if available
- const IOCallback notifyUnbufferedIO_; //throw X
+ const IoCallback notifyUnbufferedIO_; //throw X
std::vector<std::byte> memBuf_ = std::vector<std::byte>(getBlockSize());
size_t bufPos_ = 0; //buffered I/O; see file_io.cpp
@@ -240,7 +240,7 @@ std::unique_ptr<HttpInputStream::Impl> sendHttpRequestImpl(const Zstring& url,
const std::string& contentType, //required for POST
const Zstring& userAgent,
const Zstring* caCertFilePath /*optional: enable certificate validation*/,
- const IOCallback& notifyUnbufferedIO) //throw SysError, X
+ const IoCallback& notifyUnbufferedIO) //throw SysError, X
{
Zstring urlRed = url;
//"A user agent should not automatically redirect a request more than five times, since such redirections usually indicate an infinite loop."
@@ -339,14 +339,14 @@ std::vector<std::pair<std::string, std::string>> zen::xWwwFormUrlDecode(const st
}
-HttpInputStream zen::sendHttpGet(const Zstring& url, const Zstring& userAgent, const Zstring* caCertFilePath, const IOCallback& notifyUnbufferedIO) //throw SysError, X
+HttpInputStream zen::sendHttpGet(const Zstring& url, const Zstring& userAgent, const Zstring* caCertFilePath, const IoCallback& notifyUnbufferedIO) //throw SysError, X
{
return sendHttpRequestImpl(url, nullptr /*postBuf*/, "" /*contentType*/, userAgent, caCertFilePath, notifyUnbufferedIO); //throw SysError, X, X
}
HttpInputStream zen::sendHttpPost(const Zstring& url, const std::vector<std::pair<std::string, std::string>>& postParams,
- const Zstring& userAgent, const Zstring* caCertFilePath, const IOCallback& notifyUnbufferedIO) //throw SysError, X
+ const Zstring& userAgent, const Zstring* caCertFilePath, const IoCallback& notifyUnbufferedIO) //throw SysError, X
{
return sendHttpPost(url, xWwwFormUrlEncode(postParams), "application/x-www-form-urlencoded", userAgent, caCertFilePath, notifyUnbufferedIO); //throw SysError, X
}
@@ -354,7 +354,7 @@ HttpInputStream zen::sendHttpPost(const Zstring& url, const std::vector<std::pai
HttpInputStream zen::sendHttpPost(const Zstring& url, const std::string& postBuf, const std::string& contentType,
- const Zstring& userAgent, const Zstring* caCertFilePath, const IOCallback& notifyUnbufferedIO) //throw SysError, X
+ const Zstring& userAgent, const Zstring* caCertFilePath, const IoCallback& notifyUnbufferedIO) //throw SysError, X
{
return sendHttpRequestImpl(url, &postBuf, contentType, userAgent, caCertFilePath, notifyUnbufferedIO); //throw SysError, X
}
diff --git a/zen/http.h b/zen/http.h
index 6cb107bf..07c3f28c 100644
--- a/zen/http.h
+++ b/zen/http.h
@@ -39,19 +39,19 @@ private:
HttpInputStream sendHttpGet(const Zstring& url,
const Zstring& userAgent,
const Zstring* caCertFilePath /*optional: enable certificate validation*/,
- const IOCallback& notifyUnbufferedIO /*throw X*/); //throw SysError, X
+ const IoCallback& notifyUnbufferedIO /*throw X*/); //throw SysError, X
HttpInputStream sendHttpPost(const Zstring& url,
const std::vector<std::pair<std::string, std::string>>& postParams,
const Zstring& userAgent,
const Zstring* caCertFilePath /*optional: enable certificate validation*/,
- const IOCallback& notifyUnbufferedIO /*throw X*/); //throw SysError, X
+ const IoCallback& notifyUnbufferedIO /*throw X*/); //throw SysError, X
HttpInputStream sendHttpPost(const Zstring& url,
const std::string& postBuf, const std::string& contentType,
const Zstring& userAgent,
const Zstring* caCertFilePath /*optional: enable certificate validation*/,
- const IOCallback& notifyUnbufferedIO /*throw X*/); //throw SysError, X
+ const IoCallback& notifyUnbufferedIO /*throw X*/); //throw SysError, X
bool internetIsAlive(); //noexcept
std::wstring formatHttpError(int httpStatus);
diff --git a/zen/json.h b/zen/json.h
index a3740664..f6458d6a 100644
--- a/zen/json.h
+++ b/zen/json.h
@@ -372,7 +372,7 @@ public:
if (*it == '"')
{
Token tk(Token::Type::string);
- tk.primVal = jsonUnescape({ pos_, it });
+ tk.primVal = jsonUnescape({pos_, it});
pos_ = ++it;
return tk;
}
diff --git a/zen/open_ssl.cpp b/zen/open_ssl.cpp
index ea77db43..7c94263a 100644
--- a/zen/open_ssl.cpp
+++ b/zen/open_ssl.cpp
@@ -79,7 +79,7 @@ std::wstring formatLastOpenSSLError(const char* functionName)
std::shared_ptr<EVP_PKEY> generateRsaKeyPair(int bits) //throw SysError
{
- EVP_PKEY_CTX* keyCtx = ::EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, //int id,
+ EVP_PKEY_CTX* keyCtx = ::EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, //int id
nullptr); //ENGINE* e
if (!keyCtx)
throw SysError(formatLastOpenSSLError("EVP_PKEY_CTX_new_id"));
@@ -110,9 +110,9 @@ std::shared_ptr<EVP_PKEY> streamToEvpKey(const std::string& keyStream, BioToEvpF
throw SysError(formatLastOpenSSLError("BIO_new_mem_buf"));
ZEN_ON_SCOPE_EXIT(::BIO_free_all(bio));
- if (EVP_PKEY* evp = bioToEvp(bio, //BIO* bp,
- nullptr, //EVP_PKEY** x,
- nullptr, //pem_password_cb* cb,
+ if (EVP_PKEY* evp = bioToEvp(bio, //BIO* bp
+ nullptr, //EVP_PKEY** x
+ nullptr, //pem_password_cb* cb
nullptr)) //void* u
return std::shared_ptr<EVP_PKEY>(evp, ::EVP_PKEY_free);
throw SysError(formatLastOpenSSLError(functionName));
@@ -128,9 +128,9 @@ std::shared_ptr<EVP_PKEY> streamToEvpKey(const std::string& keyStream, BioToRsaF
throw SysError(formatLastOpenSSLError("BIO_new_mem_buf"));
ZEN_ON_SCOPE_EXIT(::BIO_free_all(bio));
- RSA* rsa = bioToRsa(bio, //BIO* bp,
- nullptr, //RSA** x,
- nullptr, //pem_password_cb* cb,
+ RSA* rsa = bioToRsa(bio, //BIO* bp
+ nullptr, //RSA** x
+ nullptr, //pem_password_cb* cb
nullptr); //void* u
if (!rsa)
throw SysError(formatLastOpenSSLError(functionName));
@@ -168,9 +168,9 @@ std::shared_ptr<EVP_PKEY> streamToKey(const std::string& keyStream, RsaStreamTyp
}
auto tmp = reinterpret_cast<const unsigned char*>(keyStream.c_str());
- EVP_PKEY* evp = (publicKey ? ::d2i_PublicKey : ::d2i_PrivateKey)(EVP_PKEY_RSA, //int type,
- nullptr, //EVP_PKEY** a,
- &tmp, /*changes tmp pointer itself!*/ //const unsigned char** pp,
+ EVP_PKEY* evp = (publicKey ? ::d2i_PublicKey : ::d2i_PrivateKey)(EVP_PKEY_RSA, //int type
+ nullptr, //EVP_PKEY** a
+ &tmp, /*changes tmp pointer itself!*/ //const unsigned char** pp
static_cast<long>(keyStream.size())); //long length
if (!evp)
throw SysError(formatLastOpenSSLError(publicKey ? "d2i_PublicKey" : "d2i_PrivateKey"));
@@ -238,23 +238,23 @@ std::string evpKeyToStream(EVP_PKEY* evp, RsaToBioFunc rsaToBio, const char* fun
//fix OpenSSL API inconsistencies:
int PEM_write_bio_PrivateKey2(BIO* bio, EVP_PKEY* key)
{
- return ::PEM_write_bio_PrivateKey(bio, //BIO* bp,
- key, //EVP_PKEY* x,
- nullptr, //const EVP_CIPHER* enc,
- nullptr, //unsigned char* kstr,
- 0, //int klen,
- nullptr, //pem_password_cb* cb,
+ return ::PEM_write_bio_PrivateKey(bio, //BIO* bp
+ key, //EVP_PKEY* x
+ nullptr, //const EVP_CIPHER* enc
+ nullptr, //unsigned char* kstr
+ 0, //int klen
+ nullptr, //pem_password_cb* cb
nullptr); //void* u
}
int PEM_write_bio_RSAPrivateKey2(BIO* bio, RSA* rsa)
{
- return ::PEM_write_bio_RSAPrivateKey(bio, //BIO* bp,
- rsa, //RSA* x,
- nullptr, //const EVP_CIPHER* enc,
- nullptr, //unsigned char* kstr,
- 0, //int klen,
- nullptr, //pem_password_cb* cb,
+ return ::PEM_write_bio_RSAPrivateKey(bio, //BIO* bp
+ rsa, //RSA* x
+ nullptr, //const EVP_CIPHER* enc
+ nullptr, //unsigned char* kstr
+ 0, //int klen
+ nullptr, //pem_password_cb* cb
nullptr); //void* u
}
@@ -286,7 +286,7 @@ std::string keyToStream(EVP_PKEY* evp, RsaStreamType streamType, bool publicKey)
throw SysError(formatLastOpenSSLError(publicKey ? "i2d_PublicKey" : "i2d_PrivateKey"));
ZEN_ON_SCOPE_EXIT(::OPENSSL_free(buf)); //memory is only allocated for bufSize > 0
- return { reinterpret_cast<const char*>(buf), static_cast<size_t>(bufSize) };
+ return {reinterpret_cast<const char*>(buf), static_cast<size_t>(bufSize)};
}
//================================================================================
@@ -299,29 +299,29 @@ std::string createSignature(const std::string& message, EVP_PKEY* privateKey) //
throw SysError(formatSystemError("EVP_MD_CTX_create", L"", L"Unexpected failure.")); //no more error details
ZEN_ON_SCOPE_EXIT(::EVP_MD_CTX_destroy(mdctx));
- if (::EVP_DigestSignInit(mdctx, //EVP_MD_CTX* ctx,
- nullptr, //EVP_PKEY_CTX** pctx,
- EVP_sha256(), //const EVP_MD* type,
- nullptr, //ENGINE* e,
+ if (::EVP_DigestSignInit(mdctx, //EVP_MD_CTX* ctx
+ nullptr, //EVP_PKEY_CTX** pctx
+ EVP_sha256(), //const EVP_MD* type
+ nullptr, //ENGINE* e
privateKey) != 1) //EVP_PKEY* pkey
throw SysError(formatLastOpenSSLError("EVP_DigestSignInit"));
- if (::EVP_DigestSignUpdate(mdctx, //EVP_MD_CTX* ctx,
- message.c_str(), //const void* d,
+ if (::EVP_DigestSignUpdate(mdctx, //EVP_MD_CTX* ctx
+ message.c_str(), //const void* d
message.size()) != 1) //size_t cnt
throw SysError(formatLastOpenSSLError("EVP_DigestSignUpdate"));
size_t sigLenMax = 0; //"first call to EVP_DigestSignFinal returns the maximum buffer size required"
- if (::EVP_DigestSignFinal(mdctx, //EVP_MD_CTX* ctx,
- nullptr, //unsigned char* sigret,
+ if (::EVP_DigestSignFinal(mdctx, //EVP_MD_CTX* ctx
+ nullptr, //unsigned char* sigret
&sigLenMax) != 1) //size_t* siglen
throw SysError(formatLastOpenSSLError("EVP_DigestSignFinal"));
std::string signature(sigLenMax, '\0');
size_t sigLen = sigLenMax;
- if (::EVP_DigestSignFinal(mdctx, //EVP_MD_CTX* ctx,
- reinterpret_cast<unsigned char*>(&signature[0]), //unsigned char* sigret,
+ if (::EVP_DigestSignFinal(mdctx, //EVP_MD_CTX* ctx
+ reinterpret_cast<unsigned char*>(&signature[0]), //unsigned char* sigret
&sigLen) != 1) //size_t* siglen
throw SysError(formatLastOpenSSLError("EVP_DigestSignFinal"));
@@ -338,20 +338,20 @@ void verifySignature(const std::string& message, const std::string& signature, E
throw SysError(formatSystemError("EVP_MD_CTX_create", L"", L"Unexpected failure.")); //no more error details
ZEN_ON_SCOPE_EXIT(::EVP_MD_CTX_destroy(mdctx));
- if (::EVP_DigestVerifyInit(mdctx, //EVP_MD_CTX* ctx,
- nullptr, //EVP_PKEY_CTX** pctx,
- EVP_sha256(), //const EVP_MD* type,
- nullptr, //ENGINE* e,
+ if (::EVP_DigestVerifyInit(mdctx, //EVP_MD_CTX* ctx
+ nullptr, //EVP_PKEY_CTX** pctx
+ EVP_sha256(), //const EVP_MD* type
+ nullptr, //ENGINE* e
publicKey) != 1) //EVP_PKEY* pkey
throw SysError(formatLastOpenSSLError("EVP_DigestVerifyInit"));
- if (::EVP_DigestVerifyUpdate(mdctx, //EVP_MD_CTX* ctx,
- message.c_str(), //const void* d,
+ if (::EVP_DigestVerifyUpdate(mdctx, //EVP_MD_CTX* ctx
+ message.c_str(), //const void* d
message.size()) != 1) //size_t cnt
throw SysError(formatLastOpenSSLError("EVP_DigestVerifyUpdate"));
- if (::EVP_DigestVerifyFinal(mdctx, //EVP_MD_CTX* ctx,
- reinterpret_cast<const unsigned char*>(signature.c_str()), //const unsigned char* sig,
+ if (::EVP_DigestVerifyFinal(mdctx, //EVP_MD_CTX* ctx
+ reinterpret_cast<const unsigned char*>(signature.c_str()), //const unsigned char* sig
signature.size()) != 1) //size_t siglen
throw SysError(formatLastOpenSSLError("EVP_DigestVerifyFinal"));
}
@@ -735,10 +735,10 @@ std::string zen::convertPuttyKeyToPkix(const std::string& keyStream, const std::
throw SysError(formatSystemError("EVP_CIPHER_CTX_new", L"", L"Unexpected failure.")); //no more error details
ZEN_ON_SCOPE_EXIT(::EVP_CIPHER_CTX_free(cipCtx));
- if (::EVP_DecryptInit_ex(cipCtx, //EVP_CIPHER_CTX* ctx,
- EVP_aes_256_cbc(), //const EVP_CIPHER* type,
- nullptr, //ENGINE* impl,
- key, //const unsigned char* key, => implied length of 256 bit!
+ if (::EVP_DecryptInit_ex(cipCtx, //EVP_CIPHER_CTX* ctx
+ EVP_aes_256_cbc(), //const EVP_CIPHER* type
+ nullptr, //ENGINE* impl
+ key, //const unsigned char* key => implied length of 256 bit!
nullptr) != 1) //const unsigned char* iv
throw SysError(formatLastOpenSSLError("EVP_DecryptInit_ex"));
@@ -749,16 +749,16 @@ std::string zen::convertPuttyKeyToPkix(const std::string& keyStream, const std::
//"EVP_DecryptUpdate() should have room for (inl + cipher_block_size) bytes"
int decLen1 = 0;
- if (::EVP_DecryptUpdate(cipCtx, //EVP_CIPHER_CTX* ctx,
- reinterpret_cast<unsigned char*>(&privateBlob[0]), //unsigned char* out,
- &decLen1, //int* outl,
- reinterpret_cast<const unsigned char*>(privateBlobEnc.c_str()), //const unsigned char* in,
+ if (::EVP_DecryptUpdate(cipCtx, //EVP_CIPHER_CTX* ctx
+ reinterpret_cast<unsigned char*>(&privateBlob[0]), //unsigned char* out
+ &decLen1, //int* outl
+ reinterpret_cast<const unsigned char*>(privateBlobEnc.c_str()), //const unsigned char* in
static_cast<int>(privateBlobEnc.size())) != 1) //int inl
throw SysError(formatLastOpenSSLError("EVP_DecryptUpdate"));
int decLen2 = 0;
- if (::EVP_DecryptFinal_ex(cipCtx, //EVP_CIPHER_CTX* ctx,
- reinterpret_cast<unsigned char*>(&privateBlob[decLen1]), //unsigned char* outm,
+ if (::EVP_DecryptFinal_ex(cipCtx, //EVP_CIPHER_CTX* ctx
+ reinterpret_cast<unsigned char*>(&privateBlob[decLen1]), //unsigned char* outm
&decLen2) != 1) //int* outl
throw SysError(formatLastOpenSSLError("EVP_DecryptFinal_ex"));
@@ -777,7 +777,7 @@ std::string zen::convertPuttyKeyToPkix(const std::string& keyStream, const std::
{
static_assert(std::endian::native == std::endian::little&& sizeof(n) >= 4);
const char* numStr = reinterpret_cast<const char*>(&n);
- return { numStr[3], numStr[2], numStr[1], numStr[0] }; //big endian!
+ return {numStr[3], numStr[2], numStr[1], numStr[0]}; //big endian!
};
const std::string macData = numToBeString(algorithm .size()) + algorithm +
@@ -787,13 +787,13 @@ std::string zen::convertPuttyKeyToPkix(const std::string& keyStream, const std::
numToBeString(privateBlob .size()) + privateBlob;
char md[EVP_MAX_MD_SIZE] = {};
unsigned int mdLen = 0;
- if (!::HMAC(EVP_sha1(), //const EVP_MD* evp_md,
- macKey, //const void* key,
- sizeof(macKey), //int key_len,
- reinterpret_cast<const unsigned char*>(macData.c_str()), //const unsigned char* d,
- static_cast<int>(macData.size()), //int n,
- reinterpret_cast<unsigned char*>(md), //unsigned char* md,
- &mdLen)) //unsigned int* md_len
+ if (!::HMAC(EVP_sha1(), //const EVP_MD* evp_md
+ macKey, //const void* key
+ sizeof(macKey), //int key_len
+ reinterpret_cast<const unsigned char*>(macData.c_str()), //const unsigned char* d
+ static_cast<int>(macData.size()), //int n
+ reinterpret_cast<unsigned char*>(md), //unsigned char* md
+ &mdLen)) //unsigned int* md_len
throw SysError(formatSystemError("HMAC", L"", L"Unexpected failure.")); //no more error details
const bool hashValid = mac == std::string_view(md, mdLen);
@@ -979,10 +979,10 @@ std::string zen::convertPuttyKeyToPkix(const std::string& keyStream, const std::
throw SysError(formatLastOpenSSLError("EC_POINT_new"));
ZEN_ON_SCOPE_EXIT(::EC_POINT_free(ecPoint));
- if (::EC_POINT_oct2point(ecGroup, //const EC_GROUP* group,
- ecPoint, //EC_POINT* p,
- reinterpret_cast<const unsigned char*>(&pointStream[0]), //const unsigned char* buf,
- pointStream.size(), //size_t len,
+ if (::EC_POINT_oct2point(ecGroup, //const EC_GROUP* group
+ ecPoint, //EC_POINT* p
+ reinterpret_cast<const unsigned char*>(&pointStream[0]), //const unsigned char* buf
+ pointStream.size(), //size_t len
nullptr) != 1) //BN_CTX* ctx
throw SysError(formatLastOpenSSLError("EC_POINT_oct2point"));
@@ -1008,9 +1008,9 @@ std::string zen::convertPuttyKeyToPkix(const std::string& keyStream, const std::
//const std::string pubStream = extractStringPub(); -> we don't need the public key
const std::string priStream = extractStringPriv();
- EVP_PKEY* evpPriv = ::EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, //int type,
- nullptr, //ENGINE* e,
- reinterpret_cast<const unsigned char*>(&priStream[0]), //const unsigned char* priv,
+ EVP_PKEY* evpPriv = ::EVP_PKEY_new_raw_private_key(EVP_PKEY_ED25519, //int type
+ nullptr, //ENGINE* e
+ reinterpret_cast<const unsigned char*>(&priStream[0]), //const unsigned char* priv
priStream.size()); //size_t len
if (!evpPriv)
throw SysError(formatLastOpenSSLError("EVP_PKEY_new_raw_private_key"));
diff --git a/zen/perf.h b/zen/perf.h
index 6bc328bb..2ebf1955 100644
--- a/zen/perf.h
+++ b/zen/perf.h
@@ -23,21 +23,20 @@
static zen::PerfTimer perfTest(true); //startPaused
perfTest.resume();
- ZEN_ON_SCOPE_EXIT(perfTest.pause());
-*/
+ ZEN_ON_SCOPE_EXIT(perfTest.pause()); */
namespace zen
{
-//issue with wxStopWatch? https://freefilesync.org/forum/viewtopic.php?t=1426
-// => wxStopWatch implementation uses QueryPerformanceCounter: https://github.com/wxWidgets/wxWidgets/blob/17d72a48ffd4d8ff42eed070ac48ee2de50ceabd/src/common/stopwatch.cpp
-// => whatever the problem was, it's almost certainly not caused by QueryPerformanceCounter():
-// MSDN: "How often does QPC roll over? Not less than 100 years from the most recent system boot"
-// https://docs.microsoft.com/en-us/windows/win32/sysinfo/acquiring-high-resolution-time-stamps#general-faq-about-qpc-and-tsc
-//
-// => using the system clock is problematic: https://freefilesync.org/forum/viewtopic.php?t=5280
-//
-// std::chrono::system_clock wraps ::GetSystemTimePreciseAsFileTime()
-// std::chrono::steady_clock wraps ::QueryPerformanceCounter()
+/* issue with wxStopWatch? https://freefilesync.org/forum/viewtopic.php?t=1426
+ - wxStopWatch implementation uses QueryPerformanceCounter: https://github.com/wxWidgets/wxWidgets/blob/17d72a48ffd4d8ff42eed070ac48ee2de50ceabd/src/common/stopwatch.cpp
+ - whatever the problem was, it's almost certainly not caused by QueryPerformanceCounter():
+ MSDN: "How often does QPC roll over? Not less than 100 years from the most recent system boot"
+ https://docs.microsoft.com/en-us/windows/win32/sysinfo/acquiring-high-resolution-time-stamps#general-faq-about-qpc-and-tsc
+
+ - using the system clock is problematic: https://freefilesync.org/forum/viewtopic.php?t=5280
+
+ std::chrono::system_clock wraps ::GetSystemTimePreciseAsFileTime()
+ std::chrono::steady_clock wraps ::QueryPerformanceCounter() */
class StopWatch
{
public:
diff --git a/zen/process_exec.cpp b/zen/process_exec.cpp
index bbc87c51..b82c2565 100644
--- a/zen/process_exec.cpp
+++ b/zen/process_exec.cpp
@@ -117,7 +117,7 @@ std::pair<int /*exit code*/, std::string> processExecuteImpl(const Zstring& file
if (::dup(fdLifeSignW) == -1) //O_CLOEXEC does NOT propagate with dup()
THROW_LAST_SYS_ERROR("dup(fdLifeSignW)");
- std::vector<const char*> argv{ filePath.c_str() };
+ std::vector<const char*> argv{filePath.c_str()};
for (const Zstring& arg : arguments)
argv.push_back(arg.c_str());
argv.push_back(nullptr);
@@ -147,6 +147,8 @@ std::pair<int /*exit code*/, std::string> processExecuteImpl(const Zstring& file
if (flags == -1)
THROW_LAST_SYS_ERROR("fcntl(F_GETFL)");
+ //fcntl() success: Linux: 0
+ // macOS: "Value other than -1."
if (::fcntl(fdLifeSignR, F_SETFL, flags | O_NONBLOCK) == -1)
THROW_LAST_SYS_ERROR("fcntl(F_SETFL, O_NONBLOCK)");
@@ -174,7 +176,7 @@ std::pair<int /*exit code*/, std::string> processExecuteImpl(const Zstring& file
const auto waitTimeMs = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - now).count();
- struct ::timeval tv = {};
+ timeval tv = {};
tv.tv_sec = static_cast<long>(waitTimeMs / 1000);
tv.tv_usec = static_cast<long>(waitTimeMs - tv.tv_sec * 1000) * 1000;
@@ -219,7 +221,7 @@ std::pair<int /*exit code*/, std::string> processExecuteImpl(const Zstring& file
exitCode == 127) //details should have been streamed to STDERR: used by /bin/sh, e.g. failure to execute due to missing .so file
throw SysError(utfTo<std::wstring>(trimCpy(output)));
- return { exitCode, output };
+ return {exitCode, output};
}
}
diff --git a/zen/resolve_path.cpp b/zen/resolve_path.cpp
index 76999500..0e714528 100644
--- a/zen/resolve_path.cpp
+++ b/zen/resolve_path.cpp
@@ -5,17 +5,12 @@
// *****************************************************************************
#include "resolve_path.h"
-//#include <set> //not necessarily included by <map>!
-//#include <map>
#include "time.h"
#include "thread.h"
-//#include "utf.h"
-//#include "scope_guard.h"
-//#include "globals.h"
#include "file_access.h"
#include <stdlib.h> //getenv()
- #include <unistd.h> //getcwd
+ #include <unistd.h> //getcwd()
using namespace zen;
@@ -251,7 +246,7 @@ std::vector<Zstring> zen::getFolderPathAliases(const Zstring& folderPathPhrase)
tmp.erase(dirPath);
tmp.erase(Zstring());
- return { tmp.begin(), tmp.end() };
+ return {tmp.begin(), tmp.end()};
}
diff --git a/zen/ring_buffer.h b/zen/ring_buffer.h
index 240262fa..ae2377d8 100644
--- a/zen/ring_buffer.h
+++ b/zen/ring_buffer.h
@@ -196,11 +196,11 @@ public:
using iterator = Iterator< RingBuffer, T>;
using const_iterator = Iterator<const RingBuffer, const T>;
- iterator begin() { return { *this, 0 }; }
- iterator end () { return { *this, size_ }; }
+ iterator begin() { return {*this, 0 }; }
+ iterator end () { return {*this, size_}; }
- const_iterator begin() const { return { *this, 0 }; }
- const_iterator end () const { return { *this, size_ }; }
+ const_iterator begin() const { return {*this, 0 }; }
+ const_iterator end () const { return {*this, size_}; }
const_iterator cbegin() const { return begin(); }
const_iterator cend () const { return end (); }
diff --git a/zen/serialize.h b/zen/serialize.h
index 6c57e4ee..f9677630 100644
--- a/zen/serialize.h
+++ b/zen/serialize.h
@@ -35,7 +35,7 @@ struct BufferedInputStream
Optional: support stream-copying
--------------------------------
size_t getBlockSize() const;
- const IOCallback& notifyUnbufferedIO
+ const IoCallback& notifyUnbufferedIO
};
--------------------------------
@@ -47,9 +47,9 @@ struct BufferedOutputStream
Optional: support stream-copying
--------------------------------
- const IOCallback& notifyUnbufferedIO
+ const IoCallback& notifyUnbufferedIO
}; */
-using IOCallback = std::function<void(int64_t bytesDelta)>; //throw X
+using IoCallback = std::function<void(int64_t bytesDelta)>; //throw X
//functions based on buffered stream abstraction
@@ -75,7 +75,7 @@ template < class BufferedInputStream> void readArray (BufferedInputSt
struct IOCallbackDivider
{
- IOCallbackDivider(const IOCallback& notifyUnbufferedIO, int64_t& totalUnbufferedIO) : totalUnbufferedIO_(totalUnbufferedIO), notifyUnbufferedIO_(notifyUnbufferedIO) {}
+ IOCallbackDivider(const IoCallback& notifyUnbufferedIO, int64_t& totalUnbufferedIO) : totalUnbufferedIO_(totalUnbufferedIO), notifyUnbufferedIO_(notifyUnbufferedIO) {}
void operator()(int64_t bytesDelta)
{
@@ -85,7 +85,7 @@ struct IOCallbackDivider
private:
int64_t& totalUnbufferedIO_;
- const IOCallback& notifyUnbufferedIO_;
+ const IoCallback& notifyUnbufferedIO_;
};
@@ -206,7 +206,7 @@ void writeArray(BufferedOutputStream& stream, const void* buffer, size_t len)
template <class N, class BufferedOutputStream> inline
void writeNumber(BufferedOutputStream& stream, const N& num)
{
- static_assert(IsArithmetic<N>::value || std::is_same_v<N, bool> || std::is_enum_v<N>);
+ static_assert(IsArithmeticV<N> || std::is_same_v<N, bool> || std::is_enum_v<N>);
writeArray(stream, &num, sizeof(N));
}
@@ -234,7 +234,7 @@ void readArray(BufferedInputStream& stream, void* buffer, size_t len) //throw Sy
template <class N, class BufferedInputStream> inline
N readNumber(BufferedInputStream& stream) //throw SysErrorUnexpectedEos
{
- static_assert(IsArithmetic<N>::value || std::is_same_v<N, bool> || std::is_enum_v<N>);
+ static_assert(IsArithmeticV<N> || std::is_same_v<N, bool> || std::is_enum_v<N>);
N num{};
readArray(stream, &num, sizeof(N)); //throw SysErrorUnexpectedEos
return num;
diff --git a/zen/stl_tools.h b/zen/stl_tools.h
index 495ff8d1..53b95241 100644
--- a/zen/stl_tools.h
+++ b/zen/stl_tools.h
@@ -128,7 +128,7 @@ void removeDuplicates(std::vector<T, Alloc>& v, CompLess less)
template <class T, class Alloc> inline
void removeDuplicates(std::vector<T, Alloc>& v)
{
- removeDuplicates(v, std::less<T>(), std::equal_to<T>());
+ removeDuplicates(v, std::less(), std::equal_to());
}
@@ -233,6 +233,7 @@ class FNV1aHash
{
public:
FNV1aHash() {}
+ explicit FNV1aHash(Num startVal) : hashVal_(startVal) {}
void add(Num n)
{
@@ -243,8 +244,8 @@ public:
Num get() const { return hashVal_; }
private:
- static_assert(IsUnsignedInt<Num>::value);
- static_assert(sizeof(Num) == 4 || sizeof(Num) == 8); //macOS: size_t is "unsigned long"
+ static_assert(IsUnsignedIntV<Num>);
+ static_assert(sizeof(Num) == 4 || sizeof(Num) == 8);
static constexpr Num base_ = sizeof(Num) == 4 ? 2166136261U : 14695981039346656037ULL;
static constexpr Num prime_ = sizeof(Num) == 4 ? 16777619U : 1099511628211ULL;
@@ -257,7 +258,7 @@ Num hashArray(ByteIterator first, ByteIterator last)
{
using ValType = typename std::iterator_traits<ByteIterator>::value_type;
static_assert(sizeof(ValType) <= sizeof(Num));
- static_assert(IsInteger<ValType>::value || std::is_same_v<ValType, char> || std::is_same_v<ValType, wchar_t>);
+ static_assert(IsIntegerV<ValType> || std::is_same_v<ValType, char> || std::is_same_v<ValType, wchar_t>);
FNV1aHash<Num> hash;
std::for_each(first, last, [&hash](ValType v) { hash.add(v); });
@@ -265,8 +266,7 @@ Num hashArray(ByteIterator first, ByteIterator last)
}
-//support for custom string classes in std::unordered_set/map
-struct StringHash
+struct StringHash //support for custom string classes with std::unordered_set/map
{
template <class String>
size_t operator()(const String& str) const
diff --git a/zen/string_tools.h b/zen/string_tools.h
index 883c45b8..8150df05 100644
--- a/zen/string_tools.h
+++ b/zen/string_tools.h
@@ -395,7 +395,7 @@ std::vector<S> split(const S& str, const T& delimiter, SplitOnEmpty soe)
{
if (str.empty() && soe == SplitOnEmpty::skip)
return {};
- return { str };
+ return {str};
}
const auto* const delimFirst = strBegin(delimiter);
@@ -800,9 +800,9 @@ template <class S, class Num> inline
S numberTo(const Num& number)
{
using TypeTag = std::integral_constant<impl::NumberType,
- IsSignedInt <Num>::value ? impl::NumberType::signedInt :
- IsUnsignedInt<Num>::value ? impl::NumberType::unsignedInt :
- IsFloat <Num>::value ? impl::NumberType::floatingPoint :
+ IsSignedIntV <Num> ? impl::NumberType::signedInt :
+ IsUnsignedIntV<Num> ? impl::NumberType::unsignedInt :
+ IsFloatV <Num> ? impl::NumberType::floatingPoint :
impl::NumberType::other>;
return impl::numberTo<S>(number, TypeTag());
@@ -813,9 +813,9 @@ template <class Num, class S> inline
Num stringTo(const S& str)
{
using TypeTag = std::integral_constant<impl::NumberType,
- IsSignedInt <Num>::value ? impl::NumberType::signedInt :
- IsUnsignedInt<Num>::value ? impl::NumberType::unsignedInt :
- IsFloat <Num>::value ? impl::NumberType::floatingPoint :
+ IsSignedIntV <Num> ? impl::NumberType::signedInt :
+ IsUnsignedIntV<Num> ? impl::NumberType::unsignedInt :
+ IsFloatV <Num> ? impl::NumberType::floatingPoint :
impl::NumberType::other>;
return impl::stringTo<Num>(str, TypeTag());
@@ -836,7 +836,7 @@ std::pair<char, char> hexify(unsigned char c, bool upperCase)
else
return static_cast<char>('a' + (num - 10));
};
- return { hexifyDigit(c / 16), hexifyDigit(c % 16) };
+ return {hexifyDigit(c / 16), hexifyDigit(c % 16)};
}
diff --git a/zen/string_traits.h b/zen/string_traits.h
index d9ce589c..ca40f7d6 100644
--- a/zen/string_traits.h
+++ b/zen/string_traits.h
@@ -120,19 +120,12 @@ public:
};
}
-template <class T>
-struct IsStringLike : std::bool_constant<impl::StringTraits<T>::isStringLike> {};
-template <class T>
-struct GetCharType { using Type = typename impl::StringTraits<T>::CharType; };
-
-
-//template alias helpers:
template<class T>
-constexpr bool IsStringLikeV = IsStringLike<T>::value;
+constexpr bool IsStringLikeV = impl::StringTraits<T>::isStringLike;
template<class T>
-using GetCharTypeT = typename GetCharType<T>::Type;
+using GetCharTypeT = typename impl::StringTraits<T>::CharType;
namespace impl
diff --git a/zen/symlink_target.h b/zen/symlink_target.h
index 42010fd2..32b1211d 100644
--- a/zen/symlink_target.h
+++ b/zen/symlink_target.h
@@ -70,11 +70,11 @@ Zstring getResolvedSymlinkPath_impl(const Zstring& linkPath) //throw FileError
namespace zen
{
inline
-SymlinkRawContent getSymlinkRawContent(const Zstring& linkPath) { return getSymlinkRawContent_impl(linkPath); }
+SymlinkRawContent getSymlinkRawContent(const Zstring& linkPath) { return getSymlinkRawContent_impl(linkPath); } //throw FileError
inline
-Zstring getSymlinkResolvedPath(const Zstring& linkPath) { return getResolvedSymlinkPath_impl(linkPath); }
+Zstring getSymlinkResolvedPath(const Zstring& linkPath) { return getResolvedSymlinkPath_impl(linkPath); } //throw FileError
}
diff --git a/zen/sys_info.cpp b/zen/sys_info.cpp
index f6045f7e..1a0d18f5 100644
--- a/zen/sys_info.cpp
+++ b/zen/sys_info.cpp
@@ -25,17 +25,14 @@ using namespace zen;
std::wstring zen::getUserName() //throw FileError
{
- const uid_t userIdNo = ::getuid(); //"real user ID"; never fails
-
- std::vector<char> buffer(std::max<long>(10000, ::sysconf(_SC_GETPW_R_SIZE_MAX))); //::sysconf may return long(-1)
- struct passwd buffer2 = {};
- struct passwd* pwsEntry = nullptr;
- if (::getpwuid_r(userIdNo, &buffer2, &buffer[0], buffer.size(), &pwsEntry) != 0) //getlogin() is deprecated and not working on Ubuntu at all!!!
- THROW_LAST_FILE_ERROR(_("Cannot get process information."), "getpwuid_r");
- if (!pwsEntry)
- throw FileError(_("Cannot get process information."), L"no login found"); //should not happen?
-
- return utfTo<std::wstring>(pwsEntry->pw_name);
+ //https://linux.die.net/man/3/getlogin
+ //https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getlogin.2.html
+ const char* loginUser = ::getlogin();
+ if (!loginUser)
+ THROW_LAST_FILE_ERROR(_("Cannot get process information."), "getlogin");
+ //getlogin() is smarter than simply evaluating $LOGNAME! even in contexts without
+ //$LOGNAME, e.g. "sudo su" on Ubuntu, it returns the correct non-root user!
+ return utfTo<std::wstring>(loginUser);
}
@@ -64,7 +61,7 @@ ComputerModel zen::getComputerModel() //throw FileError
cm.vendor = tryGetInfo("/sys/devices/virtual/dmi/id/sys_vendor"); //
//clean up:
- cm.model = beforeFirst(cm.model, L'\u00ff', IfNotFoundReturn::all); //fix broken BIOS entries:
+ cm.model = beforeFirst(cm.model, L'\u00ff', IfNotFoundReturn::all); //fix broken BIOS entries:
cm.vendor = beforeFirst(cm.vendor, L'\u00ff', IfNotFoundReturn::all); //0xff can be considered 0
for (const char* dummyModel :
@@ -119,21 +116,25 @@ Zstring zen::getRealProcessPath() //throw FileError
}
+Zstring zen::getUserDataPath() //throw FileError
+{
+ if (::getuid() != 0) //nofail; root(0) => consider as request for elevation, NOT impersonation
+ if (const char* xdgCfgPath = ::getenv("XDG_CONFIG_HOME"); //no extended error reporting
+ xdgCfgPath && xdgCfgPath[0] != 0)
+ return xdgCfgPath;
+
+ return Zstring("/home/") + utfTo<Zstring>(getUserName()) + "/.config"; //throw FileError
+}
+
+
Zstring zen::getUserDownloadsPath() //throw FileError
{
try
{
- Zstring cmdLine;
- if (getuid() == 0) //nofail; root(0) => consider as request for elevation, NOT impersonation
- {
- const char* loginUser = getlogin(); //https://linux.die.net/man/3/getlogin
- if (!loginUser)
- THROW_LAST_SYS_ERROR("getlogin");
-
- cmdLine = Zstring("sudo -u ") + loginUser + " xdg-user-dir DOWNLOAD"; //sudo better be installed :>
- }
- else
- cmdLine = "xdg-user-dir DOWNLOAD";
+ const Zstring cmdLine = ::getuid() == 0 ? //nofail; root(0) => consider as request for elevation, NOT impersonation
+ //sudo better be installed :>
+ "sudo -u " + utfTo<Zstring>(getUserName()) + " xdg-user-dir DOWNLOAD" : //throw FileError
+ "xdg-user-dir DOWNLOAD";
const auto& [exitCode, output] = consoleExecute(cmdLine, std::nullopt /*timeoutMs*/); //throw SysError
if (exitCode != 0)
@@ -145,4 +146,3 @@ Zstring zen::getUserDownloadsPath() //throw FileError
}
catch (const SysError& e) { throw FileError(_("Cannot get process information."), e.toString()); }
}
-
diff --git a/zen/sys_info.h b/zen/sys_info.h
index 1b046fb6..4f83a9a3 100644
--- a/zen/sys_info.h
+++ b/zen/sys_info.h
@@ -31,6 +31,7 @@ std::wstring getOsDescription(); //throw FileError
Zstring getRealProcessPath(); //throw FileError
Zstring getUserDownloadsPath(); //throw FileError
+Zstring getUserDataPath(); //throw FileError
}
diff --git a/zen/thread.cpp b/zen/thread.cpp
index 89fa0233..e14afac7 100644
--- a/zen/thread.cpp
+++ b/zen/thread.cpp
@@ -28,7 +28,7 @@ const std::thread::id globalMainThreadId = std::this_thread::get_id();
bool zen::runningOnMainThread()
{
- if (globalMainThreadId == std::thread::id()) //called during static initialization!
+ if (globalMainThreadId == std::thread::id()) //if called during static initialization!
return true;
return std::this_thread::get_id() == globalMainThreadId;
diff --git a/zen/thread.h b/zen/thread.h
index 1bea95ea..136c7a5c 100644
--- a/zen/thread.h
+++ b/zen/thread.h
@@ -173,18 +173,18 @@ public:
void run(Function&& wi /*should throw ThreadStopRequest when needed*/, bool insertFront = false)
{
{
- std::lock_guard dummy(workLoad_->lock);
+ std::lock_guard dummy(workLoad_.ref().lock);
if (insertFront)
- workLoad_->tasks.push_front(std::move(wi));
+ workLoad_.ref().tasks.push_front(std::move(wi));
else
- workLoad_->tasks.push_back(std::move(wi));
- const size_t tasksPending = ++(workLoad_->tasksPending);
+ workLoad_.ref().tasks.push_back(std::move(wi));
+ const size_t tasksPending = ++(workLoad_.ref().tasksPending);
if (worker_.size() < std::min(tasksPending, threadCountMax_))
addWorkerThread();
}
- workLoad_->conditionNewTask.notify_all();
+ workLoad_.ref().conditionNewTask.notify_all();
}
//context of controlling thread, blocking:
@@ -203,12 +203,12 @@ public:
//non-blocking wait()-alternative: context of controlling thread:
void notifyWhenDone(const std::function<void()>& onCompletion /*noexcept! runs on worker thread!*/)
{
- std::lock_guard dummy(workLoad_->lock);
+ std::lock_guard dummy(workLoad_.ref().lock);
- if (workLoad_->tasksPending == 0)
+ if (workLoad_.ref().tasksPending == 0)
onCompletion();
else
- workLoad_->onCompletionCallbacks.push_back(onCompletion);
+ workLoad_.ref().onCompletionCallbacks.push_back(onCompletion);
}
//context of controlling thread:
@@ -222,27 +222,28 @@ private:
{
Zstring threadName = groupName_ + Zstr('[') + numberTo<Zstring>(worker_.size() + 1) + Zstr('/') + numberTo<Zstring>(threadCountMax_) + Zstr(']');
- worker_.emplace_back([wl = workLoad_, threadName = std::move(threadName)] //don't capture "this"! consider detach() and move operations
+ worker_.emplace_back([workLoad_ /*clang bug*/= workLoad_ /*share ownership!*/, threadName = std::move(threadName)]() mutable //don't capture "this"! consider detach() and move operations
{
setCurrentThreadName(threadName);
+ WorkLoad& workLoad = workLoad_.ref();
- std::unique_lock dummy(wl->lock);
+ std::unique_lock dummy(workLoad.lock);
for (;;)
{
- interruptibleWait(wl->conditionNewTask, dummy, [&tasks = wl->tasks] { return !tasks.empty(); }); //throw ThreadStopRequest
+ interruptibleWait(workLoad.conditionNewTask, dummy, [&tasks = workLoad.tasks] { return !tasks.empty(); }); //throw ThreadStopRequest
- Function task = std::move(wl->tasks. front()); //noexcept thanks to move
- /**/ wl->tasks.pop_front(); //
+ Function task = std::move(workLoad.tasks. front()); //noexcept thanks to move
+ /**/ workLoad.tasks.pop_front(); //
dummy.unlock();
task(); //throw ThreadStopRequest?
dummy.lock();
- if (--(wl->tasksPending) == 0)
- if (!wl->onCompletionCallbacks.empty())
+ if (--(workLoad.tasksPending) == 0)
+ if (!workLoad.onCompletionCallbacks.empty())
{
std::vector<std::function<void()>> callbacks;
- callbacks.swap(wl->onCompletionCallbacks);
+ callbacks.swap(workLoad.onCompletionCallbacks);
dummy.unlock();
for (const auto& cb : callbacks)
@@ -263,7 +264,7 @@ private:
};
std::vector<InterruptibleThread> worker_;
- std::shared_ptr<WorkLoad> workLoad_ = std::make_shared<WorkLoad>();
+ SharedRef<WorkLoad> workLoad_ = makeSharedRef<WorkLoad>();
bool detach_ = false;
size_t threadCountMax_;
Zstring groupName_;
@@ -446,7 +447,7 @@ private:
activeCondition_ = cv;
}
- std::atomic<bool> stopRequested_{ false }; //std:atomic is uninitialized by default!!!
+ std::atomic<bool> stopRequested_{false}; //std:atomic is uninitialized by default!!!
//"The default constructor is trivial: no initialization takes place other than zero initialization of static and thread-local objects."
std::condition_variable* activeCondition_ = nullptr;
diff --git a/zen/time.h b/zen/time.h
index aaf36983..903b2e87 100644
--- a/zen/time.h
+++ b/zen/time.h
@@ -271,7 +271,7 @@ TimeComp parseTime(const String& format, const String2& str)
if (strLast - itStr < 3)
return TimeComp();
- const char* months[] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" };
+ const char* months[] = {"jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"};
auto itMonth = std::find_if(std::begin(months), std::end(months), [&](const char* month)
{
return equalAsciiNoCase(makeStringView(itStr, 3), month);
diff --git a/zen/type_traits.h b/zen/type_traits.h
index 03fbd768..a4194c05 100644
--- a/zen/type_traits.h
+++ b/zen/type_traits.h
@@ -20,6 +20,7 @@ struct GetFirstOf
};
template<class... T> using GetFirstOfT = typename GetFirstOf<T...>::Type;
+
template <class F>
class FunctionReturnType
{
@@ -48,40 +49,40 @@ template<class T> inline auto makeSigned (T t) { return static_cast<std::make_s
template<class T> inline auto makeUnsigned(T t) { return static_cast<std::make_unsigned_t<T>>(t); }
//################# Built-in Types ########################
-//Example: "IsSignedInt<int>::value" evaluates to "true"
-
//unfortunate standardized nonsense: std::is_integral<> includes bool, char, wchar_t! => roll our own:
-template <class T> struct IsUnsignedInt;
-template <class T> struct IsSignedInt;
-
-template <class T> using IsFloat = std::is_floating_point<T>;
-template <class T> using IsInteger = std::bool_constant<IsUnsignedInt<T>::value || IsSignedInt<T>::value>;
-template <class T> using IsArithmetic = std::bool_constant<IsInteger <T>::value || IsFloat <T>::value>;
-
-//remaining non-arithmetic types: bool, char, wchar_t
-
-
-//optional: specialize new types like:
-//template <> struct IsUnsignedInt<UInt64> : std::true_type {};
+template<class T> constexpr bool IsUnsignedIntV = std::is_same_v<std::remove_cv_t<T>, unsigned char> ||
+ std::is_same_v<std::remove_cv_t<T>, unsigned short int> ||
+ std::is_same_v<std::remove_cv_t<T>, unsigned int> ||
+ std::is_same_v<std::remove_cv_t<T>, unsigned long int> ||
+ std::is_same_v<std::remove_cv_t<T>, unsigned long long int>;
+
+template<class T> constexpr bool IsSignedIntV = std::is_same_v<std::remove_cv_t<T>, signed char> ||
+ std::is_same_v<std::remove_cv_t<T>, short int> ||
+ std::is_same_v<std::remove_cv_t<T>, int> ||
+ std::is_same_v<std::remove_cv_t<T>, long int> ||
+ std::is_same_v<std::remove_cv_t<T>, long long int>;
+
+template<class T> constexpr bool IsIntegerV = IsUnsignedIntV<T> || IsSignedIntV<T>;
+template<class T> constexpr bool IsFloatV = std::is_floating_point_v<T>;
+template<class T> constexpr bool IsArithmeticV = IsIntegerV<T> || IsFloatV<T>;
//################# Class Members ########################
/* Detect data or function members of a class by name: ZEN_INIT_DETECT_MEMBER + HasMember_
Example: 1. ZEN_INIT_DETECT_MEMBER(c_str);
2. HasMemberV_c_str<T> -> use boolean
-*/
-/* Detect data or function members of a class by name *and* type: ZEN_INIT_DETECT_MEMBER2 + HasMember_
+
+ Detect data or function members of a class by name *and* type: ZEN_INIT_DETECT_MEMBER2 + HasMember_
Example: 1. ZEN_INIT_DETECT_MEMBER2(size, size_t (T::*)() const);
2. HasMember_size<T>::value -> use as boolean
-*/
-/* Detect member type of a class: ZEN_INIT_DETECT_MEMBER_TYPE + HasMemberType_
+
+ Detect member type of a class: ZEN_INIT_DETECT_MEMBER_TYPE + HasMemberType_
Example: 1. ZEN_INIT_DETECT_MEMBER_TYPE(value_type);
- 2. HasMemberTypeV_value_type<T> -> use as boolean
-*/
+ 2. HasMemberTypeV_value_type<T> -> use as boolean */
//########## Sorting ##############################
/*
@@ -114,25 +115,6 @@ LessDescending<Predicate> makeSortDirection(Predicate pred, std::false_type) { r
//################ implementation ######################
-template <class T>
-struct IsUnsignedInt : std::false_type {};
-
-template <> struct IsUnsignedInt<unsigned char > : std::true_type {};
-template <> struct IsUnsignedInt<unsigned short int > : std::true_type {};
-template <> struct IsUnsignedInt<unsigned int > : std::true_type {};
-template <> struct IsUnsignedInt<unsigned long int > : std::true_type {};
-template <> struct IsUnsignedInt<unsigned long long int> : std::true_type {};
-
-template <class T>
-struct IsSignedInt : std::false_type {};
-
-template <> struct IsSignedInt<signed char > : std::true_type {};
-template <> struct IsSignedInt<short int > : std::true_type {};
-template <> struct IsSignedInt<int > : std::true_type {};
-template <> struct IsSignedInt<long int > : std::true_type {};
-template <> struct IsSignedInt<long long int> : std::true_type {};
-//####################################################################
-
#define ZEN_INIT_DETECT_MEMBER(NAME) \
\
template<bool isClass, class T> \
bgstack15