diff options
author | B. Stack <bgstack15@gmail.com> | 2022-10-19 10:53:07 -0400 |
---|---|---|
committer | B. Stack <bgstack15@gmail.com> | 2022-10-19 10:53:07 -0400 |
commit | a53560254596460a4778a27f50b89ce92f810055 (patch) | |
tree | 551fdc08cbece3cca567d04870b91eaa115a4675 /zen | |
parent | Merge branch 'b11.26' into 'master' (diff) | |
download | FreeFileSync-a53560254596460a4778a27f50b89ce92f810055.tar.gz FreeFileSync-a53560254596460a4778a27f50b89ce92f810055.tar.bz2 FreeFileSync-a53560254596460a4778a27f50b89ce92f810055.zip |
add upstream 11.2711.27
Diffstat (limited to 'zen')
-rw-r--r-- | zen/dir_watcher.cpp | 2 | ||||
-rw-r--r-- | zen/file_access.cpp | 100 | ||||
-rw-r--r-- | zen/file_access.h | 9 | ||||
-rw-r--r-- | zen/file_io.cpp | 12 | ||||
-rw-r--r-- | zen/file_traverser.cpp | 8 | ||||
-rw-r--r-- | zen/file_traverser.h | 8 | ||||
-rw-r--r-- | zen/http.cpp | 1 | ||||
-rw-r--r-- | zen/open_ssl.cpp | 2 | ||||
-rw-r--r-- | zen/symlink_target.h | 2 | ||||
-rw-r--r-- | zen/thread.h | 2 |
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 { |