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() { ...@@ -278,7 +278,7 @@ func (c *Cache) Trim() {
// Ignore errors from here: if we don't write the complete timestamp, the // 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. // 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. // trimSubdir trims a single cache subdirectory.
......
...@@ -488,7 +488,7 @@ func writeDiskCache(file string, data []byte) error { ...@@ -488,7 +488,7 @@ func writeDiskCache(file string, data []byte) error {
return err return err
} }
if err := renameio.WriteFile(file, data); err != nil { if err := renameio.WriteFile(file, data, 0666); err != nil {
return err return err
} }
...@@ -550,7 +550,7 @@ func rewriteVersionList(dir string) { ...@@ -550,7 +550,7 @@ func rewriteVersionList(dir string) {
return 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) base.Fatalf("go: failed to write version list: %v", err)
} }
} }
...@@ -248,7 +248,7 @@ func downloadZip(mod module.Version, zipfile string) (err error) { ...@@ -248,7 +248,7 @@ func downloadZip(mod module.Version, zipfile string) (err error) {
} }
checkModSum(mod, hash) 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 return err
} }
if err := os.Rename(f.Name(), zipfile); err != nil { if err := os.Rename(f.Name(), zipfile); err != nil {
...@@ -565,7 +565,7 @@ func WriteGoSum() { ...@@ -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) base.Fatalf("go: writing go.sum: %v", err)
} }
......
...@@ -715,7 +715,7 @@ func WriteGoMod() { ...@@ -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) base.Fatalf("error writing go.mod: %v", err)
} }
modFileData = new modFileData = new
......
...@@ -8,13 +8,14 @@ package renameio ...@@ -8,13 +8,14 @@ package renameio
import ( import (
"bytes" "bytes"
"io" "io"
"io/ioutil" "math/rand"
"os" "os"
"path/filepath" "path/filepath"
"strconv"
"time" "time"
) )
const patternSuffix = "*.tmp" const patternSuffix = ".tmp"
// Pattern returns a glob pattern that matches the unrenamed temporary files // Pattern returns a glob pattern that matches the unrenamed temporary files
// created when writing to filename. // created when writing to filename.
...@@ -27,14 +28,14 @@ func Pattern(filename string) string { ...@@ -27,14 +28,14 @@ func Pattern(filename string) string {
// final name. // final name.
// //
// That ensures that the final location, if it exists, is always a complete file. // That ensures that the final location, if it exists, is always a complete file.
func WriteFile(filename string, data []byte) (err error) { func WriteFile(filename string, data []byte, perm os.FileMode) (err error) {
return WriteToFile(filename, bytes.NewReader(data)) return WriteToFile(filename, bytes.NewReader(data), perm)
} }
// WriteToFile is a variant of WriteFile that accepts the data as an io.Reader // WriteToFile is a variant of WriteFile that accepts the data as an io.Reader
// instead of a slice. // instead of a slice.
func WriteToFile(filename string, data io.Reader) (err error) { func WriteToFile(filename string, data io.Reader, perm os.FileMode) (err error) {
f, err := ioutil.TempFile(filepath.Dir(filename), filepath.Base(filename)+patternSuffix) f, err := tempFile(filepath.Dir(filename), filepath.Base(filename), perm)
if err != nil { if err != nil {
return err return err
} }
...@@ -79,3 +80,16 @@ func WriteToFile(filename string, data io.Reader) (err error) { ...@@ -79,3 +80,16 @@ func WriteToFile(filename string, data io.Reader) (err error) {
time.Sleep(5 * time.Millisecond) 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