github.com/cdoern/storage@v1.12.13/pkg/mount/sharedsubtree_linux_test.go (about) 1 // +build linux 2 3 package mount 4 5 import ( 6 "os" 7 "path" 8 "testing" 9 10 "golang.org/x/sys/unix" 11 ) 12 13 // nothing is propagated in or out 14 func TestSubtreePrivate(t *testing.T) { 15 tmp := path.Join(os.TempDir(), "mount-tests") 16 if err := os.MkdirAll(tmp, 0777); err != nil { 17 t.Fatal(err) 18 } 19 defer os.RemoveAll(tmp) 20 21 var ( 22 sourceDir = path.Join(tmp, "source") 23 targetDir = path.Join(tmp, "target") 24 outside1Dir = path.Join(tmp, "outside1") 25 outside2Dir = path.Join(tmp, "outside2") 26 27 outside1Path = path.Join(outside1Dir, "file.txt") 28 outside2Path = path.Join(outside2Dir, "file.txt") 29 outside1CheckPath = path.Join(targetDir, "a", "file.txt") 30 outside2CheckPath = path.Join(sourceDir, "b", "file.txt") 31 ) 32 if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil { 33 t.Fatal(err) 34 } 35 if err := os.MkdirAll(path.Join(sourceDir, "b"), 0777); err != nil { 36 t.Fatal(err) 37 } 38 if err := os.Mkdir(targetDir, 0777); err != nil { 39 t.Fatal(err) 40 } 41 if err := os.Mkdir(outside1Dir, 0777); err != nil { 42 t.Fatal(err) 43 } 44 if err := os.Mkdir(outside2Dir, 0777); err != nil { 45 t.Fatal(err) 46 } 47 48 if err := createFile(outside1Path); err != nil { 49 t.Fatal(err) 50 } 51 if err := createFile(outside2Path); err != nil { 52 t.Fatal(err) 53 } 54 55 // mount the shared directory to a target 56 if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil { 57 t.Fatal(err) 58 } 59 defer func() { 60 if err := Unmount(targetDir); err != nil { 61 t.Fatal(err) 62 } 63 }() 64 65 // next, make the target private 66 if err := MakePrivate(targetDir); err != nil { 67 t.Fatal(err) 68 } 69 defer func() { 70 if err := Unmount(targetDir); err != nil { 71 t.Fatal(err) 72 } 73 }() 74 75 // mount in an outside path to a mounted path inside the _source_ 76 if err := Mount(outside1Dir, path.Join(sourceDir, "a"), "none", "bind,rw"); err != nil { 77 t.Fatal(err) 78 } 79 defer func() { 80 if err := Unmount(path.Join(sourceDir, "a")); err != nil { 81 t.Fatal(err) 82 } 83 }() 84 85 // check that this file _does_not_ show in the _target_ 86 if _, err := os.Stat(outside1CheckPath); err != nil && !os.IsNotExist(err) { 87 t.Fatal(err) 88 } else if err == nil { 89 t.Fatalf("%q should not be visible, but is", outside1CheckPath) 90 } 91 92 // next mount outside2Dir into the _target_ 93 if err := Mount(outside2Dir, path.Join(targetDir, "b"), "none", "bind,rw"); err != nil { 94 t.Fatal(err) 95 } 96 defer func() { 97 if err := Unmount(path.Join(targetDir, "b")); err != nil { 98 t.Fatal(err) 99 } 100 }() 101 102 // check that this file _does_not_ show in the _source_ 103 if _, err := os.Stat(outside2CheckPath); err != nil && !os.IsNotExist(err) { 104 t.Fatal(err) 105 } else if err == nil { 106 t.Fatalf("%q should not be visible, but is", outside2CheckPath) 107 } 108 } 109 110 // Testing that when a target is a shared mount, 111 // then child mounts propagate to the source 112 func TestSubtreeShared(t *testing.T) { 113 tmp := path.Join(os.TempDir(), "mount-tests") 114 if err := os.MkdirAll(tmp, 0777); err != nil { 115 t.Fatal(err) 116 } 117 defer os.RemoveAll(tmp) 118 119 var ( 120 sourceDir = path.Join(tmp, "source") 121 targetDir = path.Join(tmp, "target") 122 outsideDir = path.Join(tmp, "outside") 123 124 outsidePath = path.Join(outsideDir, "file.txt") 125 sourceCheckPath = path.Join(sourceDir, "a", "file.txt") 126 ) 127 128 if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil { 129 t.Fatal(err) 130 } 131 if err := os.Mkdir(targetDir, 0777); err != nil { 132 t.Fatal(err) 133 } 134 if err := os.Mkdir(outsideDir, 0777); err != nil { 135 t.Fatal(err) 136 } 137 138 if err := createFile(outsidePath); err != nil { 139 t.Fatal(err) 140 } 141 142 // mount the source as shared 143 if err := MakeShared(sourceDir); err != nil { 144 t.Fatal(err) 145 } 146 defer func() { 147 if err := Unmount(sourceDir); err != nil { 148 t.Fatal(err) 149 } 150 }() 151 152 // mount the shared directory to a target 153 if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil { 154 t.Fatal(err) 155 } 156 defer func() { 157 if err := Unmount(targetDir); err != nil { 158 t.Fatal(err) 159 } 160 }() 161 162 // mount in an outside path to a mounted path inside the target 163 if err := Mount(outsideDir, path.Join(targetDir, "a"), "none", "bind,rw"); err != nil { 164 t.Fatal(err) 165 } 166 defer func() { 167 if err := Unmount(path.Join(targetDir, "a")); err != nil { 168 t.Fatal(err) 169 } 170 }() 171 172 // NOW, check that the file from the outside directory is available in the source directory 173 if _, err := os.Stat(sourceCheckPath); err != nil { 174 t.Fatal(err) 175 } 176 } 177 178 // testing that mounts to a shared source show up in the slave target, 179 // and that mounts into a slave target do _not_ show up in the shared source 180 func TestSubtreeSharedSlave(t *testing.T) { 181 tmp := path.Join(os.TempDir(), "mount-tests") 182 if err := os.MkdirAll(tmp, 0777); err != nil { 183 t.Fatal(err) 184 } 185 defer os.RemoveAll(tmp) 186 187 var ( 188 sourceDir = path.Join(tmp, "source") 189 targetDir = path.Join(tmp, "target") 190 outside1Dir = path.Join(tmp, "outside1") 191 outside2Dir = path.Join(tmp, "outside2") 192 193 outside1Path = path.Join(outside1Dir, "file.txt") 194 outside2Path = path.Join(outside2Dir, "file.txt") 195 outside1CheckPath = path.Join(targetDir, "a", "file.txt") 196 outside2CheckPath = path.Join(sourceDir, "b", "file.txt") 197 ) 198 if err := os.MkdirAll(path.Join(sourceDir, "a"), 0777); err != nil { 199 t.Fatal(err) 200 } 201 if err := os.MkdirAll(path.Join(sourceDir, "b"), 0777); err != nil { 202 t.Fatal(err) 203 } 204 if err := os.Mkdir(targetDir, 0777); err != nil { 205 t.Fatal(err) 206 } 207 if err := os.Mkdir(outside1Dir, 0777); err != nil { 208 t.Fatal(err) 209 } 210 if err := os.Mkdir(outside2Dir, 0777); err != nil { 211 t.Fatal(err) 212 } 213 214 if err := createFile(outside1Path); err != nil { 215 t.Fatal(err) 216 } 217 if err := createFile(outside2Path); err != nil { 218 t.Fatal(err) 219 } 220 221 // mount the source as shared 222 if err := MakeShared(sourceDir); err != nil { 223 t.Fatal(err) 224 } 225 defer func() { 226 if err := Unmount(sourceDir); err != nil { 227 t.Fatal(err) 228 } 229 }() 230 231 // mount the shared directory to a target 232 if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil { 233 t.Fatal(err) 234 } 235 defer func() { 236 if err := Unmount(targetDir); err != nil { 237 t.Fatal(err) 238 } 239 }() 240 241 // next, make the target slave 242 if err := MakeSlave(targetDir); err != nil { 243 t.Fatal(err) 244 } 245 defer func() { 246 if err := Unmount(targetDir); err != nil { 247 t.Fatal(err) 248 } 249 }() 250 251 // mount in an outside path to a mounted path inside the _source_ 252 if err := Mount(outside1Dir, path.Join(sourceDir, "a"), "none", "bind,rw"); err != nil { 253 t.Fatal(err) 254 } 255 defer func() { 256 if err := Unmount(path.Join(sourceDir, "a")); err != nil { 257 t.Fatal(err) 258 } 259 }() 260 261 // check that this file _does_ show in the _target_ 262 if _, err := os.Stat(outside1CheckPath); err != nil { 263 t.Fatal(err) 264 } 265 266 // next mount outside2Dir into the _target_ 267 if err := Mount(outside2Dir, path.Join(targetDir, "b"), "none", "bind,rw"); err != nil { 268 t.Fatal(err) 269 } 270 defer func() { 271 if err := Unmount(path.Join(targetDir, "b")); err != nil { 272 t.Fatal(err) 273 } 274 }() 275 276 // check that this file _does_not_ show in the _source_ 277 if _, err := os.Stat(outside2CheckPath); err != nil && !os.IsNotExist(err) { 278 t.Fatal(err) 279 } else if err == nil { 280 t.Fatalf("%q should not be visible, but is", outside2CheckPath) 281 } 282 } 283 284 func TestSubtreeUnbindable(t *testing.T) { 285 tmp := path.Join(os.TempDir(), "mount-tests") 286 if err := os.MkdirAll(tmp, 0777); err != nil { 287 t.Fatal(err) 288 } 289 defer os.RemoveAll(tmp) 290 291 var ( 292 sourceDir = path.Join(tmp, "source") 293 targetDir = path.Join(tmp, "target") 294 ) 295 if err := os.MkdirAll(sourceDir, 0777); err != nil { 296 t.Fatal(err) 297 } 298 if err := os.MkdirAll(targetDir, 0777); err != nil { 299 t.Fatal(err) 300 } 301 302 // next, make the source unbindable 303 if err := MakeUnbindable(sourceDir); err != nil { 304 t.Fatal(err) 305 } 306 defer func() { 307 if err := Unmount(sourceDir); err != nil { 308 t.Fatal(err) 309 } 310 }() 311 312 // then attempt to mount it to target. It should fail 313 if err := Mount(sourceDir, targetDir, "none", "bind,rw"); err != nil && err != unix.EINVAL { 314 t.Fatal(err) 315 } else if err == nil { 316 t.Fatalf("%q should not have been bindable", sourceDir) 317 } 318 defer func() { 319 if err := Unmount(targetDir); err != nil { 320 t.Fatal(err) 321 } 322 }() 323 } 324 325 func createFile(path string) error { 326 f, err := os.Create(path) 327 if err != nil { 328 return err 329 } 330 f.WriteString("hello world!") 331 return f.Close() 332 }