github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/fs/file_overlay_test.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package fs_test 16 17 import ( 18 "reflect" 19 "testing" 20 21 "github.com/SagerNet/gvisor/pkg/context" 22 "github.com/SagerNet/gvisor/pkg/sentry/fs" 23 "github.com/SagerNet/gvisor/pkg/sentry/fs/fsutil" 24 "github.com/SagerNet/gvisor/pkg/sentry/fs/ramfs" 25 "github.com/SagerNet/gvisor/pkg/sentry/kernel/contexttest" 26 ) 27 28 func TestReaddir(t *testing.T) { 29 ctx := contexttest.Context(t) 30 ctx = &rootContext{ 31 Context: ctx, 32 root: fs.NewDirent(ctx, newTestRamfsDir(ctx, nil, nil), "root"), 33 } 34 for _, test := range []struct { 35 // Test description. 36 desc string 37 38 // Lookup parameters. 39 dir *fs.Inode 40 41 // Want from lookup. 42 err error 43 names []string 44 }{ 45 { 46 desc: "no upper, lower has entries", 47 dir: fs.NewTestOverlayDir(ctx, 48 nil, /* upper */ 49 newTestRamfsDir(ctx, []dirContent{ 50 {name: "a"}, 51 {name: "b"}, 52 }, nil), /* lower */ 53 false /* revalidate */), 54 names: []string{".", "..", "a", "b"}, 55 }, 56 { 57 desc: "upper has entries, no lower", 58 dir: fs.NewTestOverlayDir(ctx, 59 newTestRamfsDir(ctx, []dirContent{ 60 {name: "a"}, 61 {name: "b"}, 62 }, nil), /* upper */ 63 nil, /* lower */ 64 false /* revalidate */), 65 names: []string{".", "..", "a", "b"}, 66 }, 67 { 68 desc: "upper and lower, entries combine", 69 dir: fs.NewTestOverlayDir(ctx, 70 newTestRamfsDir(ctx, []dirContent{ 71 {name: "a"}, 72 }, nil), /* upper */ 73 newTestRamfsDir(ctx, []dirContent{ 74 {name: "b"}, 75 }, nil), /* lower */ 76 false /* revalidate */), 77 names: []string{".", "..", "a", "b"}, 78 }, 79 { 80 desc: "upper and lower, entries combine, none are masked", 81 dir: fs.NewTestOverlayDir(ctx, 82 newTestRamfsDir(ctx, []dirContent{ 83 {name: "a"}, 84 }, []string{"b"}), /* upper */ 85 newTestRamfsDir(ctx, []dirContent{ 86 {name: "c"}, 87 }, nil), /* lower */ 88 false /* revalidate */), 89 names: []string{".", "..", "a", "c"}, 90 }, 91 { 92 desc: "upper and lower, entries combine, upper masks some of lower", 93 dir: fs.NewTestOverlayDir(ctx, 94 newTestRamfsDir(ctx, []dirContent{ 95 {name: "a"}, 96 }, []string{"b"}), /* upper */ 97 newTestRamfsDir(ctx, []dirContent{ 98 {name: "b"}, /* will be masked */ 99 {name: "c"}, 100 }, nil), /* lower */ 101 false /* revalidate */), 102 names: []string{".", "..", "a", "c"}, 103 }, 104 } { 105 t.Run(test.desc, func(t *testing.T) { 106 openDir, err := test.dir.GetFile(ctx, fs.NewDirent(ctx, test.dir, "stub"), fs.FileFlags{Read: true}) 107 if err != nil { 108 t.Fatalf("GetFile got error %v, want nil", err) 109 } 110 stubSerializer := &fs.CollectEntriesSerializer{} 111 err = openDir.Readdir(ctx, stubSerializer) 112 if err != test.err { 113 t.Fatalf("Readdir got error %v, want nil", err) 114 } 115 if err != nil { 116 return 117 } 118 if !reflect.DeepEqual(stubSerializer.Order, test.names) { 119 t.Errorf("Readdir got names %v, want %v", stubSerializer.Order, test.names) 120 } 121 }) 122 } 123 } 124 125 func TestReaddirRevalidation(t *testing.T) { 126 ctx := contexttest.Context(t) 127 ctx = &rootContext{ 128 Context: ctx, 129 root: fs.NewDirent(ctx, newTestRamfsDir(ctx, nil, nil), "root"), 130 } 131 132 // Create an overlay with two directories, each with one file. 133 upper := newTestRamfsDir(ctx, []dirContent{{name: "a"}}, nil) 134 lower := newTestRamfsDir(ctx, []dirContent{{name: "b"}}, nil) 135 overlay := fs.NewTestOverlayDir(ctx, upper, lower, true /* revalidate */) 136 137 // Get a handle to the dirent in the upper filesystem so that we can 138 // modify it without going through the dirent. 139 upperDir := upper.InodeOperations.(*dir).InodeOperations.(*ramfs.Dir) 140 141 // Check that overlay returns the files from both upper and lower. 142 openDir, err := overlay.GetFile(ctx, fs.NewDirent(ctx, overlay, "stub"), fs.FileFlags{Read: true}) 143 if err != nil { 144 t.Fatalf("GetFile got error %v, want nil", err) 145 } 146 ser := &fs.CollectEntriesSerializer{} 147 if err := openDir.Readdir(ctx, ser); err != nil { 148 t.Fatalf("Readdir got error %v, want nil", err) 149 } 150 got, want := ser.Order, []string{".", "..", "a", "b"} 151 if !reflect.DeepEqual(got, want) { 152 t.Errorf("Readdir got names %v, want %v", got, want) 153 } 154 155 // Remove "a" from the upper and add "c". 156 if err := upperDir.Remove(ctx, upper, "a"); err != nil { 157 t.Fatalf("error removing child: %v", err) 158 } 159 upperDir.AddChild(ctx, "c", fs.NewInode(ctx, fsutil.NewSimpleFileInode(ctx, fs.RootOwner, fs.FilePermissions{}, 0), 160 upper.MountSource, fs.StableAttr{Type: fs.RegularFile})) 161 162 // Seek to beginning of the directory and do the readdir again. 163 if _, err := openDir.Seek(ctx, fs.SeekSet, 0); err != nil { 164 t.Fatalf("error seeking to beginning of dir: %v", err) 165 } 166 ser = &fs.CollectEntriesSerializer{} 167 if err := openDir.Readdir(ctx, ser); err != nil { 168 t.Fatalf("Readdir got error %v, want nil", err) 169 } 170 171 // Readdir should return the updated children. 172 got, want = ser.Order, []string{".", "..", "b", "c"} 173 if !reflect.DeepEqual(got, want) { 174 t.Errorf("Readdir got names %v, want %v", got, want) 175 } 176 } 177 178 type rootContext struct { 179 context.Context 180 root *fs.Dirent 181 } 182 183 // Value implements context.Context. 184 func (r *rootContext) Value(key interface{}) interface{} { 185 switch key { 186 case fs.CtxRoot: 187 r.root.IncRef() 188 return r.root 189 default: 190 return r.Context.Value(key) 191 } 192 }