// Copyright (c) 2026 Petr BalvĂ­n (https://petrbalvin.org) // SPDX-License-Identifier: MIT //go:build linux package nfsfs import ( "os" "path/filepath" "testing" ) func TestLocalXattr(t *testing.T) { root := t.TempDir() if err := os.WriteFile(filepath.Join(root, "a.txt"), []byte("x"), 0o644); err != nil { t.Fatal(err) } l, err := NewLocal(root) if err != nil { t.Fatal(err) } rootHandle, err := l.Root() if err != nil { t.Fatal(err) } fh, _, err := l.Lookup(rootHandle, "a.txt") if err != nil { t.Fatal(err) } if _, err := l.GetXattr(fh, "user.tag", 0); err != ErrNoXattr { t.Fatalf("missing attribute: %v", err) } if err := l.SetXattr(fh, "user.tag", []byte("value"), XattrModeCreate); err != nil { t.Fatalf("create: %v", err) } if err := l.SetXattr(fh, "user.tag", []byte("again"), XattrModeCreate); err == nil { t.Fatal("create over a live attribute succeeded") } got, err := l.GetXattr(fh, "user.tag", 0) if err != nil || string(got) != "value" { t.Fatalf("value after the refused create %q: %v", got, err) } if err := l.SetXattr(fh, "user.tag", []byte("again"), XattrModeReplace); err != nil { t.Fatalf("replace: %v", err) } got, err = l.GetXattr(fh, "user.tag", 0) if err != nil || string(got) != "again" { t.Fatalf("value after the replace %q: %v", got, err) } names, err := l.ListXattr(fh, 0) if err != nil || len(names) != 1 || names[0] != "user.tag" { t.Fatalf("names %v: %v", names, err) } if err := l.SetXattr(fh, "system.nfs", []byte("x"), XattrModeCreate); err == nil { t.Fatal("a foreign namespace was accepted") } if err := l.RemoveXattr(fh, "user.tag"); err != nil { t.Fatalf("remove: %v", err) } if err := l.RemoveXattr(fh, "user.tag"); err != ErrNoXattr { t.Fatalf("remove again: %v", err) } }