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/file_access.cpp | |
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/file_access.cpp')
-rw-r--r-- | zen/file_access.cpp | 100 |
1 files changed, 61 insertions, 39 deletions
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" |