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