Commit 0aaef6dd authored by Jakob Unterwurzacher's avatar Jakob Unterwurzacher

fs: allow inode number 1

The root directory always get nodeid 1, and the v2 api
originally had "nodeid == inode number".

But since 1d0096e5,
inode number and node id are independent, and we can allow
inode number 1.

Why does this matter? MacOS actually uses inode number 1 on ExFAT
mounts, triggering a panic on overlay filesystems like gocryptfs:

    panic: using reserved ID 1 for inode number

Fixes: https://github.com/rfjakob/gocryptfs/issues/585
Change-Id: I5e3476da65400d32efdb3dac1fe4901c64c00a89
parent efbe2d7d
...@@ -270,9 +270,6 @@ func NewNodeFS(root InodeEmbedder, opts *Options) fuse.RawFileSystem { ...@@ -270,9 +270,6 @@ func NewNodeFS(root InodeEmbedder, opts *Options) fuse.RawFileSystem {
nextNodeId: 2, // the root node has nodeid 1 nextNodeId: 2, // the root node has nodeid 1
stableAttrs: make(map[StableAttr]*Inode), stableAttrs: make(map[StableAttr]*Inode),
} }
if bridge.automaticIno == 1 {
bridge.automaticIno++
}
if bridge.automaticIno == 0 { if bridge.automaticIno == 0 {
bridge.automaticIno = 1 << 63 bridge.automaticIno = 1 << 63
......
...@@ -201,3 +201,40 @@ func (n *testDeletedIno) Getattr(ctx context.Context, f FileHandle, out *fuse.At ...@@ -201,3 +201,40 @@ func (n *testDeletedIno) Getattr(ctx context.Context, f FileHandle, out *fuse.At
// Otherwise EILSEQ // Otherwise EILSEQ
return syscall.EILSEQ return syscall.EILSEQ
} }
// TestIno1 tests that inode number 1 is allowed.
//
// We used to panic like this because inode number 1 was special:
//
// panic: using reserved ID 1 for inode number
//
func TestIno1(t *testing.T) {
rootNode := testIno1{}
mnt, _, clean := testMount(t, &rootNode, nil)
defer clean()
var st syscall.Stat_t
err := syscall.Stat(mnt+"/ino1", &st)
if err != nil {
t.Fatal(err)
}
if st.Ino != 1 {
t.Errorf("wrong inode number: want=1 have=%d", st.Ino)
}
}
type testIno1 struct {
Inode
}
func (fn *testIno1) Lookup(ctx context.Context, name string, out *fuse.EntryOut) (*Inode, syscall.Errno) {
if name != "ino1" {
return nil, syscall.ENOENT
}
stable := StableAttr{
Mode: syscall.S_IFREG,
Ino: 1,
}
child := fn.NewInode(ctx, &testIno1{}, stable)
return child, 0
}
...@@ -27,8 +27,8 @@ type StableAttr struct { ...@@ -27,8 +27,8 @@ type StableAttr struct {
// The inode number must be unique among the currently live // The inode number must be unique among the currently live
// objects in the file system. It is used to communicate to // objects in the file system. It is used to communicate to
// the kernel about this file object. The values uint64(-1), // the kernel about this file object. The value uint64(-1)
// and 1 are reserved. When using Ino==0, a unique, sequential // is reserved. When using Ino==0, a unique, sequential
// number is assigned (starting at 2^63 by default) on Inode creation. // number is assigned (starting at 2^63 by default) on Inode creation.
Ino uint64 Ino uint64
...@@ -41,7 +41,7 @@ type StableAttr struct { ...@@ -41,7 +41,7 @@ type StableAttr struct {
// Reserved returns if the StableAttr is using reserved Inode numbers. // Reserved returns if the StableAttr is using reserved Inode numbers.
func (i *StableAttr) Reserved() bool { func (i *StableAttr) Reserved() bool {
return i.Ino == 1 || i.Ino == ^uint64(0) return i.Ino == ^uint64(0) // fuse.pollHackInode = ^uint64(0)
} }
// Inode is a node in VFS tree. Inodes are one-to-one mapped to // Inode is a node in VFS tree. Inodes are one-to-one mapped to
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment