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