...

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		"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