Source file
src/io/ioutil/tempfile.go
1
2
3
4
5 package ioutil
6
7 import (
8 "errors"
9 "os"
10 "path/filepath"
11 "strconv"
12 "strings"
13 "sync"
14 "time"
15 )
16
17
18
19
20
21 var rand uint32
22 var randmu sync.Mutex
23
24 func reseed() uint32 {
25 return uint32(time.Now().UnixNano() + int64(os.Getpid()))
26 }
27
28 func nextRandom() string {
29 randmu.Lock()
30 r := rand
31 if r == 0 {
32 r = reseed()
33 }
34 r = r*1664525 + 1013904223
35 rand = r
36 randmu.Unlock()
37 return strconv.Itoa(int(1e9 + r%1e9))[1:]
38 }
39
40
41
42
43
44
45
46
47
48
49
50
51 func TempFile(dir, pattern string) (f *os.File, err error) {
52 if dir == "" {
53 dir = os.TempDir()
54 }
55
56 prefix, suffix, err := prefixAndSuffix(pattern)
57 if err != nil {
58 return
59 }
60
61 nconflict := 0
62 for i := 0; i < 10000; i++ {
63 name := filepath.Join(dir, prefix+nextRandom()+suffix)
64 f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
65 if os.IsExist(err) {
66 if nconflict++; nconflict > 10 {
67 randmu.Lock()
68 rand = reseed()
69 randmu.Unlock()
70 }
71 continue
72 }
73 break
74 }
75 return
76 }
77
78 var errPatternHasSeparator = errors.New("pattern contains path separator")
79
80
81
82 func prefixAndSuffix(pattern string) (prefix, suffix string, err error) {
83 if strings.ContainsRune(pattern, os.PathSeparator) {
84 err = errPatternHasSeparator
85 return
86 }
87 if pos := strings.LastIndex(pattern, "*"); pos != -1 {
88 prefix, suffix = pattern[:pos], pattern[pos+1:]
89 } else {
90 prefix = pattern
91 }
92 return
93 }
94
95
96
97
98
99
100
101
102
103
104 func TempDir(dir, pattern string) (name string, err error) {
105 if dir == "" {
106 dir = os.TempDir()
107 }
108
109 prefix, suffix, err := prefixAndSuffix(pattern)
110 if err != nil {
111 return
112 }
113
114 nconflict := 0
115 for i := 0; i < 10000; i++ {
116 try := filepath.Join(dir, prefix+nextRandom()+suffix)
117 err = os.Mkdir(try, 0700)
118 if os.IsExist(err) {
119 if nconflict++; nconflict > 10 {
120 randmu.Lock()
121 rand = reseed()
122 randmu.Unlock()
123 }
124 continue
125 }
126 if os.IsNotExist(err) {
127 if _, err := os.Stat(dir); os.IsNotExist(err) {
128 return "", err
129 }
130 }
131 if err == nil {
132 name = try
133 }
134 break
135 }
136 return
137 }
138
View as plain text