I know, that this is not the right forum for asking my question. But somehow I am a little bit desperate, because I don't see any solution for my problem and maybe here is one experienced developer who can maybe help:
I'd ask on Apple dev forums where knowledgeable people like @eskimo are. Not sure what's the best "tag" would be in this case. Opening a dev support indecent (incident of course ) is another possibility.
But anyway: You suggest I should rebind open and close to my application? I then would need to check for every call, if my specific file was opened or closed. I'm not sure if this solves my high cpu problem ;)
Perhaps the DispatchSource API helps here or is it also somehow coupled to a specific Timer? Haven't really used this API, just am privy that it's leveraged for file change observation tracking.
Thanks @nikola (wow, your first post!). That's actually what I tried too. But somehow, DispatchSource.makeFileSystemObjectSource doesn't fire, when the file is closed. In a strange way, it's either not fired when there is a write to the file, maybe there is actually a bug in the system.
This is my code so far:
private func startFileMonitor() throws {
if self.fileDescriptor == -1 || self.fileDescriptor == nil {
throw FileMonitorError.cannotOpenAndMonitor
}
let queue = DispatchQueue(label: "FileMonitorQueue")
self.fileEventHandler = DispatchSource.makeFileSystemObjectSource(fileDescriptor: self.fileDescriptor!,
eventMask: .all,
queue: queue)
self.fileEventHandler.setEventHandler { [weak self] in
if let fileEventHandler = self?.fileEventHandler {
if fileEventHandler.data.contains(.attrib) {
print("attributes changed")
}
if fileEventHandler.data.contains(.delete) {
self?.restartFileMonitoring()
if let path = self?.fileURL.path() {
if !FileManager.default.fileExists(atPath: path) {
self?.fileDeleted()
}
}
}
if fileEventHandler.data.contains(.extend) {
print("file size changed")
}
if fileEventHandler.data.contains(.funlock) {
print("file unlocked")
}
if fileEventHandler.data.contains(.link) {
self?.restartFileMonitoring()
}
if fileEventHandler.data.contains(.rename) {
self?.restartFileMonitoring()
// check the new destination or the new name
if !FileManager.default.fileExists(atPath: self!.fileURL.path()) {
var buffer = [CChar](repeating: 0, count: Int(MAXPATHLEN))
if let fd = self?.fileDescriptor {
_ = fcntl(fd, F_GETPATH, &buffer)
let newPath = String(cString: buffer)
// update the fileURL
self?.fileURL = URL(fileURLWithPath: newPath)
self?.fileMoved()
}
}
}
if fileEventHandler.data.contains(.revoke) {
print("file revoked")
}
if fileEventHandler.data.contains(.write) {
print("file write")
}
if fileEventHandler.data.contains(.all) {
print("all???")
}
}
}
self.fileEventHandler!.activate()
}
With some googling in the net, I found this link:
So maybe there is some file system event for it, but I couldn't find a way how to listen to it.
As tera says, this is something better handled on DevForums. Tag your thread with Files and Storage so that I see it.
IMO the key sticking point is this:
I would like to get informed, whether a file on macOS is
opened or closed.
You’re not looking to hear about modifications, you’re looking to hear about opens. That rules out all the usual suspects, like Dispatch sources and FSEvents.
This raises a question - what exactly do you need those open/close notifications for? E.g. the file is opened, then one second later it is modified, another second later it is modified again and in another second it is closed - what do you want to do upon the closure and can’t you do that upon the modification?
As told, the FileEventHandler doesn't contain the .write, when my file is saved. You can test my code above.
But anyway, that wouldn't help me. I really need to know if the file is open or closed. I am developing a server client application with a document management system. When a client wants to access a file, the file is sent from the server to the client and so that no other clients can edit the file, it's getting locked for everbody else. If the client, where the file is opened, now save his changes and when he closes the file, the new file should automatically be uploaded to the server and then be unlocked. For now every user has to do this manually, what is a little bit annoying.
I see, did something similar in the past via Finder extension. Do you support arbitrary third-party applications that could edit files, a vetted collection of third-party applications or only your own editor application? If it is the latter you could signal open/close events by the means of your own transport, and if it is the former – beware than many apps don't keep files open during editing.
Well, you can import every file type as you wish and then they will be opened by the systems default application. So I cannot go this way, I really need to know, if another process is accessing the file. Unfortunately macOS doesn't have the /proc/<pid>/fd folder, otherwise I could just watch this folder ...
What do you mean with "many apps don't keep files open during editing"? Would be interesting, which apps do this (and especially why).