github.com/hlts2/go@v0.0.0-20170904000733-812b34efaed8/src/io/ioutil/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 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 os.IsNotExist(err) {
    94  			if _, err := os.Stat(dir); os.IsNotExist(err) {
    95  				return "", err
    96  			}
    97  		}
    98  		if err == nil {
    99  			name = try
   100  		}
   101  		break
   102  	}
   103  	return
   104  }