跳转到内容

权限与扩展属性 ​

一个文件能不能被打开、修改、删除,在 macOS 上由四层信息共同决定:Unix 权限位、访问控制列表(ACL)、文件标志,以及扩展属性。

ls -l 只显示了第一层。很多「明明是我的文件却动不了」的情况,答案在另外三层里。

开始之前 ​

本文大部分命令只读。会修改状态的命令都单独标注,并给出撤销方法。建议在一个临时目录里练习:

sh
mkdir -p /tmp/perm-test && cd /tmp/perm-test && touch demo.txt

第一层:Unix 权限位 ​

sh
ls -l demo.txt

输出形如 -rw-r--r-- 1 yourname staff 0 ...。前十个字符从左到右是:文件类型(- 普通文件、d 目录、l 符号链接),然后三组各三位,分别是所有者、所属组、其他人的读(r)、写(w)、执行(x)权限。

chmod 改权限,chown 改所有者:

sh
chmod 600 demo.txt

600 是八进制写法:所有者 6(读 4 + 写 2),组和其他人都是 0。再执行一次 ls -l 能看到变成 -rw-------。

对目录来说,x 的含义不是「执行」而是「可以进入」。一个目录有 r 没有 x,你能列出名字却进不去——这是排查目录访问问题时容易忽略的一点。

第二层:ACL ​

Unix 权限只能表达三种身份。需要更细的规则时,macOS 用 ACL:

sh
ls -le demo.txt

-e 显示 ACL。普通文件通常没有,输出和 ls -l 一样。看一个确实有 ACL 的位置:

sh
ls -lde ~/Downloads

-d 表示看目录本身。这里通常能看到 0: group:everyone deny delete 一类的条目——它明确禁止删除,并且优先于权限位。

这解释了一类怪事:权限位显示你有写权限,删除却被拒绝。原因是一条 deny ACL。查看用 ls -le,修改用 chmod -a,但在系统目录上动 ACL 之前请先确认你真的知道那条规则是干什么的。

第三层:文件标志 ​

sh
ls -lO demo.txt

-O(大写字母 O)显示文件标志。常见的是 uchg——用户不可更改,对应访达「显示简介」里的「已锁定」。

sh
chflags uchg demo.txt

执行后再尝试 rm demo.txt 会被拒绝。解除:

sh
chflags nouchg demo.txt

nouchg 就是在标志名前加 no。这一对命令是「文件删不掉但权限看起来正常」的常见答案。

第四层:扩展属性 ​

扩展属性是挂在文件上的额外数据,ls -l 里表现为权限位后面的一个 @:

sh
ls -l@ demo.txt

列出具体内容:

sh
xattr -l demo.txt

xattr 是管理扩展属性的命令,-l 列出全部属性及其值。新建的空文件通常什么都没有。从网上下载的文件则不同,常见这几个:

属性名含义
com.apple.quarantine隔离标记:这个文件来自互联网,尚未通过首次打开的安全检查
com.apple.metadata:kMDItemWhereFroms下载来源网址
com.apple.FinderInfo访达使用的旧式元数据

查看某个下载文件的来源:

sh
xattr -p com.apple.metadata:kMDItemWhereFroms ~/Downloads/某个文件

-p 打印指定属性的值。输出是二进制 plist,看起来是一串十六进制,可以接着解码:

sh
xattr -p com.apple.metadata:kMDItemWhereFroms ~/Downloads/某个文件 | xxd -r -p | plutil -p -

xxd -r -p 把十六进制文本还原成二进制(-r 反向转换,-p 纯十六进制格式),plutil -p - 把 plist 以易读形式打印(- 表示从标准输入读)。

关于删除隔离属性 ​

网上很多教程会让你执行 xattr -d com.apple.quarantine 某个应用 来「修复」打不开的应用。这不是标准安装步骤。

隔离属性正是让系统在首次打开时做签名与公证检查的那个标记。删掉它,检查就不再发生——而检查本来是为了发现文件是否被篡改。软件因为它打不开时,正确的处理顺序见应用无法打开,机制背景见SIP 与公证。

确有必要删除时(例如你自己编译的、明确知道来源的文件),命令是:

sh
xattr -d com.apple.quarantine 文件路径

-d 删除指定属性。这个操作不可撤销——属性删掉就没了,除非重新下载该文件。

两种失败,两种含义 ​

这是本文最实用的一条:

Permission denied

POSIX 层面的拒绝。改权限位、换所有者、或者用 sudo 通常能解决。

Operation not permitted

即使用 sudo 也照样出现的话,这不是权限位问题,而是隐私保护(TCC)或系统完整性保护(SIP)在拦截。典型场景是在终端里访问 ~/Library/Mail:

sh
ls ~/Library/Mail

终端没有完全磁盘访问权限时,这条命令会返回 Operation not permitted。加 sudo 结果一样——因为拦截它的不是权限系统。处理办法见TCC 隐私授权。

学会区分这两行报错,能省下大量在错误方向上的尝试。

检查结果 ​

在测试目录里走一遍,每步都能预测结果:

sh
cd /tmp/perm-test
chmod 000 demo.txt && cat demo.txt

应当报 Permission denied。恢复:chmod 644 demo.txt。

sh
chflags uchg demo.txt && rm demo.txt

应当报操作被拒。解除:chflags nouchg demo.txt。

sh
ls ~/Library/Mail

若报 Operation not permitted,说明你已经见到了第二类失败。

动手练习 ​

  1. 在 /tmp/perm-test 里用 touch 建一个文件,用 ls -l@eO 一次看全四层信息(这些选项可以合并)。
  2. 用 chflags uchg 锁定它,在访达里打开「显示简介」,确认「已锁定」被勾上——命令行与图形界面看到的是同一件事。
  3. 在访达里取消勾选,回到终端用 ls -lO 确认 uchg 消失了。
  4. 找一个从浏览器下载的文件,用 xattr -l 看它带哪些属性。
  5. rm -rf /tmp/perm-test 清理。

成功标准是第 2、3 步——确认图形界面的开关和命令行的标志是同一份数据的两种呈现。以后遇到「访达里显示正常但命令行报错」,你就知道该去看哪几层。

返回系统内部