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