Commit 84b0e366 authored by Bryan C. Mills's avatar Bryan C. Mills

cmd/go: add a flag to avoid creating unwritable directories in the module cache

This change adds the '-modcacherw' build flag, which leaves
newly-created directories (but not the files!) in the module cache
read-write instead of making them unwritable.

Fixes #31481

Change-Id: I7c21a53dd145676627c3b51096914ce797991d99
Reviewed-on: https://go-review.googlesource.com/c/go/+/202079
Run-TryBot: Bryan C. Mills <bcmills@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarJay Conrod <jayconrod@google.com>
parent b653c878
...@@ -112,6 +112,17 @@ TODO ...@@ -112,6 +112,17 @@ TODO
graphic characters and spaces. graphic characters and spaces.
</p> </p>
<p><!-- golang.org/issue/31481 -->
The <code>go</code> command now accepts a new flag, <code>-modcacherw</code>,
which leaves newly-created directories in the module cache at their default
permissions rather than making them read-only.
The use of this flag makes it more likely that tests or other tools will
accidentally add files not included in the module's verified checksum.
However, it allows the use of <code>rm</code> <code>-rf</code>
(instead of <code>go</code> <code>clean</code> <code>-modcache</code>)
to remove the module cache.
</p>
<h2 id="runtime">Runtime</h2> <h2 id="runtime">Runtime</h2>
<p> <p>
......
...@@ -150,6 +150,9 @@ ...@@ -150,6 +150,9 @@
// -mod mode // -mod mode
// module download mode to use: readonly or vendor. // module download mode to use: readonly or vendor.
// See 'go help modules' for more. // See 'go help modules' for more.
// -modcacherw
// leave newly-created directories in the module cache read-write
// instead of making them read-only.
// -pkgdir dir // -pkgdir dir
// install and load all packages from dir instead of the usual locations. // install and load all packages from dir instead of the usual locations.
// For example, when building with a non-standard configuration, // For example, when building with a non-standard configuration,
......
...@@ -33,6 +33,7 @@ var ( ...@@ -33,6 +33,7 @@ var (
BuildN bool // -n flag BuildN bool // -n flag
BuildO string // -o flag BuildO string // -o flag
BuildP = runtime.NumCPU() // -p flag BuildP = runtime.NumCPU() // -p flag
BuildModcacheRW bool // -modcacherw flag
BuildPkgdir string // -pkgdir flag BuildPkgdir string // -pkgdir flag
BuildRace bool // -race flag BuildRace bool // -race flag
BuildToolexec []string // -toolexec flag BuildToolexec []string // -toolexec flag
......
...@@ -125,9 +125,11 @@ func download(mod module.Version, dir string) (err error) { ...@@ -125,9 +125,11 @@ func download(mod module.Version, dir string) (err error) {
return err return err
} }
// Make dir read-only only *after* renaming it. if !cfg.BuildModcacheRW {
// os.Rename was observed to fail for read-only directories on macOS. // Make dir read-only only *after* renaming it.
makeDirsReadOnly(dir) // os.Rename was observed to fail for read-only directories on macOS.
makeDirsReadOnly(dir)
}
return nil return nil
} }
......
...@@ -102,6 +102,9 @@ and test commands: ...@@ -102,6 +102,9 @@ and test commands:
-mod mode -mod mode
module download mode to use: readonly or vendor. module download mode to use: readonly or vendor.
See 'go help modules' for more. See 'go help modules' for more.
-modcacherw
leave newly-created directories in the module cache read-write
instead of making them read-only.
-pkgdir dir -pkgdir dir
install and load all packages from dir instead of the usual locations. install and load all packages from dir instead of the usual locations.
For example, when building with a non-standard configuration, For example, when building with a non-standard configuration,
...@@ -243,6 +246,7 @@ func AddBuildFlags(cmd *base.Command, mask BuildFlagMask) { ...@@ -243,6 +246,7 @@ func AddBuildFlags(cmd *base.Command, mask BuildFlagMask) {
cmd.Flag.StringVar(&cfg.BuildContext.InstallSuffix, "installsuffix", "", "") cmd.Flag.StringVar(&cfg.BuildContext.InstallSuffix, "installsuffix", "", "")
cmd.Flag.Var(&load.BuildLdflags, "ldflags", "") cmd.Flag.Var(&load.BuildLdflags, "ldflags", "")
cmd.Flag.BoolVar(&cfg.BuildLinkshared, "linkshared", false, "") cmd.Flag.BoolVar(&cfg.BuildLinkshared, "linkshared", false, "")
cmd.Flag.BoolVar(&cfg.BuildModcacheRW, "modcacherw", false, "")
cmd.Flag.StringVar(&cfg.BuildPkgdir, "pkgdir", "", "") cmd.Flag.StringVar(&cfg.BuildPkgdir, "pkgdir", "", "")
cmd.Flag.BoolVar(&cfg.BuildRace, "race", false, "") cmd.Flag.BoolVar(&cfg.BuildRace, "race", false, "")
cmd.Flag.BoolVar(&cfg.BuildMSan, "msan", false, "") cmd.Flag.BoolVar(&cfg.BuildMSan, "msan", false, "")
......
...@@ -502,9 +502,6 @@ func (ts *testScript) doCmdCmp(args []string, env, quiet bool) { ...@@ -502,9 +502,6 @@ func (ts *testScript) doCmdCmp(args []string, env, quiet bool) {
// cp copies files, maybe eventually directories. // cp copies files, maybe eventually directories.
func (ts *testScript) cmdCp(neg bool, args []string) { func (ts *testScript) cmdCp(neg bool, args []string) {
if neg {
ts.fatalf("unsupported: ! cp")
}
if len(args) < 2 { if len(args) < 2 {
ts.fatalf("usage: cp src... dst") ts.fatalf("usage: cp src... dst")
} }
...@@ -543,7 +540,14 @@ func (ts *testScript) cmdCp(neg bool, args []string) { ...@@ -543,7 +540,14 @@ func (ts *testScript) cmdCp(neg bool, args []string) {
if dstDir { if dstDir {
targ = filepath.Join(dst, filepath.Base(src)) targ = filepath.Join(dst, filepath.Base(src))
} }
ts.check(ioutil.WriteFile(targ, data, mode)) err := ioutil.WriteFile(targ, data, mode)
if neg {
if err == nil {
ts.fatalf("unexpected command success")
}
} else {
ts.check(err)
}
} }
} }
......
...@@ -107,7 +107,7 @@ The commands are: ...@@ -107,7 +107,7 @@ The commands are:
Like cmp, but environment variables are substituted in the file contents Like cmp, but environment variables are substituted in the file contents
before the comparison. For example, $GOOS is replaced by the target GOOS. before the comparison. For example, $GOOS is replaced by the target GOOS.
- cp src... dst - [!] cp src... dst
Copy the listed files to the target file or existing directory. Copy the listed files to the target file or existing directory.
src can include "stdout" or "stderr" to use the standard output or standard error src can include "stdout" or "stderr" to use the standard output or standard error
from the most recent exec or go command. from the most recent exec or go command.
......
# Regression test for golang.org/issue/31481.
env GO111MODULE=on
# golang.org/issue/31481: an explicit flag should make directories in the module
# cache writable in order to work around the historical inability of 'rm -rf' to
# forcibly remove files in unwritable directories.
go get -modcacherw -d rsc.io/quote@v1.5.2
cp $WORK/extraneous.txt $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/extraneous_file.go
# After adding an extraneous file, 'go mod verify' should fail.
! go mod verify
# However, files within those directories should still be read-only to avoid
# accidental mutations.
# TODO: Today, this does not seem to be effective on Windows.
# (https://golang.org/issue/35033)
[!windows] [!root] ! cp $WORK/extraneous.txt $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod
# If all 'go' commands ran with the flag, the system's 'rm' binary
# should be able to remove the module cache if the '-rf' flags are set.
[!windows] [exec:rm] exec rm -rf $GOPATH/pkg/mod
[!windows] [!exec:rm] go clean -modcache
[windows] [exec:rmdir] exec rmdir /s /q $GOPATH\pkg\mod
[windows] [!exec:rmdir] go clean -modcache
! exists $GOPATH/pkg/mod
# The directories in the module cache should by default be unwritable,
# so that tests and tools will not accidentally add extraneous files to them.
go get -d rsc.io/quote@latest
[!windows] [!root] ! cp $WORK/extraneous.txt $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/go.mod
[!windows] [!root] ! cp $WORK/extraneous.txt $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/extraneous_file.go
! exists $GOPATH/pkg/mod/rsc.io/quote@v1.5.2/extraneous_file.go
-- $WORK/extraneous.txt --
module oops
-- go.mod --
module golang.org/issue/31481
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