123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- // Copyright 2010 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- package os
- import (
- "errors"
- "internal/itoa"
- )
- // fastrand provided by runtime.
- // We generate random temporary file names so that there's a good
- // chance the file doesn't exist yet - keeps the number of tries in
- // TempFile to a minimum.
- func fastrand() uint32
- func nextRandom() string {
- return itoa.Uitoa(uint(fastrand()))
- }
- // CreateTemp creates a new temporary file in the directory dir,
- // opens the file for reading and writing, and returns the resulting file.
- // The filename is generated by taking pattern and adding a random string to the end.
- // If pattern includes a "*", the random string replaces the last "*".
- // If dir is the empty string, CreateTemp uses the default directory for temporary files, as returned by TempDir.
- // Multiple programs or goroutines calling CreateTemp simultaneously will not choose the same file.
- // The caller can use the file's Name method to find the pathname of the file.
- // It is the caller's responsibility to remove the file when it is no longer needed.
- func CreateTemp(dir, pattern string) (*File, error) {
- if dir == "" {
- dir = TempDir()
- }
- prefix, suffix, err := prefixAndSuffix(pattern)
- if err != nil {
- return nil, &PathError{Op: "createtemp", Path: pattern, Err: err}
- }
- prefix = joinPath(dir, prefix)
- try := 0
- for {
- name := prefix + nextRandom() + suffix
- f, err := OpenFile(name, O_RDWR|O_CREATE|O_EXCL, 0600)
- if IsExist(err) {
- if try++; try < 10000 {
- continue
- }
- return nil, &PathError{Op: "createtemp", Path: prefix + "*" + suffix, Err: ErrExist}
- }
- return f, err
- }
- }
- var errPatternHasSeparator = errors.New("pattern contains path separator")
- // prefixAndSuffix splits pattern by the last wildcard "*", if applicable,
- // returning prefix as the part before "*" and suffix as the part after "*".
- func prefixAndSuffix(pattern string) (prefix, suffix string, err error) {
- for i := 0; i < len(pattern); i++ {
- if IsPathSeparator(pattern[i]) {
- return "", "", errPatternHasSeparator
- }
- }
- if pos := lastIndex(pattern, '*'); pos != -1 {
- prefix, suffix = pattern[:pos], pattern[pos+1:]
- } else {
- prefix = pattern
- }
- return prefix, suffix, nil
- }
- // MkdirTemp creates a new temporary directory in the directory dir
- // and returns the pathname of the new directory.
- // The new directory's name is generated by adding a random string to the end of pattern.
- // If pattern includes a "*", the random string replaces the last "*" instead.
- // If dir is the empty string, MkdirTemp uses the default directory for temporary files, as returned by TempDir.
- // Multiple programs or goroutines calling MkdirTemp simultaneously will not choose the same directory.
- // It is the caller's responsibility to remove the directory when it is no longer needed.
- func MkdirTemp(dir, pattern string) (string, error) {
- if dir == "" {
- dir = TempDir()
- }
- prefix, suffix, err := prefixAndSuffix(pattern)
- if err != nil {
- return "", &PathError{Op: "mkdirtemp", Path: pattern, Err: err}
- }
- prefix = joinPath(dir, prefix)
- try := 0
- for {
- name := prefix + nextRandom() + suffix
- err := Mkdir(name, 0700)
- if err == nil {
- return name, nil
- }
- if IsExist(err) {
- if try++; try < 10000 {
- continue
- }
- return "", &PathError{Op: "mkdirtemp", Path: dir + string(PathSeparator) + prefix + "*" + suffix, Err: ErrExist}
- }
- if IsNotExist(err) {
- if _, err := Stat(dir); IsNotExist(err) {
- return "", err
- }
- }
- return "", err
- }
- }
- func joinPath(dir, name string) string {
- if len(dir) > 0 && IsPathSeparator(dir[len(dir)-1]) {
- return dir + name
- }
- return dir + string(PathSeparator) + name
- }
- // LastIndexByte from the strings package.
- func lastIndex(s string, sep byte) int {
- for i := len(s) - 1; i >= 0; i-- {
- if s[i] == sep {
- return i
- }
- }
- return -1
- }
|