From cefc0bbc9011baa62a8284d61452ba33245e8455 Mon Sep 17 00:00:00 2001 From: Baokun Lee Date: Thu, 9 May 2019 11:24:30 +0800 Subject: [PATCH] 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 TryBot-Result: Gobot Gobot Reviewed-by: Bryan C. Mills --- src/cmd/go/internal/cache/cache.go | 2 +- src/cmd/go/internal/modfetch/cache.go | 4 +- src/cmd/go/internal/modfetch/fetch.go | 4 +- src/cmd/go/internal/modload/init.go | 2 +- src/cmd/go/internal/renameio/renameio.go | 26 ++++++++--- src/cmd/go/internal/renameio/renameio_test.go | 44 +++++++++++++++++++ 6 files changed, 70 insertions(+), 12 deletions(-) create mode 100644 src/cmd/go/internal/renameio/renameio_test.go diff --git a/src/cmd/go/internal/cache/cache.go b/src/cmd/go/internal/cache/cache.go index 3e386a0881..c1d073806e 100644 --- a/src/cmd/go/internal/cache/cache.go +++ b/src/cmd/go/internal/cache/cache.go @@ -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. diff --git a/src/cmd/go/internal/modfetch/cache.go b/src/cmd/go/internal/modfetch/cache.go index 1ccd43dc2a..f269c47f59 100644 --- a/src/cmd/go/internal/modfetch/cache.go +++ b/src/cmd/go/internal/modfetch/cache.go @@ -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) } } diff --git a/src/cmd/go/internal/modfetch/fetch.go b/src/cmd/go/internal/modfetch/fetch.go index 8f9e50da75..817f7657e2 100644 --- a/src/cmd/go/internal/modfetch/fetch.go +++ b/src/cmd/go/internal/modfetch/fetch.go @@ -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) } diff --git a/src/cmd/go/internal/modload/init.go b/src/cmd/go/internal/modload/init.go index c55f8e3760..b51e411421 100644 --- a/src/cmd/go/internal/modload/init.go +++ b/src/cmd/go/internal/modload/init.go @@ -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 diff --git a/src/cmd/go/internal/renameio/renameio.go b/src/cmd/go/internal/renameio/renameio.go index 0bd40a544a..5fe5bb7dd4 100644 --- a/src/cmd/go/internal/renameio/renameio.go +++ b/src/cmd/go/internal/renameio/renameio.go @@ -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 +} diff --git a/src/cmd/go/internal/renameio/renameio_test.go b/src/cmd/go/internal/renameio/renameio_test.go new file mode 100644 index 0000000000..53f879803e --- /dev/null +++ b/src/cmd/go/internal/renameio/renameio_test.go @@ -0,0 +1,44 @@ +// 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) + } +} -- 2.50.0