summaryrefslogtreecommitdiff
path: root/zen/file_access.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'zen/file_access.cpp')
-rw-r--r--zen/file_access.cpp100
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"
bgstack15