github.com/lovishpuri/go-40569/src@v0.0.0-20230519171745-f8623e7c56cf/os/tempfile.go (about) 1 // Copyright 2010 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 6 7 import ( 8 "errors" 9 "internal/itoa" 10 ) 11 12 // fastrand provided by runtime. 13 // We generate random temporary file names so that there's a good 14 // chance the file doesn't exist yet - keeps the number of tries in 15 // TempFile to a minimum. 16 func fastrand() uint32 17 18 func nextRandom() string { 19 return itoa.Uitoa(uint(fastrand())) 20 } 21 22 // CreateTemp creates a new temporary file in the directory dir, 23 // opens the file for reading and writing, and returns the resulting file. 24 // The filename is generated by taking pattern and adding a random string to the end. 25 // If pattern includes a "*", the random string replaces the last "*". 26 // If dir is the empty string, CreateTemp uses the default directory for temporary files, as returned by TempDir. 27 // Multiple programs or goroutines calling CreateTemp simultaneously will not choose the same file. 28 // The caller can use the file's Name method to find the pathname of the file. 29 // It is the caller's responsibility to remove the file when it is no longer needed. 30 func CreateTemp(dir, pattern string) (*File, error) { 31 if dir == "" { 32 dir = TempDir() 33 } 34 35 prefix, suffix, err := prefixAndSuffix(pattern) 36 if err != nil { 37 return nil, &PathError{Op: "createtemp", Path: pattern, Err: err} 38 } 39 prefix = joinPath(dir, prefix) 40 41 try := 0 42 for { 43 name := prefix + nextRandom() + suffix 44 f, err := OpenFile(name, O_RDWR|O_CREATE|O_EXCL, 0600) 45 if IsExist(err) { 46 if try++; try < 10000 { 47 continue 48 } 49 return nil, &PathError{Op: "createtemp", Path: prefix + "*" + suffix, Err: ErrExist} 50 } 51 return f, err 52 } 53 } 54 55 var errPatternHasSeparator = errors.New("pattern contains path separator") 56 57 // prefixAndSuffix splits pattern by the last wildcard "*", if applicable, 58 // returning prefix as the part before "*" and suffix as the part after "*". 59 func prefixAndSuffix(pattern string) (prefix, suffix string, err error) { 60 for i := 0; i < len(pattern); i++ { 61 if IsPathSeparator(pattern[i]) { 62 return "", "", errPatternHasSeparator 63 } 64 } 65 if pos := lastIndex(pattern, '*'); pos != -1 { 66 prefix, suffix = pattern[:pos], pattern[pos+1:] 67 } else { 68 prefix = pattern 69 } 70 return prefix, suffix, nil 71 } 72 73 // MkdirTemp creates a new temporary directory in the directory dir 74 // and returns the pathname of the new directory. 75 // The new directory's name is generated by adding a random string to the end of pattern. 76 // If pattern includes a "*", the random string replaces the last "*" instead. 77 // If dir is the empty string, MkdirTemp uses the default directory for temporary files, as returned by TempDir. 78 // Multiple programs or goroutines calling MkdirTemp simultaneously will not choose the same directory. 79 // It is the caller's responsibility to remove the directory when it is no longer needed. 80 func MkdirTemp(dir, pattern string) (string, error) { 81 if dir == "" { 82 dir = TempDir() 83 } 84 85 prefix, suffix, err := prefixAndSuffix(pattern) 86 if err != nil { 87 return "", &PathError{Op: "mkdirtemp", Path: pattern, Err: err} 88 } 89 prefix = joinPath(dir, prefix) 90 91 try := 0 92 for { 93 name := prefix + nextRandom() + suffix 94 err := Mkdir(name, 0700) 95 if err == nil { 96 return name, nil 97 } 98 if IsExist(err) { 99 if try++; try < 10000 { 100 continue 101 } 102 return "", &PathError{Op: "mkdirtemp", Path: dir + string(PathSeparator) + prefix + "*" + suffix, Err: ErrExist} 103 } 104 if IsNotExist(err) { 105 if _, err := Stat(dir); IsNotExist(err) { 106 return "", err 107 } 108 } 109 return "", err 110 } 111 } 112 113 func joinPath(dir, name string) string { 114 if len(dir) > 0 && IsPathSeparator(dir[len(dir)-1]) { 115 return dir + name 116 } 117 return dir + string(PathSeparator) + name 118 } 119 120 // lastIndex from the strings package. 121 func lastIndex(s string, sep byte) int { 122 for i := len(s) - 1; i >= 0; i-- { 123 if s[i] == sep { 124 return i 125 } 126 } 127 return -1 128 }