mirror of
https://github.com/golang/go
synced 2024-11-26 07:38:00 -07:00
io/ioutil: forward TempFile and TempDir to os package
For #42026 Fixes #44311 Change-Id: I3dabcf902d155f95800b4adf1d7578906a194ce6 Reviewed-on: https://go-review.googlesource.com/c/go/+/285378 Trust: Ian Lance Taylor <iant@golang.org> Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com>
This commit is contained in:
parent
04edf418d2
commit
07c658316b
@ -1,7 +0,0 @@
|
|||||||
// Copyright 2020 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 ioutil
|
|
||||||
|
|
||||||
var ErrPatternHasSeparator = errPatternHasSeparator
|
|
@ -5,38 +5,9 @@
|
|||||||
package ioutil
|
package ioutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Random number state.
|
|
||||||
// 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.
|
|
||||||
var rand uint32
|
|
||||||
var randmu sync.Mutex
|
|
||||||
|
|
||||||
func reseed() uint32 {
|
|
||||||
return uint32(time.Now().UnixNano() + int64(os.Getpid()))
|
|
||||||
}
|
|
||||||
|
|
||||||
func nextRandom() string {
|
|
||||||
randmu.Lock()
|
|
||||||
r := rand
|
|
||||||
if r == 0 {
|
|
||||||
r = reseed()
|
|
||||||
}
|
|
||||||
r = r*1664525 + 1013904223 // constants from Numerical Recipes
|
|
||||||
rand = r
|
|
||||||
randmu.Unlock()
|
|
||||||
return strconv.Itoa(int(1e9 + r%1e9))[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
// TempFile creates a new temporary file in the directory dir,
|
// TempFile creates a new temporary file in the directory dir,
|
||||||
// opens the file for reading and writing, and returns the resulting *os.File.
|
// opens the file for reading and writing, and returns the resulting *os.File.
|
||||||
// The filename is generated by taking pattern and adding a random
|
// The filename is generated by taking pattern and adding a random
|
||||||
@ -48,48 +19,10 @@ func nextRandom() string {
|
|||||||
// will not choose the same file. The caller can use f.Name()
|
// will not choose the same file. The caller can use f.Name()
|
||||||
// to find the pathname of the file. It is the caller's responsibility
|
// to find the pathname of the file. It is the caller's responsibility
|
||||||
// to remove the file when no longer needed.
|
// to remove the file when no longer needed.
|
||||||
|
//
|
||||||
|
// As of Go 1.16, this function simply calls os.CreateTemp.
|
||||||
func TempFile(dir, pattern string) (f *os.File, err error) {
|
func TempFile(dir, pattern string) (f *os.File, err error) {
|
||||||
if dir == "" {
|
return os.CreateTemp(dir, pattern)
|
||||||
dir = os.TempDir()
|
|
||||||
}
|
|
||||||
|
|
||||||
prefix, suffix, err := prefixAndSuffix(pattern)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
nconflict := 0
|
|
||||||
for i := 0; i < 10000; i++ {
|
|
||||||
name := filepath.Join(dir, prefix+nextRandom()+suffix)
|
|
||||||
f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
|
|
||||||
if os.IsExist(err) {
|
|
||||||
if nconflict++; nconflict > 10 {
|
|
||||||
randmu.Lock()
|
|
||||||
rand = reseed()
|
|
||||||
randmu.Unlock()
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
if strings.ContainsRune(pattern, os.PathSeparator) {
|
|
||||||
err = errPatternHasSeparator
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if pos := strings.LastIndex(pattern, "*"); pos != -1 {
|
|
||||||
prefix, suffix = pattern[:pos], pattern[pos+1:]
|
|
||||||
} else {
|
|
||||||
prefix = pattern
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TempDir creates a new temporary directory in the directory dir.
|
// TempDir creates a new temporary directory in the directory dir.
|
||||||
@ -101,37 +34,8 @@ func prefixAndSuffix(pattern string) (prefix, suffix string, err error) {
|
|||||||
// Multiple programs calling TempDir simultaneously
|
// Multiple programs calling TempDir simultaneously
|
||||||
// will not choose the same directory. It is the caller's responsibility
|
// will not choose the same directory. It is the caller's responsibility
|
||||||
// to remove the directory when no longer needed.
|
// to remove the directory when no longer needed.
|
||||||
|
//
|
||||||
|
// As of Go 1.16, this function simply calls os.MkdirTemp.
|
||||||
func TempDir(dir, pattern string) (name string, err error) {
|
func TempDir(dir, pattern string) (name string, err error) {
|
||||||
if dir == "" {
|
return os.MkdirTemp(dir, pattern)
|
||||||
dir = os.TempDir()
|
|
||||||
}
|
|
||||||
|
|
||||||
prefix, suffix, err := prefixAndSuffix(pattern)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
nconflict := 0
|
|
||||||
for i := 0; i < 10000; i++ {
|
|
||||||
try := filepath.Join(dir, prefix+nextRandom()+suffix)
|
|
||||||
err = os.Mkdir(try, 0700)
|
|
||||||
if os.IsExist(err) {
|
|
||||||
if nconflict++; nconflict > 10 {
|
|
||||||
randmu.Lock()
|
|
||||||
rand = reseed()
|
|
||||||
randmu.Unlock()
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err == nil {
|
|
||||||
name = try
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,9 @@ func TestTempFile_pattern(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This string is from os.errPatternHasSeparator.
|
||||||
|
const patternHasSeparator = "pattern contains path separator"
|
||||||
|
|
||||||
func TestTempFile_BadPattern(t *testing.T) {
|
func TestTempFile_BadPattern(t *testing.T) {
|
||||||
tmpDir, err := TempDir("", t.Name())
|
tmpDir, err := TempDir("", t.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -81,9 +84,8 @@ func TestTempFile_BadPattern(t *testing.T) {
|
|||||||
if tt.wantErr {
|
if tt.wantErr {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected an error for pattern %q", tt.pattern)
|
t.Errorf("Expected an error for pattern %q", tt.pattern)
|
||||||
}
|
} else if !strings.Contains(err.Error(), patternHasSeparator) {
|
||||||
if g, w := err, ErrPatternHasSeparator; g != w {
|
t.Errorf("Error mismatch: got %#v, want %q for pattern %q", err, patternHasSeparator, tt.pattern)
|
||||||
t.Errorf("Error mismatch: got %#v, want %#v for pattern %q", g, w, tt.pattern)
|
|
||||||
}
|
}
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
t.Errorf("Unexpected error %v for pattern %q", err, tt.pattern)
|
t.Errorf("Unexpected error %v for pattern %q", err, tt.pattern)
|
||||||
@ -183,9 +185,8 @@ func TestTempDir_BadPattern(t *testing.T) {
|
|||||||
if tt.wantErr {
|
if tt.wantErr {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Expected an error for pattern %q", tt.pattern)
|
t.Errorf("Expected an error for pattern %q", tt.pattern)
|
||||||
}
|
} else if !strings.Contains(err.Error(), patternHasSeparator) {
|
||||||
if g, w := err, ErrPatternHasSeparator; g != w {
|
t.Errorf("Error mismatch: got %#v, want %q for pattern %q", err, patternHasSeparator, tt.pattern)
|
||||||
t.Errorf("Error mismatch: got %#v, want %#v for pattern %q", g, w, tt.pattern)
|
|
||||||
}
|
}
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
t.Errorf("Unexpected error %v for pattern %q", err, tt.pattern)
|
t.Errorf("Unexpected error %v for pattern %q", err, tt.pattern)
|
||||||
|
Loading…
Reference in New Issue
Block a user