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