OS X 中 xattr 的最大大小

Maximum size of xattr in OS X

我想使用 xattr 将一些元数据直接存储在文件上。这些基本上是我在搜索文件时用于文件分类的标签。我的目标是通过将更多信息与每个标签相关联来扩展通常的 Mac OS X 标签,例如添加该标签的日期和其他内容。

我正在考虑使用 xattr -w 向文件添加 xattr。我的第一个猜测是在这个 xattr 值中存储类似 JSON 的东西,但我想知道

1) 我可以在 xattr 中存储的大小限制是多少? (xattr 的人是 vauge,指的是我无法在任何地方找到的东西 _PC_XATTR_SIZE_BITS

2) 将 JSON 格式的字符串存储为 xattr 有什么问题吗?

我似乎至少可以写 260kB,就像这样生成 260kB 的空值并将它们转换为字母 a 这样我就可以看到它们:

xattr -w myattr "$(dd if=/dev/zero bs=260000 count=1|tr '[=10=]' a)" fred
1+0 records in
1+0 records out
260000 bytes transferred in 0.010303 secs (25235318 bytes/sec)

然后读回:

xattr -l fred 
myattr:  aaaaaaaaaaaaaaaaaa...aaa

并检查返回的长度:

xattr -l fred | wc -c
260009

我怀疑这实际上是命令行上 ARGMAX 的限制:

sysctl kern.argmax
kern.argmax: 262144

此外,仅仅因为您可以在 xattr 中存储 260kB,这并不意味着它是可取的。我不知道 HFS+,但在某些 Unixy 文件系统上,属性可以直接存储在 inode 中,但如果超过一定限制,则必须在磁盘上为数据分配额外的 space。

——-

随着 High SierraAPFS 取代 HFS+ 的出现,请务必在两个文件系统上进行测试 - 还要确保 Time Machine 也备份和恢复数据,dittotar 和 Finder 等实用程序在 copying/moving/archiving 文件时传播它们。

还要考虑当通过电子邮件发送标记文件或将其复制到 FAT 格式的 USB 记忆棒时会发生什么。


我还尝试在单个文件上设置多个属性,下面的脚本成功地将 1,000 个属性(称为 attr-0attr-1 ... attr-999)写入一个 260kB 的文件中单个文件 - 意味着该文件有效携带 260MB 的属性:

#!/bin/bash
for ((a=1;a<=1000;a++)) ; do
   echo Setting attr-$a
   xattr -w attr-$a "$(dd if=/dev/zero bs=260000 count=1 2> /dev/null | tr '[=14=]' a)" fred
   if [ $? -ne 0 ]; then
      echo ERROR: Failed to set attr
      exit
   fi
done

这些都可以看,也可以回读——我查过了。

根据man pathconf,有一个名为_PC_XATTR_SIZE_BITS的“可配置系统限制或选项变量”,它是

the number of bits used to store maximum extended attribute size in bytes. For example, if the maximum attribute size supported by a file system is 128K, the value returned will be 18. However a value 18 can mean that the maximum attribute size can be anywhere from (256KB - 1) to 128KB. As a special case, the resource fork can have much larger size, and some file system specific extended attributes can have smaller and preset size; for example, Finder Info is always 32 bytes.

您可以使用 Swift 4 中编写的这个小型命令行工具来确定此参数的值:

import Foundation

let args = CommandLine.arguments.dropFirst()

guard let pathArg = args.first else {
  print ("File path argument missing!")
  exit (EXIT_FAILURE)
}

let v = pathconf(pathArg, _PC_XATTR_SIZE_BITS)

print ("_PC_XATTR_SIZE_BITS: \(v)")

exit (EXIT_SUCCESS)

我得到:

  • HFS+ 31 位 OS X 10.11
  • Mac 上的 APFS 为 64 位OS 10.13

作为用于存储最大扩展属性大小的位数。这意味着实际的最大 xattr 大小在范围

中的某处
  • 1 GiB ≤ 最大值 < 2 GiB for HFS+ on OS X 10.11
  • Mac 上的 APFS 8 EiB ≤ 最大值 < 16 EiBOS 10.13