github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/os/removeall_test.go (about) 1 //go:build darwin || (linux && !baremetal && !js && !wasi) 2 3 // TODO: implement ReadDir on windows 4 5 // Copyright 2018 The Go Authors. All rights reserved. 6 // Use of this source code is governed by a BSD-style 7 // license that can be found in the LICENSE file. 8 9 package os_test 10 11 import ( 12 "fmt" 13 "os" 14 . "os" 15 "path/filepath" 16 "runtime" 17 "testing" 18 ) 19 20 func TestRemoveAll(t *testing.T) { 21 tmpDir, _ := os.MkdirTemp("", "TestRemoveAll") 22 if err := RemoveAll(""); err != nil { 23 t.Errorf("RemoveAll(\"\"): %v; want nil", err) 24 } 25 26 file := filepath.Join(tmpDir, "file") 27 path := filepath.Join(tmpDir, "_TestRemoveAll_") 28 fpath := filepath.Join(path, "file") 29 dpath := filepath.Join(path, "dir") 30 31 // Make a regular file and remove 32 fd, err := Create(file) 33 if err != nil { 34 t.Fatalf("create %q: %s", file, err) 35 } 36 fd.Close() 37 if err = RemoveAll(file); err != nil { 38 t.Fatalf("RemoveAll %q (first): %s", file, err) 39 } 40 if _, err = Lstat(file); err == nil { 41 t.Fatalf("Lstat %q succeeded after RemoveAll (first)", file) 42 } 43 44 // Make directory with 1 file and remove. 45 if err := MkdirAll(path, 0777); err != nil { 46 t.Fatalf("MkdirAll %q: %s", path, err) 47 } 48 fd, err = Create(fpath) 49 if err != nil { 50 t.Fatalf("create %q: %s", fpath, err) 51 } 52 fd.Close() 53 if err = RemoveAll(path); err != nil { 54 t.Fatalf("RemoveAll %q (second): %s", path, err) 55 } 56 if _, err = Lstat(path); err == nil { 57 t.Fatalf("Lstat %q succeeded after RemoveAll (second)", path) 58 } 59 60 // Make directory with file and subdirectory and remove. 61 if err = MkdirAll(dpath, 0777); err != nil { 62 t.Fatalf("MkdirAll %q: %s", dpath, err) 63 } 64 fd, err = Create(fpath) 65 if err != nil { 66 t.Fatalf("create %q: %s", fpath, err) 67 } 68 fd.Close() 69 fd, err = Create(dpath + "/file") 70 if err != nil { 71 t.Fatalf("create %q: %s", fpath, err) 72 } 73 fd.Close() 74 if err = RemoveAll(path); err != nil { 75 t.Fatalf("RemoveAll %q (third): %s", path, err) 76 } 77 if _, err := Lstat(path); err == nil { 78 t.Fatalf("Lstat %q succeeded after RemoveAll (third)", path) 79 } 80 81 // Chmod is not supported under Windows and test fails as root. 82 if runtime.GOOS != "windows" && Getuid() != 0 { 83 // Make directory with file and subdirectory and trigger error. 84 if err = MkdirAll(dpath, 0777); err != nil { 85 t.Fatalf("MkdirAll %q: %s", dpath, err) 86 } 87 88 for _, s := range []string{fpath, dpath + "/file1", path + "/zzz"} { 89 fd, err = Create(s) 90 if err != nil { 91 t.Fatalf("create %q: %s", s, err) 92 } 93 fd.Close() 94 } 95 if err = Chmod(dpath, 0); err != nil { 96 t.Fatalf("Chmod %q 0: %s", dpath, err) 97 } 98 99 // No error checking here: either RemoveAll 100 // will or won't be able to remove dpath; 101 // either way we want to see if it removes fpath 102 // and path/zzz. Reasons why RemoveAll might 103 // succeed in removing dpath as well include: 104 // * running as root 105 // * running on a file system without permissions (FAT) 106 RemoveAll(path) 107 Chmod(dpath, 0777) 108 109 for _, s := range []string{fpath, path + "/zzz"} { 110 if _, err = Lstat(s); err == nil { 111 t.Fatalf("Lstat %q succeeded after partial RemoveAll", s) 112 } 113 } 114 } 115 if err = RemoveAll(path); err != nil { 116 t.Fatalf("RemoveAll %q after partial RemoveAll: %s", path, err) 117 } 118 if _, err = Lstat(path); err == nil { 119 t.Fatalf("Lstat %q succeeded after RemoveAll (final)", path) 120 } 121 } 122 123 // Test RemoveAll on a large directory. 124 func TestRemoveAllLarge(t *testing.T) { 125 if testing.Short() { 126 t.Skip("skipping in short mode") 127 } 128 129 tmpDir, _ := os.MkdirTemp("", "TestRemoveAllLarge") 130 path := filepath.Join(tmpDir, "_TestRemoveAllLarge_") 131 132 // Make directory with 1000 files and remove. 133 if err := MkdirAll(path, 0777); err != nil { 134 t.Fatalf("MkdirAll %q: %s", path, err) 135 } 136 for i := 0; i < 1000; i++ { 137 fpath := fmt.Sprintf("%s/file%d", path, i) 138 fd, err := Create(fpath) 139 if err != nil { 140 t.Fatalf("create %q: %s", fpath, err) 141 } 142 fd.Close() 143 } 144 if err := RemoveAll(path); err != nil { 145 t.Fatalf("RemoveAll %q: %s", path, err) 146 } 147 if _, err := Lstat(path); err == nil { 148 t.Fatalf("Lstat %q succeeded after RemoveAll", path) 149 } 150 } 151 152 func TestRemoveAllDot(t *testing.T) { 153 prevDir, err := Getwd() 154 if err != nil { 155 t.Fatalf("Could not get wd: %s", err) 156 } 157 tempDir, err := os.MkdirTemp("", "TestRemoveAllDot-") 158 if err != nil { 159 t.Fatalf("Could not create TempDir: %s", err) 160 } 161 defer RemoveAll(tempDir) 162 163 err = Chdir(tempDir) 164 if err != nil { 165 t.Fatalf("Could not chdir to tempdir: %s", err) 166 } 167 168 err = RemoveAll(".") 169 if err == nil { 170 t.Errorf("RemoveAll succeed to remove .") 171 } 172 173 err = Chdir(prevDir) 174 if err != nil { 175 t.Fatalf("Could not chdir %s: %s", prevDir, err) 176 } 177 } 178 179 func TestRemoveAllDotDot(t *testing.T) { 180 t.Parallel() 181 182 tempDir, _ := os.MkdirTemp("", "TestRemoveAllDotDot") 183 subdir := filepath.Join(tempDir, "x") 184 subsubdir := filepath.Join(subdir, "y") 185 if err := MkdirAll(subsubdir, 0777); err != nil { 186 t.Fatal(err) 187 } 188 if err := RemoveAll(filepath.Join(subsubdir, "..")); err != nil { 189 t.Error(err) 190 } 191 for _, dir := range []string{subsubdir, subdir} { 192 if _, err := Stat(dir); err == nil { 193 t.Errorf("%s: exists after RemoveAll", dir) 194 } 195 } 196 } 197 198 // Issue #29178. 199 func TestRemoveReadOnlyDir(t *testing.T) { 200 t.Parallel() 201 202 tempDir, _ := os.MkdirTemp("", "TestRemoveReadOnlyDir") 203 subdir := filepath.Join(tempDir, "x") 204 if err := Mkdir(subdir, 0); err != nil { 205 t.Fatal(err) 206 } 207 208 // If an error occurs make it more likely that removing the 209 // temporary directory will succeed. 210 defer Chmod(subdir, 0777) 211 212 if err := RemoveAll(subdir); err != nil { 213 t.Fatal(err) 214 } 215 216 if _, err := Stat(subdir); err == nil { 217 t.Error("subdirectory was not removed") 218 } 219 } 220 221 // Issue #29983. 222 func TestRemoveAllButReadOnlyAndPathError(t *testing.T) { 223 switch runtime.GOOS { 224 case "js", "windows": 225 t.Skipf("skipping test on %s", runtime.GOOS) 226 } 227 228 if Getuid() == 0 { 229 t.Skip("skipping test when running as root") 230 } 231 232 t.Parallel() 233 234 tempDir, _ := os.MkdirTemp("", "TestRemoveAllButReadOnlyAndPathError") 235 dirs := []string{ 236 "a", 237 "a/x", 238 "a/x/1", 239 "b", 240 "b/y", 241 "b/y/2", 242 "c", 243 "c/z", 244 "c/z/3", 245 } 246 readonly := []string{ 247 "b", 248 } 249 inReadonly := func(d string) bool { 250 for _, ro := range readonly { 251 if d == ro { 252 return true 253 } 254 dd, _ := filepath.Split(d) 255 if filepath.Clean(dd) == ro { 256 return true 257 } 258 } 259 return false 260 } 261 262 for _, dir := range dirs { 263 if err := Mkdir(filepath.Join(tempDir, dir), 0777); err != nil { 264 t.Fatal(err) 265 } 266 } 267 for _, dir := range readonly { 268 d := filepath.Join(tempDir, dir) 269 if err := Chmod(d, 0555); err != nil { 270 t.Fatal(err) 271 } 272 273 // Defer changing the mode back so that the deferred 274 // RemoveAll(tempDir) can succeed. 275 defer Chmod(d, 0777) 276 } 277 278 err := RemoveAll(tempDir) 279 if err == nil { 280 t.Fatal("RemoveAll succeeded unexpectedly") 281 } 282 283 // The error should be of type *PathError. 284 // see issue 30491 for details. 285 if pathErr, ok := err.(*PathError); ok { 286 want := filepath.Join(tempDir, "b", "y") 287 if pathErr.Path != want { 288 t.Errorf("RemoveAll(%q): err.Path=%q, want %q", tempDir, pathErr.Path, want) 289 } 290 } else { 291 t.Errorf("RemoveAll(%q): error has type %T, want *fs.PathError", tempDir, err) 292 } 293 294 for _, dir := range dirs { 295 _, err := Stat(filepath.Join(tempDir, dir)) 296 if inReadonly(dir) { 297 if err != nil { 298 t.Errorf("file %q was deleted but should still exist", dir) 299 } 300 } else { 301 if err == nil { 302 t.Errorf("file %q still exists but should have been deleted", dir) 303 } 304 } 305 } 306 } 307 308 func TestRemoveUnreadableDir(t *testing.T) { 309 switch runtime.GOOS { 310 case "js": 311 t.Skipf("skipping test on %s", runtime.GOOS) 312 } 313 314 if Getuid() == 0 { 315 t.Skip("skipping test when running as root") 316 } 317 318 t.Parallel() 319 320 tempDir, _ := os.MkdirTemp("", "TestRemoveUnreadableDir") 321 target := filepath.Join(tempDir, "d0", "d1", "d2") 322 if err := MkdirAll(target, 0755); err != nil { 323 t.Fatal(err) 324 } 325 if err := Chmod(target, 0300); err != nil { 326 t.Fatal(err) 327 } 328 if err := RemoveAll(filepath.Join(tempDir, "d0")); err != nil { 329 t.Fatal(err) 330 } 331 } 332 333 // Issue 29921 334 func TestRemoveAllWithMoreErrorThanReqSize(t *testing.T) { 335 if testing.Short() { 336 t.Skip("skipping in short mode") 337 } 338 339 tmpDir, _ := os.MkdirTemp("", "TestRemoveAllWithMoreErrorThanReqSize") 340 path := filepath.Join(tmpDir, "_TestRemoveAllWithMoreErrorThanReqSize_") 341 342 // Make directory with 1025 read-only files. 343 if err := MkdirAll(path, 0777); err != nil { 344 t.Fatalf("MkdirAll %q: %s", path, err) 345 } 346 for i := 0; i < 1025; i++ { 347 fpath := filepath.Join(path, fmt.Sprintf("file%d", i)) 348 fd, err := Create(fpath) 349 if err != nil { 350 t.Fatalf("create %q: %s", fpath, err) 351 } 352 fd.Close() 353 } 354 355 // Make the parent directory read-only. On some platforms, this is what 356 // prevents os.Remove from removing the files within that directory. 357 if err := Chmod(path, 0555); err != nil { 358 t.Fatal(err) 359 } 360 defer Chmod(path, 0755) 361 362 // This call should not hang, even on a platform that disallows file deletion 363 // from read-only directories. 364 err := RemoveAll(path) 365 366 if Getuid() == 0 { 367 // On many platforms, root can remove files from read-only directories. 368 return 369 } 370 if err == nil { 371 if runtime.GOOS == "windows" { 372 // Marking a directory as read-only in Windows does not prevent the RemoveAll 373 // from creating or removing files within it. 374 return 375 } 376 t.Fatal("RemoveAll(<read-only directory>) = nil; want error") 377 } 378 379 dir, err := Open(path) 380 if err != nil { 381 t.Fatal(err) 382 } 383 defer dir.Close() 384 385 names, _ := dir.Readdirnames(1025) 386 if len(names) < 1025 { 387 t.Fatalf("RemoveAll(<read-only directory>) unexpectedly removed %d read-only files from that directory", 1025-len(names)) 388 } 389 }