summaryrefslogtreecommitdiff
path: root/shared
diff options
context:
space:
mode:
Diffstat (limited to 'shared')
-rw-r--r--shared/dir_name.cpp2
-rw-r--r--shared/file_handling.cpp75
-rw-r--r--shared/file_handling.h1
-rw-r--r--shared/resolve_path.cpp9
4 files changed, 56 insertions, 31 deletions
diff --git a/shared/dir_name.cpp b/shared/dir_name.cpp
index 6945fb9c..f1b0c3c2 100644
--- a/shared/dir_name.cpp
+++ b/shared/dir_name.cpp
@@ -37,7 +37,7 @@ void setDirectoryNameImpl(const wxString& dirname, wxDirPickerCtrl* dirPicker, w
staticBox->GetStaticBox()->SetLabel(dirNormalized == dirFormatted ? wxString(_("Drag && drop")) : dirFormatted);
}
-
+
if (dirPicker)
{
if (!dirFormatted.empty() &&
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!
+ }
}
diff --git a/shared/file_handling.h b/shared/file_handling.h
index 113168f3..bdd73bea 100644
--- a/shared/file_handling.h
+++ b/shared/file_handling.h
@@ -66,6 +66,7 @@ void createDirectory(const Zstring& directory); //throw (FileError); -> function
void copyFile(const Zstring& sourceFile, //throw (FileError: ErrorTargetPathMissing, ErrorFileLocked (Windows-only));
const Zstring& targetFile,
bool copyFilePermissions,
+ bool transactionalCopy,
CallbackCopyFile* callback); //may be NULL
//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:
diff --git a/shared/resolve_path.cpp b/shared/resolve_path.cpp
index a9d1e0e5..2a9cb7e6 100644
--- a/shared/resolve_path.cpp
+++ b/shared/resolve_path.cpp
@@ -29,18 +29,21 @@ Zstring resolveBrokenNetworkMap(const Zstring& dirname) //circumvent issue with
if (dirname.size() >= 2 && iswalpha(dirname[0]) && dirname[1] == L':')
{
Zstring driveLetter(dirname.c_str(), 2); //e.g.: "Q:"
- if (::GetFileAttributes((driveLetter + L'\\').c_str()) == INVALID_FILE_ATTRIBUTES)
+
+ //if (::GetFileAttributes((driveLetter + L'\\').c_str()) == INVALID_FILE_ATTRIBUTES) <- this will seriously block if network is not reachable!!!
{
DWORD bufferSize = 10000;
std::vector<wchar_t> remoteNameBuffer(bufferSize);
DWORD rv = ::WNetGetConnection(driveLetter.c_str(), //__in LPCTSTR lpLocalName in the form "<driveletter>:"
&remoteNameBuffer[0], //__out LPTSTR lpRemoteName,
&bufferSize); //__inout LPDWORD lpnLength
- (void)rv;
- //no error check here! remoteNameBuffer will be filled on ERROR_CONNECTION_UNAVAIL and maybe others?
+ if (rv == NO_ERROR ||
+ rv == ERROR_CONNECTION_UNAVAIL) //remoteNameBuffer will be filled nevertheless!
+ {
Zstring networkShare = &remoteNameBuffer[0];
if (!networkShare.empty())
return networkShare + (dirname.c_str() + 2); //replace "Q:\subdir" by "\\server\share\subdir"
+ }
}
}
return dirname;
bgstack15