...
Run Format

Source file src/io/ioutil/tempfile.go

Documentation: io/ioutil

     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