+ unsigned retry_count = 0;
+ DWORD dwFlagsAndAttributes = FILE_FLAG_BACKUP_SEMANTICS;
+
+retry:
+ /* WRITE_OWNER and WRITE_DAC privileges are required for some reason,
+ * even through we're creating a new file. */
+ h = CreateFile(path, WRITE_OWNER | WRITE_DAC, 0, NULL,
+ CREATE_ALWAYS, dwFlagsAndAttributes, NULL);
+ if (h == INVALID_HANDLE_VALUE) {
+ /* File couldn't be created. */
+ DWORD err = GetLastError();
+ if (err == ERROR_ACCESS_DENIED && retry_count == 0) {
+
+ /* Access denied error for the first time. Try
+ * adjusting file attributes. */
+
+ /* Get attributes of the existing file. */
+ DWORD attribs = GetFileAttributes(path);
+ if (attribs != INVALID_FILE_ATTRIBUTES &&
+ (attribs & (FILE_ATTRIBUTE_HIDDEN |
+ FILE_ATTRIBUTE_SYSTEM |
+ FILE_ATTRIBUTE_READONLY)))
+ {
+ /* If the existing file has
+ * FILE_ATTRIBUTE_HIDDEN and/or
+ * FILE_ATTRIBUTE_SYSTEM, they must be set in
+ * the call to CreateFile(). This is true even
+ * when FILE_ATTRIBUTE_NORMAL was not specified,
+ * contrary to the MS "documentation". */
+ dwFlagsAndAttributes |= (attribs &
+ (FILE_ATTRIBUTE_HIDDEN |
+ FILE_ATTRIBUTE_SYSTEM));
+ /* If the existing file has
+ * FILE_ATTRIBUTE_READONLY, it must be cleared
+ * before attempting to create a new file over
+ * it. This is true even when the process has
+ * the SE_RESTORE_NAME privilege and requested
+ * the FILE_FLAG_BACKUP_SEMANTICS flag to
+ * CreateFile(). */
+ if (attribs & FILE_ATTRIBUTE_READONLY) {
+ SetFileAttributes(path,
+ attribs & ~FILE_ATTRIBUTE_READONLY);
+ }
+ retry_count++;
+ goto retry;
+ }
+ }
+ set_errno_from_win32_error(err);
+ return WIMLIB_ERR_OPEN;
+ }