“我错过了什么”

“我错过了什么”

据我了解,目录的“读取”权限允许列出所有目录名字在该目录下,仅此而已。

基于对 FS 设计的普遍理解,如果一个目录存储为文件,那么它的内容除了文件名之外,还至少应该包含对其 inode 的引用。使用 Unix 的“一切都是文件”哲学,“读”权限授予对目录本身的“文件内容”的访问权限,从而应该足以检索每个文件的索引节点号。然而,这种情况并非如此。

我在这里缺少什么?

答案1

作为@muru 已表明,你绝对可以通过读取目录内容来获取 inode 编号(在任何 POSIX 系统上,而不仅仅是 Linux)(无论目录是否像早期的 Unices 一样被实现为普通文件)。

可能导致您认为自己做不到的原因是您尝试过

ls -i dir

在您拥有的目录上但不是搜索许可并看到:

file1: Permission denied
file2: Permission denied

这是因为您的ls实现确实尝试lstat()对返回的每个条目执行 a,而不是仅在条目中readdir()打印。d_ino

并非所有实现都这样做。例如,lsksh93 的内置函数(如果在构建时包含并使用 启用builtin ls)会打印d_inoby 返回的内容,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。这些人假装是其他人。

相关内容