I'm using a file descriptor to write into a file. I've encountered a problem where if the underlying file is removed or recreated, the file descriptor becomes unstable. I have no reliable way to confirm if it's writing on the expected file.
let url = URL(fileURLWithPath: "/path/")
try FileManager.default.removeItem(at: url)
FileManager.default.createFile(atPath: url.path, contents: .empty)
let filePath = FilePath(url.path)
var fileDescriptor = try FileDescriptor.open(filePath, .readWrite)
// The file is recreated - may be done from a different process.
try FileManager.default.removeItem(at: url) // L9
FileManager.default.createFile(atPath: url.path, contents: .empty) // L10
let dataToWrite = Data([1,1,1,1])
try fileDescriptor.writeAll(dataToWrite) // L13
let dataWritten = try Data(contentsOf: url)
print(dataToWrite == dataWritten) // false
I would expect L13
to result in an error. Given it doesn't:
- Is there a way to determine where
fileDescriptor
is writing? - Is there a way to ensure that
fileDescriptor
is writing the content in the expectedfilePath
?
- Is there a way to ensure that
fileDescriptor
is writing the content in the expectedfilePath
?
This can be done by comparing their inodes.
var fdStat = stat()
var fpStat = stat()
let isValid = fstat(fileDescriptor.rawValue, &fdStat) == 0 && stat(filePath.string, &fpStat) == 0 && fdStat.st_ino == fpStat.st_ino
If it's not pointing to filePath
, recreate the file descriptor.
if !isValid {
fileDescriptor = try FileDescriptor.open(filePath, .readWrite)
}
This works, but is there a better way? Also, is there a high-level API in FileManager
that does fstat
and stat
?