summaryrefslogtreecommitdiff
path: root/zen/file_access.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'zen/file_access.cpp')
-rwxr-xr-xzen/file_access.cpp89
1 files changed, 44 insertions, 45 deletions
diff --git a/zen/file_access.cpp b/zen/file_access.cpp
index ea19b6c7..d257b7c2 100755
--- a/zen/file_access.cpp
+++ b/zen/file_access.cpp
@@ -170,16 +170,6 @@ namespace
}
-uint64_t zen::getFileSize(const Zstring& filePath) //throw FileError
-{
- struct ::stat fileInfo = {};
- if (::stat(filePath.c_str(), &fileInfo) != 0)
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(filePath)), L"stat");
-
- return fileInfo.st_size;
-}
-
-
uint64_t zen::getFreeDiskSpace(const Zstring& path) //throw FileError, returns 0 if not available
{
struct ::statfs info = {};
@@ -190,13 +180,19 @@ uint64_t zen::getFreeDiskSpace(const Zstring& path) //throw FileError, returns 0
}
-FileId /*optional*/ zen::getFileId(const Zstring& itemPath) //throw FileError
+FileDetails zen::getFileDetails(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 extractFileId(fileInfo);
+ return
+ {
+ makeUnsigned(fileInfo.st_size),
+ fileInfo.st_mtime,
+ fileInfo.st_dev,
+ //FileIndex fileIndex = fileInfo.st_ino;
+ };
}
@@ -301,19 +297,14 @@ namespace
/* Usage overview: (avoid circular pattern!)
- renameFile() --> renameFile_sub()
- | /|\
- \|/ |
- Fix8Dot3NameClash()
+ moveAndRenameItem() --> moveAndRenameFileSub()
+ | /|\
+ \|/ |
+ Fix8Dot3NameClash()
*/
//wrapper for file system rename function:
-void renameFile_sub(const Zstring& pathSource, const Zstring& pathTarget) //throw FileError, ErrorDifferentVolume, ErrorTargetExisting
+void moveAndRenameFileSub(const Zstring& pathSource, const Zstring& pathTarget, bool replaceExisting) //throw FileError, ErrorDifferentVolume, ErrorTargetExisting
{
- //rename() will never fail with EEXIST, but always (atomically) overwrite!
- //=> equivalent to SetFileInformationByHandle() + FILE_RENAME_INFO::ReplaceIfExists or ::MoveFileEx + MOVEFILE_REPLACE_EXISTING
- //Linux: renameat2() with RENAME_NOREPLACE -> still new, probably buggy
- //macOS: no solution
-
auto throwException = [&](int ec)
{
const std::wstring errorMsg = replaceCpy(replaceCpy(_("Cannot move file %x to %y."), L"%x", L"\n" + fmtPath(pathSource)), L"%y", L"\n" + fmtPath(pathTarget));
@@ -326,19 +317,27 @@ void renameFile_sub(const Zstring& pathSource, const Zstring& pathTarget) //thro
throw FileError(errorMsg, errorDescr);
};
- struct ::stat infoSrc = {};
- if (::lstat(pathSource.c_str(), &infoSrc) != 0)
- THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(pathSource)), L"stat");
+ //rename() will never fail with EEXIST, but always (atomically) overwrite!
+ //=> equivalent to SetFileInformationByHandle() + FILE_RENAME_INFO::ReplaceIfExists or ::MoveFileEx() + MOVEFILE_REPLACE_EXISTING
+ //Linux: renameat2() with RENAME_NOREPLACE -> still new, probably buggy
+ //macOS: no solution https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man2/rename.2.html
+ if (!replaceExisting)
+ {
+ struct ::stat infoSrc = {};
+ if (::lstat(pathSource.c_str(), &infoSrc) != 0)
+ THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(pathSource)), L"stat");
- struct ::stat infoTrg = {};
- if (::lstat(pathTarget.c_str(), &infoTrg) == 0)
- {
- if (infoSrc.st_dev != infoTrg.st_dev ||
- infoSrc.st_ino != infoTrg.st_ino)
- throwException(EEXIST); //that's what we're really here for
- //else: continue with a rename in case
- }
- //else: not existing or access error (hopefully ::rename will also fail!)
+ struct ::stat infoTrg = {};
+ if (::lstat(pathTarget.c_str(), &infoTrg) == 0)
+ {
+ if (infoSrc.st_dev != infoTrg.st_dev ||
+ infoSrc.st_ino != infoTrg.st_ino)
+ throwException(EEXIST); //that's what we're really here for
+ //else: continue with a rename in case
+ //caveat: if we have a hardlink referenced by two different paths, the source one will be unlinked => fine, but not exactly a "rename"...
+ }
+ //else: not existing or access error (hopefully ::rename will also fail!)
+ }
if (::rename(pathSource.c_str(), pathTarget.c_str()) != 0)
throwException(errno);
@@ -349,11 +348,11 @@ void renameFile_sub(const Zstring& pathSource, const Zstring& pathTarget) //thro
//rename file: no copying!!!
-void zen::renameFile(const Zstring& pathSource, const Zstring& pathTarget) //throw FileError, ErrorDifferentVolume, ErrorTargetExisting
+void zen::moveAndRenameItem(const Zstring& pathSource, const Zstring& pathTarget, bool replaceExisting) //throw FileError, ErrorDifferentVolume, ErrorTargetExisting
{
try
{
- renameFile_sub(pathSource, pathTarget); //throw FileError, ErrorDifferentVolume, ErrorTargetExisting
+ moveAndRenameFileSub(pathSource, pathTarget, replaceExisting); //throw FileError, ErrorDifferentVolume, ErrorTargetExisting
}
catch (ErrorTargetExisting&)
{
@@ -369,9 +368,9 @@ void zen::renameFile(const Zstring& pathSource, const Zstring& pathTarget) //thr
return; //non-sensical request
const Zstring tempFilePath = getTemporaryPath8Dot3(pathSource); //throw FileError
- renameFile_sub(pathSource, tempFilePath); //throw FileError, ErrorDifferentVolume, ErrorTargetExisting
- ZEN_ON_SCOPE_FAIL(renameFile_sub(tempFilePath, pathSource)); //"try" our best to be "atomic" :>
- renameFile_sub(tempFilePath, pathTarget); //throw FileError, ErrorDifferentVolume, ErrorTargetExisting
+ moveAndRenameFileSub(pathSource, tempFilePath); //throw FileError, ErrorDifferentVolume, ErrorTargetExisting
+ ZEN_ON_SCOPE_FAIL(moveAndRenameFileSub(tempFilePath, pathSource)); //"try" our best to be "atomic" :>
+ moveAndRenameFileSub(tempFilePath, pathTarget); //throw FileError, ErrorDifferentVolume, ErrorTargetExisting
return;
}
#endif
@@ -398,7 +397,7 @@ void setWriteTimeNative(const Zstring& itemPath, const struct ::timespec& modTim
struct ::timespec newTimes[2] = {};
newTimes[0].tv_sec = ::time(nullptr); //access time; using UTIME_OMIT for tv_nsec would trigger even more bugs: https://freefilesync.org/forum/viewtopic.php?t=1701
newTimes[1] = modTime; //modification time
- //test: even modTime == 0 is correctly applied (no NOOP!) test2: same behavior for "utime()"
+ //test: even modTime == 0 is correctly applied (no NOOP!) test2: same behavior for "utime()"
if (procSl == ProcSymlink::FOLLOW)
{
@@ -680,8 +679,8 @@ FileCopyResult copyFileOsSpecific(const Zstring& sourceFile, //throw FileError,
FileCopyResult result;
result.fileSize = sourceInfo.st_size;
result.modTime = sourceInfo.st_mtim.tv_sec; //
- result.sourceFileId = extractFileId(sourceInfo);
- result.targetFileId = extractFileId(targetInfo);
+ result.sourceFileId = generateFileId(sourceInfo);
+ result.targetFileId = generateFileId(targetInfo);
result.errorModTime = errorModTime;
return result;
}
@@ -700,10 +699,10 @@ copyFileWindowsDefault(::CopyFileEx) copyFileWindowsStream(::BackupRead/::Backu
}
-FileCopyResult zen::copyNewFile(const Zstring& sourceFile, const Zstring& targetFile, bool copyFilePermissions, //throw FileError, ErrorTargetExisting, ErrorFileLocked
- const IOCallback& notifyUnbufferedIO)
+FileCopyResult zen::copyNewFile(const Zstring& sourceFile, const Zstring& targetFile, bool copyFilePermissions, //throw FileError, ErrorTargetExisting, ErrorFileLocked, X
+ const IOCallback& notifyUnbufferedIO /*throw X*/)
{
- const FileCopyResult result = copyFileOsSpecific(sourceFile, targetFile, notifyUnbufferedIO); //throw FileError, ErrorTargetExisting, ErrorFileLocked
+ const FileCopyResult result = copyFileOsSpecific(sourceFile, targetFile, notifyUnbufferedIO); //throw FileError, ErrorTargetExisting, ErrorFileLocked, X
//at this point we know we created a new file, so it's fine to delete it for cleanup!
ZEN_ON_SCOPE_FAIL(try { removeFilePlain(targetFile); }
bgstack15