github.com/bir3/gocompiler@v0.9.2202/extra/mkdir.go (about) 1 // Copyright 2023 Bergur Ragnarsson 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 extra 6 7 import ( 8 "fmt" 9 "os" 10 "path/filepath" 11 ) 12 13 type FileMode = os.FileMode 14 15 func MkdirAllRace(dir string, perm FileMode) error { 16 // safe for many processes to run concurrently 17 dir = filepath.Clean(dir) 18 if !filepath.IsAbs(dir) { 19 return fmt.Errorf("not absolute path: %s", dir) 20 } 21 missing, err := missingFolders(dir, []string{}) 22 if err != nil { 23 return err 24 } 25 for _, d2 := range missing { 26 os.Mkdir(d2, perm) // ignore error as we may race 27 } 28 29 // at the end, we want a folder to exist 30 // - no matter who created it: 31 info, err := os.Stat(dir) 32 if err != nil { 33 return fmt.Errorf("failed to create folder %s - %w", dir, err) 34 } 35 if !info.IsDir() { 36 return fmt.Errorf("not a folder %s", dir) 37 } 38 39 return nil 40 } 41 42 func missingFolders(dir string, missing []string) ([]string, error) { 43 for { 44 info, err := os.Stat(dir) 45 if err == nil { 46 if info.IsDir() { 47 return missing, nil 48 } 49 return []string{}, fmt.Errorf("not a folder: %s", dir) 50 } 51 missing = append([]string{dir}, missing...) // prepend => reverse order 52 d2 := filepath.Dir(dir) 53 if d2 == dir { 54 break 55 } 56 dir = d2 57 } 58 return []string{}, fmt.Errorf("program error at folder: %s", dir) 59 }