diff options
Diffstat (limited to 'shared/file_handling.cpp')
-rw-r--r-- | shared/file_handling.cpp | 75 |
1 files changed, 48 insertions, 27 deletions
diff --git a/shared/file_handling.cpp b/shared/file_handling.cpp index 6b41f4f5..8fa8568a 100644 --- a/shared/file_handling.cpp +++ b/shared/file_handling.cpp @@ -492,7 +492,7 @@ void zen::moveFile(const Zstring& sourceFile, const Zstring& targetFile, bool ig if (symlinkExists(sourceFile)) copySymlink(sourceFile, targetFile, SYMLINK_TYPE_FILE, false); //throw (FileError) dont copy filesystem permissions else - copyFile(sourceFile, targetFile, false, copyCallback.get()); //throw (FileError); + copyFile(sourceFile, targetFile, false, true, copyCallback.get()); //throw (FileError); //attention: if copy-operation was cancelled an exception is thrown => sourcefile is not deleted, as we wish! } @@ -1441,6 +1441,8 @@ void rawCopyWinApi(const Zstring& sourceFile, dst::isFatDrive(targetFile) && getFilesize(sourceFile) >= 4U * UInt64(1024U * 1024 * 1024)) //throw (FileError) errorMessage += L"\nFAT volume cannot store files larger than 4 gigabyte!"; + + //note: ERROR_INVALID_PARAMETER can also occur when copying to a SharePoint server or MS SkyDrive and the target filename is of a restricted type. } catch(...) {} @@ -1715,7 +1717,7 @@ void rawCopyWinApi(const Zstring& sourceFile, // totalBytesTransferred += bytesRead; // //#ifndef _MSC_VER -//#warning totalBytesTransferred kann größer als filesize sein!! +//#warning totalBytesTransferred kann größer als filesize sein!! //#endif // // //invoke callback method to update progress indicators @@ -1878,41 +1880,60 @@ void copyFileImpl(const Zstring& sourceFile, void zen::copyFile(const Zstring& sourceFile, //throw (FileError: ErrorTargetPathMissing, ErrorFileLocked); const Zstring& targetFile, bool copyFilePermissions, + bool transactionalCopy, CallbackCopyFile* callback) { - Zstring temporary = targetFile + zen::TEMP_FILE_ENDING; //use temporary file until a correct date has been set - Loki::ScopeGuard guardTempFile = Loki::MakeGuard([&]() { removeFile(temporary); }); //transactional behavior: ensure cleanup (e.g. network drop) -> ref to temporary[!] - - //raw file copy - try + if (transactionalCopy) { - copyFileImpl(sourceFile, temporary, callback); //throw FileError: ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked - } - catch (ErrorTargetExisting&) - { - //determine non-used temp file name "first": - //using optimistic strategy: assume everything goes well, but recover on error -> minimize file accesses - temporary = createTempName(targetFile); + Zstring temporary = targetFile + zen::TEMP_FILE_ENDING; //use temporary file until a correct date has been set + Loki::ScopeGuard guardTempFile = Loki::MakeGuard([&]() { removeFile(temporary); }); //transactional behavior: ensure cleanup (e.g. network drop) -> ref to temporary[!] - //retry - copyFileImpl(sourceFile, temporary, callback); //throw FileError - } + //raw file copy + try + { + copyFileImpl(sourceFile, temporary, callback); //throw FileError: ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked + } + catch (ErrorTargetExisting&) + { + //determine non-used temp file name "first": + //using optimistic strategy: assume everything goes well, but recover on error -> minimize file accesses + temporary = createTempName(targetFile); - //have target file deleted (after read access on source and target has been confirmed) => allow for almost transactional overwrite - if (callback) callback->deleteTargetFile(targetFile); + //retry + copyFileImpl(sourceFile, temporary, callback); //throw FileError + } - //rename temporary file: - //perf: this call is REALLY expensive on unbuffered volumes! ~40% performance decrease on FAT USB stick! - renameFile(temporary, targetFile); //throw (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); - guardTempFile.Dismiss(); - Loki::ScopeGuard guardTargetFile = Loki::MakeGuard(&removeFile, targetFile); + //rename temporary file: + //perf: this call is REALLY expensive on unbuffered volumes! ~40% performance decrease on FAT USB stick! + renameFile(temporary, targetFile); //throw (FileError) - //perf: interestingly it is much faster to apply file times BEFORE renaming temporary! + guardTempFile.Dismiss(); + + //perf: interestingly it is much faster to apply file times BEFORE renaming temporary! + } + else + { + //have target file deleted + if (callback) callback->deleteTargetFile(targetFile); + + copyFileImpl(sourceFile, targetFile, callback); //throw FileError: ErrorTargetPathMissing, ErrorTargetExisting, ErrorFileLocked + } +/* + Note: non-transactional file copy solves at least four problems: + -> skydrive - doesn't allow for .ffs_tmp extension and returns ERROR_INVALID_PARAMETER + -> network renaming issues + -> allow for true delete before copy to handle low disk space problems + -> higher performance on non-buffered drives (e.g. usb sticks) +*/ //set file permissions if (copyFilePermissions) + { + Loki::ScopeGuard guardTargetFile = Loki::MakeGuard(&removeFile, targetFile); copyObjectPermissions(sourceFile, targetFile, true); //throw (FileError) - - guardTargetFile.Dismiss(); //target has been created successfully! + guardTargetFile.Dismiss(); //target has been created successfully! + } } |