summaryrefslogtreecommitdiff
path: root/zen
diff options
context:
space:
mode:
Diffstat (limited to 'zen')
-rw-r--r--zen/dir_watcher.cpp2
-rw-r--r--zen/file_access.cpp100
-rw-r--r--zen/file_access.h9
-rw-r--r--zen/file_io.cpp12
-rw-r--r--zen/file_traverser.cpp8
-rw-r--r--zen/file_traverser.h8
-rw-r--r--zen/http.cpp1
-rw-r--r--zen/open_ssl.cpp2
-rw-r--r--zen/symlink_target.h2
-rw-r--r--zen/thread.h2
10 files changed, 85 insertions, 61 deletions
diff --git a/zen/dir_watcher.cpp b/zen/dir_watcher.cpp
index 87fa3596..e0b4a338 100644
--- a/zen/dir_watcher.cpp
+++ b/zen/dir_watcher.cpp
@@ -35,7 +35,7 @@ DirWatcher::DirWatcher(const Zstring& dirPath) : //throw FileError
//get all subdirectories
std::vector<Zstring> fullFolderList {baseDirPath_};
{
- std::function<void (const Zstring& path)> traverse;
+ std::function<void(const Zstring& path)> traverse;
traverse = [&traverse, &fullFolderList](const Zstring& path)
{
diff --git a/zen/file_access.cpp b/zen/file_access.cpp
index 1da8bd1b..a52ea9b8 100644
--- a/zen/file_access.cpp
+++ b/zen/file_access.cpp
@@ -29,28 +29,13 @@ using namespace zen;
namespace
{
-}
-
-
-ItemType zen::getItemType(const Zstring& itemPath) //throw FileError
-{
- 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");
-
- if (S_ISLNK(itemInfo.st_mode))
- return ItemType::symlink;
- if (S_ISDIR(itemInfo.st_mode))
- return ItemType::folder;
- return ItemType::file; //S_ISREG || S_ISCHR || S_ISBLK || S_ISFIFO || S_ISSOCK
-}
-std::optional<ItemType> zen::itemStillExists(const Zstring& itemPath) //throw FileError
+std::pair<Zstring, ItemType> getExistingPath(const Zstring& itemPath) //throw FileError
{
try
{
- return getItemType(itemPath); //throw FileError
+ return {itemPath, getItemType(itemPath)}; //throw FileError
}
catch (const FileError& e) //not existing or access error
{
@@ -61,14 +46,14 @@ std::optional<ItemType> zen::itemStillExists(const Zstring& itemPath) //throw Fi
// ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, ERROR_INVALID_NAME, ERROR_INVALID_DRIVE,
// ERROR_NOT_READY, ERROR_INVALID_PARAMETER, ERROR_BAD_PATHNAME, ERROR_BAD_NETPATH => not reliable
- const Zstring itemName = afterLast(itemPath, FILE_NAME_SEPARATOR, IfNotFoundReturn::all);
- assert(!itemName.empty());
-
- const std::optional<ItemType> parentType = itemStillExists(*parentPath); //throw FileError
+ auto [existingPath, existingType] = getExistingPath(*parentPath); //throw FileError
- if (parentType && *parentType != ItemType::file /*obscure, but possible (and not an error)*/)
+ if (existingPath == *parentPath && existingType != ItemType::file /*obscure, but possible (and not an error)*/)
try
{
+ const Zstring itemName = afterLast(itemPath, FILE_NAME_SEPARATOR, IfNotFoundReturn::all);
+ assert(!itemName.empty());
+
traverseFolder(*parentPath,
[&](const FileInfo& fi) { if (fi.itemName == itemName) throw ItemType::file; }, //case-sensitive! itemPath must be normalized!
[&](const FolderInfo& fi) { if (fi.itemName == itemName) throw ItemType::folder; },
@@ -79,9 +64,35 @@ std::optional<ItemType> zen::itemStillExists(const Zstring& itemPath) //throw Fi
{
throw FileError(_("Temporary access error:") + L' ' + e.toString());
}
- return {};
+
+ return {std::move(existingPath), existingType};
}
}
+}
+
+
+ItemType zen::getItemType(const Zstring& itemPath) //throw FileError
+{
+ 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");
+
+ if (S_ISLNK(itemInfo.st_mode))
+ return ItemType::symlink;
+ if (S_ISDIR(itemInfo.st_mode))
+ return ItemType::folder;
+ return ItemType::file; //S_ISREG || S_ISCHR || S_ISBLK || S_ISFIFO || S_ISSOCK
+}
+
+
+std::optional<ItemType> zen::itemStillExists(const Zstring& itemPath) //throw FileError
+{
+ const auto& [existingPath, existingType] = getExistingPath(itemPath); //throw FileError
+ if (existingPath == itemPath)
+ return existingType;
+ else
+ return {};
+}
bool zen::fileAvailable(const Zstring& filePath) //noexcept
@@ -109,18 +120,29 @@ namespace
}
-int64_t zen::getFreeDiskSpace(const Zstring& path) //throw FileError, returns < 0 if not available
+//- symlink handling: follow
+//- returns < 0 if not available
+//- folderPath does not need to exist (yet)
+int64_t zen::getFreeDiskSpace(const Zstring& folderPath) //throw FileError
{
- 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;
+ const auto& [existingPath, existingType] = getExistingPath(folderPath); //throw FileError
+
+ warn_static("what if existingType is symlink?")
+
+ try
+ {
+ struct statfs info = {};
+ if (::statfs(existingPath.c_str(), &info) != 0) //follows symlinks!
+ THROW_LAST_SYS_ERROR("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;
+ }
+ catch (const SysError& e) { throw FileError(replaceCpy(_("Cannot determine free disk space for %x."), L"%x", fmtPath(folderPath)), e.toString()); }
}
@@ -528,10 +550,10 @@ void zen::createDirectoryIfMissingRecursion(const Zstring& dirPath) //throw File
void zen::tryCopyDirectoryAttributes(const Zstring& sourcePath, const Zstring& targetPath) //throw FileError
{
-//do NOT copy attributes for volume root paths which return as: FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY
-//https://freefilesync.org/forum/viewtopic.php?t=5550
-if (!getParentFolderPath(sourcePath)) //=> root path
- return;
+ //do NOT copy attributes for volume root paths which return as: FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_DIRECTORY
+ //https://freefilesync.org/forum/viewtopic.php?t=5550
+ if (!getParentFolderPath(sourcePath)) //=> root path
+ return;
}
@@ -616,7 +638,7 @@ FileCopyResult zen::copyNewFile(const Zstring& sourceFile, const Zstring& target
#if 0
//clean file system cache: needed at all? no user complaints at all!!!
//posix_fadvise(POSIX_FADV_DONTNEED) does nothing, unless data was already read from/written to disk: https://insights.oetiker.ch/linux/fadvise/
- // => should be "most" of the data at this point => good enough?
+ // => should be "most" of the data at this point => good enough?
if (::posix_fadvise(fileIn.getHandle(), 0 /*offset*/, 0 /*len*/, POSIX_FADV_DONTNEED) != 0) //"len == 0" means "end of the file"
THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file %x."), L"%x", fmtPath(sourceFile)), "posix_fadvise(POSIX_FADV_DONTNEED)");
if (::posix_fadvise(fileOut.getHandle(), 0 /*offset*/, 0 /*len*/, POSIX_FADV_DONTNEED) != 0) //"len == 0" means "end of the file"
diff --git a/zen/file_access.h b/zen/file_access.h
index 639abf64..d87fcd0d 100644
--- a/zen/file_access.h
+++ b/zen/file_access.h
@@ -28,7 +28,7 @@ const int FAT_FILE_TIME_PRECISION_SEC = 2; //https://devblogs.microsoft.com/oldn
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 time_t nativeFileTimeToTimeT(const timespec& ft) { return ft.tv_sec; } //follow Windows Explorer: always round down!
inline timespec timetToNativeFileTime(time_t utcTime) { return {.tv_sec = utcTime}; }
enum class ItemType
@@ -51,8 +51,13 @@ enum class ProcSymlink
};
void setFileTime(const Zstring& filePath, time_t modTime, ProcSymlink procSl); //throw FileError
+
+int64_t getFreeDiskSpace(const Zstring& folderPath); //throw FileError, returns < 0 if not available
+//- symlink handling: follow
+//- returns < 0 if not available
+//- folderPath does not need to exist (yet)
+
//symlink handling: follow
-int64_t getFreeDiskSpace(const Zstring& path); //throw FileError, returns < 0 if not available
uint64_t getFileSize(const Zstring& filePath); //throw FileError
//get per-user directory designated for temporary files:
diff --git a/zen/file_io.cpp b/zen/file_io.cpp
index ef3cbebb..7dd11a1d 100644
--- a/zen/file_io.cpp
+++ b/zen/file_io.cpp
@@ -165,14 +165,13 @@ size_t FileInputPlain::tryRead(void* buffer, size_t bytesToRead) //throw FileErr
while (bytesRead < 0 && errno == EINTR); //Compare copy_reg() in copy.c: ftp://ftp.gnu.org/gnu/coreutils/coreutils-8.23.tar.xz
//EINTR is not checked on macOS' copyfile: https://opensource.apple.com/source/copyfile/copyfile-173.40.2/copyfile.c.auto.html
//read() on macOS: https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man2/read.2.html
+ //if ::read is interrupted (EINTR) right in the middle, it will return successfully with "bytesRead < bytesToRead"
if (bytesRead < 0)
THROW_LAST_SYS_ERROR("read");
- if (makeUnsigned(bytesRead) > bytesToRead) //better safe than sorry
- throw SysError(formatSystemError("ReadFile", L"", L"Buffer overflow."));
-
- //if ::read is interrupted (EINTR) right in the middle, it will return successfully with "bytesRead < bytesToRead"
+ if (makeUnsigned(bytesRead) > bytesToRead) //better safe than sorry
+ throw SysError(formatSystemError("read", L"", L"Buffer overflow."));
return bytesRead; //"zero indicates end of file"
}
catch (const SysError& e) { throw FileError(replaceCpy(_("Cannot read file %x."), L"%x", fmtPath(getFilePath())), e.toString()); }
@@ -276,6 +275,7 @@ size_t FileOutputPlain::tryWrite(const void* buffer, size_t bytesToWrite) //thro
}
while (bytesWritten < 0 && errno == EINTR);
//write() on macOS: https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man2/write.2.html
+ //if ::write() is interrupted (EINTR) right in the middle, it will return successfully with "bytesWritten < bytesToWrite"!
if (bytesWritten <= 0)
{
@@ -284,10 +284,8 @@ size_t FileOutputPlain::tryWrite(const void* buffer, size_t bytesToWrite) //thro
THROW_LAST_SYS_ERROR("write");
}
- if (bytesWritten > static_cast<ssize_t>(bytesToWrite)) //better safe than sorry
+ if (makeUnsigned(bytesWritten) > bytesToWrite) //better safe than sorry
throw SysError(formatSystemError("write", L"", L"Buffer overflow."));
-
- //if ::write() is interrupted (EINTR) right in the middle, it will return successfully with "bytesWritten < bytesToWrite"!
return bytesWritten;
}
catch (const SysError& e) { throw FileError(replaceCpy(_("Cannot write file %x."), L"%x", fmtPath(getFilePath())), e.toString()); }
diff --git a/zen/file_traverser.cpp b/zen/file_traverser.cpp
index ff588562..3a6099d9 100644
--- a/zen/file_traverser.cpp
+++ b/zen/file_traverser.cpp
@@ -15,10 +15,10 @@ using namespace zen;
void zen::traverseFolder(const Zstring& dirPath,
- const std::function<void (const FileInfo& fi)>& onFile,
- const std::function<void (const FolderInfo& fi)>& onFolder,
- const std::function<void (const SymlinkInfo& si)>& onSymlink,
- const std::function<void (const std::wstring& errorMsg)>& onError)
+ const std::function<void(const FileInfo& fi)>& onFile,
+ const std::function<void(const FolderInfo& fi)>& onFolder,
+ const std::function<void(const SymlinkInfo& si)>& onSymlink,
+ const std::function<void(const std::wstring& errorMsg)>& onError)
{
try
{
diff --git a/zen/file_traverser.h b/zen/file_traverser.h
index 11c3eaa0..8bd32f2c 100644
--- a/zen/file_traverser.h
+++ b/zen/file_traverser.h
@@ -36,10 +36,10 @@ struct SymlinkInfo
//- non-recursive
//- directory path may end with PATH_SEPARATOR
void traverseFolder(const Zstring& dirPath, //noexcept
- const std::function<void (const FileInfo& fi)>& onFile, //
- const std::function<void (const FolderInfo& fi)>& onFolder, //optional
- const std::function<void (const SymlinkInfo& si)>& onSymlink, //
- const std::function<void (const std::wstring& errorMsg)>& onError); //
+ const std::function<void(const FileInfo& fi)>& onFile, //
+ const std::function<void(const FolderInfo& fi)>& onFolder, //optional
+ const std::function<void(const SymlinkInfo& si)>& onSymlink, //
+ const std::function<void(const std::wstring& errorMsg)>& onError); //
}
#endif //FILER_TRAVERSER_H_127463214871234
diff --git a/zen/http.cpp b/zen/http.cpp
index ee71e5b3..5054ef3f 100644
--- a/zen/http.cpp
+++ b/zen/http.cpp
@@ -84,7 +84,6 @@ public:
std::vector<CurlOption> extraOptions {{CURLOPT_USERAGENT, userAgent.c_str()}};
//CURLOPT_FOLLOWLOCATION already off by default :)
-
std::function<size_t(std::span<char> buf)> readRequest;
if (postBuf)
{
diff --git a/zen/open_ssl.cpp b/zen/open_ssl.cpp
index 4494b76f..6a5be3e8 100644
--- a/zen/open_ssl.cpp
+++ b/zen/open_ssl.cpp
@@ -549,7 +549,7 @@ std::string zen::convertPuttyKeyToPkix(const std::string& keyStream, const std::
auto numToBeString = [](size_t n) -> std::string
{
- static_assert(std::endian::native == std::endian::little&& sizeof(n) >= 4);
+ 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!
};
diff --git a/zen/symlink_target.h b/zen/symlink_target.h
index 44c15ab2..89c00571 100644
--- a/zen/symlink_target.h
+++ b/zen/symlink_target.h
@@ -47,7 +47,7 @@ zen::SymlinkRawContent getSymlinkRawContent_impl(const Zstring& linkPath) //thro
const ssize_t bytesWritten = ::readlink(linkPath.c_str(), buf.data(), bufSize);
if (bytesWritten < 0)
THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtPath(linkPath)), "readlink");
- if (bytesWritten >= static_cast<ssize_t>(bufSize)) //detect truncation; not an error for readlink!
+ if (makeUnsigned(bytesWritten) >= bufSize) //detect truncation; not an error for readlink!
throw FileError(replaceCpy(_("Cannot resolve symbolic link %x."), L"%x", fmtPath(linkPath)), formatSystemError("readlink", L"", L"Buffer truncated."));
return {.targetPath = Zstring(buf.data(), bytesWritten)}; //readlink does not append 0-termination!
diff --git a/zen/thread.h b/zen/thread.h
index 931f2c0d..1823eefc 100644
--- a/zen/thread.h
+++ b/zen/thread.h
@@ -122,7 +122,7 @@ private:
//------------------------------------------------------------------------------------------
//value associated with mutex and guaranteed protected access:
-//TODO: use std::synchronized_value when available http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0290r2.html
+//TODO: use std::synchronized_value when available https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rconc-mutex
template <class T>
class Protected
{
bgstack15