...

Source file src/os/tempfile.go

Documentation: os

		 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 os
		 6  
		 7  import (
		 8  	"errors"
		 9  	"internal/itoa"
		10  )
		11  
		12  // fastrand provided by runtime.
		13  // We generate random temporary file names so that there's a good
		14  // chance the file doesn't exist yet - keeps the number of tries in
		15  // TempFile to a minimum.
		16  func fastrand() uint32
		17  
		18  func nextRandom() string {
		19  	return itoa.Uitoa(uint(fastrand()))
		20  }
		21  
		22  // CreateTemp creates a new temporary file in the directory dir,
		23  // opens the file for reading and writing, and returns the resulting file.
		24  // The filename is generated by taking pattern and adding a random string to the end.
		25  // If pattern includes a "*", the random string replaces the last "*".
		26  // If dir is the empty string, CreateTemp uses the default directory for temporary files, as returned by TempDir.
		27  // Multiple programs or goroutines calling CreateTemp simultaneously will not choose the same file.
		28  // The caller can use the file's Name method to find the pathname of the file.
		29  // It is the caller's responsibility to remove the file when it is no longer needed.
		30  func CreateTemp(dir, pattern string) (*File, error) {
		31  	if dir == "" {
		32  		dir = TempDir()
		33  	}
		34  
		35  	prefix, suffix, err := prefixAndSuffix(pattern)
		36  	if err != nil {
		37  		return nil, &PathError{Op: "createtemp", Path: pattern, Err: err}
		38  	}
		39  	prefix = joinPath(dir, prefix)
		40  
		41  	try := 0
		42  	for {
		43  		name := prefix + nextRandom() + suffix
		44  		f, err := OpenFile(name, O_RDWR|O_CREATE|O_EXCL, 0600)
		45  		if IsExist(err) {
		46  			if try++; try < 10000 {
		47  				continue
		48  			}
		49  			return nil, &PathError{Op: "createtemp", Path: dir + string(PathSeparator) + prefix + "*" + suffix, Err: ErrExist}
		50  		}
		51  		return f, err
		52  	}
		53  }
		54  
		55  var errPatternHasSeparator = errors.New("pattern contains path separator")
		56  
		57  // prefixAndSuffix splits pattern by the last wildcard "*", if applicable,
		58  // returning prefix as the part before "*" and suffix as the part after "*".
		59  func prefixAndSuffix(pattern string) (prefix, suffix string, err error) {
		60  	for i := 0; i < len(pattern); i++ {
		61  		if IsPathSeparator(pattern[i]) {
		62  			return "", "", errPatternHasSeparator
		63  		}
		64  	}
		65  	if pos := lastIndex(pattern, '*'); pos != -1 {
		66  		prefix, suffix = pattern[:pos], pattern[pos+1:]
		67  	} else {
		68  		prefix = pattern
		69  	}
		70  	return prefix, suffix, nil
		71  }
		72  
		73  // MkdirTemp creates a new temporary directory in the directory dir
		74  // and returns the pathname of the new directory.
		75  // The new directory's name is generated by adding a random string to the end of pattern.
		76  // If pattern includes a "*", the random string replaces the last "*" instead.
		77  // If dir is the empty string, MkdirTemp uses the default directory for temporary files, as returned by TempDir.
		78  // Multiple programs or goroutines calling MkdirTemp simultaneously will not choose the same directory.
		79  // It is the caller's responsibility to remove the directory when it is no longer needed.
		80  func MkdirTemp(dir, pattern string) (string, error) {
		81  	if dir == "" {
		82  		dir = TempDir()
		83  	}
		84  
		85  	prefix, suffix, err := prefixAndSuffix(pattern)
		86  	if err != nil {
		87  		return "", &PathError{Op: "mkdirtemp", Path: pattern, Err: err}
		88  	}
		89  	prefix = joinPath(dir, prefix)
		90  
		91  	try := 0
		92  	for {
		93  		name := prefix + nextRandom() + suffix
		94  		err := Mkdir(name, 0700)
		95  		if err == nil {
		96  			return name, nil
		97  		}
		98  		if IsExist(err) {
		99  			if try++; try < 10000 {
	 100  				continue
	 101  			}
	 102  			return "", &PathError{Op: "mkdirtemp", Path: dir + string(PathSeparator) + prefix + "*" + suffix, Err: ErrExist}
	 103  		}
	 104  		if IsNotExist(err) {
	 105  			if _, err := Stat(dir); IsNotExist(err) {
	 106  				return "", err
	 107  			}
	 108  		}
	 109  		return "", err
	 110  	}
	 111  }
	 112  
	 113  func joinPath(dir, name string) string {
	 114  	if len(dir) > 0 && IsPathSeparator(dir[len(dir)-1]) {
	 115  		return dir + name
	 116  	}
	 117  	return dir + string(PathSeparator) + name
	 118  }
	 119  
	 120  // LastIndexByte from the strings package.
	 121  func lastIndex(s string, sep byte) int {
	 122  	for i := len(s) - 1; i >= 0; i-- {
	 123  		if s[i] == sep {
	 124  			return i
	 125  		}
	 126  	}
	 127  	return -1
	 128  }
	 129  

View as plain text