In POSIX, you can theoretically use inode zero

May 30, 2025

When I wrote about the length of file names in early Unix, I noted that inode numbers were unsigned 16-bit integers and thus you could only have at most 65,536 inodes in any given filesystem. Over on the Fediverse, JdeBP correctly noted that I had an off by one error. The original Unix directory entry format used a zero inode number to mark deleted entries, which meant that you couldn't actually use inode zero for anything (not even the root directory of the filesystem, which needed a non-zero inode number in order to have a '.' entry).

(Contrary to what I said in that Fediverse thread, I think that V7 and earlier may not have actually had a zero inode. The magic happens in usr/sys/h/param.h in the itod() and itoo() macros. These give a result for inode 0, but I suspect they're never supposed to be used; if I'm doing it right, inode 1 is at offset 0 within block 2.)

Since I'm the sort of person that I am, this made me wonder if you could legally use inode zero today in a POSIX compliant system. The Single Unix Specification, which is more or less POSIX, sets out that ino_t is some unsigned integer type, but it doesn't constrain its value. Instead, inode numbers are simply called the 'file serial number' in places like sys/stat.h and dirent.h, and the stat() family of functions, readdir() and posix_getdents() don't put any restrictions on the inode numbers except that st_dev and st_ino together uniquely identify a file. In the normal way to read standards, anything not explicitly commented on is allowed, so you're allowed to return a zero for the inode value in these things (provided that there is only one per st_dev, or at least that all of them are the same file, hardlinked together).

On Linux, I don't think there's any official restrictions on whether there can be a zero inode in some weird filesystem (eg, also), although kernel and user-space code may make assumptions. FreeBSD doesn't document any restrictions in stat(2) or getdirentries(2). The OpenBSD stat(2) and getdents(2) manual pages are similarly silent about whether or not the inode number can be zero.

(The tar archive format doesn't include inode numbers. The cpio archive format does, but I can't find a mention of a zero inode value having special meaning. The POSIX pax archive format is similarly silent; both cpio and pax use the inode number only as part of recording hardlinks.)

Whether it would be a good idea to make a little filesystem that returned a zero inode value for some file is another question. Enterprising people can try it and see, which these days might be possible with various 'filesystem in user space' features (although these might filter and restrict the inode numbers that you can use). My personal expectation is that there are a variety of things that expect non-zero inode numbers for any real file and might use a zero inode number as, for example, a 'no such file' signal value.


Comments on this page:

I find this kind of topic fascinating. Quite a few things in unix have a numeric "namespace" with unspoken but api enforced constraints.

pid_t was the first one I noticed. It's a signed int so a pid can be any 32 bit positive or negative number, right?

No. Because fork(2) . It will return 0 to the child when it succeeds or, if it fails, a -1 to the parent. Ah, but there could still be negative pids - just not -1.

Nope. Those get excluded due to kill(2) . How it handles its pid_t argument is kind of complicated but it removes any possibility of a negative pid.

These constraints aren't obvious from the type and they're not very clearly written down. But they're known because the APIs depend on those constraints existing.

By Chris Barts at 2025-06-02 02:27:05:

The kernel.org documentation says inode 0 is impossible:

There is no inode 0.

[snip]

Each block group contains sb->s_inodes_per_group inodes. Because inode 0 is defined not to exist, this formula can be used to find the block group that an inode lives in: bg = (inode_num - 1) / sb->s_inodes_per_group.

https://www.kernel.org/doc/html/latest/filesystems/ext4/inodes.html

By Gavin at 2025-06-02 03:31:57:

Chris -- that just means ext4 can't have a 0 inode. That doesn't stop some other hypothetical filesystem from having a 0 inode.

By Philip Guenther at 2025-06-02 14:34:12:

The OpenBSD stat(2) and getdents(2) manual pages are similarly silent about whether or not the inode number can be zero.

I think you missed this line on the getdents(2) page:

Invalid entries with d_fileno set to 0 may be returned among regular entries.

The proper handling of that in readdir(3) was actually key to a fix in 2008 for a bug dating from at least 4.2BSD (25+ years). Here's the wayback machine view of Marc Balmer's blog point about it.

I tried to get a similar line into the posix_getdents() specification but it was rejected. I haven't implemented posix_getdents() for OpenBSD yet, but I'll probably have it zero out the (non-standard) d_off member of the entries that it returns, because I don't think we can give per-entry offset consistency without the ability to return an "ignore this" entry at offset zero (and probably at the start of each block).

Written on 30 May 2025.
« My blocking of some crawlers is an editorial decision unrelated to crawl volume
The types of TLS seen on our external SMTP MX (as of May 2025) »

Page tools: View Source, View Normal.
Search:
Login: Password:

Last modified: Fri May 30 21:17:39 2025
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.