为什么 `.` 和 `..` 在 Mac 上的 `/` 中有不同的索引节点号?

Why does `.` and `..` have different inode numbers inside `/` on a Mac?

我正在尝试实现自己的 pwd 命令。要找到整个路径,我需要遍历 inode 树直到到达根,判断我已经到达根的方法是检查为 [= 存储的相等 inode 数字16=] 和 ...

但在我的 Mac 看来情况并非如此,至少如果您查看下面的 table。

    dirent |       stat | link to
-----------+------------+--------
  34078072 |   34078072 | self
  31103058 |   31103058 | parent
  31103058 |   31103058 | self
  31103020 |   31103020 | parent
  31103020 |   31103020 | self
    613497 |     613497 | parent
    613497 |     613497 | self
    603204 |     603204 | parent
    603204 |     603204 | self
    157433 |     157433 | parent
    157433 |     157433 | self
         2 |          2 | parent
         2 |          2 | self   // This is root aka /
         1 |          2 | parent // There is something above it?

这是使用下面的代码生成的。 stat 结构似乎运行良好,但 dirent 在涉及 / 时具有不同的值。为什么会这样? direntstat 不应该具有相同的 inode 编号值吗?为什么 Mac 不同?

#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
#include <unistd.h>

void inodes();

int main()
{
    printf("    dirent |       stat | link to\n");
    printf("-----------+------------+--------\n");
    inodes();
    return 0;
}

void inodes()
{
    DIR* directory = opendir(".");
    struct dirent* entry = NULL;
    struct stat status;
    ino_t self = -1;
    ino_t parent = -1;

    while ((entry = readdir(directory))) {
        stat(entry->d_name, &status);
        if (strcmp(entry->d_name, ".") == 0) {
            self = status.st_ino;
            printf("%10.llu | %10.llu | self\n", entry->d_ino, self);
        }
        if (strcmp(entry->d_name, "..") == 0) {
            parent = status.st_ino;
            printf("%10.llu | %10.llu | parent\n", entry->d_ino, parent);
        }
    }
    if (self != parent) {
        if (chdir("..") != -1) {
            inodes();
        }
    }
}

在 Macintosh HFS+ 文件系统上,每个文件和文件夹都有一个唯一的 "file ID"。该文件系统在 Apple 的 "Technical Note TN1150 – HFS Plus Volume Format".

特别是,根文件夹 始终 具有文件 ID 2 和父文件夹 ID 1。在 TN1150 中,这些记录为

enum {
    kHFSRootParentID            = 1,
    kHFSRootFolderID            = 2,
    ...
}

kHFSRootParentID
    Parent ID of the root folder.
kHFSRootFolderID
    Folder ID of the root folder.

HFS+ 文件系统上的 inode 准确反映 文件 ID。这可以解释为什么 readdir() 报告索引节点 2 为“.”根文件夹的条目,inode 1 根文件夹的“..”条目。 (但我对这一事实没有明确的参考。可以尝试在以下位置找到源代码 http://www.opensource.apple.com:)

另一方面,根文件夹中的“..”始终是 link 根文件夹本身。因此,当

stat(entry->d_name, &status);

为 ".." 条目执行,根文件夹上的 stat() 已完成, 所以这再次给出了 inode 2