diff options
author | Russ Cox <rsc@golang.org> | 2010-06-03 16:29:34 -0700 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2010-06-03 16:29:34 -0700 |
commit | 28852c15312fefac1cd962681686f7f635041873 (patch) | |
tree | a06a83173ae5d207e7d0060d88285ceb2f60d258 | |
parent | 47bc1f2e4b25505102e856220ed9a6ff7c98e068 (diff) | |
download | go-28852c15312fefac1cd962681686f7f635041873.tar.gz go-28852c15312fefac1cd962681686f7f635041873.zip |
io/ioutil: add TempFile
R=r
CC=golang-dev
https://golang.org/cl/1472042
-rw-r--r-- | src/pkg/io/ioutil/Makefile | 1 | ||||
-rw-r--r-- | src/pkg/io/ioutil/tempfile.go | 63 | ||||
-rw-r--r-- | src/pkg/io/ioutil/tempfile_test.go | 29 |
3 files changed, 93 insertions, 0 deletions
diff --git a/src/pkg/io/ioutil/Makefile b/src/pkg/io/ioutil/Makefile index 3abf7143a6..77b75bcec6 100644 --- a/src/pkg/io/ioutil/Makefile +++ b/src/pkg/io/ioutil/Makefile @@ -7,5 +7,6 @@ include ../../../Make.$(GOARCH) TARG=io/ioutil GOFILES=\ ioutil.go\ + tempfile.go\ include ../../../Make.pkg diff --git a/src/pkg/io/ioutil/tempfile.go b/src/pkg/io/ioutil/tempfile.go new file mode 100644 index 0000000000..55fcf47026 --- /dev/null +++ b/src/pkg/io/ioutil/tempfile.go @@ -0,0 +1,63 @@ +// 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 ioutil + +import ( + "os" + "strconv" +) + +// Random number state, accessed without lock; racy but harmless. +// 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 + +func reseed() uint32 { + sec, nsec, _ := os.Time() + return uint32(sec*1e9 + nsec + int64(os.Getpid())) +} + +func nextSuffix() string { + r := rand + if r == 0 { + r = reseed() + } + r = r*1664525 + 1013904223 // constants from Numerical Recipes + rand = r + return strconv.Itoa(int(1e9 + r%1e9))[1:] +} + +// TempFile creates a new temporary file in the directory dir +// with a name beginning with prefix, opens the file for reading +// and writing, and returns the resulting *os.File. +// If dir is the empty string, TempFile uses the value of the +// environment variable $TMPDIR or, if that is empty,/tmp. +// Multiple programs calling TempFile simultaneously +// will not choose the same file. The caller can use f.Name() +// to find the name of the file. It is the caller's responsibility to +// remove the file when no longer needed. +func TempFile(dir, prefix string) (f *os.File, err os.Error) { + if dir == "" { + dir = os.Getenv("TMPDIR") + if dir == "" { + dir = "/tmp" + } + } + + nconflict := 0 + for i := 0; i < 10000; i++ { + name := dir + "/" + prefix + nextSuffix() + f, err = os.Open(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600) + if pe, ok := err.(*os.PathError); ok && pe.Error == os.EEXIST { + if nconflict++; nconflict > 10 { + rand = reseed() + } + continue + } + break + } + return +} diff --git a/src/pkg/io/ioutil/tempfile_test.go b/src/pkg/io/ioutil/tempfile_test.go new file mode 100644 index 0000000000..fbe45dc6dd --- /dev/null +++ b/src/pkg/io/ioutil/tempfile_test.go @@ -0,0 +1,29 @@ +// 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 ioutil_test + +import ( + . "io/ioutil" + "os" + "testing" +) + +func TestTempFile(t *testing.T) { + f, err := TempFile("/_not_exists_", "foo") + if f != nil || err == nil { + t.Errorf("TempFile(`/_not_exists_`, `foo`) = %v, %v", f, err) + } + + f, err = TempFile("/tmp", "ioutil_test") + if f == nil || err != nil { + t.Errorf("TempFile(`/tmp`, `ioutil_test`) = %v, %v", f, err) + } + re := testing.MustCompile("^/tmp/ioutil_test[0-9]+$") + if !re.MatchString(f.Name()) { + t.Fatalf("TempFile(`/tmp`, `ioutil_test`) created bad name %s", f.Name()) + } + os.Remove(f.Name()) + f.Close() +} |