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