cmd/go: don't lock .mod and .sum files for read in overlay

On Plan 9, locking a file requires a chmod call. In general, the go
command should not modify files in the overlay, even metadata. With
this change, we won't lock these files for reading.

The go command already reported errors when attempting to write these
files if they were in the overlay, but this change moves those checks
to the point of access for clearer error
messages. cmd/go/internal/lockedfile no longer imports
cmd/go/internal/fsys.

Fixes #44700

Change-Id: Ib544459dd6cf56ca0f7a27b3285f045f08040d7e
Reviewed-on: https://go-review.googlesource.com/c/go/+/333012
Trust: Jay Conrod <jayconrod@google.com>
Run-TryBot: Jay Conrod <jayconrod@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Bryan C. Mills <bcmills@google.com>
This commit is contained in:
Jay Conrod 2021-07-06 10:38:18 -07:00
parent 186a3bb4b0
commit 991fd381d5
6 changed files with 53 additions and 15 deletions

View File

@ -11,7 +11,6 @@ import (
"io/fs" "io/fs"
"os" "os"
"cmd/go/internal/fsys"
"cmd/go/internal/lockedfile/internal/filelock" "cmd/go/internal/lockedfile/internal/filelock"
) )
@ -21,7 +20,7 @@ func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) {
// calls for Linux and Windows anyway, so it's simpler to use that approach // calls for Linux and Windows anyway, so it's simpler to use that approach
// consistently. // consistently.
f, err := fsys.OpenFile(name, flag&^os.O_TRUNC, perm) f, err := os.OpenFile(name, flag&^os.O_TRUNC, perm)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -13,8 +13,6 @@ import (
"os" "os"
"strings" "strings"
"time" "time"
"cmd/go/internal/fsys"
) )
// Opening an exclusive-use file returns an error. // Opening an exclusive-use file returns an error.
@ -59,7 +57,7 @@ func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) {
// If the file was unpacked or created by some other program, it might not // If the file was unpacked or created by some other program, it might not
// have the ModeExclusive bit set. Set it before we call OpenFile, so that we // have the ModeExclusive bit set. Set it before we call OpenFile, so that we
// can be confident that a successful OpenFile implies exclusive use. // can be confident that a successful OpenFile implies exclusive use.
if fi, err := fsys.Stat(name); err == nil { if fi, err := os.Stat(name); err == nil {
if fi.Mode()&fs.ModeExclusive == 0 { if fi.Mode()&fs.ModeExclusive == 0 {
if err := os.Chmod(name, fi.Mode()|fs.ModeExclusive); err != nil { if err := os.Chmod(name, fi.Mode()|fs.ModeExclusive); err != nil {
return nil, err return nil, err
@ -72,7 +70,7 @@ func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) {
nextSleep := 1 * time.Millisecond nextSleep := 1 * time.Millisecond
const maxSleep = 500 * time.Millisecond const maxSleep = 500 * time.Millisecond
for { for {
f, err := fsys.OpenFile(name, flag, perm|fs.ModeExclusive) f, err := os.OpenFile(name, flag, perm|fs.ModeExclusive)
if err == nil { if err == nil {
return f, nil return f, nil
} }

View File

@ -22,6 +22,7 @@ import (
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/fsys"
"cmd/go/internal/lockedfile" "cmd/go/internal/lockedfile"
"cmd/go/internal/par" "cmd/go/internal/par"
"cmd/go/internal/robustio" "cmd/go/internal/robustio"
@ -416,7 +417,18 @@ func initGoSum() (bool, error) {
goSum.m = make(map[module.Version][]string) goSum.m = make(map[module.Version][]string)
goSum.status = make(map[modSum]modSumStatus) goSum.status = make(map[modSum]modSumStatus)
data, err := lockedfile.Read(GoSumFile) var (
data []byte
err error
)
if actualSumFile, ok := fsys.OverlayPath(GoSumFile); ok {
// Don't lock go.sum if it's part of the overlay.
// On Plan 9, locking requires chmod, and we don't want to modify any file
// in the overlay. See #44700.
data, err = os.ReadFile(actualSumFile)
} else {
data, err = lockedfile.Read(GoSumFile)
}
if err != nil && !os.IsNotExist(err) { if err != nil && !os.IsNotExist(err) {
return false, err return false, err
} }
@ -716,6 +728,9 @@ Outer:
if cfg.BuildMod == "readonly" { if cfg.BuildMod == "readonly" {
base.Fatalf("go: updates to go.sum needed, disabled by -mod=readonly") base.Fatalf("go: updates to go.sum needed, disabled by -mod=readonly")
} }
if _, ok := fsys.OverlayPath(GoSumFile); ok {
base.Fatalf("go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay")
}
// Make a best-effort attempt to acquire the side lock, only to exclude // Make a best-effort attempt to acquire the side lock, only to exclude
// previous versions of the 'go' command from making simultaneous edits. // previous versions of the 'go' command from making simultaneous edits.

View File

@ -412,7 +412,16 @@ func loadModFile(ctx context.Context) (rs *Requirements, needCommit bool) {
} }
gomod := ModFilePath() gomod := ModFilePath()
data, err := lockedfile.Read(gomod) var data []byte
var err error
if gomodActual, ok := fsys.OverlayPath(gomod); ok {
// Don't lock go.mod if it's part of the overlay.
// On Plan 9, locking requires chmod, and we don't want to modify any file
// in the overlay. See #44700.
data, err = os.ReadFile(gomodActual)
} else {
data, err = lockedfile.Read(gomodActual)
}
if err != nil { if err != nil {
base.Fatalf("go: %v", err) base.Fatalf("go: %v", err)
} }
@ -1026,6 +1035,13 @@ func commitRequirements(ctx context.Context, goVersion string, rs *Requirements)
} }
return return
} }
gomod := ModFilePath()
if _, ok := fsys.OverlayPath(gomod); ok {
if dirty {
base.Fatalf("go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay")
}
return
}
new, err := modFile.Format() new, err := modFile.Format()
if err != nil { if err != nil {

View File

@ -8,6 +8,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"os"
"path/filepath" "path/filepath"
"strings" "strings"
"sync" "sync"
@ -15,6 +16,7 @@ import (
"cmd/go/internal/base" "cmd/go/internal/base"
"cmd/go/internal/cfg" "cmd/go/internal/cfg"
"cmd/go/internal/fsys"
"cmd/go/internal/lockedfile" "cmd/go/internal/lockedfile"
"cmd/go/internal/modfetch" "cmd/go/internal/modfetch"
"cmd/go/internal/par" "cmd/go/internal/par"
@ -601,8 +603,16 @@ func rawGoModSummary(m module.Version) (*modFileSummary, error) {
dir = filepath.Join(ModRoot(), dir) dir = filepath.Join(ModRoot(), dir)
} }
gomod := filepath.Join(dir, "go.mod") gomod := filepath.Join(dir, "go.mod")
var data []byte
data, err := lockedfile.Read(gomod) var err error
if gomodActual, ok := fsys.OverlayPath(gomod); ok {
// Don't lock go.mod if it's part of the overlay.
// On Plan 9, locking requires chmod, and we don't want to modify any file
// in the overlay. See #44700.
data, err = os.ReadFile(gomodActual)
} else {
data, err = lockedfile.Read(gomodActual)
}
if err != nil { if err != nil {
return cached{nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(gomod), err))} return cached{nil, module.VersionError(m, fmt.Errorf("reading %s: %v", base.ShortPath(gomod), err))}
} }

View File

@ -21,7 +21,7 @@ go list -deps -overlay overlay.json .
cd $WORK/gopath/src/get-doesnt-add-dep cd $WORK/gopath/src/get-doesnt-add-dep
cp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod cp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod
! go get -d -overlay overlay.json . ! go get -d -overlay overlay.json .
stderr 'overlaid files can''t be opened for write' stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$'
cmp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod cmp $WORK/overlay/get_doesnt_add_dep_go_mod $WORK/want_go_mod
# Content of overlaid go.sum is used. # Content of overlaid go.sum is used.
@ -41,10 +41,10 @@ go mod verify -overlay overlay.json
# attempting to update the file # attempting to update the file
cp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums cp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums
! go get -d -overlay overlay.json . ! go get -d -overlay overlay.json .
stderr 'overlaid files can''t be opened for write' stderr '^go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay$'
cmp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums cmp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums
! go mod tidy -overlay overlay.json ! go mod tidy -overlay overlay.json
stderr 'overlaid files can''t be opened for write' stderr '^go: updates to go.sum needed, but go.sum is part of the overlay specified with -overlay$'
cmp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums cmp incomplete-sum-file $WORK/overlay/overlay-sum-used-correct-sums
# -overlay works with -modfile. # -overlay works with -modfile.
@ -56,7 +56,7 @@ go list -modfile=alternate.mod -overlay overlay.json .
stdout 'found.the/module' stdout 'found.the/module'
# Even with -modfile, overlaid files can't be opened for write. # Even with -modfile, overlaid files can't be opened for write.
! go get -modfile=alternate.mod -overlay overlay.json -d rsc.io/quote ! go get -modfile=alternate.mod -overlay overlay.json -d rsc.io/quote
stderr 'overlaid files can''t be opened for write' stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$'
# Carving out a module by adding an overlaid go.mod file # Carving out a module by adding an overlaid go.mod file
cd $WORK/gopath/src/carve cd $WORK/gopath/src/carve
@ -78,7 +78,7 @@ go list -overlay overlay.json all
stdout ^carve2/nomod$ stdout ^carve2/nomod$
# Editing go.mod file fails because overlay is read only # Editing go.mod file fails because overlay is read only
! go get -overlay overlay.json -d rsc.io/quote ! go get -overlay overlay.json -d rsc.io/quote
stderr 'overlaid files can''t be opened for write' stderr '^go: updates to go.mod needed, but go.mod is part of the overlay specified with -overlay$'
! grep rsc.io/quote $WORK/overlay/carve2-nomod-go.mod ! grep rsc.io/quote $WORK/overlay/carve2-nomod-go.mod
# Editing go.mod file succeeds because we use -modfile to redirect to same file # Editing go.mod file succeeds because we use -modfile to redirect to same file
go get -overlay overlay.json -modfile $WORK/overlay/carve2-nomod-go.mod -d rsc.io/quote go get -overlay overlay.json -modfile $WORK/overlay/carve2-nomod-go.mod -d rsc.io/quote