From 4cfb31bf6abb2d42181e78e8d0758cf74a8a774a Mon Sep 17 00:00:00 2001 From: Daniel Wilhelm Date: Fri, 18 Apr 2014 17:30:04 +0200 Subject: 6.0 --- zen/assert_static.h | 4 +- zen/file_handling.cpp | 139 +++++++++++++++++++++++++--------------------- zen/file_handling.h | 49 ++++++---------- zen/file_traverser.cpp | 2 +- zen/osx_throw_exception.h | 4 +- zen/recycler.cpp | 27 +++++---- zen/recycler.h | 12 +--- zen/scope_guard.h | 4 +- zen/stl_tools.h | 4 +- zen/string_base.h | 8 +-- zen/string_tools.h | 4 +- zen/string_traits.h | 4 +- zen/type_tools.h | 4 +- zen/type_traits.h | 4 +- zen/utf.h | 4 +- 15 files changed, 136 insertions(+), 137 deletions(-) (limited to 'zen') diff --git a/zen/assert_static.h b/zen/assert_static.h index 469e0299..17d5c370 100644 --- a/zen/assert_static.h +++ b/zen/assert_static.h @@ -1,6 +1,6 @@ // ************************************************************************** -// * This file is part of the zen::Xml project. It is distributed under the * -// * Boost Software License: http://www.boost.org/LICENSE_1_0.txt * +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** diff --git a/zen/file_handling.cpp b/zen/file_handling.cpp index 621c2b1b..8c5584db 100644 --- a/zen/file_handling.cpp +++ b/zen/file_handling.cpp @@ -511,7 +511,9 @@ private: }; -void removeDirectoryImpl(const Zstring& directory, CallbackRemoveDir* callback) //throw FileError +void removeDirectoryImpl(const Zstring& directory, //throw FileError + const std::function& onBeforeFileDeletion, + const std::function& onBeforeDirDeletion) { assert(somethingExists(directory)); //[!] @@ -525,7 +527,8 @@ void removeDirectoryImpl(const Zstring& directory, CallbackRemoveDir* callback) //attention: check if directory is a symlink! Do NOT traverse into it deleting contained files!!! if (symlinkExists(directory)) //remove symlink directly { - if (callback) callback->onBeforeDirDeletion(directory); //once per symlink + if (onBeforeDirDeletion) + onBeforeDirDeletion(directory); //once per symlink #ifdef ZEN_WIN const wchar_t functionName[] = L"RemoveDirectory"; if (!::RemoveDirectory(directoryFmt.c_str())) @@ -546,22 +549,20 @@ void removeDirectoryImpl(const Zstring& directory, CallbackRemoveDir* callback) } //delete directories recursively - std::for_each(dirList.begin(), dirList.end(), - [&](const Zstring& dirname) - { - removeDirectoryImpl(dirname, callback); //throw FileError; call recursively to correctly handle symbolic links - }); + for (const Zstring& dirname : dirList) + removeDirectoryImpl(dirname, onBeforeFileDeletion, onBeforeDirDeletion); //throw FileError; call recursively to correctly handle symbolic links //delete files - std::for_each(fileList.begin(), fileList.end(), - [&](const Zstring& filename) + for (const Zstring& filename : fileList) { - if (callback) callback->onBeforeFileDeletion(filename); //call once per file + if (onBeforeFileDeletion) + onBeforeFileDeletion(filename); //call once per file removeFile(filename); //throw FileError - }); + } //parent directory is deleted last - if (callback) callback->onBeforeDirDeletion(directory); //and once per folder + if (onBeforeDirDeletion) + onBeforeDirDeletion(directory); //and once per folder #ifdef ZEN_WIN const wchar_t functionName[] = L"RemoveDirectory"; if (!::RemoveDirectory(directoryFmt.c_str())) @@ -647,7 +648,7 @@ void setFileTimeRaw(const Zstring& filename, const FILETIME& creationTime, const nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | //needed to open a directory - (procSl == SYMLINK_DIRECT ? FILE_FLAG_OPEN_REPARSE_POINT : 0), //process symlinks + (procSl == ProcSymlink::DIRECT ? FILE_FLAG_OPEN_REPARSE_POINT : 0), //process symlinks nullptr); }; @@ -805,7 +806,7 @@ void setFileTimeRaw(const Zstring& filename, const FILETIME& creationTime, const nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | //needed to open a directory - (procSl == SYMLINK_DIRECT ? FILE_FLAG_OPEN_REPARSE_POINT : 0), + (procSl == ProcSymlink::DIRECT ? FILE_FLAG_OPEN_REPARSE_POINT : 0), nullptr); assert(hFile != INVALID_HANDLE_VALUE); ZEN_ON_SCOPE_EXIT(::CloseHandle(hFile)); @@ -823,12 +824,14 @@ void setFileTimeRaw(const Zstring& filename, const FILETIME& creationTime, const } -void zen::removeDirectory(const Zstring& directory, CallbackRemoveDir* callback) +void zen::removeDirectory(const Zstring& directory, //throw FileError + const std::function& onBeforeFileDeletion, + const std::function& onBeforeDirDeletion) { //no error situation if directory is not existing! manual deletion relies on it! if (!somethingExists(directory)) return; //neither directory nor any other object (e.g. broken symlink) with that name existing - removeDirectoryImpl(directory, callback); + removeDirectoryImpl(directory, onBeforeFileDeletion, onBeforeDirDeletion); } @@ -865,7 +868,7 @@ void zen::setFileTime(const Zstring& filename, const Int64& modTime, ProcSymlink newTimes[0].tv_sec = ::time(nullptr); //access time (seconds) newTimes[1].tv_sec = to(modTime); //modification time (seconds) - const int rv = procSl == SYMLINK_FOLLOW ? + const int rv = procSl == ProcSymlink::FOLLOW ? :: utimes(filename.c_str(), newTimes) : //utimensat() not yet implemented on OS X ::lutimes(filename.c_str(), newTimes); if (rv != 0) @@ -960,8 +963,8 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, ProcSym //CAVEAT: if a file system does not support ACLs, GetFileSecurity() will return successfully with a *valid* security descriptor containing *no* ACL entries! //NOTE: ::GetFileSecurity()/::SetFileSecurity() do NOT follow Symlinks! getResolvedFilePath() requires Vista or later! - const Zstring sourceResolved = procSl == SYMLINK_FOLLOW && symlinkExists(source) ? getResolvedFilePath(source) : source; //throw FileError - const Zstring targetResolved = procSl == SYMLINK_FOLLOW && symlinkExists(target) ? getResolvedFilePath(target) : target; // + const Zstring sourceResolved = procSl == ProcSymlink::FOLLOW && symlinkExists(source) ? getResolvedFilePath(source) : source; //throw FileError + const Zstring targetResolved = procSl == ProcSymlink::FOLLOW && symlinkExists(target) ? getResolvedFilePath(target) : target; // //setting privileges requires admin rights! try @@ -1111,7 +1114,7 @@ void copyObjectPermissions(const Zstring& source, const Zstring& target, ProcSym #endif struct stat fileInfo = {}; - if (procSl == SYMLINK_FOLLOW) + if (procSl == ProcSymlink::FOLLOW) { if (::stat(source.c_str(), &fileInfo) != 0) throw FileError(replaceCpy(_("Cannot read permissions of %x."), L"%x", fmtFileName(source)), formatSystemError(L"stat", getLastError())); @@ -1339,7 +1342,7 @@ void zen::makeDirectoryPlain(const Zstring& directory, //throw FileError, ErrorT //enforce copying file permissions: it's advertized on GUI... if (copyFilePermissions) - copyObjectPermissions(templateDir, directory, SYMLINK_FOLLOW); //throw FileError + copyObjectPermissions(templateDir, directory, ProcSymlink::FOLLOW); //throw FileError guardNewDir.dismiss(); //target has been created successfully! } @@ -1397,18 +1400,18 @@ void zen::copySymlink(const Zstring& sourceLink, const Zstring& targetLink, bool &sourceAttr)) //__out LPVOID lpFileInformation throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(sourceLink)), formatSystemError(L"GetFileAttributesEx", getLastError())); - setFileTimeRaw(targetLink, sourceAttr.ftCreationTime, sourceAttr.ftLastWriteTime, SYMLINK_DIRECT); //throw FileError + setFileTimeRaw(targetLink, sourceAttr.ftCreationTime, sourceAttr.ftLastWriteTime, ProcSymlink::DIRECT); //throw FileError #elif defined ZEN_LINUX || defined ZEN_MAC struct ::stat srcInfo = {}; if (::lstat(sourceLink.c_str(), &srcInfo) != 0) throw FileError(replaceCpy(_("Cannot read file attributes of %x."), L"%x", fmtFileName(sourceLink)), formatSystemError(L"lstat", getLastError())); - setFileTime(targetLink, Int64(srcInfo.st_mtime), SYMLINK_DIRECT); //throw FileError + setFileTime(targetLink, Int64(srcInfo.st_mtime), ProcSymlink::DIRECT); //throw FileError #endif if (copyFilePermissions) - copyObjectPermissions(sourceLink, targetLink, SYMLINK_DIRECT); //throw FileError + copyObjectPermissions(sourceLink, targetLink, ProcSymlink::DIRECT); //throw FileError guardNewLink.dismiss(); //target has been created successfully! } @@ -1516,7 +1519,7 @@ bool canCopyAsSparse(const Zstring& sourceFile, const Zstring& targetFile) //thr //precondition: canCopyAsSparse() must return "true"! void copyFileWindowsSparse(const Zstring& sourceFile, const Zstring& targetFile, - CallbackCopyFile* callback, + const std::function& onUpdateCopyStatus, InSyncAttributes* newAttrib) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked { assert(canCopyAsSparse(sourceFile, targetFile)); @@ -1701,8 +1704,8 @@ void copyFileWindowsSparse(const Zstring& sourceFile, //total bytes transferred may be larger than file size! context information + ADS or smaller (sparse, compressed)! //invoke callback method to update progress indicators - if (callback) - callback->updateCopyStatus(Int64(bytesRead)); //throw X! + if (onUpdateCopyStatus) + onUpdateCopyStatus(Int64(bytesRead)); //throw X! if (bytesRead > 0) someBytesWritten = true; @@ -1764,12 +1767,12 @@ DEFINE_NEW_FILE_ERROR(ErrorShouldCopyAsSparse); class ErrorHandling { public: - ErrorHandling() : shouldCopyAsSparse(false), exceptionInUserCallback(nullptr) {} + ErrorHandling() : shouldCopyAsSparse(false) {} //call context: copyCallbackInternal() void reportErrorShouldCopyAsSparse() { shouldCopyAsSparse = true; } - void reportUserException(CallbackCopyFile& userCallback) { exceptionInUserCallback = &userCallback; } + void reportUserException(const std::function& onUpdateCopyStatus) { exceptionInUserCallback = onUpdateCopyStatus; } void reportError(const std::wstring& msg, const std::wstring& description) { errorMsg = std::make_pair(msg, description); } @@ -1780,7 +1783,12 @@ public: throw ErrorShouldCopyAsSparse(L"sparse dummy value"); if (exceptionInUserCallback) - exceptionInUserCallback->updateCopyStatus(0); //rethrow (hopefully!) + try + { + exceptionInUserCallback(0); //should throw again!!! + assert(false); + } + catch (...) { throw; } if (!errorMsg.first.empty()) throw FileError(errorMsg.first, errorMsg.second); @@ -1789,25 +1797,25 @@ public: private: bool shouldCopyAsSparse; // std::pair errorMsg; //these are exclusive! - CallbackCopyFile* exceptionInUserCallback; // + std::function exceptionInUserCallback; // -> optional }; struct CallbackData { - CallbackData(CallbackCopyFile* cb, //may be nullptr + CallbackData(const std::function& onUpdateCopyStatus, const Zstring& sourceFile, const Zstring& targetFile) : sourceFile_(sourceFile), targetFile_(targetFile), - userCallback(cb), + onUpdateCopyStatus_(onUpdateCopyStatus), fileInfoSrc(), fileInfoTrg() {} const Zstring& sourceFile_; const Zstring& targetFile_; + const std::function& onUpdateCopyStatus_; - CallbackCopyFile* const userCallback; //optional! ErrorHandling errorHandler; BY_HANDLE_FILE_INFORMATION fileInfoSrc; //modified by CopyFileEx() at beginning BY_HANDLE_FILE_INFORMATION fileInfoTrg; // @@ -1899,18 +1907,17 @@ DWORD CALLBACK copyCallbackInternal(LARGE_INTEGER totalFileSize, //called after copy operation is finished - note: for 0-sized files this callback is invoked just ONCE! //if (totalFileSize.QuadPart == totalBytesTransferred.QuadPart && dwStreamNumber == 1) {} - if (cbd.userCallback && - totalBytesTransferred.QuadPart >= 0) //should be always true, but let's still check + if (cbd.onUpdateCopyStatus_ && totalBytesTransferred.QuadPart >= 0) //should be always true, but let's still check try { - cbd.userCallback->updateCopyStatus(totalBytesTransferred.QuadPart - cbd.bytesReported); //throw X! + cbd.onUpdateCopyStatus_(totalBytesTransferred.QuadPart - cbd.bytesReported); //throw X! cbd.bytesReported = totalBytesTransferred.QuadPart; } catch (...) { //#warning migrate to std::exception_ptr when available - cbd.errorHandler.reportUserException(*cbd.userCallback); + cbd.errorHandler.reportUserException(cbd.onUpdateCopyStatus_); return PROGRESS_CANCEL; } return PROGRESS_CONTINUE; @@ -1924,7 +1931,7 @@ const bool supportNonEncryptedDestination = winXpOrLater(); //encrypted destinat void copyFileWindowsDefault(const Zstring& sourceFile, const Zstring& targetFile, - CallbackCopyFile* callback, + const std::function& onUpdateCopyStatus, InSyncAttributes* newAttrib) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked, ErrorShouldCopyAsSparse { //try to get backup read and write privileges: who knows, maybe this helps solve some obscure "access denied" errors @@ -1947,7 +1954,7 @@ void copyFileWindowsDefault(const Zstring& sourceFile, //documentation on CopyFile2() even states: "It is not recommended to pause copies that are using this flag." How dangerous is this thing, why offer it at all??? //perf advantage: ~15% faster - CallbackData cbd(callback, sourceFile, targetFile); + CallbackData cbd(onUpdateCopyStatus, sourceFile, targetFile); const bool success = ::CopyFileEx( //same performance like CopyFile() applyLongPathPrefix(sourceFile).c_str(), //__in LPCTSTR lpExistingFileName, @@ -2051,7 +2058,7 @@ void copyFileWindowsDefault(const Zstring& sourceFile, } //####################################### DST hack ########################################### - setFileTimeRaw(targetFile, creationTimeOut, lastWriteTimeOut, SYMLINK_FOLLOW); //throw FileError + setFileTimeRaw(targetFile, creationTimeOut, lastWriteTimeOut, ProcSymlink::FOLLOW); //throw FileError } guardTarget.dismiss(); //target has been created successfully! @@ -2060,26 +2067,29 @@ void copyFileWindowsDefault(const Zstring& sourceFile, //another layer to support copying sparse files inline -void copyFileWindowsSelectRoutine(const Zstring& sourceFile, const Zstring& targetFile, CallbackCopyFile* callback, InSyncAttributes* sourceAttr) +void copyFileWindowsSelectRoutine(const Zstring& sourceFile, const Zstring& targetFile, const std::function& onUpdateCopyStatus, InSyncAttributes* sourceAttr) { try { - copyFileWindowsDefault(sourceFile, targetFile, callback, sourceAttr); //throw ErrorShouldCopyAsSparse et al. + copyFileWindowsDefault(sourceFile, targetFile, onUpdateCopyStatus, sourceAttr); //throw ErrorShouldCopyAsSparse et al. } catch (ErrorShouldCopyAsSparse&) //we cheaply check for this condition within callback of ::CopyFileEx()! { - copyFileWindowsSparse(sourceFile, targetFile, callback, sourceAttr); + copyFileWindowsSparse(sourceFile, targetFile, onUpdateCopyStatus, sourceAttr); } } //another layer of indirection solving 8.3 name clashes inline -void copyFileWindows(const Zstring& sourceFile, const Zstring& targetFile, CallbackCopyFile* callback, InSyncAttributes* sourceAttr) +void copyFileWindows(const Zstring& sourceFile, + const Zstring& targetFile, + const std::function& onUpdateCopyStatus, + InSyncAttributes* sourceAttr) { try { - copyFileWindowsSelectRoutine(sourceFile, targetFile, callback, sourceAttr); //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked + copyFileWindowsSelectRoutine(sourceFile, targetFile, onUpdateCopyStatus, sourceAttr); //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked } catch (const ErrorTargetExisting&) { @@ -2087,7 +2097,7 @@ void copyFileWindows(const Zstring& sourceFile, const Zstring& targetFile, Callb if (have8dot3NameClash(targetFile)) { Fix8Dot3NameClash dummy(targetFile); //throw FileError; move clashing filename to the side - copyFileWindowsSelectRoutine(sourceFile, targetFile, callback, sourceAttr); //throw FileError; the short filename name clash is solved, this should work now + copyFileWindowsSelectRoutine(sourceFile, targetFile, onUpdateCopyStatus, sourceAttr); //throw FileError; the short filename name clash is solved, this should work now return; } throw; @@ -2098,7 +2108,7 @@ void copyFileWindows(const Zstring& sourceFile, const Zstring& targetFile, Callb #elif defined ZEN_LINUX || defined ZEN_MAC void copyFileLinuxMac(const Zstring& sourceFile, const Zstring& targetFile, - CallbackCopyFile* callback, + const std::function& onUpdateCopyStatus, InSyncAttributes* newAttrib) //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting { //open sourceFile for reading @@ -2123,8 +2133,8 @@ void copyFileLinuxMac(const Zstring& sourceFile, fileOut.write(&buffer[0], bytesRead); //throw FileError //invoke callback method to update progress indicators - if (callback) - callback->updateCopyStatus(Int64(bytesRead)); //throw X! + if (onUpdateCopyStatus) + onUpdateCopyStatus(Int64(bytesRead)); //throw X! } while (!fileIn.eof()); @@ -2155,7 +2165,7 @@ void copyFileLinuxMac(const Zstring& sourceFile, //http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=340236 //http://comments.gmane.org/gmane.linux.file-systems.cifs/2854 //on the other hand we thereby have to reopen https://sourceforge.net/p/freefilesync/bugs/230/ - setFileTime(targetFile, sourceInfo.st_mtime, SYMLINK_FOLLOW); //throw FileError + setFileTime(targetFile, sourceInfo.st_mtime, ProcSymlink::FOLLOW); //throw FileError guardTarget.dismiss(); //target has been created successfully! } @@ -2190,13 +2200,16 @@ copyFileWindowsDefault(::CopyFileEx) copyFileWindowsSparse(::BackupRead/::Backu */ inline -void copyFileSelectOs(const Zstring& sourceFile, const Zstring& targetFile, CallbackCopyFile* callback, InSyncAttributes* sourceAttr) +void copyFileSelectOs(const Zstring& sourceFile, + const Zstring& targetFile, + const std::function& onUpdateCopyStatus, + InSyncAttributes* sourceAttr) { #ifdef ZEN_WIN - copyFileWindows(sourceFile, targetFile, callback, sourceAttr); //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked + copyFileWindows(sourceFile, targetFile, onUpdateCopyStatus, sourceAttr); //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked #elif defined ZEN_LINUX || defined ZEN_MAC - copyFileLinuxMac(sourceFile, targetFile, callback, sourceAttr); //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting + copyFileLinuxMac(sourceFile, targetFile, onUpdateCopyStatus, sourceAttr); //throw FileError, ErrorTargetPathMissing, ErrorTargetExisting #endif } } @@ -2206,7 +2219,8 @@ void zen::copyFile(const Zstring& sourceFile, //throw FileError, ErrorTargetPath const Zstring& targetFile, bool copyFilePermissions, bool transactionalCopy, - CallbackCopyFile* callback, + const std::function& onDeleteTargetFile, + const std::function& onUpdateCopyStatus, InSyncAttributes* sourceAttr) { if (transactionalCopy) @@ -2216,7 +2230,7 @@ void zen::copyFile(const Zstring& sourceFile, //throw FileError, ErrorTargetPath //raw file copy try { - copyFileSelectOs(sourceFile, temporary, callback, sourceAttr); //throw FileError: ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked + copyFileSelectOs(sourceFile, temporary, onUpdateCopyStatus, sourceAttr); //throw FileError: ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked } catch (ErrorTargetExisting&) { @@ -2225,15 +2239,15 @@ void zen::copyFile(const Zstring& sourceFile, //throw FileError, ErrorTargetPath temporary = findUnusedTempName(targetFile); //retry - copyFileSelectOs(sourceFile, temporary, callback, sourceAttr); //throw FileError + copyFileSelectOs(sourceFile, temporary, onUpdateCopyStatus, sourceAttr); //throw FileError } //transactional behavior: ensure cleanup; not needed before copyFileSelectOs() which is already transactional zen::ScopeGuard guardTempFile = zen::makeGuard([&] { try { removeFile(temporary); } catch (FileError&) {} }); //have target file deleted (after read access on source and target has been confirmed) => allow for almost transactional overwrite - if (callback) - callback->deleteTargetFile(targetFile); //throw X + if (onDeleteTargetFile) + onDeleteTargetFile(); //throw X //rename temporary file: //perf: this call is REALLY expensive on unbuffered volumes! ~40% performance decrease on FAT USB stick! @@ -2264,9 +2278,10 @@ void zen::copyFile(const Zstring& sourceFile, //throw FileError, ErrorTargetPath } else { - if (callback) callback->deleteTargetFile(targetFile); + if (onDeleteTargetFile) + onDeleteTargetFile(); - copyFileSelectOs(sourceFile, targetFile, callback, sourceAttr); //throw FileError: ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked + copyFileSelectOs(sourceFile, targetFile, onUpdateCopyStatus, sourceAttr); //throw FileError: ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked } /* Note: non-transactional file copy solves at least four problems: @@ -2281,7 +2296,7 @@ void zen::copyFile(const Zstring& sourceFile, //throw FileError, ErrorTargetPath { zen::ScopeGuard guardTargetFile = zen::makeGuard([&] { try { removeFile(targetFile); } catch (FileError&) {}}); - copyObjectPermissions(sourceFile, targetFile, SYMLINK_FOLLOW); //throw FileError + copyObjectPermissions(sourceFile, targetFile, ProcSymlink::FOLLOW); //throw FileError guardTargetFile.dismiss(); //target has been created successfully! } diff --git a/zen/file_handling.h b/zen/file_handling.h index b3d5ca1a..48a762d7 100644 --- a/zen/file_handling.h +++ b/zen/file_handling.h @@ -7,6 +7,7 @@ #ifndef FILE_HANDLING_H_8017341345614857 #define FILE_HANDLING_H_8017341345614857 +#include #include "zstring.h" #include "file_error.h" #include "file_id_def.h" @@ -14,19 +15,15 @@ namespace zen { -struct CallbackRemoveDir; -struct CallbackCopyFile; - - bool fileExists (const Zstring& filename); //noexcept; check whether file or file-symlink exists bool dirExists (const Zstring& dirname ); //noexcept; check whether directory or dir-symlink exists bool symlinkExists (const Zstring& linkname); //noexcept; check whether a symbolic link exists bool somethingExists(const Zstring& objname ); //noexcept; check whether any object with this name exists -enum ProcSymlink +enum class ProcSymlink { - SYMLINK_DIRECT, - SYMLINK_FOLLOW + DIRECT, + FOLLOW }; void setFileTime(const Zstring& filename, const Int64& modificationTime, ProcSymlink procSl); //throw FileError @@ -37,7 +34,9 @@ UInt64 getFreeDiskSpace(const Zstring& path); //throw FileError //file handling bool removeFile(const Zstring& filename); //throw FileError; return "false" if file is not existing -void removeDirectory(const Zstring& directory, CallbackRemoveDir* callback = nullptr); //throw FileError +void removeDirectory(const Zstring& directory, //throw FileError + const std::function& onBeforeFileDeletion = nullptr, //optional; + const std::function& onBeforeDirDeletion = nullptr); //one call for each *existing* object! //rename file or directory: no copying!!! void renameFile(const Zstring& oldName, const Zstring& newName); //throw FileError, ErrorDifferentVolume, ErrorTargetExisting @@ -64,37 +63,21 @@ void copyFile(const Zstring& sourceFile, //throw FileError, ErrorTargetPathMissi const Zstring& targetFile, //symlink handling: dereference source bool copyFilePermissions, bool transactionalCopy, - CallbackCopyFile* callback, //may be nullptr + //if target is existing user needs to implement deletion: copyFile() NEVER overwrites target if already existing! + //if transactionalCopy == true, full read access on source had been proven at this point, so it's safe to delete it. + const std::function& onDeleteTargetFile, //may be nullptr; throw X! + //Linux: unconditionally + //Windows: first exception is swallowed, updateCopyStatus() is then called again where it should throw again and the exception will propagate as expected + //accummulated delta != file size! consider ADS, sparse, compressed files + const std::function& onUpdateCopyStatus, //may be nullptr; throw X! + InSyncAttributes* newAttrib = nullptr); //return current attributes at the time of copy + //Note: it MAY happen that copyFile() leaves temp files behind, e.g. temporary network drop. // => clean them up at an appropriate time (automatically set sync directions to delete them). They have the following ending: const Zstring TEMP_FILE_ENDING = Zstr(".ffs_tmp"); void copySymlink(const Zstring& sourceLink, const Zstring& targetLink, bool copyFilePermissions); //throw FileError - - - -//----------- callbacks --------------- -struct CallbackRemoveDir -{ - virtual ~CallbackRemoveDir() {} - virtual void onBeforeFileDeletion(const Zstring& filename) = 0; //one call for each *existing* object! - virtual void onBeforeDirDeletion (const Zstring& dirname ) = 0; // -}; - -struct CallbackCopyFile -{ - virtual ~CallbackCopyFile() {} - - //if target is existing user needs to implement deletion: copyFile() NEVER overwrites target if already existing! - //if transactionalCopy == true, full read access on source had been proven at this point, so it's safe to delete it. - virtual void deleteTargetFile(const Zstring& targetFile) = 0; //may throw exceptions - - //may throw: - //Linux: unconditionally - //Windows: first exception is swallowed, updateCopyStatus() is then called again where it should throw again and the exception will propagate as expected - virtual void updateCopyStatus(Int64 bytesDelta) = 0; //accummulated delta != file size! consider ADS, sparse, compressed files -}; } #endif //FILE_HANDLING_H_8017341345614857 diff --git a/zen/file_traverser.cpp b/zen/file_traverser.cpp index 0e06d6c5..9c1b01a4 100644 --- a/zen/file_traverser.cpp +++ b/zen/file_traverser.cpp @@ -452,7 +452,7 @@ private: try { //set modification time including DST hack: this function is too clever to not introduce this dependency - setFileTime(it->first, it->second, SYMLINK_FOLLOW); //throw FileError + setFileTime(it->first, it->second, ProcSymlink::FOLLOW); //throw FileError } catch (FileError&) { diff --git a/zen/osx_throw_exception.h b/zen/osx_throw_exception.h index 018e9456..07e3af3e 100644 --- a/zen/osx_throw_exception.h +++ b/zen/osx_throw_exception.h @@ -35,9 +35,9 @@ inline void throwSysError(NSException* e) //throw SysError { std::string msg; -if (const char* name = [[e name ] cStringUsingEncoding:NSUTF8StringEncoding]) //"const char*" NOT owned by us! + if (const char* name = [[e name ] cStringUsingEncoding:NSUTF8StringEncoding]) //"const char*" NOT owned by us! msg += name; -if (const char* descr = [[e reason] cStringUsingEncoding:NSUTF8StringEncoding]) + if (const char* descr = [[e reason] cStringUsingEncoding:NSUTF8StringEncoding]) { msg += "\n"; msg += descr; diff --git a/zen/recycler.cpp b/zen/recycler.cpp index a1353f0b..16c2ac11 100644 --- a/zen/recycler.cpp +++ b/zen/recycler.cpp @@ -49,22 +49,23 @@ const bool useIFileOperation = vistaOrLater(); //caveat: function scope static i struct CallbackData { - CallbackData(CallbackRecycling* cb) : - userCallback(cb), + CallbackData(const std::function& notifyDeletionStatus) : + notifyDeletionStatus_(notifyDeletionStatus), exceptionInUserCallback(false) {} - CallbackRecycling* const userCallback; //optional! + const std::function& notifyDeletionStatus_; //optional! bool exceptionInUserCallback; }; + bool recyclerCallback(const wchar_t* filename, void* sink) { CallbackData& cbd = *static_cast(sink); //sink is NOT optional here - if (cbd.userCallback) + if (cbd.notifyDeletionStatus_) try { - cbd.userCallback->updateStatus(filename); //throw ? + cbd.notifyDeletionStatus_(filename); //throw ? } catch (...) { @@ -75,7 +76,7 @@ bool recyclerCallback(const wchar_t* filename, void* sink) } } -void zen::recycleOrDelete(const std::vector& filenames, CallbackRecycling* callback) +void zen::recycleOrDelete(const std::vector& filenames, const std::function& notifyDeletionStatus) { if (filenames.empty()) return; @@ -95,14 +96,20 @@ void zen::recycleOrDelete(const std::vector& filenames, CallbackRecycli replaceCpy(_("Cannot load file %x."), L"%x", fmtFileName(getDllName()))); std::vector cNames; - for (auto it = filenames.begin(); it != filenames.end(); ++it) //CAUTION: to not create temporary strings here!! + for (auto it = filenames.begin(); it != filenames.end(); ++it) //CAUTION: do not create temporary strings here!! cNames.push_back(it->c_str()); - CallbackData cbd(callback); + CallbackData cbd(notifyDeletionStatus); if (!moveToRecycler(&cNames[0], cNames.size(), recyclerCallback, &cbd)) { - if (cbd.exceptionInUserCallback) //now we may throw... - callback->updateStatus(Zstring()); //should throw again! + if (cbd.exceptionInUserCallback) + try + { + assert(notifyDeletionStatus); + notifyDeletionStatus(Zstring()); //should throw again!!! + assert(false); + } + catch (...) { throw; } std::wstring filenameFmt = fmtFileName(filenames[0]); //probably not the correct file name for file lists larger than 1! if (filenames.size() > 1) diff --git a/zen/recycler.h b/zen/recycler.h index f55971ac..80b31160 100644 --- a/zen/recycler.h +++ b/zen/recycler.h @@ -7,6 +7,7 @@ #ifndef RECYCLER_H_INCLUDED #define RECYCLER_H_INCLUDED +#include #include #include #include @@ -44,16 +45,9 @@ enum StatusRecycler StatusRecycler recycleBinStatus(const Zstring& pathName); //test existence of Recycle Bin API for certain path //Win: blocks heavily if recycle bin is really full and drive is slow!!! -struct CallbackRecycling -{ - virtual ~CallbackRecycling() {} - - //may throw: first exception is swallowed, updateStatus() is then called again where it should throw again and the exception will propagate as expected - virtual void updateStatus(const Zstring& currentItem) = 0; //currentItem may be empty -}; - void recycleOrDelete(const std::vector& filenames, //throw FileError, return "true" if file/dir was actually deleted - CallbackRecycling* callback); //optional + //may throw: first exception is swallowed, updateStatus() is then called again where it should throw again and the exception will propagate as expected + const std::function& notifyDeletionStatus); //optional; currentItem may be empty #endif } diff --git a/zen/scope_guard.h b/zen/scope_guard.h index 000853fd..d48eb922 100644 --- a/zen/scope_guard.h +++ b/zen/scope_guard.h @@ -1,6 +1,6 @@ // ************************************************************************** -// * This file is part of the zen::Xml project. It is distributed under the * -// * Boost Software License: http://www.boost.org/LICENSE_1_0.txt * +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** diff --git a/zen/stl_tools.h b/zen/stl_tools.h index bf47bb1c..2bb4fd3f 100644 --- a/zen/stl_tools.h +++ b/zen/stl_tools.h @@ -1,6 +1,6 @@ // ************************************************************************** -// * This file is part of the zen::Xml project. It is distributed under the * -// * Boost Software License: http://www.boost.org/LICENSE_1_0.txt * +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** diff --git a/zen/string_base.h b/zen/string_base.h index 31a09e63..c828b240 100644 --- a/zen/string_base.h +++ b/zen/string_base.h @@ -60,7 +60,7 @@ template //Allocator Policy + class AP> //Allocator Policy class StorageDeepCopy : public AP { protected: @@ -113,7 +113,7 @@ private: template //Allocator Policy + class AP> //Allocator Policy class StorageRefCountThreadSafe : public AP { protected: @@ -188,8 +188,8 @@ private: //perf note: interestingly StorageDeepCopy and StorageRefCountThreadSafe show same performance in FFS comparison template class SP = StorageRefCountThreadSafe, //Storage Policy - class AP = AllocatorOptimalSpeed> //Allocator Policy + template class SP = StorageRefCountThreadSafe, //Storage Policy + class AP = AllocatorOptimalSpeed> //Allocator Policy class Zbase : public SP { public: diff --git a/zen/string_tools.h b/zen/string_tools.h index 35e5af2b..1dd5905d 100644 --- a/zen/string_tools.h +++ b/zen/string_tools.h @@ -1,6 +1,6 @@ // ************************************************************************** -// * This file is part of the zen::Xml project. It is distributed under the * -// * Boost Software License: http://www.boost.org/LICENSE_1_0.txt * +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** diff --git a/zen/string_traits.h b/zen/string_traits.h index eb79831e..887752c0 100644 --- a/zen/string_traits.h +++ b/zen/string_traits.h @@ -1,6 +1,6 @@ // ************************************************************************** -// * This file is part of the zen::Xml project. It is distributed under the * -// * Boost Software License: http://www.boost.org/LICENSE_1_0.txt * +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** diff --git a/zen/type_tools.h b/zen/type_tools.h index 76a12a5a..1f782a2d 100644 --- a/zen/type_tools.h +++ b/zen/type_tools.h @@ -1,6 +1,6 @@ // ************************************************************************** -// * This file is part of the zen::Xml project. It is distributed under the * -// * Boost Software License: http://www.boost.org/LICENSE_1_0.txt * +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** diff --git a/zen/type_traits.h b/zen/type_traits.h index a90b9793..b6e05871 100644 --- a/zen/type_traits.h +++ b/zen/type_traits.h @@ -1,6 +1,6 @@ // ************************************************************************** -// * This file is part of the zen::Xml project. It is distributed under the * -// * Boost Software License: http://www.boost.org/LICENSE_1_0.txt * +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** diff --git a/zen/utf.h b/zen/utf.h index e428422b..16e543c8 100644 --- a/zen/utf.h +++ b/zen/utf.h @@ -1,6 +1,6 @@ // ************************************************************************** -// * This file is part of the zen::Xml project. It is distributed under the * -// * Boost Software License: http://www.boost.org/LICENSE_1_0.txt * +// * This file is part of the FreeFileSync project. It is distributed under * +// * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** -- cgit