From cd25218468b896a0a5e47dc6ae644fba7901c044 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Thu, 4 Sep 2025 16:05:56 -0700 Subject: [PATCH] FoundationEssentials: retry with modified permissions On an access denied, reset the system permissions and retry the rename. The original variant seemed to work, this reduces some of the complexity in the hopes that it is sufficiently robust. --- .../FoundationEssentials/Data/Data+Writing.swift | 13 +++++++++++++ .../FoundationEssentials/WinSDK+Extensions.swift | 7 +++++++ 2 files changed, 20 insertions(+) diff --git a/Sources/FoundationEssentials/Data/Data+Writing.swift b/Sources/FoundationEssentials/Data/Data+Writing.swift index 6f51c3d16..9dd1bd1b0 100644 --- a/Sources/FoundationEssentials/Data/Data+Writing.swift +++ b/Sources/FoundationEssentials/Data/Data+Writing.swift @@ -457,6 +457,19 @@ private func writeToFileAux(path inPath: PathOrURL, buffer: UnsafeRawBufferPoint if !SetFileInformationByHandle(hFile, FileRenameInfoEx, pInfo, dwSize) { let dwError = GetLastError() + if dwError == ERROR_ACCESS_DENIED { + let dwAttributes = GetFileAttributesW(pwszPath) + if dwAttributes > 0, + dwAttributes & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM) != 0 { + if SetFileAttributesW(pwszPath, dwAttributes & ~(FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) { + if SetFileInformationByHandle(hFile, FileRenameInfoEx, pInfo, dwSize) { + return + } + // Try to restore the attributes, but ignore any error + _ = SetFileAttributesW(pwszPath, dwAttributes) + } + } + } guard dwError == ERROR_NOT_SAME_DEVICE else { throw CocoaError.errorWithFilePath(inPath, win32: dwError, reading: false) } diff --git a/Sources/FoundationEssentials/WinSDK+Extensions.swift b/Sources/FoundationEssentials/WinSDK+Extensions.swift index 6322c4c86..729477a9e 100644 --- a/Sources/FoundationEssentials/WinSDK+Extensions.swift +++ b/Sources/FoundationEssentials/WinSDK+Extensions.swift @@ -137,11 +137,18 @@ package var FILE_ATTRIBUTE_READONLY: DWORD { DWORD(WinSDK.FILE_ATTRIBUTE_READONLY) } +package var FILE_ATTRIBUTE_HIDDEN: DWORD { + DWORD(WinSDK.FILE_ATTRIBUTE_HIDDEN) +} package var FILE_ATTRIBUTE_REPARSE_POINT: DWORD { DWORD(WinSDK.FILE_ATTRIBUTE_REPARSE_POINT) } +package var FILE_ATTRIBUTE_SYSTEM: DWORD { + DWORD(WinSDK.FILE_ATTRIBUTE_SYSTEM) +} + package var FILE_FLAG_BACKUP_SEMANTICS: DWORD { DWORD(WinSDK.FILE_FLAG_BACKUP_SEMANTICS) }