diff options
author | B Stack <bgstack15@gmail.com> | 2021-03-03 01:18:05 +0000 |
---|---|---|
committer | B Stack <bgstack15@gmail.com> | 2021-03-03 01:18:05 +0000 |
commit | 320f1ae680d73da35a0cfe4846eb687d8616bcac (patch) | |
tree | 6fb17404841b30822a2d9204e3e0932e55f05ebb /zen/file_access.cpp | |
parent | Merge branch '11.6' into 'master' (diff) | |
parent | add upstream 11.7 (diff) | |
download | FreeFileSync-320f1ae680d73da35a0cfe4846eb687d8616bcac.tar.gz FreeFileSync-320f1ae680d73da35a0cfe4846eb687d8616bcac.tar.bz2 FreeFileSync-320f1ae680d73da35a0cfe4846eb687d8616bcac.zip |
Merge branch '11.7' into 'master'11.7
add upstream 11.7
See merge request opensource-tracking/FreeFileSync!31
Diffstat (limited to 'zen/file_access.cpp')
-rw-r--r-- | zen/file_access.cpp | 98 |
1 files changed, 45 insertions, 53 deletions
diff --git a/zen/file_access.cpp b/zen/file_access.cpp index 4c9af652..fb770f19 100644 --- a/zen/file_access.cpp +++ b/zen/file_access.cpp @@ -12,7 +12,6 @@ #include "file_traverser.h" #include "scope_guard.h" #include "symlink_target.h" -#include "file_id_def.h" #include "file_io.h" #include "crc.h" #include "guid.h" @@ -45,7 +44,7 @@ std::optional<PathComponents> zen::parsePathComponents(const Zstring& itemPath) Zstring relPath(it + 1, itemPathFmt.end()); trim(relPath, true, true, [](Zchar c) { return c == FILE_NAME_SEPARATOR; }); - return PathComponents({ rootPath, relPath }); + return PathComponents({rootPath, relPath}); } return {}; }; @@ -100,7 +99,7 @@ std::optional<Zstring> zen::getParentFolderPath(const Zstring& itemPath) ItemType zen::getItemType(const Zstring& itemPath) //throw FileError { - struct ::stat itemInfo = {}; + 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"); @@ -153,7 +152,7 @@ std::optional<ItemType> zen::itemStillExists(const Zstring& itemPath) //throw Fi bool zen::fileAvailable(const Zstring& filePath) //noexcept { //symbolic links (broken or not) are also treated as existing files! - struct ::stat fileInfo = {}; + struct stat fileInfo = {}; if (::stat(filePath.c_str(), &fileInfo) == 0) //follow symlinks! return S_ISREG(fileInfo.st_mode); return false; @@ -163,7 +162,7 @@ bool zen::fileAvailable(const Zstring& filePath) //noexcept bool zen::dirAvailable(const Zstring& dirPath) //noexcept { //symbolic links (broken or not) are also treated as existing directories! - struct ::stat dirInfo = {}; + struct stat dirInfo = {}; if (::stat(dirPath.c_str(), &dirInfo) == 0) //follow symlinks! return S_ISDIR(dirInfo.st_mode); return false; @@ -177,29 +176,22 @@ namespace int64_t zen::getFreeDiskSpace(const Zstring& path) //throw FileError, returns < 0 if not available { - struct ::statfs info = {}; - if (::statfs(path.c_str(), &info) != 0) + 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; } -VolumeId zen::getVolumeId(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)), "stat"); - - warn_static("NOT STABLE!") - - return fileInfo.st_dev; -} - - uint64_t zen::getFileSize(const Zstring& filePath) //throw FileError { - struct ::stat fileInfo = {}; + 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)), "stat"); @@ -207,6 +199,8 @@ uint64_t zen::getFileSize(const Zstring& filePath) //throw FileError } + + Zstring zen::getTempFolderPath() //throw FileError { if (const char* tempPath = ::getenv("TMPDIR")) //no extended error reporting @@ -336,15 +330,15 @@ void moveAndRenameFileSub(const Zstring& pathFrom, const Zstring& pathTo, bool r //macOS: no solution https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man2/rename.2.html if (!replaceExisting) { - struct ::stat infoSrc = {}; - if (::lstat(pathFrom.c_str(), &infoSrc) != 0) + struct stat sourceInfo = {}; + if (::lstat(pathFrom.c_str(), &sourceInfo) != 0) THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(pathFrom)), "stat"); - struct ::stat infoTrg = {}; - if (::lstat(pathTo.c_str(), &infoTrg) == 0) + struct stat targetInfo = {}; + if (::lstat(pathTo.c_str(), &targetInfo) == 0) { - if (infoSrc.st_dev != infoTrg.st_dev || - infoSrc.st_ino != infoTrg.st_ino) + if (sourceInfo.st_dev != targetInfo.st_dev || + sourceInfo.st_ino != targetInfo.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"... @@ -376,7 +370,7 @@ void zen::moveAndRenameItem(const Zstring& pathFrom, const Zstring& pathTo, bool namespace { -void setWriteTimeNative(const Zstring& itemPath, const struct ::timespec& modTime, ProcSymlink procSl) //throw FileError +void setWriteTimeNative(const Zstring& itemPath, const timespec& modTime, ProcSymlink procSl) //throw FileError { /* [2013-05-01] sigh, we can't use utimensat() on NTFS volumes on Ubuntu: silent failure!!! what morons are programming this shit??? @@ -388,12 +382,12 @@ void setWriteTimeNative(const Zstring& itemPath, const struct ::timespec& modTim => let's give utimensat another chance: using open()/futimens() for regular files and utimensat(AT_SYMLINK_NOFOLLOW) for symlinks is consistent with "cp" and "touch"! */ - struct ::timespec newTimes[2] = {}; + 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()" - if (procSl == ProcSymlink::FOLLOW) + if (procSl == ProcSymlink::follow) { //hell knows why files on gvfs-mounted Samba shares fail to open(O_WRONLY) returning EOPNOTSUPP: //https://freefilesync.org/forum/viewtopic.php?t=2803 => utimensat() works (but not for gvfs SFTP) @@ -422,10 +416,8 @@ void setWriteTimeNative(const Zstring& itemPath, const struct ::timespec& modTim void zen::setFileTime(const Zstring& filePath, time_t modTime, ProcSymlink procSl) //throw FileError { - struct ::timespec writeTime = {}; - writeTime.tv_sec = modTime; - setWriteTimeNative(filePath, writeTime, procSl); //throw FileError - + setWriteTimeNative(filePath, timetToNativeFileTime(modTime), + procSl); //throw FileError } @@ -442,7 +434,7 @@ namespace void copySecurityContext(const Zstring& source, const Zstring& target, ProcSymlink procSl) //throw FileError { security_context_t contextSource = nullptr; - const int rv = procSl == ProcSymlink::FOLLOW ? + const int rv = procSl == ProcSymlink::follow ? ::getfilecon (source.c_str(), &contextSource) : ::lgetfilecon(source.c_str(), &contextSource); if (rv < 0) @@ -457,7 +449,7 @@ void copySecurityContext(const Zstring& source, const Zstring& target, ProcSymli { security_context_t contextTarget = nullptr; - const int rv2 = procSl == ProcSymlink::FOLLOW ? + const int rv2 = procSl == ProcSymlink::follow ? ::getfilecon(target.c_str(), &contextTarget) : ::lgetfilecon(target.c_str(), &contextTarget); if (rv2 < 0) @@ -475,7 +467,7 @@ void copySecurityContext(const Zstring& source, const Zstring& target, ProcSymli } } - const int rv3 = procSl == ProcSymlink::FOLLOW ? + const int rv3 = procSl == ProcSymlink::follow ? ::setfilecon(target.c_str(), contextSource) : ::lsetfilecon(target.c_str(), contextSource); if (rv3 < 0) @@ -493,8 +485,8 @@ void zen::copyItemPermissions(const Zstring& sourcePath, const Zstring& targetPa copySecurityContext(sourcePath, targetPath, procSl); //throw FileError #endif - struct ::stat fileInfo = {}; - if (procSl == ProcSymlink::FOLLOW) + struct stat fileInfo = {}; + if (procSl == ProcSymlink::follow) { if (::stat(sourcePath.c_str(), &fileInfo) != 0) THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read permissions of %x."), L"%x", fmtPath(sourcePath)), "stat"); @@ -614,22 +606,22 @@ void zen::copySymlink(const Zstring& sourcePath, const Zstring& targetPath) //th catch (FileError&) {}); //file times: essential for syncing a symlink: enforce this! (don't just try!) - struct ::stat sourceInfo = {}; + struct stat sourceInfo = {}; if (::lstat(sourcePath.c_str(), &sourceInfo) != 0) THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(sourcePath)), "lstat"); - setWriteTimeNative(targetPath, sourceInfo.st_mtim, ProcSymlink::DIRECT); //throw FileError + setWriteTimeNative(targetPath, sourceInfo.st_mtim, ProcSymlink::direct); //throw FileError } FileCopyResult zen::copyNewFile(const Zstring& sourceFile, const Zstring& targetFile, //throw FileError, ErrorTargetExisting, (ErrorFileLocked), X - const IOCallback& notifyUnbufferedIO /*throw X*/) + const IoCallback& notifyUnbufferedIO /*throw X*/) { int64_t totalUnbufferedIO = 0; FileInput fileIn(sourceFile, IOCallbackDivider(notifyUnbufferedIO, totalUnbufferedIO)); //throw FileError, (ErrorFileLocked -> Windows-only) - struct ::stat sourceInfo = {}; + struct stat sourceInfo = {}; if (::fstat(fileIn.getHandle(), &sourceInfo) != 0) THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(sourceFile)), "fstat"); @@ -637,7 +629,7 @@ FileCopyResult zen::copyNewFile(const Zstring& sourceFile, const Zstring& target //it seems we don't need S_IWUSR, not even for the setFileTime() below! (tested with source file having different user/group!) //=> need copyItemPermissions() only for "chown" and umask-agnostic permissions - const int fdTarget = ::open(targetFile.c_str(), O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, mode); + const int fdTarget = ::open(targetFile.c_str(), O_CREAT | O_EXCL | O_WRONLY | O_CLOEXEC, mode); if (fdTarget == -1) { const int ec = errno; //copy before making other system calls! @@ -659,7 +651,7 @@ FileCopyResult zen::copyNewFile(const Zstring& sourceFile, const Zstring& target //flush intermediate buffers before fiddling with the raw file handle fileOut.flushBuffers(); //throw FileError, X - struct ::stat targetInfo = {}; + struct stat targetInfo = {}; if (::fstat(fileOut.getHandle(), &targetInfo) != 0) THROW_LAST_FILE_ERROR(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtPath(targetFile)), "fstat"); @@ -673,12 +665,12 @@ FileCopyResult zen::copyNewFile(const Zstring& sourceFile, const Zstring& target std::optional<FileError> errorModTime; try { - //we cannot set the target file times (::futimes) while the file descriptor is still open after a write operation: - //this triggers bugs on samba shares where the modification time is set to current time instead. - //Linux: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=340236 - // http://comments.gmane.org/gmane.linux.file-systems.cifs/2854 - //OS X: https://freefilesync.org/forum/viewtopic.php?t=356 - setWriteTimeNative(targetFile, sourceInfo.st_mtim, ProcSymlink::FOLLOW); //throw FileError + /* we cannot set the target file times (::futimes) while the file descriptor is still open after a write operation: + this triggers bugs on Samba shares where the modification time is set to current time instead. + Linux: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=340236 + http://comments.gmane.org/gmane.linux.file-systems.cifs/2854 + macOS: https://freefilesync.org/forum/viewtopic.php?t=356 */ + setWriteTimeNative(targetFile, sourceInfo.st_mtim, ProcSymlink::follow); //throw FileError } catch (const FileError& e) { @@ -687,9 +679,9 @@ FileCopyResult zen::copyNewFile(const Zstring& sourceFile, const Zstring& target FileCopyResult result; result.fileSize = sourceInfo.st_size; - result.modTime = sourceInfo.st_mtim.tv_sec; // - result.sourceFileId = generateFileId(sourceInfo); - result.targetFileId = generateFileId(targetInfo); + result.sourceModTime = sourceInfo.st_mtim; + result.sourceFileIdx = sourceInfo.st_ino; + result.targetFileIdx = targetInfo.st_ino; result.errorModTime = errorModTime; return result; } |