aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/go/internal/modfetch/fetch.go
diff options
context:
space:
mode:
authorMichael Matloob <matloob@golang.org>2020-12-11 17:03:17 -0500
committerMichael Matloob <matloob@golang.org>2021-03-11 20:01:00 +0000
commit4dd9c7cadcbe689ef607931ed839456509e59104 (patch)
treec970dff270b7f5bb667e0ec09b174fe75274b21b /src/cmd/go/internal/modfetch/fetch.go
parent43d5f213e22029039f234edd1ac72c4ff9dd5ae9 (diff)
downloadgo-4dd9c7cadcbe689ef607931ed839456509e59104.tar.gz
go-4dd9c7cadcbe689ef607931ed839456509e59104.zip
cmd/go: remove some fsyncs when writing files
cache.Trim, dowloadZip, rewriteVersionList, writeDiskCache all use renameio.WriteFile to write their respective files to disk. For the uses in cache.Trim and downloadZip, instead do of renameio.WriteFile, do a truncate to the length of the file, then write the relevant bytes so that a corrupt file (which would contain null bytes because of the truncate) could be detected. For rewriteVersionList, use lockedfile.Transform to do the write (which does a truncate as part of the write too. writeDiskCache stays the same in this CL. Also desete renameio methods that aren't used and remove the renameio.WriteFile wrapper and just use renameio.WriteToFile which it wraps. There is a possibility of corrupt files in the cache (which was true even before this CL) so later CLs will add facilities to clear corrupt files in the cache. Change-Id: I0d0bda40095e4cb898314315bf313e71650d8d25 Reviewed-on: https://go-review.googlesource.com/c/go/+/277412 Trust: Michael Matloob <matloob@golang.org> Run-TryBot: Michael Matloob <matloob@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Bryan C. Mills <bcmills@google.com> Reviewed-by: Jay Conrod <jayconrod@google.com>
Diffstat (limited to 'src/cmd/go/internal/modfetch/fetch.go')
-rw-r--r--src/cmd/go/internal/modfetch/fetch.go66
1 files changed, 55 insertions, 11 deletions
diff --git a/src/cmd/go/internal/modfetch/fetch.go b/src/cmd/go/internal/modfetch/fetch.go
index 7b4ce2154c..4ee490c5ea 100644
--- a/src/cmd/go/internal/modfetch/fetch.go
+++ b/src/cmd/go/internal/modfetch/fetch.go
@@ -8,6 +8,8 @@ import (
"archive/zip"
"bytes"
"context"
+ "crypto/sha256"
+ "encoding/base64"
"errors"
"fmt"
"io"
@@ -296,12 +298,6 @@ func downloadZip(ctx context.Context, mod module.Version, zipfile string) (err e
}
}
- // Sync the file before renaming it: otherwise, after a crash the reader may
- // observe a 0-length file instead of the actual contents.
- // See https://golang.org/issue/22397#issuecomment-380831736.
- if err := f.Sync(); err != nil {
- return err
- }
if err := f.Close(); err != nil {
return err
}
@@ -332,7 +328,21 @@ func hashZip(mod module.Version, zipfile, ziphashfile string) error {
if err := checkModSum(mod, hash); err != nil {
return err
}
- return renameio.WriteFile(ziphashfile, []byte(hash), 0666)
+ hf, err := lockedfile.Create(ziphashfile)
+ if err != nil {
+ return err
+ }
+ if err := hf.Truncate(int64(len(hash))); err != nil {
+ return err
+ }
+ if _, err := hf.WriteAt([]byte(hash), 0); err != nil {
+ return err
+ }
+ if err := hf.Close(); err != nil {
+ return err
+ }
+
+ return nil
}
// makeDirsReadOnly makes a best-effort attempt to remove write permissions for dir
@@ -483,11 +493,24 @@ func checkMod(mod module.Version) {
if err != nil {
base.Fatalf("verifying %v", module.VersionError(mod, err))
}
- data, err := renameio.ReadFile(ziphash)
+ data, err := lockedfile.Read(ziphash)
if err != nil {
base.Fatalf("verifying %v", module.VersionError(mod, err))
}
- h := strings.TrimSpace(string(data))
+ data = bytes.TrimSpace(data)
+ if !isValidSum(data) {
+ // Recreate ziphash file from zip file and use that to check the mod sum.
+ zip, err := CachePath(mod, "zip")
+ if err != nil {
+ base.Fatalf("verifying %v", module.VersionError(mod, err))
+ }
+ err = hashZip(mod, zip, ziphash)
+ if err != nil {
+ base.Fatalf("verifying %v", module.VersionError(mod, err))
+ }
+ return
+ }
+ h := string(data)
if !strings.HasPrefix(h, "h1:") {
base.Fatalf("verifying %v", module.VersionError(mod, fmt.Errorf("unexpected ziphash: %q", h)))
}
@@ -632,11 +655,32 @@ func Sum(mod module.Version) string {
if err != nil {
return ""
}
- data, err := renameio.ReadFile(ziphash)
+ data, err := lockedfile.Read(ziphash)
if err != nil {
return ""
}
- return strings.TrimSpace(string(data))
+ data = bytes.TrimSpace(data)
+ if !isValidSum(data) {
+ return ""
+ }
+ return string(data)
+}
+
+// isValidSum returns true if data is the valid contents of a zip hash file.
+// Certain critical files are written to disk by first truncating
+// then writing the actual bytes, so that if the write fails
+// the corrupt file should contain at least one of the null
+// bytes written by the truncate operation.
+func isValidSum(data []byte) bool {
+ if bytes.IndexByte(data, '\000') >= 0 {
+ return false
+ }
+
+ if len(data) != len("h1:")+base64.StdEncoding.EncodedLen(sha256.Size) {
+ return false
+ }
+
+ return true
}
// WriteGoSum writes the go.sum file if it needs to be updated.