I was playing around with implementing my own pwd
command. To find the entire path, I need to traverse the inode
tree until I reach the root, and the way to tell that I've hit the root is by checking for equal inode
numbers stored for .
and ..
.
But on my Mac that seems to not be case, at least if you look at this table below.
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?
This was generated using the code below. The stat
struct seems to be doing fine, but dirent
has a different value when it comes to /
. Why is that the case? Shouldn't dirent
and stat
have the same values for inode number? Why is it different on a 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();
}
}
}
On the Macintosh HFS+ file system, every file and folder has a unique "file ID". This file system is described in Apple's "Technical Note TN1150 – HFS Plus Volume Format".
In particular, the root folder always has the file ID 2 and the parent ID 1. In the TN1150, these are documented as
enum {
kHFSRootParentID = 1,
kHFSRootFolderID = 2,
...
}
kHFSRootParentID
Parent ID of the root folder.
kHFSRootFolderID
Folder ID of the root folder.
The inode on a HFS+ file system reflects exactly
the file ID. This might explain why readdir()
reports the inode
2
for the "." entry of the root folder, and the inode 1
for
the ".." entry of the root folder. (But I do not have a definite reference for this fact. One could try to find the source code at
http://www.opensource.apple.com :)
On the other hand, ".." in the root folder is always a link to the root folder itself. Therefore, when
stat(entry->d_name, &status);
is executed for the ".." entry, a stat()
on the root folder is done,
so this gives the inode 2
again.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With