"writeToFile:atomically:" Fails on File with Certain ACL

355 Views Asked by At

If I have a writable file with an ACL-rule of deny delete, any [plistableObject writeFoFile:undeletableFile atomically:YES] call returns NO, whereas non-atomic writes succeed.

I know, that the atomic write means that a temporary file is written and — if written successfully — eventually renamed. This particular implication of it feels odd, though.
So I wonder, is this due to...

  1. lack of a direct 'rename' in HFS+,
  2. a deficiency in the implementation of -[NS(Array|Dictionary|Data|String) writeToFile:atomically:] or
  3. a deficiency in the implementation of ACLs in Mac OS X?

Thanks in Advance

Daniel


Original question:
I've found this odd behavior the other day on a Mac I restored from a backup:
Most applications were unable to persist their preferences — especially Mail.app which warned with an error message, suggesting that it was unable to write to ~/Library/Preferences.

Digging deeper, I found that — somehow — most plists had an ACL with the directive group:everyone deny delete in place; ditching this rule saved the day.

I suspected NSArray|NSDictionary|NSWhatHaveYou's writeToFile:atomically: to be responsible* for this behavior and — sure enough — the test-tool I wrote only succeeds when passed NO as the second argument if the file exists and has such an ACL in place...

(* where by "responsible" I only mean the not-writing-part; the ACL situation was something else entirely)

So I wonder:

Is this a bug or a feature?

While — technically — this method writes a file and upon completion renames it, from a user perspective it is not deleting anything...

If it's a bug:
Should it be filed against NSArray and friends or against the implementation of ACLs?

Any thoughts much appreciated!

Cheers

Daniel

1

There are 1 best solutions below

0
On BEST ANSWER

After some digging in the HFS source I've come to the conclusion that there is no such thing as a filesystem-native rename function in Mac OS.

Instead, it is implemented as (pseudocode)

link!
successful:
   return 0
// otherwise
unlink!
successful:
  link!
  return error_code
// otherwise
return error_code

So this behavior is to be expected :-(

That said, I don't know enough about either filesystems or low-level programming to decide whether the creation of a native rename would be worth the hassle implementing it.

I strongly feel it would be the right thing to do so, but...


Edit

As jfortman pointed out, an atomic rename would actually be possible and pretty straight-forward through use of the following sequence:

  1. write to tempfile
  2. exchangedata( path_to_tempfile, path_to_destination_file, options ) (by the way: the manpage states that this function is around since Darwin 1.3.1/Mac OS X 10.0...)
  3. delete tempfile