扩展属性

扩展属性 (xattrs) 通常存储在磁盘上的一个单独数据块中,并通过 inode.i_file_acl* 从 inode 引用。扩展属性的首次使用似乎是为了存储文件 ACL 和其他安全数据 (selinux)。通过 user_xattr 挂载选项,只要所有属性名称以“user”开头,用户就可以存储扩展属性;此限制似乎已在 Linux 3.0 中消失。

扩展属性可以在两个地方找到。第一个地方是每个 inode 条目的末尾和下一个 inode 条目的开头之间。例如,如果 inode.i_extra_isize = 28 且 sb.inode_size = 256,则有 256 - (128 + 28) = 100 字节可用于 inode 内部的扩展属性存储。扩展属性可以找到的第二个地方是由 inode.i_file_acl 指向的块中。截至 Linux 3.11,此块不可能包含指向第二个扩展属性块(甚至一个簇的其余块)的指针。理论上,每个属性的值都可以存储在单独的数据块中,但截至 Linux 3.11,代码不允许这样做。

键通常假定为 ASCIIZ 字符串,而值可以是字符串或二进制数据。

扩展属性在 inode 之后存储时,有一个 4 字节长的头 ext4_xattr_ibody_header

偏移量

类型

名称

描述

0x0

__le32

h_magic

用于标识的魔数,0xEA020000。此值由 Linux 驱动程序设置,但 e2fsprogs 似乎没有检查它(?)

扩展属性块的开头是 struct ext4_xattr_header,它长 32 字节

偏移量

类型

名称

描述

0x0

__le32

h_magic

用于标识的魔数,0xEA020000。

0x4

__le32

h_refcount

引用计数。

0x8

__le32

h_blocks

使用的磁盘块数量。

0xC

__le32

h_hash

所有属性的哈希值。

0x10

__le32

h_checksum

扩展属性块的校验和。

0x14

__u32

h_reserved[3]

零。

校验和是根据文件系统 UUID、扩展属性块的 64 位块号以及整个块(头 + 条目)计算的。

struct ext4_xattr_headerstruct ext4_xattr_ibody_header 之后是一个 struct ext4_xattr_entry 数组;这些条目中的每一个至少长 16 字节。当存储在外部块中时,struct ext4_xattr_entry 条目必须按排序顺序存储。排序顺序是 e_name_index,然后是 e_name_len,最后是 e_name。存储在 inode 内部的属性不需要按排序顺序存储。

偏移量

类型

名称

描述

0x0

__u8

e_name_len

名称长度。

0x1

__u8

e_name_index

属性名称索引。下面有关于此的讨论。

0x2

__le16

e_value_offs

此属性值在存储它的磁盘块上的位置。多个属性可以共享相同的值。对于 inode 属性,此值是相对于第一个条目开始的;对于块,此值是相对于块开始(即头部)的。

0x4

__le32

e_value_inum

存储值的 inode。零表示值与此条目在同一块中。此字段仅在启用 INCOMPAT_EA_INODE 功能时使用。

0x8

__le32

e_value_size

属性值长度。

0xC

__le32

e_hash

属性名称和属性值的哈希值。内核不更新 inode 内部属性的哈希值,因此在这种情况下,此值必须为零,因为 e2fsck 会验证任何非零哈希值,无论 xattr 位于何处。

0x10

char

e_name[e_name_len]

属性名称。不包含尾随 NULL。

属性值可以跟在条目表的末尾。似乎要求它们对齐到 4 字节边界。这些值从块的末尾开始存储,并向 xattr_header/xattr_entry 表的方向增长。当两者冲突时,溢出部分会放入一个单独的磁盘块中。如果磁盘块填满,文件系统将返回 -ENOSPC。

ext4_xattr_entry 的前四个字段设置为零,以标记键列表的结束。

属性名称索引

从逻辑上讲,扩展属性是一系列键值对。键假定为以 NULL 结尾的字符串。为了减少键占用的磁盘空间量,键字符串的开头会与属性名称索引进行匹配。如果找到匹配项,则设置属性名称索引字段,并从键名中删除匹配的字符串。以下是名称索引值到键前缀的映射:

名称索引

键前缀

0

(无前缀)

1

“user.”

2

“system.posix_acl_access”

3

“system.posix_acl_default”

4

“trusted.”

6

“security.”

7

“system.” (仅限 inline_data?)

8

“system.richacl” (仅限 SuSE 内核?)

例如,如果属性键是“user.fubar”,则属性名称索引设置为 1,并且“fubar”名称记录在磁盘上。

POSIX ACL

POSIX ACL 存储在 Linux 内核(和 libacl)内部 ACL 格式的简化版本中。主要区别在于版本号不同 (1),并且 e_id 字段仅针对命名的用户和组 ACL 存储。