Commit cefc0bbc authored by Baokun Lee's avatar Baokun Lee Committed by Bryan C. Mills

cmd/go/internal/renameio: allow write file with the specified permissions

Now renameio package creates file use ioutil.TempFile, which calls
OpenFile with mode 0600, we should support creates a file with given
permission bits.

Fixes #31871

Change-Id: I0436e9f7081f2fce18bf9f3b14d55b02d4d995fb
Reviewed-on: https://go-review.googlesource.com/c/go/+/175958
Run-TryBot: Baokun Lee <nototon@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarBryan C. Mills <bcmills@google.com>
parent 1e3ffb0c
......@@ -278,7 +278,7 @@ func (c *Cache) Trim() {
// 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.
......
......@@ -488,7 +488,7 @@ func writeDiskCache(file string, data []byte) error {
return err
}
if err := renameio.WriteFile(file, data); err != nil {
if err := renameio.WriteFile(file, data, 0666); err != nil {
return err
}
......@@ -550,7 +550,7 @@ func rewriteVersionList(dir string) {
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)
}
}
......@@ -248,7 +248,7 @@ func downloadZip(mod module.Version, zipfile string) (err error) {
}
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 {
......@@ -565,7 +565,7 @@ func WriteGoSum() {
}
}
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)
}
......
......@@ -715,7 +715,7 @@ func WriteGoMod() {
}
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
......
......@@ -8,13 +8,14 @@ package renameio
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.
......@@ -27,14 +28,14 @@ func Pattern(filename string) string {
// 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
}
......@@ -79,3 +80,16 @@ func WriteToFile(filename string, data io.Reader) (err error) {
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
}
// 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)
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment