Skip to content

Commit 21f5313

Browse files
authored
Merge pull request #2410 from gmittert/YouOnlyGetToChooseOne
[Windows] Mark Symlinked Directories as Symlinks
2 parents 407cbc8 + be67538 commit 21f5313

File tree

2 files changed

+30
-25
lines changed

2 files changed

+30
-25
lines changed

Foundation/FileManager+Win32.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,8 @@ extension FileManager {
219219

220220
try _contentsOfDir(atPath: path, { (entryName, entryType) throws in
221221
contents.append(entryName)
222-
if entryType & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY {
222+
if entryType & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY
223+
&& entryType & FILE_ATTRIBUTE_REPARSE_POINT != FILE_ATTRIBUTE_REPARSE_POINT {
223224
let subPath: String = joinPath(prefix: path, suffix: entryName)
224225
let entries = try subpathsOfDirectory(atPath: subPath)
225226
contents.append(contentsOf: entries.map { joinPath(prefix: entryName, suffix: $0).standardizingPath })

Foundation/FileManager.swift

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,31 +1225,35 @@ public struct FileAttributeType : RawRepresentable, Equatable, Hashable {
12251225

12261226
#if os(Windows)
12271227
internal init(attributes: WIN32_FILE_ATTRIBUTE_DATA, atPath path: String) {
1228-
if attributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_DIRECTORY) == DWORD(FILE_ATTRIBUTE_DIRECTORY) {
1229-
self = .typeDirectory
1230-
} else if attributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_DEVICE) == DWORD(FILE_ATTRIBUTE_DEVICE) {
1231-
self = .typeCharacterSpecial
1232-
} else if attributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_REPARSE_POINT) == DWORD(FILE_ATTRIBUTE_REPARSE_POINT) {
1233-
// A reparse point may or may not actually be a symbolic link, we need to read the reparse tag
1234-
let fileHandle = path.withCString(encodedAs: UTF16.self) {
1235-
CreateFileW(/*lpFileName=*/$0,
1236-
/*dwDesiredAccess=*/DWORD(0),
1237-
/*dwShareMode=*/DWORD(FILE_SHARE_READ | FILE_SHARE_WRITE),
1238-
/*lpSecurityAttributes=*/nil,
1239-
/*dwCreationDisposition=*/DWORD(OPEN_EXISTING),
1240-
/*dwFlagsAndAttributes=*/DWORD(FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS),
1241-
/*hTemplateFile=*/nil)
1242-
}
1243-
defer { CloseHandle(fileHandle) }
1244-
var tagInfo = FILE_ATTRIBUTE_TAG_INFO()
1245-
guard GetFileInformationByHandleEx(fileHandle, FileAttributeTagInfo, &tagInfo, DWORD(MemoryLayout<FILE_ATTRIBUTE_TAG_INFO>.size)) else {
1246-
self = .typeUnknown
1247-
return
1228+
if attributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_DEVICE) == DWORD(FILE_ATTRIBUTE_DEVICE) {
1229+
self = .typeCharacterSpecial
1230+
} else if attributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_REPARSE_POINT) == DWORD(FILE_ATTRIBUTE_REPARSE_POINT) {
1231+
// A reparse point may or may not actually be a symbolic link, we need to read the reparse tag
1232+
let handle = path.withCString(encodedAs: UTF16.self) {
1233+
CreateFileW($0, /*dwDesiredAccess=*/DWORD(0), DWORD(FILE_SHARE_READ | FILE_SHARE_WRITE), /*lpSecurityAttributes=*/nil,
1234+
DWORD(OPEN_EXISTING), DWORD(FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS), /*hTemplateFile=*/nil)
1235+
}
1236+
guard handle != INVALID_HANDLE_VALUE else {
1237+
self = .typeUnknown
1238+
return
1239+
}
1240+
defer { CloseHandle(handle) }
1241+
var tagInfo = FILE_ATTRIBUTE_TAG_INFO()
1242+
guard GetFileInformationByHandleEx(handle, FileAttributeTagInfo, &tagInfo, DWORD(MemoryLayout<FILE_ATTRIBUTE_TAG_INFO>.size)) else {
1243+
self = .typeUnknown
1244+
return
1245+
}
1246+
self = tagInfo.ReparseTag == IO_REPARSE_TAG_SYMLINK ? .typeSymbolicLink : .typeRegular
1247+
} else if attributes.dwFileAttributes & DWORD(FILE_ATTRIBUTE_DIRECTORY) == DWORD(FILE_ATTRIBUTE_DIRECTORY) {
1248+
// Note: Since Windows marks directory symlinks as both
1249+
// directories and reparse points, having this after the
1250+
// reparse point check implicitly encodes Windows
1251+
// directory symlinks as not directories, which matches
1252+
// POSIX behavior.
1253+
self = .typeDirectory
1254+
} else {
1255+
self = .typeRegular
12481256
}
1249-
self = tagInfo.ReparseTag == IO_REPARSE_TAG_SYMLINK ? .typeSymbolicLink : .typeRegular
1250-
} else {
1251-
self = .typeRegular
1252-
}
12531257
}
12541258
#else
12551259
internal init(statMode: mode_t) {

0 commit comments

Comments
 (0)