summaryrefslogtreecommitdiff
path: root/tests/defaults/overlayfs_test.go
blob: 8cb773da04c337d96f7a4934c10d00f0f3f15768 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
//go:build linux
// +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
			dir, err := os.Open(test_helpers.DefaultPlainDir)
			if err != nil {
				t.Fatal(err)
			}
			defer dir.Close()
			_, err = dir.Readdir(0)
			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
		dir, err := os.Open(test_helpers.DefaultPlainDir)
		if err != nil {
			t.Fatal(err)
		}
		defer dir.Close()
		_, err = dir.Readdir(0)
		if err != nil {
			t.Error(err)
		}
	}
}

// Looks like the FUSE protocol does support O_TMPFILE yet
func TestOTmpfile(t *testing.T) {
	p := test_helpers.DefaultPlainDir + "/" + t.Name()
	fd, err := unix.Openat(-1, p, unix.O_TMPFILE, 0600)
	if err != nil {
		t.Skip(err)
	}
	unix.Close(fd)
}