Skip to content

Commit

Permalink
Merge pull request #2700 from fumoboy007/master
Browse files Browse the repository at this point in the history
  • Loading branch information
swift-ci committed Jun 18, 2020
2 parents ff75ac8 + b6eea02 commit d97be9a
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 2 deletions.
12 changes: 10 additions & 2 deletions Sources/Foundation/FileManager+POSIX.swift
Expand Up @@ -346,8 +346,16 @@ extension FileManager {
try createDirectory(atPath: parent, withIntermediateDirectories: true, attributes: attributes)
}
if mkdir(pathFsRep, S_IRWXU | S_IRWXG | S_IRWXO) != 0 {
throw _NSErrorWithErrno(errno, reading: false, path: path)
} else if let attr = attributes {
let posixError = errno
if posixError == EEXIST && fileExists(atPath: path, isDirectory: &isDir) && isDir.boolValue {
// Continue; if there is an existing file and it is a directory, that is still a success.
// There can be an existing file if another thread or process concurrently creates the
// same file.
} else {
throw _NSErrorWithErrno(posixError, reading: false, path: path)
}
}
if let attr = attributes {
try self.setAttributes(attr, ofItemAtPath: path)
}
} else if isDir.boolValue {
Expand Down
46 changes: 46 additions & 0 deletions Tests/Foundation/Tests/TestFileManager.swift
Expand Up @@ -15,6 +15,8 @@
#endif
#endif

import Dispatch

class TestFileManager : XCTestCase {
#if os(Windows)
let pathSep = "\\"
Expand Down Expand Up @@ -1870,6 +1872,49 @@ VIDEOS=StopgapVideos
try checkPath(path: path)
}
}

/**
Tests that we can get an item replacement directory concurrently.
- Bug: [SR-12272](https://bugs.swift.org/browse/SR-12272)
*/
func test_concurrentGetItemReplacementDirectory() throws {
let fileManager = FileManager.default

let operationCount = 10

var directoryURLs = [URL?](repeating: nil, count: operationCount)
var errors = [Error?](repeating: nil, count: operationCount)

let dispatchGroup = DispatchGroup()
for operationIndex in 0..<operationCount {
DispatchQueue.global().async(group: dispatchGroup) {
do {
let directory = try fileManager.url(for: .itemReplacementDirectory,
in: .userDomainMask,
appropriateFor: URL(fileURLWithPath: NSTemporaryDirectory(),
isDirectory: true),
create: true)
directoryURLs[operationIndex] = directory
} catch {
errors[operationIndex] = error
}
}
}
dispatchGroup.wait()

for directoryURL in directoryURLs {
if let directoryURL = directoryURL {
try? fileManager.removeItem(at: directoryURL)
}
}

for error in errors {
if let error = error {
XCTFail("One of the concurrent calls to get the item replacement directory failed: \(error)")
}
}
}

// -----

Expand Down Expand Up @@ -1928,6 +1973,7 @@ VIDEOS=StopgapVideos
("test_contentsEqual", test_contentsEqual),
/* ⚠️ */ ("test_replacement", testExpectedToFail(test_replacement,
/* ⚠️ */ "<https://bugs.swift.org/browse/SR-10819> Re-enable Foundation test TestFileManager.test_replacement")),
("test_concurrentGetItemReplacementDirectory", test_concurrentGetItemReplacementDirectory),
]

#if !DEPLOYMENT_RUNTIME_OBJC && NS_FOUNDATION_ALLOWS_TESTABLE_IMPORT && !os(Android)
Expand Down

0 comments on commit d97be9a

Please sign in to comment.