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