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 ioutil 6 7 import ( 8 "os" 9 "path/filepath" 10 "strconv" 11 "strings" 12 "sync" 13 "time" 14 ) 15 16 // Random number state. 17 // We generate random temporary file names so that there's a good 18 // chance the file doesn't exist yet - keeps the number of tries in 19 // TempFile to a minimum. 20 var rand uint32 21 var randmu sync.Mutex 22 23 func reseed() uint32 { 24 return uint32(time.Now().UnixNano() + int64(os.Getpid())) 25 } 26 27 func nextRandom() string { 28 randmu.Lock() 29 r := rand 30 if r == 0 { 31 r = reseed() 32 } 33 r = r*1664525 + 1013904223 // constants from Numerical Recipes 34 rand = r 35 randmu.Unlock() 36 return strconv.Itoa(int(1e9 + r%1e9))[1:] 37 } 38 39 // TempFile creates a new temporary file in the directory dir, 40 // opens the file for reading and writing, and returns the resulting *os.File. 41 // The filename is generated by taking pattern and adding a random 42 // string to the end. If pattern includes a "*", the random string 43 // replaces the last "*". 44 // If dir is the empty string, TempFile uses the default directory 45 // for temporary files (see os.TempDir). 46 // Multiple programs calling TempFile simultaneously 47 // will not choose the same file. The caller can use f.Name() 48 // to find the pathname of the file. It is the caller's responsibility 49 // to remove the file when no longer needed. 50 func TempFile(dir, pattern string) (f *os.File, err error) { 51 if dir == "" { 52 dir = os.TempDir() 53 } 54 55 var prefix, suffix string 56 if pos := strings.LastIndex(pattern, "*"); pos != -1 { 57 prefix, suffix = pattern[:pos], pattern[pos+1:] 58 } else { 59 prefix = pattern 60 } 61 62 nconflict := 0 63 for i := 0; i < 10000; i++ { 64 name := filepath.Join(dir, prefix+nextRandom()+suffix) 65 f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600) 66 if os.IsExist(err) { 67 if nconflict++; nconflict > 10 { 68 randmu.Lock() 69 rand = reseed() 70 randmu.Unlock() 71 } 72 continue 73 } 74 break 75 } 76 return 77 } 78 79 // TempDir creates a new temporary directory in the directory dir 80 // with a name beginning with prefix and returns the path of the 81 // new directory. If dir is the empty string, TempDir uses the 82 // default directory for temporary files (see os.TempDir). 83 // Multiple programs calling TempDir simultaneously 84 // will not choose the same directory. It is the caller's responsibility 85 // to remove the directory when no longer needed. 86 func TempDir(dir, prefix string) (name string, err error) { 87 if dir == "" { 88 dir = os.TempDir() 89 } 90 91 nconflict := 0 92 for i := 0; i < 10000; i++ { 93 try := filepath.Join(dir, prefix+nextRandom()) 94 err = os.Mkdir(try, 0700) 95 if os.IsExist(err) { 96 if nconflict++; nconflict > 10 { 97 randmu.Lock() 98 rand = reseed() 99 randmu.Unlock() 100 } 101 continue 102 } 103 if os.IsNotExist(err) { 104 if _, err := os.Stat(dir); os.IsNotExist(err) { 105 return "", err 106 } 107 } 108 if err == nil { 109 name = try 110 } 111 break 112 } 113 return 114 } 115
View as plain text