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