据我了解,目录的“读取”权限允许列出所有目录名字在该目录下,仅此而已。
基于对 FS 设计的普遍理解,如果一个目录存储为文件,那么它的内容除了文件名之外,还至少应该包含对其 inode 的引用。使用 Unix 的“一切都是文件”哲学,“读”权限授予对目录本身的“文件内容”的访问权限,从而应该足以检索每个文件的索引节点号。然而,这种情况并非如此。
我在这里缺少什么?
答案1
作为@muru 已表明,你绝对可以通过读取目录内容来获取 inode 编号(在任何 POSIX 系统上,而不仅仅是 Linux)(无论目录是否像早期的 Unices 一样被实现为普通文件)。
可能导致您认为自己做不到的原因是您尝试过
ls -i dir
在您拥有的目录上读但不是搜索许可并看到:
file1: Permission denied
file2: Permission denied
这是因为您的ls
实现确实尝试lstat()
对返回的每个条目执行 a,而不是仅在条目中readdir()
打印。d_ino
并非所有实现都这样做。例如,ls
ksh93 的内置函数(如果在构建时包含并使用 启用builtin ls
)会打印d_ino
by 返回的内容,readdir()
而不是lstat()
ing 每个文件。
ls
大多数实现使用检索 inode 编号的原因之一lstat()
可能是,否则,您通常会为作为挂载点的文件获取错误的 inode 编号:
% ksh93 -o emacs
$ builtin ls
$ /bin/ls -i /
21 bin 28 home-blank 6 lost+found 22 root 5 tmp
2 boot 9 home-test 26 media 1 run 2 u
8 cdrom 14 lib 17 mnt 15 sbin 13 usr
1 dev 23 lib32 855691 opt 25 snap 229376 var
19 etc 20 lib64 34 pool0 18 srv
34 home 4 libx32 1 proc 1 sys
$ ls -i /
21 bin 28 home-blank 6 lost+found 22 root 5 tmp
24 boot 9 home-test 26 media 12 run 2 u
8 cdrom 14 lib 17 mnt 15 sbin 13 usr
3 dev 23 lib32 855691 opt 25 snap 229376 var
19 etc 20 lib64 11 pool0 18 srv
265966 home 4 libx32 7 proc 16 sys
了解对于作为挂载点的文件(如上面的/boot
、/proc
、/sys
),ksh93 的内置函数如何ls
给出根文件系统中文件的 inode 编号,而/bin/ls
(在我的例子中是 GNU ls
)给出这些文件的有效 inode 编号,即根文件系统的 inode 编号已安装文件系统的目录。
无论如何, ls -id some/file
都会lstat()
对文件执行 a (ksh93ls
实际上会执行 astat()
使其不符合 POSIX 标准)。
$ ls -id /boot
2 /boot
(同时使用 ksh93 和 GNU ls
)。
答案2
确实如此,至少在我尝试过的 Linux 系统上是这样:
设置:
mkdir foo
touch foo/bar
# remove as much permission as possible, so that the program still works (only leave `r`).
chmod ugo-wx foo
chmod ugo+r #incase your umask, caused it not to be set
sudo chown root:root foo -R
与:
//readinode.cpp
#include <iostream>
#include <dirent.h>
int main(int argc, char* argv[])
{
for (int i = 1; i < argc; i++)
{
auto dir = opendir(argv[i]);
for(auto direntry = readdir(dir); direntry; direntry = readdir(dir))
{
std::cout << direntry->d_ino << ' ' << direntry->d_name << '\n';
}
}
}
我得到:
% ./readinode foo
3933790 .
3932162 ..
3933910 bar
答案3
“我错过了什么”
不要认为您没有获取 inode 信息的主张是错误的 - 尽管 inode 的概念与非 UNIX 文件系统的映射不同。
但我认为你错过的是你混淆了用户界面理想(“一切都是文件”)与实施细节:
我想说,您只是试图对文件系统目录概念的内部结构进行假设。
无论目录如何实现,访问语义都是如此定义的那里确实没有什么可理解的(或者相反,没有什么可误解的);这就是它们的定义方式。文件系统的内部结构对此没有影响。
个人备注
我注意到“目录存储为文件”是一文件系统实现目录的方式。这不是唯一的一个。这文章解释了 Linux 内核中最古老的 POSIX 样式文件系统之一如何根本不处理像文件这样的小目录条目列表 - 目录条目不存储在数据范围中,但通常数据范围描述符列表将存储在数据范围中对于小目录来说,它是一个B+树,对于大目录来说,它是一个B+树,它本身存储在盘区中(XFS 算法和数据结构第三版,秒。 17.5 和 16.2)——但没有什么比文件作为连续范围的映射更重要了。
因此,“目录内部只是一个文件”的假设确实不成立。
老实说,我不知道最后一次举行是什么时候——XFS 是从 1993/94 年开始的,现在已经在 Linux 中存在了 22 年; ext3 和随后的 ext4 也有类似的块树方法来目录,并且 ext3 也自 2001 年以来就已经存在。老实说,我不知道在这里考虑 ext2 是否有意义 – 我还没有设置自 2008 年以来,人们开始使用 ext2 文件系统,因为没有日志记录的 ext3 始终比它具有严格的优势,而且我发现 Linux 发行版和嵌入式工具往往也以同样的方式看待它。
答案4
就像在狗公园一样:一切都是狗。这并不意味着有一只普通的狗,而其他的只是这只狗,只是戴着不同的面具。这意味着他们都拥有某种狗财产。
- 他们都有名字。
- 他们都可以改名。
- 他们都在狗公园/目录中闲逛。
- 它们可以被传送到另一个目录(在同一文件系统上)。
- 它们都包含数据(但不一定以相同的方式)。有些文件比其他文件更像其他文件。例如块设备文件更像是常规文件而不是目录。常规文件和块设备都类似于管道、流、套接字和字符设备(但反之则不然)。
文件可能具有一组接口。其中包括(我可能错过了一些东西):
- 文件名(位于目录树中):块设备、字符设备、常规文件、目录、符号链接、命名管道、命名套接字。
- 顺序可读/可写:管道、套接字、字符设备、块设备、字符设备、常规文件、命名管道、命名套接字、
- 随机访问:常规文件、块设备。
我错过了一些东西/proc
,一些东西/sys
,一些东西/net
。这些人假装是其他人。