summaryrefslogtreecommitdiff
path: root/shared/file_handling.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'shared/file_handling.cpp')
-rw-r--r--shared/file_handling.cpp75
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!
+ }
}
bgstack15