Reputation: 11083
We are unable to successfully write data on an iOS app using this KMP code. We would like to know what we can change to make it write successfully:
suspend fun HttpResponse.saveBodyToFile(fileSystem: FileSystem, outputFile: Path): Boolean {
var success = false
try {
// if the target file already exists, remove it.
fileSystem.delete(outputFile)
val parentDir = outputFile.parent ?: return false
if (!fileSystem.exists(parentDir)) {
fileSystem.createDirectories(parentDir)
}
val byteReadChannel: ByteReadChannel = body()
fileSystem.sink(outputFile).buffer().use {
byteReadChannel.readFully(it)
}
success = fileSystem.exists(outputFile)
} catch (e: KtorIoException) {
Logger.e(e) { "Failed to save response stream to ${outputFile.name}" }
Logger.e { "I/O Exception ${e.message}"}
fileSystem.delete(outputFile)
} catch (e: OkioIOException) {
Logger.e { "I/O Exception ${e.message}"}
Logger.e(e) { "Failed to save response stream to ${outputFile.name}" }
Logger.e { "I/O Exception ${e.message}"}
fileSystem.delete(outputFile)
}
return success
}
Strangely enough it creates a directory, but throws this error: š“ I/O Exception Read-only file system
If the directory already exists, it still evaluates this as true:
(!fileSystem.exists(parentDir))
and tries to create it again.
If the directory exists, and this section of code is commented out:
if (!fileSystem.exists(parentDir)) {
fileSystem.createDirectories(parentDir)
}
then this section of code:
fileSystem.sink(outputFile).buffer().use {
byteReadChannel.readFully(it)
}
throws this error: š“ I/O Exception Read-only file system
We are passing in a subdirectory of the Cache directory:
file:/Users/myname/Library/Developer/CoreSimulator/Devices/85FF4164-D3CF-446C-AF42-EC64B5473BCA/data/Containers/Data/Application/7F890ECD-83DB-4D91-8BBD-102F631594A6/Library/Caches/syncFiles/sync-proxy.json
Upvotes: 2
Views: 1245
Reputation: 2430
So we are using Okio for KMP I/O operations. To access the appropriate directory
guard let cacheDirectory = FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first?.appendingPathComponent("syncFiles")
Than passing cacheDirectory.absoluteString
as the parent directory to okio's filesystem. absoluteString
returns a string in the form of file:<path>
Okio uses lstat
to determine if a path exists. lstat
does not support url formated paths, whereas okio does support url formatted file paths.
When createDirectories
is called it uses lstat
which returns false to okio and it will try to create all the parent directories which already exist and are read only causing the crash.
The fix is quite simple instead of calling cacheDirectory.absoluteString
change it to cacheDirectory.path()
which removes the file:
and lstat
reports back correctly.
Upvotes: 3