summaryrefslogtreecommitdiff
path: root/shared/file_update_handle.h
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:13:13 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:13:13 +0200
commit7f23ee90fd545995a29e2175f15e8b97e59ca67a (patch)
treef8d0afac51995032e58b9a475ccbbc73ba207baf /shared/file_update_handle.h
parent3.19 (diff)
downloadFreeFileSync-7f23ee90fd545995a29e2175f15e8b97e59ca67a.tar.gz
FreeFileSync-7f23ee90fd545995a29e2175f15e8b97e59ca67a.tar.bz2
FreeFileSync-7f23ee90fd545995a29e2175f15e8b97e59ca67a.zip
3.20
Diffstat (limited to 'shared/file_update_handle.h')
-rw-r--r--shared/file_update_handle.h67
1 files changed, 67 insertions, 0 deletions
diff --git a/shared/file_update_handle.h b/shared/file_update_handle.h
new file mode 100644
index 00000000..1ffb7000
--- /dev/null
+++ b/shared/file_update_handle.h
@@ -0,0 +1,67 @@
+#ifndef FILE_UPDATE_HANDLE_H_INCLUDED
+#define FILE_UPDATE_HANDLE_H_INCLUDED
+
+#include <wx/msw/wrapwin.h> //includes "windows.h"
+#include "long_path_prefix.h"
+
+namespace
+{
+//manage file handle to update existing files (temporarily resetting read-only if necessary)
+//CreateFileCmd: lambda directly returning non-owned file handle from ::CreateFile()
+class FileUpdateHandle
+{
+public:
+ template <class CreateFileCmd>
+ FileUpdateHandle(const Zstring& filename, CreateFileCmd cmd) :
+ filenameFmt(zen::applyLongPathPrefix(filename)),
+ hFile(INVALID_HANDLE_VALUE),
+ attr(INVALID_FILE_ATTRIBUTES)
+ {
+ hFile = cmd();
+ if (hFile != INVALID_HANDLE_VALUE)
+ return;
+
+ const DWORD lastError = ::GetLastError();
+ if (lastError == ERROR_ACCESS_DENIED) //function fails if file is read-only
+ {
+ Loki::ScopeGuard guardErrorCode = Loki::MakeGuard(::SetLastError, lastError); //transactional behavior: ensure cleanup (e.g. network drop) -> cref [!]
+
+ //read-only file attribute may cause trouble: temporarily reset it
+ const DWORD tmpAttr = ::GetFileAttributes(filenameFmt.c_str());
+ if (tmpAttr != INVALID_FILE_ATTRIBUTES && (tmpAttr & FILE_ATTRIBUTE_READONLY))
+ {
+ if (::SetFileAttributes(filenameFmt.c_str(), FILE_ATTRIBUTE_NORMAL))
+ {
+ guardErrorCode.Dismiss();
+ attr = tmpAttr; //"create" guard on read-only attribute
+
+ //now try again
+ hFile = cmd();
+ }
+ }
+ }
+ }
+
+ ~FileUpdateHandle()
+ {
+ if (hFile != INVALID_HANDLE_VALUE)
+ ::CloseHandle(hFile);
+
+ if (attr != INVALID_FILE_ATTRIBUTES)
+ ::SetFileAttributes(filenameFmt.c_str(), attr);
+ }
+
+ //may return INVALID_FILE_ATTRIBUTES, in which case ::GetLastError() may be called directly after FileUpdateHandle()
+ HANDLE get() const { return hFile; }
+
+private:
+ FileUpdateHandle(const FileUpdateHandle&);
+ FileUpdateHandle& operator=(const FileUpdateHandle&);
+
+ Zstring filenameFmt;
+ HANDLE hFile;
+ DWORD attr;
+};
+}
+
+#endif // FILE_UPDATE_HANDLE_H_INCLUDED
bgstack15