X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=libgo%2Fgo%2Fcmd%2Fgo%2Finternal%2Fmodfetch%2Ffetch.go;h=54fbd92b43ec146987910e51ae5db66672abc508;hb=5a8ea165926cb0737ab03bc48c18dc5198ab5305;hp=51a56028c4acbeab3d3c8b2130916b408a3e6921;hpb=6ac6529e155c9baa0aaaed7aca06bd38ebda5b43;p=platform%2Fupstream%2Fgcc.git diff --git a/libgo/go/cmd/go/internal/modfetch/fetch.go b/libgo/go/cmd/go/internal/modfetch/fetch.go index 51a5602..54fbd92 100644 --- a/libgo/go/cmd/go/internal/modfetch/fetch.go +++ b/libgo/go/cmd/go/internal/modfetch/fetch.go @@ -7,6 +7,7 @@ package modfetch import ( "archive/zip" "bytes" + "errors" "fmt" "io" "io/ioutil" @@ -18,10 +19,13 @@ import ( "cmd/go/internal/base" "cmd/go/internal/cfg" - "cmd/go/internal/dirhash" - "cmd/go/internal/module" + "cmd/go/internal/lockedfile" "cmd/go/internal/par" "cmd/go/internal/renameio" + + "golang.org/x/mod/module" + "golang.org/x/mod/sumdb/dirhash" + modzip "golang.org/x/mod/zip" ) var downloadCache par.Cache @@ -69,10 +73,6 @@ func download(mod module.Version, dir string) (err error) { return err } - if cfg.CmdName != "mod download" { - fmt.Fprintf(os.Stderr, "go: extracting %s %s\n", mod.Path, mod.Version) - } - unlock, err := lockVersion(mod) if err != nil { return err @@ -114,8 +114,7 @@ func download(mod module.Version, dir string) (err error) { } }() - modpath := mod.Path + "@" + mod.Version - if err := Unzip(tmpDir, zipfile, modpath, 0); err != nil { + if err := modzip.Unzip(tmpDir, mod, zipfile); err != nil { fmt.Fprintf(os.Stderr, "-> %s\n", err) return err } @@ -124,9 +123,11 @@ func download(mod module.Version, dir string) (err error) { return err } - // Make dir read-only only *after* renaming it. - // os.Rename was observed to fail for read-only directories on macOS. - makeDirsReadOnly(dir) + if !cfg.ModCacheRW { + // Make dir read-only only *after* renaming it. + // os.Rename was observed to fail for read-only directories on macOS. + makeDirsReadOnly(dir) + } return nil } @@ -249,7 +250,9 @@ func downloadZip(mod module.Version, zipfile string) (err error) { if err != nil { return err } - checkModSum(mod, hash) + if err := checkModSum(mod, hash); err != nil { + return err + } if err := renameio.WriteFile(zipfile+"hash", []byte(hash), 0666); err != nil { return err @@ -263,6 +266,45 @@ func downloadZip(mod module.Version, zipfile string) (err error) { return nil } +// makeDirsReadOnly makes a best-effort attempt to remove write permissions for dir +// and its transitive contents. +func makeDirsReadOnly(dir string) { + type pathMode struct { + path string + mode os.FileMode + } + var dirs []pathMode // in lexical order + filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err == nil && info.Mode()&0222 != 0 { + if info.IsDir() { + dirs = append(dirs, pathMode{path, info.Mode()}) + } + } + return nil + }) + + // Run over list backward to chmod children before parents. + for i := len(dirs) - 1; i >= 0; i-- { + os.Chmod(dirs[i].path, dirs[i].mode&^0222) + } +} + +// RemoveAll removes a directory written by Download or Unzip, first applying +// any permission changes needed to do so. +func RemoveAll(dir string) error { + // Module cache has 0555 directories; make them writable in order to remove content. + filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + if err != nil { + return nil // ignore errors walking in file system + } + if info.IsDir() { + os.Chmod(path, 0777) + } + return nil + }) + return os.RemoveAll(dir) +} + var GoSumFile string // path to go.sum; set by package modload type modSum struct { @@ -281,21 +323,22 @@ var goSum struct { } // initGoSum initializes the go.sum data. -// It reports whether use of go.sum is now enabled. +// The boolean it returns reports whether the +// use of go.sum is now enabled. // The goSum lock must be held. -func initGoSum() bool { +func initGoSum() (bool, error) { if GoSumFile == "" { - return false + return false, nil } if goSum.m != nil { - return true + return true, nil } goSum.m = make(map[module.Version][]string) goSum.checked = make(map[modSum]bool) - data, err := renameio.ReadFile(GoSumFile) + data, err := lockedfile.Read(GoSumFile) if err != nil && !os.IsNotExist(err) { - base.Fatalf("go: %v", err) + return false, err } goSum.enabled = true readGoSum(goSum.m, GoSumFile, data) @@ -313,7 +356,7 @@ func initGoSum() bool { } goSum.modverify = alt } - return true + return true, nil } // emptyGoModHash is the hash of a 1-file tree containing a 0-length go.mod. @@ -323,7 +366,7 @@ const emptyGoModHash = "h1:G7mAYYxgmS0lVkHyy2hEOLQCFB0DlQFTMLWggykrydY=" // readGoSum parses data, which is the content of file, // and adds it to goSum.m. The goSum lock must be held. -func readGoSum(dst map[module.Version][]string, file string, data []byte) { +func readGoSum(dst map[module.Version][]string, file string, data []byte) error { lineno := 0 for len(data) > 0 { var line []byte @@ -340,7 +383,7 @@ func readGoSum(dst map[module.Version][]string, file string, data []byte) { continue } if len(f) != 3 { - base.Fatalf("go: malformed go.sum:\n%s:%d: wrong number of fields %v", file, lineno, len(f)) + return fmt.Errorf("malformed go.sum:\n%s:%d: wrong number of fields %v", file, lineno, len(f)) } if f[2] == emptyGoModHash { // Old bug; drop it. @@ -349,6 +392,7 @@ func readGoSum(dst map[module.Version][]string, file string, data []byte) { mod := module.Version{Path: f[0], Version: f[1]} dst[mod] = append(dst[mod], f[2]) } + return nil } // checkMod checks the given module's checksum. @@ -361,22 +405,24 @@ func checkMod(mod module.Version) { // Do the file I/O before acquiring the go.sum lock. ziphash, err := CachePath(mod, "ziphash") if err != nil { - base.Fatalf("verifying %s@%s: %v", mod.Path, mod.Version, err) + base.Fatalf("verifying %v", module.VersionError(mod, err)) } data, err := renameio.ReadFile(ziphash) if err != nil { - if os.IsNotExist(err) { + if errors.Is(err, os.ErrNotExist) { // This can happen if someone does rm -rf GOPATH/src/cache/download. So it goes. return } - base.Fatalf("verifying %s@%s: %v", mod.Path, mod.Version, err) + base.Fatalf("verifying %v", module.VersionError(mod, err)) } h := strings.TrimSpace(string(data)) if !strings.HasPrefix(h, "h1:") { - base.Fatalf("verifying %s@%s: unexpected ziphash: %q", mod.Path, mod.Version, h) + base.Fatalf("verifying %v", module.VersionError(mod, fmt.Errorf("unexpected ziphash: %q", h))) } - checkModSum(mod, h) + if err := checkModSum(mod, h); err != nil { + base.Fatalf("%s", err) + } } // goModSum returns the checksum for the go.mod contents. @@ -388,17 +434,17 @@ func goModSum(data []byte) (string, error) { // checkGoMod checks the given module's go.mod checksum; // data is the go.mod content. -func checkGoMod(path, version string, data []byte) { +func checkGoMod(path, version string, data []byte) error { h, err := goModSum(data) if err != nil { - base.Fatalf("verifying %s %s go.mod: %v", path, version, err) + return &module.ModuleError{Path: path, Version: version, Err: fmt.Errorf("verifying go.mod: %v", err)} } - checkModSum(module.Version{Path: path, Version: version + "/go.mod"}, h) + return checkModSum(module.Version{Path: path, Version: version + "/go.mod"}, h) } // checkModSum checks that the recorded checksum for mod is h. -func checkModSum(mod module.Version, h string) { +func checkModSum(mod module.Version, h string) error { // We lock goSum when manipulating it, // but we arrange to release the lock when calling checkSumDB, // so that parallel calls to checkModHash can execute parallel calls @@ -406,19 +452,24 @@ func checkModSum(mod module.Version, h string) { // Check whether mod+h is listed in go.sum already. If so, we're done. goSum.mu.Lock() - inited := initGoSum() + inited, err := initGoSum() + if err != nil { + return err + } done := inited && haveModSumLocked(mod, h) goSum.mu.Unlock() if done { - return + return nil } // Not listed, so we want to add them. // Consult checksum database if appropriate. if useSumDB(mod) { // Calls base.Fatalf if mismatch detected. - checkSumDB(mod, h) + if err := checkSumDB(mod, h); err != nil { + return err + } } // Add mod+h to go.sum, if it hasn't appeared already. @@ -427,6 +478,7 @@ func checkModSum(mod module.Version, h string) { addModSumLocked(mod, h) goSum.mu.Unlock() } + return nil } // haveModSumLocked reports whether the pair mod,h is already listed in go.sum. @@ -460,22 +512,23 @@ func addModSumLocked(mod module.Version, h string) { // checkSumDB checks the mod, h pair against the Go checksum database. // It calls base.Fatalf if the hash is to be rejected. -func checkSumDB(mod module.Version, h string) { +func checkSumDB(mod module.Version, h string) error { db, lines, err := lookupSumDB(mod) if err != nil { - base.Fatalf("verifying %s@%s: %v", mod.Path, mod.Version, err) + return module.VersionError(mod, fmt.Errorf("verifying module: %v", err)) } have := mod.Path + " " + mod.Version + " " + h prefix := mod.Path + " " + mod.Version + " h1:" for _, line := range lines { if line == have { - return + return nil } if strings.HasPrefix(line, prefix) { - base.Fatalf("verifying %s@%s: checksum mismatch\n\tdownloaded: %v\n\t%s: %v"+sumdbMismatch, mod.Path, mod.Version, h, db, line[len(prefix)-len("h1:"):]) + return module.VersionError(mod, fmt.Errorf("verifying module: checksum mismatch\n\tdownloaded: %v\n\t%s: %v"+sumdbMismatch, h, db, line[len(prefix)-len("h1:"):])) } } + return nil } // Sum returns the checksum for the downloaded copy of the given module, @@ -516,60 +569,45 @@ func WriteGoSum() { base.Fatalf("go: updates to go.sum needed, disabled by -mod=readonly") } - // We want to avoid races between creating the lockfile and deleting it, but - // we also don't want to leave a permanent lockfile in the user's repository. - // - // On top of that, if we crash while writing go.sum, we don't want to lose the - // sums that were already present in the file, so it's important that we write - // the file by renaming rather than truncating — which means that we can't - // lock the go.sum file itself. - // - // Instead, we'll lock a distinguished file in the cache directory: that will - // only race if the user runs `go clean -modcache` concurrently with a command - // that updates go.sum, and that's already racy to begin with. - // - // We'll end up slightly over-synchronizing go.sum writes if the user runs a - // bunch of go commands that update sums in separate modules simultaneously, - // but that's unlikely to matter in practice. - - unlock := SideLock() - defer unlock() + // Make a best-effort attempt to acquire the side lock, only to exclude + // previous versions of the 'go' command from making simultaneous edits. + if unlock, err := SideLock(); err == nil { + defer unlock() + } - if !goSum.overwrite { - // Re-read the go.sum file to incorporate any sums added by other processes - // in the meantime. - data, err := renameio.ReadFile(GoSumFile) - if err != nil && !os.IsNotExist(err) { - base.Fatalf("go: re-reading go.sum: %v", err) - } - - // Add only the sums that we actually checked: the user may have edited or - // truncated the file to remove erroneous hashes, and we shouldn't restore - // them without good reason. - goSum.m = make(map[module.Version][]string, len(goSum.m)) - readGoSum(goSum.m, GoSumFile, data) - for ms := range goSum.checked { - addModSumLocked(ms.mod, ms.sum) - goSum.dirty = true + err := lockedfile.Transform(GoSumFile, func(data []byte) ([]byte, error) { + if !goSum.overwrite { + // Incorporate any sums added by other processes in the meantime. + // Add only the sums that we actually checked: the user may have edited or + // truncated the file to remove erroneous hashes, and we shouldn't restore + // them without good reason. + goSum.m = make(map[module.Version][]string, len(goSum.m)) + readGoSum(goSum.m, GoSumFile, data) + for ms := range goSum.checked { + addModSumLocked(ms.mod, ms.sum) + goSum.dirty = true + } } - } - var mods []module.Version - for m := range goSum.m { - mods = append(mods, m) - } - module.Sort(mods) - var buf bytes.Buffer - for _, m := range mods { - list := goSum.m[m] - sort.Strings(list) - for _, h := range list { - fmt.Fprintf(&buf, "%s %s %s\n", m.Path, m.Version, h) + var mods []module.Version + for m := range goSum.m { + mods = append(mods, m) } - } + module.Sort(mods) + + var buf bytes.Buffer + for _, m := range mods { + list := goSum.m[m] + sort.Strings(list) + for _, h := range list { + fmt.Fprintf(&buf, "%s %s %s\n", m.Path, m.Version, h) + } + } + return buf.Bytes(), nil + }) - if err := renameio.WriteFile(GoSumFile, buf.Bytes(), 0666); err != nil { - base.Fatalf("go: writing go.sum: %v", err) + if err != nil { + base.Fatalf("go: updating go.sum: %v", err) } goSum.checked = make(map[modSum]bool) @@ -585,7 +623,11 @@ func WriteGoSum() { func TrimGoSum(keep map[module.Version]bool) { goSum.mu.Lock() defer goSum.mu.Unlock() - if !initGoSum() { + inited, err := initGoSum() + if err != nil { + base.Fatalf("%s", err) + } + if !inited { return }