summaryrefslogtreecommitdiff
path: root/zen/file_update_handle.h
diff options
context:
space:
mode:
authorDaniel Wilhelm <daniel@wili.li>2014-04-18 17:15:16 +0200
committerDaniel Wilhelm <daniel@wili.li>2014-04-18 17:15:16 +0200
commitbd6336c629841c6db3a6ca53a936d629d34db53b (patch)
tree3721ef997864108df175ce677a8a7d4342a6f1d2 /zen/file_update_handle.h
parent4.0 (diff)
downloadFreeFileSync-bd6336c629841c6db3a6ca53a936d629d34db53b.tar.gz
FreeFileSync-bd6336c629841c6db3a6ca53a936d629d34db53b.tar.bz2
FreeFileSync-bd6336c629841c6db3a6ca53a936d629d34db53b.zip
4.1
Diffstat (limited to 'zen/file_update_handle.h')
-rw-r--r--zen/file_update_handle.h67
1 files changed, 67 insertions, 0 deletions
diff --git a/zen/file_update_handle.h b/zen/file_update_handle.h
new file mode 100644
index 00000000..aa9edebd
--- /dev/null
+++ b/zen/file_update_handle.h
@@ -0,0 +1,67 @@
+#ifndef FILE_UPDATE_HANDLE_H_INCLUDED
+#define FILE_UPDATE_HANDLE_H_INCLUDED
+
+#include "win.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
+ {
+ zen::ScopeGuard guardErrorCode = zen::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