File exclusive access on macOS

Hi,

I'm trying to lock a file from objective-c (or plain C) so that other processes cannot read or write to it. So far, unsuccessfully.

I've tried to use all APIs I can think of, but none locked the file:

  • open then flock
  • open then lockf
  • open with O_EXLOCK
  • open then fcntl (F_SETLK)
  • open then NSDistributedLock

I'm running macOS 11.6.1 on an APFS drive.

For every API used, I was able to open and edit the file from command line using vi or just using cat on the file.

Isn't there any way of preventing another process from accessing a file, until I'm done with it (ie. I closed the file, or the file handle is relinquished)?

Thanks, Chris

Answered by endecotp in 720006022

What you're asking for is called "mandatory locking".

What those functions provide is "advisory locking". Advisory locking depends on all users of the file using the locking functions.

Historically, Windows has provided mandatory locking; POSIX (Unix) has provided mostly advisory locking. I believe that Mac OS, and iOS, follow POSIX here.

So no, I do not believe that you will find a way to lock a file so that another (uncooperative) process will be unable to access it.

Some work-around:

  • Modify the permissions of the file while you modify it.
  • Make a temporary copy of the file, and rename() it over the original (which is atomic) when you have finished.

(What do you really want to achieve?)

If these files are usually opened directly by the user (i.e from a Open Panel) then NSFileCoordinator might be what you want. But that is a cooperative API, i.e other processes also need to use FileCoordinator to access the file too.

Give more details on your use case.

Accepted Answer

What you're asking for is called "mandatory locking".

What those functions provide is "advisory locking". Advisory locking depends on all users of the file using the locking functions.

Historically, Windows has provided mandatory locking; POSIX (Unix) has provided mostly advisory locking. I believe that Mac OS, and iOS, follow POSIX here.

So no, I do not believe that you will find a way to lock a file so that another (uncooperative) process will be unable to access it.

Some work-around:

  • Modify the permissions of the file while you modify it.
  • Make a temporary copy of the file, and rename() it over the original (which is atomic) when you have finished.

(What do you really want to achieve?)

Thank you very much, that confirms what I suspected. On windows, one can use the _SH_DENYRD flag when calling open and this locks the file so any other process using any available file opening method will be prevented access to it.

I was merely looking for a similar functionality on macOS. I need to prevent any other process (using any open method that's not under my control) from accessing a file until I'm done with what I want to do with it. I guess my best option would be chmod then.

[A big +1 to endecotp’s response (-:]

I need to prevent any other process (using any open method that's not under my control) from accessing a file until I'm done with what I want to do with it.

To what end? What specifically are you trying to prevent here?

This matters because it informs the best path forward. For example, if your main goal is to prevent other code seeing inconsistent data, then endecotp’s suggestion of making a copy and then renaming it into place is a good one. Notably, APFS’s copy-on-write functionality makes this a relatively cheap operation.

However, if your goal is to support multiple cooperating writers then things get more complex.

I guess my best option would be chmod then.

That’s unlikely to be helpful, because chances are that the other programs accessing the file are being run by the same user.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

File exclusive access on macOS
 
 
Q