summaryrefslogtreecommitdiff
path: root/zen/file_access.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'zen/file_access.cpp')
-rwxr-xr-xzen/file_access.cpp142
1 files changed, 65 insertions, 77 deletions
diff --git a/zen/file_access.cpp b/zen/file_access.cpp
index 88b70b14..82c78760 100755
--- a/zen/file_access.cpp
+++ b/zen/file_access.cpp
@@ -50,32 +50,32 @@ std::optional<PathComponents> zen::parsePathComponents(const Zstring& itemPath)
return {};
};
- if (startsWith(itemPath, "/"))
- {
- if (startsWith(itemPath, "/media/"))
- {
- //Ubuntu: e.g. /media/zenju/DEVICE_NAME
- if (const char* username = ::getenv("USER"))
- if (startsWith(itemPath, std::string("/media/") + username + "/"))
- return doParse(4 /*sepCountVolumeRoot*/, false /*rootWithSep*/);
+ std::optional<PathComponents> pc; //"/media/zenju/" and "/Volumes/" should not fail to parse
- //Ubuntu: e.g. /media/cdrom0
- return doParse(3 /*sepCountVolumeRoot*/, false /*rootWithSep*/);
- }
+ if (!pc && startsWith(itemPath, "/mnt/")) //e.g. /mnt/DEVICE_NAME
+ pc = doParse(3 /*sepCountVolumeRoot*/, false /*rootWithSep*/);
- if (startsWith(itemPath, "/run/media/")) //Suse: e.g. /run/media/zenju/DEVICE_NAME
- if (const char* username = ::getenv("USER"))
- if (startsWith(itemPath, std::string("/run/media/") + username + "/"))
- return doParse(5 /*sepCountVolumeRoot*/, false /*rootWithSep*/);
+ if (!pc && startsWith(itemPath, "/media/")) //Ubuntu: e.g. /media/zenju/DEVICE_NAME
+ if (const char* username = ::getenv("USER"))
+ if (startsWith(itemPath, std::string("/media/") + username + "/"))
+ pc = doParse(4 /*sepCountVolumeRoot*/, false /*rootWithSep*/);
- return doParse(1 /*sepCountVolumeRoot*/, true /*rootWithSep*/);
- }
+ if (!pc && startsWith(itemPath, "/run/media/")) //Centos, Suse: e.g. /run/media/zenju/DEVICE_NAME
+ if (const char* username = ::getenv("USER"))
+ if (startsWith(itemPath, std::string("/run/media/") + username + "/"))
+ pc = doParse(5 /*sepCountVolumeRoot*/, false /*rootWithSep*/);
- //we do NOT support relative paths!
- return {};
-}
+ if (!pc && startsWith(itemPath, "/run/user/")) //Ubuntu, e.g.: /run/user/1000/gvfs/smb-share:server=192.168.62.145,share=folder
+ if (startsWith(itemPath, "/run/user/" + numberTo<std::string>(::getuid()) + "/gvfs/")) //::getuid() never fails
+ pc = doParse(6 /*sepCountVolumeRoot*/, false /*rootWithSep*/);
+ if (!pc && startsWith(itemPath, "/"))
+ pc = doParse(1 /*sepCountVolumeRoot*/, true /*rootWithSep*/);
+
+ return pc;
+}
+
std::optional<Zstring> zen::getParentFolderPath(const Zstring& itemPath)
{
@@ -108,49 +108,40 @@ ItemType zen::getItemType(const Zstring& itemPath) //throw FileError
}
-PathStatus zen::getPathStatus(const Zstring& itemPath) //throw FileError
+std::optional<ItemType> zen::itemStillExists(const Zstring& itemPath) //throw FileError
{
- const std::optional<Zstring> parentPath = getParentFolderPath(itemPath);
try
{
- return { getItemType(itemPath), itemPath, {} }; //throw FileError
+ return getItemType(itemPath); //throw FileError
}
- catch (FileError&)
+ catch (const FileError& e) //not existing or access error
{
+ const std::optional<Zstring> parentPath = getParentFolderPath(itemPath);
if (!parentPath) //device root
throw;
//else: let's dig deeper... don't bother checking Win32 codes; e.g. not existing item may have the codes:
// 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, IF_MISSING_RETURN_ALL);
- assert(!itemName.empty());
-
- PathStatus ps = getPathStatus(*parentPath); //throw FileError
- if (ps.relPath.empty() &&
- ps.existingType != ItemType::FILE) //obscure, but possible (and not an error)
- try
- {
- traverseFolder(*parentPath,
- [&](const FileInfo& fi) { if (equalFilePath(fi.itemName, itemName)) throw ItemType::FILE; },
- [&](const FolderInfo& fi) { if (equalFilePath(fi.itemName, itemName)) throw ItemType::FOLDER; },
- [&](const SymlinkInfo& si) { if (equalFilePath(si.itemName, itemName)) throw ItemType::SYMLINK; },
- [](const std::wstring& errorMsg) { throw FileError(errorMsg); });
- }
- catch (const ItemType& type) { return { type, itemPath, {} }; } //yes, exceptions for control-flow are bad design... but, but...
- //we're not CPU-bound here and finding the item after getItemType() previously failed is exceptional (even C:\pagefile.sys should be found)
-
- ps.relPath.push_back(itemName);
- return ps;
-}
+ const Zstring itemName = afterLast(itemPath, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_ALL);
+ assert(!itemName.empty());
-std::optional<ItemType> zen::getItemTypeIfExists(const Zstring& itemPath) //throw FileError
-{
- const PathStatus ps = getPathStatus(itemPath); //throw FileError
- if (ps.relPath.empty())
- return ps.existingType;
- return {};
+ const std::optional<ItemType> parentType = itemStillExists(*parentPath); //throw FileError
+ if (parentType && *parentType != ItemType::FILE /*obscure, but possible (and not an error)*/)
+ try
+ {
+ traverseFolder(*parentPath,
+ [&](const FileInfo& fi) { if (fi.itemName == itemName) throw ItemType::FILE; },
+ [&](const FolderInfo& fi) { if (fi.itemName == itemName) throw ItemType::FOLDER; },
+ [&](const SymlinkInfo& si) { if (si.itemName == itemName) throw ItemType::SYMLINK; },
+ [](const std::wstring& errorMsg) { throw FileError(errorMsg); });
+ }
+ catch (const ItemType&) //finding the item after getItemType() previously failed is exceptional
+ {
+ throw e; //yes, slicing
+ }
+ return {};
+ }
}
@@ -174,16 +165,6 @@ bool zen::dirAvailable(const Zstring& dirPath) //noexcept
}
-bool zen::itemNotExisting(const Zstring& itemPath)
-{
- try
- {
- return !getItemTypeIfExists(itemPath); //throw FileError
- }
- catch (FileError&) { return false; }
-}
-
-
namespace
{
}
@@ -209,13 +190,13 @@ uint64_t zen::getFreeDiskSpace(const Zstring& path) //throw FileError, returns 0
}
-VolumeId zen::getVolumeId(const Zstring& itemPath) //throw FileError
+FileId /*optional*/ zen::getFileId(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)), L"stat");
- return fileInfo.st_dev;
+ return extractFileId(fileInfo);
}
@@ -381,7 +362,7 @@ void zen::renameFile(const Zstring& pathSource, const Zstring& pathTarget) //thr
const Zstring parentPathSrc = beforeLast(pathSource, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE);
const Zstring parentPathTrg = beforeLast(pathTarget, FILE_NAME_SEPARATOR, IF_MISSING_RETURN_NONE);
//some (broken) devices may fail to rename case directly:
- if (equalLocalPath(parentPathSrc, parentPathTrg))
+ if (equalNativePath(parentPathSrc, parentPathTrg))
{
if (fileNameSrc == fileNameTrg)
return; //non-sensical request
@@ -567,8 +548,18 @@ void zen::createDirectory(const Zstring& dirPath) //throw FileError, ErrorTarget
void zen::createDirectoryIfMissingRecursion(const Zstring& dirPath) //throw FileError
{
- if (!getParentFolderPath(dirPath)) //device root
- return static_cast<void>(/*ItemType =*/ getItemType(dirPath)); //throw FileError
+ const std::optional<Zstring> parentPath = getParentFolderPath(dirPath);
+ if (!parentPath) //device root
+ return;
+
+ try //generally we expect that path already exists (see: ffs_paths.cpp) => check first
+ {
+ if (getItemType(dirPath) != ItemType::FILE) //throw FileError
+ return;
+ }
+ catch (FileError&) {} //not yet existing or access error? let's find out...
+
+ createDirectoryIfMissingRecursion(*parentPath); //throw FileError
try
{
@@ -576,18 +567,15 @@ void zen::createDirectoryIfMissingRecursion(const Zstring& dirPath) //throw File
}
catch (FileError&)
{
- const PathStatus ps = getPathStatus(dirPath); //throw FileError
- if (ps.existingType == ItemType::FILE)
- throw;
+ try
+ {
+ if (getItemType(dirPath) != ItemType::FILE) //throw FileError
+ return; //already existing => possible, if createDirectoryIfMissingRecursion() is run in parallel
+ }
+ catch (FileError&) {} //not yet existing or access error
+ //catch (const FileError& e2) { throw FileError(e.toString(), e2.toString()); } -> details needed???
- //ps.relPath.size() == 1 => same createDirectory() call from above? Maybe parent folder was created by parallel thread shortly after failure!
- Zstring intermediatePath = ps.existingPath;
- for (const Zstring& itemName : ps.relPath)
- try
- {
- createDirectory(intermediatePath = appendSeparator(intermediatePath) + itemName); //throw FileError, ErrorTargetExisting
- }
- catch (ErrorTargetExisting&) {} //possible, if createDirectoryIfMissingRecursion() is run in parallel
+ throw;
}
}
bgstack15