Locked Files in Mac OS X

I spend a lot of my time in the Mac OS X terminal (well, iTerm 2), and I'm at home with many of the command-line Unixy conventions. With that comfort also comes a high expectation that things will work in a specific way. This past week I've been manually restoring files from a Time Machine backup. Surprises ensued.

You may observe files with the correct ownership (chown) and permissions (chmod u+rw) that are write-locked. In my experience, the files were editable with sudo, and modification via the Finder would prompt for an administrator password. In these situations, you may be dealing with additional file attributes.

Access Control Lists (ACLs)

Your file may have an ACL that prevents writing by the current user. To view ACLs for a file, issue ls -le. Use chmod to modify ACLs. Run chmod -N to remove the ACL.

File Flags

Running "Get Info..." on a file and checking "Locked" is functionally equivalent to running chflags uchg [file]. Show flags in directory listings using ls -lO. See also: SetFile.

Extended Attributes (metadata)

For good measure, we should also mention extended attributes. xattr modifies attributes (xattr -r -c to recursively remove), and ls -l@ will display attributes.

I don't know of any specific metadata that would prevent file modification.

All Together, Now

annika@fsck:~:0$ mkdir /tmp/foo && cd /tmp/foo && touch bar
annika@fsck:/tmp/foo:0$ xattr -w com.sixohthree.test "o hai" bar
annika@fsck:/tmp/foo:0$ chmod +a 'everyone deny write,append,delete' bar
annika@fsck:/tmp/foo:0$ chflags uchg bar
annika@fsck:/tmp/foo:0$ ls -le@O
total 0
-rw-r--r--@ 1 adam  wheel  uchg 0 Dec  8 09:18 bar
        com.sixohthree.test     5  0: group:everyone deny write,delete,append

The uchg flag will prevent all file modifications, including changing ACLs and extended attributes.

annika@fsck:/tmp/foo:0$ date >> bar
-bash: bar: Operation not permitted
annika@fsck:/tmp/foo:1$ chflags nouchg bar
annika@fsck:/tmp/foo:0$ date >> bar
-bash: bar: Operation not permitted
annika@fsck:/tmp/foo:1$ chmod -N bar
annika@fsck:/tmp/foo:0$ date >> bar
annika@fsck:/tmp/foo:0$