Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions Sources/NIOFS/FileSystem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -825,6 +825,20 @@ extension FileSystem {
break loop

case let .failure(errno):
if errno == .fileExists {
switch self._info(forFileAt: path, infoAboutSymbolicLink: false) {
case let .success(maybeInfo):
if let info = maybeInfo, info.type == .directory {
break loop
} else {
// A file exists at this path.
return .failure(.mkdir(errno: errno, path: path, location: .here()))
}
case .failure:
// Unable to determine what exists at this path.
return .failure(.mkdir(errno: errno, path: path, location: .here()))
}
}
guard createIntermediateDirectories, errno == .noSuchFileOrDirectory else {
return .failure(.mkdir(errno: errno, path: path, location: .here()))
}
Expand Down
14 changes: 14 additions & 0 deletions Sources/_NIOFileSystem/FileSystem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -839,6 +839,20 @@ extension FileSystem {
break loop

case let .failure(errno):
if errno == .fileExists {
switch self._info(forFileAt: path, infoAboutSymbolicLink: false) {
case let .success(maybeInfo):
if let info = maybeInfo, info.type == .directory {
break loop
} else {
// A file exists at this path.
return .failure(.mkdir(errno: errno, path: path, location: .here()))
}
case .failure:
// Unable to determine what exists at this path.
return .failure(.mkdir(errno: errno, path: path, location: .here()))
}
}
guard createIntermediateDirectories, errno == .noSuchFileOrDirectory else {
return .failure(.mkdir(errno: errno, path: path, location: .here()))
}
Expand Down
31 changes: 31 additions & 0 deletions Tests/NIOFSIntegrationTests/FileSystemTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,37 @@ final class FileSystemTests: XCTestCase {
}
}

func testCreateDirectoryIsIdempotentWhenAlreadyExists() async throws {
let path = try await self.fs.temporaryFilePath()

try await self.fs.createDirectory(at: path, withIntermediateDirectories: false)

try await self.fs.createDirectory(at: path, withIntermediateDirectories: false)
try await self.fs.createDirectory(at: path, withIntermediateDirectories: true)

try await self.fs.withDirectoryHandle(atPath: path) { dir in
let info = try await dir.info()
XCTAssertEqual(info.type, .directory)
XCTAssertGreaterThan(info.size, 0)
}
}

func testCreateDirectoryThroughSymlinkToExistingDirectoryIsIdempotent() async throws {
let realDir = try await self.fs.temporaryFilePath()
try await self.fs.createDirectory(at: realDir, withIntermediateDirectories: false)

let linkPath = try await self.fs.temporaryFilePath()
try await self.fs.createSymbolicLink(at: linkPath, withDestination: realDir)

try await self.fs.createDirectory(at: linkPath, withIntermediateDirectories: false)

try await self.fs.withDirectoryHandle(atPath: linkPath) { dir in
let info = try await dir.info()
XCTAssertEqual(info.type, .directory)
XCTAssertGreaterThan(info.size, 0)
}
}

func testCurrentWorkingDirectory() async throws {
let directory = try await self.fs.currentWorkingDirectory
XCTAssert(!directory.underlying.isEmpty)
Expand Down
Loading