Skip to content

Commit dea5c12

Browse files
authored
Merge pull request swiftlang#2207 from gmittert/SymlinksAreHard
2 parents f80b6f2 + efd11ea commit dea5c12

File tree

1 file changed

+14
-4
lines changed

1 file changed

+14
-4
lines changed

Foundation/FileManager+Win32.swift

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,14 @@ extension FileManager {
264264
}
265265

266266
internal func _createSymbolicLink(atPath path: String, withDestinationPath destPath: String) throws {
267-
let faAttributes: WIN32_FILE_ATTRIBUTE_DATA = try windowsFileAttributes(atPath: path)
268-
var dwFlags: DWORD = DWORD(SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)
267+
var dwFlags = DWORD(SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE)
268+
// Note: windowsfileAttributes will throw if the destPath is not found.
269+
// Since on Windows, you are required to know the type of the symlink
270+
// target (file or directory) during creation, and assuming one or the
271+
// other doesn't make a lot of sense, we allow it to throw, thus
272+
// disallowing the creation of broken symlinks on Windows (unlike with
273+
// POSIX).
274+
let faAttributes = try windowsFileAttributes(atPath: destPath)
269275
if faAttributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_DIRECTORY) == DWORD(FILE_ATTRIBUTE_DIRECTORY) {
270276
dwFlags |= DWORD(SYMBOLIC_LINK_FLAG_DIRECTORY)
271277
}
@@ -286,12 +292,16 @@ extension FileManager {
286292
internal func _canonicalizedPath(toFileAtPath path: String) throws -> String {
287293
var hFile: HANDLE = INVALID_HANDLE_VALUE
288294
path.withCString(encodedAs: UTF16.self) { link in
289-
hFile = CreateFileW(link, GENERIC_READ, DWORD(FILE_SHARE_WRITE), nil, DWORD(OPEN_EXISTING), DWORD(FILE_FLAG_BACKUP_SEMANTICS), nil)
295+
// BACKUP_SEMANTICS are (confusingly) required in order to receive a
296+
// handle to a directory
297+
hFile = CreateFileW(link, 0, DWORD(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE),
298+
nil, DWORD(OPEN_EXISTING), DWORD(FILE_FLAG_BACKUP_SEMANTICS),
299+
nil)
290300
}
291-
defer { CloseHandle(hFile) }
292301
if hFile == INVALID_HANDLE_VALUE {
293302
throw _NSErrorWithWindowsError(GetLastError(), reading: true)
294303
}
304+
defer { CloseHandle(hFile) }
295305

296306
let dwLength: DWORD = GetFinalPathNameByHandleW(hFile, nil, 0, DWORD(FILE_NAME_NORMALIZED))
297307
var szPath: [WCHAR] = Array<WCHAR>(repeating: 0, count: Int(dwLength + 1))

0 commit comments

Comments
 (0)