aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2010-06-03 16:29:34 -0700
committerRuss Cox <rsc@golang.org>2010-06-03 16:29:34 -0700
commit28852c15312fefac1cd962681686f7f635041873 (patch)
treea06a83173ae5d207e7d0060d88285ceb2f60d258
parent47bc1f2e4b25505102e856220ed9a6ff7c98e068 (diff)
downloadgo-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/Makefile1
-rw-r--r--src/pkg/io/ioutil/tempfile.go63
-rw-r--r--src/pkg/io/ioutil/tempfile_test.go29
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()
+}