Skip to content

Commit cc07859

Browse files
committed
Foundation: correct directory iteration on Windows
The path that was being constructed would elide the penultimate arc in the path as the base URL was not marked as a directory. As such, it was assumed to be a file URL, and making a URL relative to it would truncate the previously last arc. Append the path component instead and explicitly indicate if it is a directory component when building the URL as we already have the information on hand. This repairs the directory traversal on Windows. The bug was identified by the DocC test suite on Windows.
1 parent bd2e810 commit cc07859

File tree

2 files changed

+19
-1
lines changed

2 files changed

+19
-1
lines changed

Diff for: Sources/Foundation/FileManager+Win32.swift

+3-1
Original file line numberDiff line numberDiff line change
@@ -986,7 +986,9 @@ extension FileManager {
986986
ffd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN == FILE_ATTRIBUTE_HIDDEN {
987987
continue
988988
}
989-
_stack.append(URL(fileURLWithPath: file, relativeTo: _lastReturned))
989+
990+
let isDirectory = ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY == FILE_ATTRIBUTE_DIRECTORY && ffd.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT == 0
991+
_stack.append(_lastReturned.appendingPathComponent(file, isDirectory: isDirectory))
990992
} while FindNextFileW(handle, &ffd)
991993
}
992994
return firstValidItem()

Diff for: Tests/Foundation/Tests/TestFileManager.swift

+16
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,21 @@ class TestFileManager : XCTestCase {
754754
XCTFail("Failed to clean up files")
755755
}
756756
}
757+
758+
func test_contentsOfDirectoryEnumeration() {
759+
let fm = FileManager.default
760+
761+
let root = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(NSUUID().uuidString, isDirectory: true)
762+
let subdirectory = root.appendingPathComponent("subdirectory", isDirectory: true)
763+
let file = subdirectory.appendingPathComponent("file", isDirectory: false)
764+
try? fm.removeItem(at: root)
765+
766+
XCTAssertNoThrow(fm.createDirectory(at: subdirectory, withIntermediateDirectories: true, attributes: nil))
767+
XCTAssertNoThrow(fm.createFile(atPath: file.path, contents: Data(), attributes: nil))
768+
let contents = try XCTUnwrap(fm.contentsOfDirectory(at: root, includingPropertiesForKeys: [.isDirectoryKey], options: [.skipsHiddenFiles]))
769+
XCTAssertEqual(contents.count, 1)
770+
XCTAssertEqual(contents, [subdirectory])
771+
}
757772

758773
func test_subpathsOfDirectoryAtPath() {
759774
let fm = FileManager.default
@@ -2032,6 +2047,7 @@ VIDEOS=StopgapVideos
20322047
("test_directoryEnumerator", test_directoryEnumerator),
20332048
("test_pathEnumerator",test_pathEnumerator),
20342049
("test_contentsOfDirectoryAtPath", test_contentsOfDirectoryAtPath),
2050+
("test_contentsOfDirectoryEnumeration", test_contentsOfDirectoryEnumeration),
20352051
("test_subpathsOfDirectoryAtPath", test_subpathsOfDirectoryAtPath),
20362052
("test_copyItemAtPathToPath", test_copyItemAtPathToPath),
20372053
("test_linkItemAtPathToPath", testExpectedToFailOnAndroid(test_linkItemAtPathToPath, "Android doesn't allow hard links")),

0 commit comments

Comments
 (0)