Home | History | Annotate | Download | only in os
      1 // Copyright 2009 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 	"internal/testenv"
      9 	"io/ioutil"
     10 	. "os"
     11 	"path/filepath"
     12 	"runtime"
     13 	"syscall"
     14 	"testing"
     15 )
     16 
     17 var isReadonlyError = func(error) bool { return false }
     18 
     19 func TestMkdirAll(t *testing.T) {
     20 	tmpDir := TempDir()
     21 	path := tmpDir + "/_TestMkdirAll_/dir/./dir2"
     22 	err := MkdirAll(path, 0777)
     23 	if err != nil {
     24 		t.Fatalf("MkdirAll %q: %s", path, err)
     25 	}
     26 	defer RemoveAll(tmpDir + "/_TestMkdirAll_")
     27 
     28 	// Already exists, should succeed.
     29 	err = MkdirAll(path, 0777)
     30 	if err != nil {
     31 		t.Fatalf("MkdirAll %q (second time): %s", path, err)
     32 	}
     33 
     34 	// Make file.
     35 	fpath := path + "/file"
     36 	f, err := Create(fpath)
     37 	if err != nil {
     38 		t.Fatalf("create %q: %s", fpath, err)
     39 	}
     40 	defer f.Close()
     41 
     42 	// Can't make directory named after file.
     43 	err = MkdirAll(fpath, 0777)
     44 	if err == nil {
     45 		t.Fatalf("MkdirAll %q: no error", fpath)
     46 	}
     47 	perr, ok := err.(*PathError)
     48 	if !ok {
     49 		t.Fatalf("MkdirAll %q returned %T, not *PathError", fpath, err)
     50 	}
     51 	if filepath.Clean(perr.Path) != filepath.Clean(fpath) {
     52 		t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", fpath, filepath.Clean(perr.Path), filepath.Clean(fpath))
     53 	}
     54 
     55 	// Can't make subdirectory of file.
     56 	ffpath := fpath + "/subdir"
     57 	err = MkdirAll(ffpath, 0777)
     58 	if err == nil {
     59 		t.Fatalf("MkdirAll %q: no error", ffpath)
     60 	}
     61 	perr, ok = err.(*PathError)
     62 	if !ok {
     63 		t.Fatalf("MkdirAll %q returned %T, not *PathError", ffpath, err)
     64 	}
     65 	if filepath.Clean(perr.Path) != filepath.Clean(fpath) {
     66 		t.Fatalf("MkdirAll %q returned wrong error path: %q not %q", ffpath, filepath.Clean(perr.Path), filepath.Clean(fpath))
     67 	}
     68 
     69 	if runtime.GOOS == "windows" {
     70 		path := tmpDir + `\_TestMkdirAll_\dir\.\dir2\`
     71 		err := MkdirAll(path, 0777)
     72 		if err != nil {
     73 			t.Fatalf("MkdirAll %q: %s", path, err)
     74 		}
     75 	}
     76 }
     77 
     78 func TestRemoveAll(t *testing.T) {
     79 	tmpDir := TempDir()
     80 	// Work directory.
     81 	path := tmpDir + "/_TestRemoveAll_"
     82 	fpath := path + "/file"
     83 	dpath := path + "/dir"
     84 
     85 	// Make directory with 1 file and remove.
     86 	if err := MkdirAll(path, 0777); err != nil {
     87 		t.Fatalf("MkdirAll %q: %s", path, err)
     88 	}
     89 	fd, err := Create(fpath)
     90 	if err != nil {
     91 		t.Fatalf("create %q: %s", fpath, err)
     92 	}
     93 	fd.Close()
     94 	if err = RemoveAll(path); err != nil {
     95 		t.Fatalf("RemoveAll %q (first): %s", path, err)
     96 	}
     97 	if _, err = Lstat(path); err == nil {
     98 		t.Fatalf("Lstat %q succeeded after RemoveAll (first)", path)
     99 	}
    100 
    101 	// Make directory with file and subdirectory and remove.
    102 	if err = MkdirAll(dpath, 0777); err != nil {
    103 		t.Fatalf("MkdirAll %q: %s", dpath, err)
    104 	}
    105 	fd, err = Create(fpath)
    106 	if err != nil {
    107 		t.Fatalf("create %q: %s", fpath, err)
    108 	}
    109 	fd.Close()
    110 	fd, err = Create(dpath + "/file")
    111 	if err != nil {
    112 		t.Fatalf("create %q: %s", fpath, err)
    113 	}
    114 	fd.Close()
    115 	if err = RemoveAll(path); err != nil {
    116 		t.Fatalf("RemoveAll %q (second): %s", path, err)
    117 	}
    118 	if _, err := Lstat(path); err == nil {
    119 		t.Fatalf("Lstat %q succeeded after RemoveAll (second)", path)
    120 	}
    121 
    122 	// Determine if we should run the following test.
    123 	testit := true
    124 	if runtime.GOOS == "windows" {
    125 		// Chmod is not supported under windows.
    126 		testit = false
    127 	} else {
    128 		// Test fails as root.
    129 		testit = Getuid() != 0
    130 	}
    131 	if testit {
    132 		// Make directory with file and subdirectory and trigger error.
    133 		if err = MkdirAll(dpath, 0777); err != nil {
    134 			t.Fatalf("MkdirAll %q: %s", dpath, err)
    135 		}
    136 
    137 		for _, s := range []string{fpath, dpath + "/file1", path + "/zzz"} {
    138 			fd, err = Create(s)
    139 			if err != nil {
    140 				t.Fatalf("create %q: %s", s, err)
    141 			}
    142 			fd.Close()
    143 		}
    144 		if err = Chmod(dpath, 0); err != nil {
    145 			t.Fatalf("Chmod %q 0: %s", dpath, err)
    146 		}
    147 
    148 		// No error checking here: either RemoveAll
    149 		// will or won't be able to remove dpath;
    150 		// either way we want to see if it removes fpath
    151 		// and path/zzz. Reasons why RemoveAll might
    152 		// succeed in removing dpath as well include:
    153 		//	* running as root
    154 		//	* running on a file system without permissions (FAT)
    155 		RemoveAll(path)
    156 		Chmod(dpath, 0777)
    157 
    158 		for _, s := range []string{fpath, path + "/zzz"} {
    159 			if _, err = Lstat(s); err == nil {
    160 				t.Fatalf("Lstat %q succeeded after partial RemoveAll", s)
    161 			}
    162 		}
    163 	}
    164 	if err = RemoveAll(path); err != nil {
    165 		t.Fatalf("RemoveAll %q after partial RemoveAll: %s", path, err)
    166 	}
    167 	if _, err = Lstat(path); err == nil {
    168 		t.Fatalf("Lstat %q succeeded after RemoveAll (final)", path)
    169 	}
    170 }
    171 
    172 func TestMkdirAllWithSymlink(t *testing.T) {
    173 	testenv.MustHaveSymlink(t)
    174 
    175 	tmpDir, err := ioutil.TempDir("", "TestMkdirAllWithSymlink-")
    176 	if err != nil {
    177 		t.Fatal(err)
    178 	}
    179 	defer RemoveAll(tmpDir)
    180 
    181 	dir := tmpDir + "/dir"
    182 	err = Mkdir(dir, 0755)
    183 	if err != nil {
    184 		t.Fatalf("Mkdir %s: %s", dir, err)
    185 	}
    186 
    187 	link := tmpDir + "/link"
    188 	err = Symlink("dir", link)
    189 	if err != nil {
    190 		t.Fatalf("Symlink %s: %s", link, err)
    191 	}
    192 
    193 	path := link + "/foo"
    194 	err = MkdirAll(path, 0755)
    195 	if err != nil {
    196 		t.Errorf("MkdirAll %q: %s", path, err)
    197 	}
    198 }
    199 
    200 func TestMkdirAllAtSlash(t *testing.T) {
    201 	switch runtime.GOOS {
    202 	case "android", "plan9", "windows":
    203 		t.Skipf("skipping on %s", runtime.GOOS)
    204 	case "darwin":
    205 		switch runtime.GOARCH {
    206 		case "arm", "arm64":
    207 			t.Skipf("skipping on darwin/%s, mkdir returns EPERM", runtime.GOARCH)
    208 		}
    209 	}
    210 	RemoveAll("/_go_os_test")
    211 	const dir = "/_go_os_test/dir"
    212 	err := MkdirAll(dir, 0777)
    213 	if err != nil {
    214 		pathErr, ok := err.(*PathError)
    215 		// common for users not to be able to write to /
    216 		if ok && (pathErr.Err == syscall.EACCES || isReadonlyError(pathErr.Err)) {
    217 			t.Skipf("could not create %v: %v", dir, err)
    218 		}
    219 		t.Fatalf(`MkdirAll "/_go_os_test/dir": %v, %s`, err, pathErr.Err)
    220 	}
    221 	RemoveAll("/_go_os_test")
    222 }
    223