FileManager.url(for:in:appropriateFor:create:) Fails After 1000 Calls

Originator:levigroker
Number:rdar://50553219 Date Originated:2019-05-07
Status:Open Resolved:
Product:Foundation Product Version:
Classification: Reproducible:Always
 
Summary:

The FileManager url(for:in:appropriateFor:create:) method, when configured to create a temporary directory, fails after 1000 calls with: Error Domain=NSCocoaErrorDomain Code=512 "The file couldn’t be saved."

Steps to Reproduce:

	func test_FileManager_url_for() {
		
		for num in 1...10000 {
			do {
				let relativeURL = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
				print("\(num): \(relativeURL)")
				let tempDirURL = try FileManager.default.url(for: .itemReplacementDirectory, in: .userDomainMask, appropriateFor: relativeURL, create: true)
				print(tempDirURL)
			}
			catch {
				XCTFail("\(error)")
				return
			}
		}
	}


Expected Results:

There should be no (reasonable) limit to the number of temporary directories which can be created.

Actual Results:

Only 1000 directories can be created and then an error is generated: Error Domain=NSCocoaErrorDomain Code=512 "The file couldn’t be saved."

Test Case '-[test_FileManager_url_for]' started.
1: file:///Users/levi/Library/Developer/CoreSimulator/Devices/B36B631A-CA93-4155-A676-345CCBC5DBF4/data/tmp/4C04A494-A861-4DAD-9DCF-1F9175214345
file:///Users/levi/Library/Developer/CoreSimulator/Devices/B36B631A-CA93-4155-A676-345CCBC5DBF4/data/tmp/(A%20Document%20Being%20Saved%20By%20xctest)/
2: file:///Users/levi/Library/Developer/CoreSimulator/Devices/B36B631A-CA93-4155-A676-345CCBC5DBF4/data/tmp/2CCD122D-ABAD-465C-89BB-810F3CDE9090
file:///Users/levi/Library/Developer/CoreSimulator/Devices/B36B631A-CA93-4155-A676-345CCBC5DBF4/data/tmp/(A%20Document%20Being%20Saved%20By%20xctest%202)/
...
1000: file:///Users/levi/Library/Developer/CoreSimulator/Devices/B36B631A-CA93-4155-A676-345CCBC5DBF4/data/tmp/0B5973DC-C1BC-4F46-BBE3-4DB574DBFAD6
file:///Users/levi/Library/Developer/CoreSimulator/Devices/B36B631A-CA93-4155-A676-345CCBC5DBF4/data/tmp/(A%20Document%20Being%20Saved%20By%20xctest%201000)/
1001: file:///Users/levi/Library/Developer/CoreSimulator/Devices/B36B631A-CA93-4155-A676-345CCBC5DBF4/data/tmp/23203909-2CD8-4B91-982C-51849A5F1851
error: -[test_FileManager_url_for] : failed - Error Domain=NSCocoaErrorDomain Code=512 "The file couldn’t be saved."

Version/Build:

Xcode 10.2.1, Swift 5

Speculation:

The FileManager code which attempts to create a uniquely named temporary directory only attempts a unique name 1000 times, then fails.

"(A Document Being Saved By xctest #NUM#)"

My concerns are:

1) The number of attempts to create a unique name is undoubtably hardcoded to the arbitrarily small value of 1000.

2) The code is apparently trying to create a unique directory, starting with "(A Document Being Saved By xctest)" as the name and then making sequential attempts ( "(A Document Being Saved By xctest 2)", (A Document Being Saved By xctest 3)", etc.) until it finds one which is available, which is a performance issue since it will have to repeat these attempts each call, going over every possibility every time.

Comments

Hi levigroker,

Is there a way I can programmatically list all the temporary folders created with .itemReplacementDirectory and remove them manually at any time? (For example when I find there are plenty of them not yet removed?)

By sergey.nesteruk at Feb. 18, 2021, 12:48 p.m. (reply...)

Apple Response:

"We’ll keep this bug to consider your feedback about how this API works, but the caller is expected to delete the directory created with .itemReplacementDirectory when you’re done using it."

By levigroker at May 13, 2019, 3:27 p.m. (reply...)

Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!