chattr
当我在我的 Linux 机器上阅读手册时( kali4-amd64
),我在文件属性定义列表中看到了这一点:
A directory with the 'P' attribute set will enforce a hierarchical
structure for project id's. This means that files and directory created in
the directory will inherit the project id of the directory, rename
operations are constrained so when a file or directory is moved into
another directory, that the project id's much match. In addition, a hard
link to file can only be created when the project id for the file and the
destination directory match.
我个人不知道 Linux/UNIX 中的“项目 ID”是什么,而且谷歌搜索也没有找到任何结果,所以我希望这里有人能帮助我。
答案1
你问的是项目配额概念的一部分。项目配额是一种管理磁盘配额。特定文件系统类型可能支持或不支持项目 ID。让我们集中讨论 ext4 并从以下开始man 8 tune2fs
:
-O [^]feature[,...]
设置或清除文件系统中指示的文件系统功能(选项)。[…][…]
project
启用项目 ID 跟踪。这用于项目配额跟踪。
quota
启用内部文件系统配额 inode。[…]
-Q quota-options
在超级块上设置“配额”功能并针对给定配额类型的配额文件进行操作。配额选项可以是以下一个或多个:
[^]usrquota
设置/清除超级块中的用户配额 inode。
[^]grpquota
设置/清除超级块中的组配额 inode。
[^]prjquota
设置/清除超级块中的项目配额 inode。
您可以在现有文件系统上启用这些选项:
tune2fs -O project,quota /your/device
(或者在创建新文件系统时提供它们mke2fs
)。然后启用项目配额(如果您愿意,可以使用用户配额和/或组配额):
tune2fs -Q prjquota /your/device
安装它:
mount /your/device /the/mountpoint
setquota
现在,您可以使用和等工具来管理配额quota
(请注意,旧版本的工具可能缺少-P
处理项目配额的选项)。传统上,您会限制用户或组可以使用的磁盘空间量。使用项目配额,您可以为“项目”执行此操作,无论参与的用户和组如何。
它的工作原理如下。首先将自己置于挂载点并创建几个目录:
cd /the/mountpoint
mkdir foo bar baz
启用其上的项目层次结构:
chattr +P foo bar baz
将它们分配给两个不同的项目:
chattr -p 123 foo # 123 is an arbitrary number, project id
chattr -p 5 bar baz # so is 5, the point is they are different
在以下位置创建文件:
echo "lorem ipsum" > foo/file1
echo "lorem ipsum" > bar/file2
echo "lorem ipsum" > baz/file3
现在调用:
lsattr -pR .
您将会看到如下几行:
123 --------------e---P ./foo/file1
5 --------------e---P ./bar/file2
5 --------------e---P ./baz/file3
这意味着file1
属于 id 为 的项目123
,file2
并且file3
属于 id 为 的项目5
。如果您为这些项目定义配额(即限制项目可以使用的磁盘空间量),则每个文件都会影响其各自项目的配额消耗。
现在你引用的内容很有意义:
目录中创建的文件和目录将继承目录的项目 ID
在我们的示例中,file1
从 继承了项目 ID foo
。如果您在 中创建更多文件/目录,foo
那么它们也将继承该 ID。这允许您(和其他用户)在其指定目录中处理项目,而您创建的文件将自动计入相应的配额。
仅当文件的项目 ID 与目标目录匹配时,才能创建文件的硬链接。
ln ./baz/file3 ./foo/
会失败(尝试一下)但ln ./baz/file3 ./bar/
会成功。操作系统不允许您轻易地将属于一个项目的文件(必须保持这种状态,因为源路径未取消链接)“嵌入”到另一个项目目录中。允许在其项目内链接文件。
当文件或目录移动到另一个目录时,项目 ID 必须匹配
我认为这有点误导。mv
即使 id 不匹配也会完成其工作。关键是如果你调用
mv baz/file3 foo/
该工具将首先尝试将rename(2)
文件移至新路径,这将失败(如上ln
所示)。通常,或者在同一个项目中,它会成功,并且原始名称会消失。显然,这种行为就是“项目 ID 必须匹配”的意思。
但mv
不会立即退出。这就像在文件系统之间移动:mv
重命名失败后,它会返回到复制+删除模式。实际上,它会创建一个复制(使用新的 inode 编号)在目标目录中。在我们的例子中,副本会继承 project id foo
(就像此目录中的任何新文件一样),因此会影响 project 的配额消耗123
。然后取消链接原始路径。这可能会影响 project 的配额消耗5
;也可能不会:硬链接或打开文件描述符将导致原始 inode 和数据保留。
请注意,这有点令人惊讶:创建了一个新文件,旧的硬链接(如果有)没有链接到新文件,指向旧文件的文件描述符与新文件无关;就好像移动操作是在文件系统之间执行的一样。
有一种方法可以重mv
命名而不是复制+删除。如果您手动将原始文件分配给目标项目
chattr -p 123 baz/file3
然后mv baz/file3 foo/
才会真正移动它而不进行复制,也不会破坏硬链接(如果有的话)。但请注意,项目编号属于 inode(不是路径、不是名称、不是目录条目),因此chattr -p
会影响所有硬链接。
因此,如果您需要移动一个大文件(即某些 inode 后面的数据,而不仅仅是众多硬链接之一)到另一个项目,则更改项目然后移动将节省不必要的复制。