// Ignore errors from here: if we don't write the complete timestamp, the
// cache will appear older than it is, and we'll trim it again next time.
- renameio.WriteFile(filepath.Join(c.dir, "trim.txt"), []byte(fmt.Sprintf("%d", now.Unix())))
+ renameio.WriteFile(filepath.Join(c.dir, "trim.txt"), []byte(fmt.Sprintf("%d", now.Unix())), 0666)
}
// trimSubdir trims a single cache subdirectory.
return err
}
- if err := renameio.WriteFile(file, data); err != nil {
+ if err := renameio.WriteFile(file, data, 0666); err != nil {
return err
}
return
}
- if err := renameio.WriteFile(listFile, buf.Bytes()); err != nil {
+ if err := renameio.WriteFile(listFile, buf.Bytes(), 0666); err != nil {
base.Fatalf("go: failed to write version list: %v", err)
}
}
}
checkModSum(mod, hash)
- if err := renameio.WriteFile(zipfile+"hash", []byte(hash)); err != nil {
+ if err := renameio.WriteFile(zipfile+"hash", []byte(hash), 0666); err != nil {
return err
}
if err := os.Rename(f.Name(), zipfile); err != nil {
}
}
- if err := renameio.WriteFile(GoSumFile, buf.Bytes()); err != nil {
+ if err := renameio.WriteFile(GoSumFile, buf.Bytes(), 0666); err != nil {
base.Fatalf("go: writing go.sum: %v", err)
}
}
- if err := renameio.WriteFile(file, new); err != nil {
+ if err := renameio.WriteFile(file, new, 0666); err != nil {
base.Fatalf("error writing go.mod: %v", err)
}
modFileData = new
import (
"bytes"
"io"
- "io/ioutil"
+ "math/rand"
"os"
"path/filepath"
+ "strconv"
"time"
)
-const patternSuffix = "*.tmp"
+const patternSuffix = ".tmp"
// Pattern returns a glob pattern that matches the unrenamed temporary files
// created when writing to filename.
// final name.
//
// That ensures that the final location, if it exists, is always a complete file.
-func WriteFile(filename string, data []byte) (err error) {
- return WriteToFile(filename, bytes.NewReader(data))
+func WriteFile(filename string, data []byte, perm os.FileMode) (err error) {
+ return WriteToFile(filename, bytes.NewReader(data), perm)
}
// WriteToFile is a variant of WriteFile that accepts the data as an io.Reader
// instead of a slice.
-func WriteToFile(filename string, data io.Reader) (err error) {
- f, err := ioutil.TempFile(filepath.Dir(filename), filepath.Base(filename)+patternSuffix)
+func WriteToFile(filename string, data io.Reader, perm os.FileMode) (err error) {
+ f, err := tempFile(filepath.Dir(filename), filepath.Base(filename), perm)
if err != nil {
return err
}
time.Sleep(5 * time.Millisecond)
}
}
+
+// tempFile creates a new temporary file with given permission bits.
+func tempFile(dir, prefix string, perm os.FileMode) (f *os.File, err error) {
+ for i := 0; i < 10000; i++ {
+ name := filepath.Join(dir, prefix+strconv.Itoa(rand.Intn(1000000000))+patternSuffix)
+ f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, perm)
+ if os.IsExist(err) {
+ continue
+ }
+ break
+ }
+ return
+}
--- /dev/null
+// Copyright 2019 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 renameio writes files atomically by renaming temporary files.
+
+//+build !nacl,!plan9,!windows,!js
+
+package renameio
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "syscall"
+ "testing"
+)
+
+func TestWriteFileModeAppliesUmask(t *testing.T) {
+ dir, err := ioutil.TempDir("", "renameio")
+ if err != nil {
+ t.Fatalf("Failed to create temporary directory: %v", err)
+ }
+
+ const mode = 0644
+ const umask = 0007
+ defer syscall.Umask(syscall.Umask(umask))
+
+ file := filepath.Join(dir, "testWrite")
+ err = WriteFile(file, []byte("go-build"), mode)
+ if err != nil {
+ t.Fatalf("Failed to write file: %v", err)
+ }
+ defer os.RemoveAll(dir)
+
+ fi, err := os.Stat(file)
+ if err != nil {
+ t.Fatalf("Stat %q (looking for mode %#o): %s", file, mode, err)
+ }
+
+ if fi.Mode()&os.ModePerm != 0640 {
+ t.Errorf("Stat %q: mode %#o want %#o", file, fi.Mode()&os.ModePerm, 0640)
+ }
+}