From 3bac814ea9f8468499c65c9b2b0a6f023e23d35e Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Sat, 22 Jan 2022 12:40:24 +0100 Subject: [PATCH] tests: add TestRenameWhiteout, TestRenameExchange f --- tests/defaults/overlayfs_test.go | 109 +++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 tests/defaults/overlayfs_test.go diff --git a/tests/defaults/overlayfs_test.go b/tests/defaults/overlayfs_test.go new file mode 100644 index 0000000..1a3298d --- /dev/null +++ b/tests/defaults/overlayfs_test.go @@ -0,0 +1,109 @@ +// +build linux + +package defaults + +import ( + "io/ioutil" + "os" + "strings" + "testing" + + "golang.org/x/sys/unix" + + "github.com/rfjakob/gocryptfs/v2/internal/syscallcompat" + "github.com/rfjakob/gocryptfs/v2/tests/test_helpers" +) + +// https://github.com/rfjakob/gocryptfs/issues/641 +// +// I was trying to run the Docker daemon with the recommended overlay2 storage driver, and encrypt its `/var/lib/docker` directory using gocryptfs. overlay2 was giving me the following errors: +// ``` +// Jan 21 19:09:43 friedhelm.rankenste.in kernel: overlayfs: upper fs does not support tmpfile. +// Jan 21 19:09:43 friedhelm.rankenste.in kernel: overlayfs: upper fs does not support RENAME_WHITEOUT. +// Jan 21 19:09:43 friedhelm.rankenste.in kernel: overlayfs: upper fs missing required features. +// ``` + +func TestRenameWhiteout(t *testing.T) { + short := t.Name() + ".short" + long := t.Name() + strings.Repeat(".long", 200/len(".long")) + + names := [][]string{ + // short to short + {short + "s2s", short + "s2s2"}, + // short to long + {short + "s2l", long + "s2l2"}, + // long to short + {long + "l2s", short + "l2s2"}, + // long to long + {long + "l2l", short + "l2l2"}, + } + + for _, flags := range []uint{syscallcompat.RENAME_WHITEOUT, syscallcompat.RENAME_WHITEOUT | syscallcompat.RENAME_NOREPLACE} { + for _, n := range names { + pSrc := test_helpers.DefaultPlainDir + "/" + n[0] + pDst := test_helpers.DefaultPlainDir + "/" + n[1] + if err := ioutil.WriteFile(pSrc, nil, 0200); err != nil { + t.Fatalf("creating empty file failed: %v", err) + } + err := unix.Renameat2(-1, pSrc, -1, pDst, flags) + if err != nil { + t.Error(err) + } + // readdir should not choke on leftover or missing .name files + _, err = os.ReadDir(test_helpers.DefaultPlainDir) + if err != nil { + t.Error(err) + } + // pSrc should now be a character device 0 file + var st unix.Stat_t + err = unix.Stat(pSrc, &st) + if err != nil { + t.Error(err) + } + if !(st.Mode&unix.S_IFMT == unix.S_IFCHR) { + t.Error("not a device file") + } + if st.Rdev != 0 { + t.Errorf("want device 0, have %d", st.Rdev) + } + unix.Unlink(pSrc) + unix.Unlink(pDst) + } + } +} + +func TestRenameExchange(t *testing.T) { + short := t.Name() + ".short" + long := t.Name() + strings.Repeat(".long", 200/len(".long")) + + names := [][]string{ + // short to short + {short + "s2s", short + "s2s2"}, + // short to long + {short + "s2l", long + "s2l2"}, + // long to short + {long + "l2s", short + "l2s2"}, + // long to long + {long + "l2l", short + "l2l2"}, + } + + for _, n := range names { + pSrc := test_helpers.DefaultPlainDir + "/" + n[0] + pDst := test_helpers.DefaultPlainDir + "/" + n[1] + if err := ioutil.WriteFile(pSrc, nil, 0200); err != nil { + t.Fatalf("creating empty file failed: %v", err) + } + if err := ioutil.WriteFile(pDst, nil, 0200); err != nil { + t.Fatalf("creating empty file failed: %v", err) + } + err := unix.Renameat2(-1, pSrc, -1, pDst, unix.RENAME_EXCHANGE) + if err != nil { + t.Error(err) + } + // readdir should not choke on leftover or missing .name files + _, err = os.ReadDir(test_helpers.DefaultPlainDir) + if err != nil { + t.Error(err) + } + } +}