src/pkg/io/ioutil/tempfile.go - The Go Programming Language

Golang

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		"time"
    12	)
    13	
    14	// Random number state, accessed without lock; racy but harmless.
    15	// We generate random temporary file names so that there's a good
    16	// chance the file doesn't exist yet - keeps the number of tries in
    17	// TempFile to a minimum.
    18	var rand uint32
    19	
    20	func reseed() uint32 {
    21		return uint32(time.Now().UnixNano() + 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 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 os.IsExist(err) {
    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 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 os.IsExist(err) {
    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	}