From a50237a54f4c210d6c4678c85b365aa64173d812 Mon Sep 17 00:00:00 2001 From: Vorapol Rinsatitnon Date: Sat, 9 Nov 2024 17:58:11 +1100 Subject: [PATCH] Add patch files --- ...tch-ProcessPrng-back-to-RtlGenRandom.patch | 159 ++ patches/0002-Restore-GOPATH-mode-get.patch | 2456 +++++++++++++++++ ...related-GOPATH-mode-go-get-functions.patch | 211 ++ .../0004-Add-back-LoadLibraryA-fallback.patch | 307 +++ ...-Windows-7-console-handle-workaround.patch | 66 + patches/0006-Add-sysSocket-fallback.patch | 177 ++ ...-Add-Windows-version-info-to-syscall.patch | 82 + 7 files changed, 3458 insertions(+) create mode 100644 patches/0001-Switch-ProcessPrng-back-to-RtlGenRandom.patch create mode 100644 patches/0002-Restore-GOPATH-mode-get.patch create mode 100644 patches/0003-Restore-related-GOPATH-mode-go-get-functions.patch create mode 100644 patches/0004-Add-back-LoadLibraryA-fallback.patch create mode 100644 patches/0005-Add-Windows-7-console-handle-workaround.patch create mode 100644 patches/0006-Add-sysSocket-fallback.patch create mode 100644 patches/0007-Add-Windows-version-info-to-syscall.patch diff --git a/patches/0001-Switch-ProcessPrng-back-to-RtlGenRandom.patch b/patches/0001-Switch-ProcessPrng-back-to-RtlGenRandom.patch new file mode 100644 index 00000000..110ce002 --- /dev/null +++ b/patches/0001-Switch-ProcessPrng-back-to-RtlGenRandom.patch @@ -0,0 +1,159 @@ +From f1f146d4534fc925bceffe523852fe2261841008 Mon Sep 17 00:00:00 2001 +From: Vorapol Rinsatitnon +Date: Sat, 21 Sep 2024 23:56:11 +1000 +Subject: [PATCH] Switch ProcessPrng back to RtlGenRandom (revert 693def1) + +--- + src/crypto/rand/rand.go | 2 +- + src/crypto/rand/rand_windows.go | 7 +++-- + .../syscall/windows/syscall_windows.go | 2 +- + .../syscall/windows/zsyscall_windows.go | 7 ++--- + src/runtime/os_windows.go | 30 ++++++++++++------- + 5 files changed, 29 insertions(+), 19 deletions(-) + +diff --git a/src/crypto/rand/rand.go b/src/crypto/rand/rand.go +index d16d7a1..cdfeb06 100644 +--- a/src/crypto/rand/rand.go ++++ b/src/crypto/rand/rand.go +@@ -16,7 +16,7 @@ import "io" + // - On macOS and iOS, Reader uses arc4random_buf(3). + // - On OpenBSD and NetBSD, Reader uses getentropy(2). + // - On other Unix-like systems, Reader reads from /dev/urandom. +-// - On Windows, Reader uses the ProcessPrng API. ++// - On Windows, Reader uses the RtlGenRandom API. + // - On js/wasm, Reader uses the Web Crypto API. + // - On wasip1/wasm, Reader uses random_get from wasi_snapshot_preview1. + var Reader io.Reader +diff --git a/src/crypto/rand/rand_windows.go b/src/crypto/rand/rand_windows.go +index 7380f1f..6c0655c 100644 +--- a/src/crypto/rand/rand_windows.go ++++ b/src/crypto/rand/rand_windows.go +@@ -15,8 +15,11 @@ func init() { Reader = &rngReader{} } + + type rngReader struct{} + +-func (r *rngReader) Read(b []byte) (int, error) { +- if err := windows.ProcessPrng(b); err != nil { ++func (r *rngReader) Read(b []byte) (n int, err error) { ++ // RtlGenRandom only returns 1<<32-1 bytes at a time. We only read at ++ // most 1<<31-1 bytes at a time so that this works the same on 32-bit ++ // and 64-bit systems. ++ if err := batched(windows.RtlGenRandom, 1<<31-1)(b); err != nil { + return 0, err + } + return len(b), nil +diff --git a/src/internal/syscall/windows/syscall_windows.go b/src/internal/syscall/windows/syscall_windows.go +index cc26a50..b0b5a64 100644 +--- a/src/internal/syscall/windows/syscall_windows.go ++++ b/src/internal/syscall/windows/syscall_windows.go +@@ -414,7 +414,7 @@ func ErrorLoadingGetTempPath2() error { + //sys DestroyEnvironmentBlock(block *uint16) (err error) = userenv.DestroyEnvironmentBlock + //sys CreateEvent(eventAttrs *SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle syscall.Handle, err error) = kernel32.CreateEventW + +-//sys ProcessPrng(buf []byte) (err error) = bcryptprimitives.ProcessPrng ++//sys RtlGenRandom(buf []byte) (err error) = advapi32.SystemFunction036 + + type FILE_ID_BOTH_DIR_INFO struct { + NextEntryOffset uint32 +diff --git a/src/internal/syscall/windows/zsyscall_windows.go b/src/internal/syscall/windows/zsyscall_windows.go +index 414ad26..062641c 100644 +--- a/src/internal/syscall/windows/zsyscall_windows.go ++++ b/src/internal/syscall/windows/zsyscall_windows.go +@@ -38,7 +38,6 @@ func errnoErr(e syscall.Errno) error { + + var ( + modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll")) +- modbcryptprimitives = syscall.NewLazyDLL(sysdll.Add("bcryptprimitives.dll")) + modiphlpapi = syscall.NewLazyDLL(sysdll.Add("iphlpapi.dll")) + modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll")) + modnetapi32 = syscall.NewLazyDLL(sysdll.Add("netapi32.dll")) +@@ -57,7 +56,7 @@ var ( + procQueryServiceStatus = modadvapi32.NewProc("QueryServiceStatus") + procRevertToSelf = modadvapi32.NewProc("RevertToSelf") + procSetTokenInformation = modadvapi32.NewProc("SetTokenInformation") +- procProcessPrng = modbcryptprimitives.NewProc("ProcessPrng") ++ procSystemFunction036 = modadvapi32.NewProc("SystemFunction036") + procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses") + procCreateEventW = modkernel32.NewProc("CreateEventW") + procGetACP = modkernel32.NewProc("GetACP") +@@ -183,12 +182,12 @@ func SetTokenInformation(tokenHandle syscall.Token, tokenInformationClass uint32 + return + } + +-func ProcessPrng(buf []byte) (err error) { ++func RtlGenRandom(buf []byte) (err error) { + var _p0 *byte + if len(buf) > 0 { + _p0 = &buf[0] + } +- r1, _, e1 := syscall.Syscall(procProcessPrng.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0) ++ r1, _, e1 := syscall.Syscall(procSystemFunction036.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0) + if r1 == 0 { + err = errnoErr(e1) + } +diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go +index 4aabc29..0273580 100644 +--- a/src/runtime/os_windows.go ++++ b/src/runtime/os_windows.go +@@ -127,8 +127,15 @@ var ( + _WriteFile, + _ stdFunction + +- // Use ProcessPrng to generate cryptographically random data. +- _ProcessPrng stdFunction ++ // Use RtlGenRandom to generate cryptographically random data. ++ // This approach has been recommended by Microsoft (see issue ++ // 15589 for details). ++ // The RtlGenRandom is not listed in advapi32.dll, instead ++ // RtlGenRandom function can be found by searching for SystemFunction036. ++ // Also some versions of Mingw cannot link to SystemFunction036 ++ // when building executable as Cgo. So load SystemFunction036 ++ // manually during runtime startup. ++ _RtlGenRandom stdFunction + + // Load ntdll.dll manually during startup, otherwise Mingw + // links wrong printf function to cgo executable (see issue +@@ -146,10 +153,11 @@ var ( + ) + + var ( +- bcryptprimitivesdll = [...]uint16{'b', 'c', 'r', 'y', 'p', 't', 'p', 'r', 'i', 'm', 'i', 't', 'i', 'v', 'e', 's', '.', 'd', 'l', 'l', 0} +- ntdlldll = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0} +- powrprofdll = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0} +- winmmdll = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0} ++ advapi32dll = [...]uint16{'a', 'd', 'v', 'a', 'p', 'i', '3', '2', '.', 'd', 'l', 'l', 0} ++ ntdlldll = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0} ++ powrprofdll = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0} ++ winmmdll = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0} ++ ws2_32dll = [...]uint16{'w', 's', '2', '_', '3', '2', '.', 'd', 'l', 'l', 0} + ) + + // Function to be called by windows CreateThread +@@ -263,11 +271,11 @@ func windows_QueryPerformanceFrequency() int64 { + } + + func loadOptionalSyscalls() { +- bcryptPrimitives := windowsLoadSystemLib(bcryptprimitivesdll[:]) +- if bcryptPrimitives == 0 { +- throw("bcryptprimitives.dll not found") ++ a32 := windowsLoadSystemLib(advapi32dll[:]) ++ if a32 == 0 { ++ throw("advapi32.dll not found") + } +- _ProcessPrng = windowsFindfunc(bcryptPrimitives, []byte("ProcessPrng\000")) ++ _RtlGenRandom = windowsFindfunc(a32, []byte("SystemFunction036\000")) + + n32 := windowsLoadSystemLib(ntdlldll[:]) + if n32 == 0 { +@@ -500,7 +508,7 @@ func osinit() { + //go:nosplit + func readRandom(r []byte) int { + n := 0 +- if stdcall2(_ProcessPrng, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 { ++ if stdcall2(_RtlGenRandom, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 { + n = len(r) + } + return n +-- +2.47.0 + diff --git a/patches/0002-Restore-GOPATH-mode-get.patch b/patches/0002-Restore-GOPATH-mode-get.patch new file mode 100644 index 00000000..4892ecd9 --- /dev/null +++ b/patches/0002-Restore-GOPATH-mode-get.patch @@ -0,0 +1,2456 @@ +From d02338f60a2671b5d8f748956aa90cf7011b72e2 Mon Sep 17 00:00:00 2001 +From: Vorapol Rinsatitnon +Date: Sun, 22 Sep 2024 00:23:47 +1000 +Subject: [PATCH] Restore GOPATH-mode get (revert de4d503) + +--- + src/cmd/go/alldocs.go | 66 ++ + src/cmd/go/go_test.go | 100 +++ + src/cmd/go/internal/get/get.go | 640 ++++++++++++++++++ + src/cmd/go/internal/get/tag_test.go | 100 +++ + src/cmd/go/internal/help/help.go | 7 + + src/cmd/go/internal/modget/get.go | 17 + + src/cmd/go/main.go | 10 + + src/cmd/go/testdata/script/get_404_meta.txt | 3 + + src/cmd/go/testdata/script/get_brace.txt | 51 ++ + .../script/get_custom_domain_wildcard.txt | 6 + + src/cmd/go/testdata/script/get_dash_t.txt | 9 + + .../go/testdata/script/get_domain_root.txt | 20 + + .../script/get_dot_slash_download.txt | 10 + + src/cmd/go/testdata/script/get_dotfiles.txt | 64 ++ + src/cmd/go/testdata/script/get_go_file.txt | 60 ++ + src/cmd/go/testdata/script/get_goroot.txt | 53 ++ + src/cmd/go/testdata/script/get_insecure.txt | 16 + + .../script/get_insecure_custom_domain.txt | 8 + + .../go/testdata/script/get_insecure_env.txt | 29 + + .../testdata/script/get_insecure_redirect.txt | 14 + + .../testdata/script/get_insecure_update.txt | 14 + + .../testdata/script/get_internal_wildcard.txt | 6 + + src/cmd/go/testdata/script/get_issue11307.txt | 9 + + src/cmd/go/testdata/script/get_issue16471.txt | 23 + + src/cmd/go/testdata/script/get_issue22125.txt | 14 + + src/cmd/go/testdata/script/get_legacy.txt | 58 ++ + src/cmd/go/testdata/script/get_non_pkg.txt | 14 + + src/cmd/go/testdata/script/get_race.txt | 8 + + src/cmd/go/testdata/script/get_test_only.txt | 6 + + src/cmd/go/testdata/script/get_tilde.txt | 25 + + src/cmd/go/testdata/script/get_update.txt | 25 + + src/cmd/go/testdata/script/get_update_all.txt | 7 + + .../script/get_update_unknown_protocol.txt | 14 + + .../testdata/script/get_update_wildcard.txt | 16 + + .../testdata/script/get_vcs_error_message.txt | 9 + + src/cmd/go/testdata/script/get_vendor.txt | 95 +++ + .../go/testdata/script/get_with_git_trace.txt | 9 + + .../go/testdata/script/gopath_moved_repo.txt | 67 ++ + src/cmd/go/testdata/script/govcs.txt | 83 +++ + src/cmd/go/testdata/script/help.txt | 2 +- + src/cmd/go/testdata/script/mod_versions.txt | 2 +- + .../script/vendor_list_issue11977.txt | 78 +-- + .../script/vendor_test_issue11864.txt | 79 +-- + .../script/vendor_test_issue14613.txt | 46 +- + 44 files changed, 1801 insertions(+), 191 deletions(-) + create mode 100644 src/cmd/go/internal/get/get.go + create mode 100644 src/cmd/go/internal/get/tag_test.go + create mode 100644 src/cmd/go/testdata/script/get_brace.txt + create mode 100644 src/cmd/go/testdata/script/get_custom_domain_wildcard.txt + create mode 100644 src/cmd/go/testdata/script/get_dash_t.txt + create mode 100644 src/cmd/go/testdata/script/get_domain_root.txt + create mode 100644 src/cmd/go/testdata/script/get_dot_slash_download.txt + create mode 100644 src/cmd/go/testdata/script/get_dotfiles.txt + create mode 100644 src/cmd/go/testdata/script/get_go_file.txt + create mode 100644 src/cmd/go/testdata/script/get_goroot.txt + create mode 100644 src/cmd/go/testdata/script/get_insecure_custom_domain.txt + create mode 100644 src/cmd/go/testdata/script/get_insecure_env.txt + create mode 100644 src/cmd/go/testdata/script/get_insecure_redirect.txt + create mode 100644 src/cmd/go/testdata/script/get_insecure_update.txt + create mode 100644 src/cmd/go/testdata/script/get_internal_wildcard.txt + create mode 100644 src/cmd/go/testdata/script/get_issue11307.txt + create mode 100644 src/cmd/go/testdata/script/get_issue16471.txt + create mode 100644 src/cmd/go/testdata/script/get_issue22125.txt + create mode 100644 src/cmd/go/testdata/script/get_legacy.txt + create mode 100644 src/cmd/go/testdata/script/get_non_pkg.txt + create mode 100644 src/cmd/go/testdata/script/get_race.txt + create mode 100644 src/cmd/go/testdata/script/get_test_only.txt + create mode 100644 src/cmd/go/testdata/script/get_tilde.txt + create mode 100644 src/cmd/go/testdata/script/get_update.txt + create mode 100644 src/cmd/go/testdata/script/get_update_all.txt + create mode 100644 src/cmd/go/testdata/script/get_update_unknown_protocol.txt + create mode 100644 src/cmd/go/testdata/script/get_update_wildcard.txt + create mode 100644 src/cmd/go/testdata/script/get_vcs_error_message.txt + create mode 100644 src/cmd/go/testdata/script/get_vendor.txt + create mode 100644 src/cmd/go/testdata/script/get_with_git_trace.txt + create mode 100644 src/cmd/go/testdata/script/gopath_moved_repo.txt + +diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go +index 75e6d65..abbad2c 100644 +--- a/src/cmd/go/alldocs.go ++++ b/src/cmd/go/alldocs.go +@@ -45,9 +45,11 @@ + // filetype file types + // go.mod the go.mod file + // gopath GOPATH environment variable ++// gopath-get legacy GOPATH go get + // goproxy module proxy protocol + // importpath import path syntax + // modules modules, module versions, and more ++// module-get module-aware go get + // module-auth module authentication using go.sum + // packages package lists and patterns + // private configuration for downloading non-public code +@@ -2661,6 +2663,70 @@ + // + // See https://golang.org/s/go15vendor for details. + // ++// # Legacy GOPATH go get ++// ++// The 'go get' command changes behavior depending on whether the ++// go command is running in module-aware mode or legacy GOPATH mode. ++// This help text, accessible as 'go help gopath-get' even in module-aware mode, ++// describes 'go get' as it operates in legacy GOPATH mode. ++// ++// Usage: go get [-d] [-f] [-t] [-u] [-v] [-fix] [build flags] [packages] ++// ++// Get downloads the packages named by the import paths, along with their ++// dependencies. It then installs the named packages, like 'go install'. ++// ++// The -d flag instructs get to stop after downloading the packages; that is, ++// it instructs get not to install the packages. ++// ++// The -f flag, valid only when -u is set, forces get -u not to verify that ++// each package has been checked out from the source control repository ++// implied by its import path. This can be useful if the source is a local fork ++// of the original. ++// ++// The -fix flag instructs get to run the fix tool on the downloaded packages ++// before resolving dependencies or building the code. ++// ++// The -t flag instructs get to also download the packages required to build ++// the tests for the specified packages. ++// ++// The -u flag instructs get to use the network to update the named packages ++// and their dependencies. By default, get uses the network to check out ++// missing packages but does not use it to look for updates to existing packages. ++// ++// The -v flag enables verbose progress and debug output. ++// ++// Get also accepts build flags to control the installation. See 'go help build'. ++// ++// When checking out a new package, get creates the target directory ++// GOPATH/src/. If the GOPATH contains multiple entries, ++// get uses the first one. For more details see: 'go help gopath'. ++// ++// When checking out or updating a package, get looks for a branch or tag ++// that matches the locally installed version of Go. The most important ++// rule is that if the local installation is running version "go1", get ++// searches for a branch or tag named "go1". If no such version exists ++// it retrieves the default branch of the package. ++// ++// When go get checks out or updates a Git repository, ++// it also updates any git submodules referenced by the repository. ++// ++// Get never checks out or updates code stored in vendor directories. ++// ++// For more about build flags, see 'go help build'. ++// ++// For more about specifying packages, see 'go help packages'. ++// ++// For more about how 'go get' finds source code to ++// download, see 'go help importpath'. ++// ++// This text describes the behavior of get when using GOPATH ++// to manage source code and dependencies. ++// If instead the go command is running in module-aware mode, ++// the details of get's flags and effects change, as does 'go help get'. ++// See 'go help modules' and 'go help module-get'. ++// ++// See also: go build, go install, go clean. ++// + // # Module proxy protocol + // + // A Go module proxy is any web server that can respond to GET requests for +diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go +index b45a905..b06fef6 100644 +--- a/src/cmd/go/go_test.go ++++ b/src/cmd/go/go_test.go +@@ -972,6 +972,77 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) { + tg.wantNotStale("p1", "", "./testgo list claims p1 is stale after building with old release") + } + ++// cmd/go: custom import path checking should not apply to Go packages without import comment. ++func TestIssue10952(t *testing.T) { ++ testenv.MustHaveExecPath(t, "git") ++ ++ tg := testgo(t) ++ defer tg.cleanup() ++ tg.parallel() ++ tg.acquireNet() ++ ++ tg.tempDir("src") ++ tg.setenv("GOPATH", tg.path(".")) ++ const importPath = "github.com/zombiezen/go-get-issue-10952" ++ tg.run("get", "-d", "-u", importPath) ++ repoDir := tg.path("src/" + importPath) ++ tg.runGit(repoDir, "remote", "set-url", "origin", "https://"+importPath+".git") ++ tg.run("get", "-d", "-u", importPath) ++} ++ ++// Test git clone URL that uses SCP-like syntax and custom import path checking. ++func TestIssue11457(t *testing.T) { ++ testenv.MustHaveExecPath(t, "git") ++ ++ tg := testgo(t) ++ defer tg.cleanup() ++ tg.parallel() ++ tg.acquireNet() ++ ++ tg.tempDir("src") ++ tg.setenv("GOPATH", tg.path(".")) ++ const importPath = "rsc.io/go-get-issue-11457" ++ tg.run("get", "-d", "-u", importPath) ++ repoDir := tg.path("src/" + importPath) ++ tg.runGit(repoDir, "remote", "set-url", "origin", "git@github.com:rsc/go-get-issue-11457") ++ ++ // At this time, custom import path checking compares remotes verbatim (rather than ++ // just the host and path, skipping scheme and user), so we expect go get -u to fail. ++ // However, the goal of this test is to verify that gitRemoteRepo correctly parsed ++ // the SCP-like syntax, and we expect it to appear in the error message. ++ tg.runFail("get", "-d", "-u", importPath) ++ want := " is checked out from ssh://git@github.com/rsc/go-get-issue-11457" ++ if !strings.HasSuffix(strings.TrimSpace(tg.getStderr()), want) { ++ t.Error("expected clone URL to appear in stderr") ++ } ++} ++ ++func TestGetGitDefaultBranch(t *testing.T) { ++ testenv.MustHaveExecPath(t, "git") ++ ++ tg := testgo(t) ++ defer tg.cleanup() ++ tg.parallel() ++ tg.acquireNet() ++ ++ tg.tempDir("src") ++ tg.setenv("GOPATH", tg.path(".")) ++ ++ // This repo has two branches, master and another-branch. ++ // The another-branch is the default that you get from 'git clone'. ++ // The go get command variants should not override this. ++ const importPath = "github.com/rsc/go-get-default-branch" ++ ++ tg.run("get", "-d", importPath) ++ repoDir := tg.path("src/" + importPath) ++ tg.runGit(repoDir, "branch", "--contains", "HEAD") ++ tg.grepStdout(`\* another-branch`, "not on correct default branch") ++ ++ tg.run("get", "-d", "-u", importPath) ++ tg.runGit(repoDir, "branch", "--contains", "HEAD") ++ tg.grepStdout(`\* another-branch`, "not on correct default branch") ++} ++ + func TestPackageMainTestCompilerFlags(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() +@@ -1292,6 +1363,35 @@ func TestDefaultGOPATH(t *testing.T) { + tg.grepStdoutNot(".", "want unset GOPATH because GOROOT=$HOME/go/") + } + ++func TestDefaultGOPATHGet(t *testing.T) { ++ testenv.MustHaveExecPath(t, "git") ++ ++ tg := testgo(t) ++ defer tg.cleanup() ++ tg.parallel() ++ tg.acquireNet() ++ ++ tg.setenv("GOPATH", "") ++ tg.tempDir("home") ++ tg.setenv(homeEnvName(), tg.path("home")) ++ ++ // warn for creating directory ++ tg.run("get", "-v", "github.com/golang/example/hello") ++ tg.grepStderr("created GOPATH="+regexp.QuoteMeta(tg.path("home/go"))+"; see 'go help gopath'", "did not create GOPATH") ++ ++ // no warning if directory already exists ++ tg.must(robustio.RemoveAll(tg.path("home/go"))) ++ tg.tempDir("home/go") ++ tg.run("get", "github.com/golang/example/hello") ++ tg.grepStderrNot(".", "expected no output on standard error") ++ ++ // error if $HOME/go is a file ++ tg.must(robustio.RemoveAll(tg.path("home/go"))) ++ tg.tempFile("home/go", "") ++ tg.runFail("get", "github.com/golang/example/hello") ++ tg.grepStderr(`mkdir .*[/\\]go: .*(not a directory|cannot find the path)`, "expected error because $HOME/go is a file") ++} ++ + func TestDefaultGOPATHPrintedSearchList(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() +diff --git a/src/cmd/go/internal/get/get.go b/src/cmd/go/internal/get/get.go +new file mode 100644 +index 0000000..06b567a +--- /dev/null ++++ b/src/cmd/go/internal/get/get.go +@@ -0,0 +1,640 @@ ++// Copyright 2011 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 get implements the “go get” command. ++package get ++ ++import ( ++ "context" ++ "fmt" ++ "os" ++ "path/filepath" ++ "runtime" ++ "strings" ++ ++ "cmd/go/internal/base" ++ "cmd/go/internal/cfg" ++ "cmd/go/internal/load" ++ "cmd/go/internal/search" ++ "cmd/go/internal/str" ++ "cmd/go/internal/vcs" ++ "cmd/go/internal/web" ++ "cmd/go/internal/work" ++ ++ "golang.org/x/mod/module" ++) ++ ++var CmdGet = &base.Command{ ++ UsageLine: "go get [-d] [-f] [-t] [-u] [-v] [-fix] [build flags] [packages]", ++ Short: "download and install packages and dependencies", ++ Long: ` ++Get downloads the packages named by the import paths, along with their ++dependencies. It then installs the named packages, like 'go install'. ++ ++The -d flag instructs get to stop after downloading the packages; that is, ++it instructs get not to install the packages. ++ ++The -f flag, valid only when -u is set, forces get -u not to verify that ++each package has been checked out from the source control repository ++implied by its import path. This can be useful if the source is a local fork ++of the original. ++ ++The -fix flag instructs get to run the fix tool on the downloaded packages ++before resolving dependencies or building the code. ++ ++The -t flag instructs get to also download the packages required to build ++the tests for the specified packages. ++ ++The -u flag instructs get to use the network to update the named packages ++and their dependencies. By default, get uses the network to check out ++missing packages but does not use it to look for updates to existing packages. ++ ++The -v flag enables verbose progress and debug output. ++ ++Get also accepts build flags to control the installation. See 'go help build'. ++ ++When checking out a new package, get creates the target directory ++GOPATH/src/. If the GOPATH contains multiple entries, ++get uses the first one. For more details see: 'go help gopath'. ++ ++When checking out or updating a package, get looks for a branch or tag ++that matches the locally installed version of Go. The most important ++rule is that if the local installation is running version "go1", get ++searches for a branch or tag named "go1". If no such version exists ++it retrieves the default branch of the package. ++ ++When go get checks out or updates a Git repository, ++it also updates any git submodules referenced by the repository. ++ ++Get never checks out or updates code stored in vendor directories. ++ ++For more about build flags, see 'go help build'. ++ ++For more about specifying packages, see 'go help packages'. ++ ++For more about how 'go get' finds source code to ++download, see 'go help importpath'. ++ ++This text describes the behavior of get when using GOPATH ++to manage source code and dependencies. ++If instead the go command is running in module-aware mode, ++the details of get's flags and effects change, as does 'go help get'. ++See 'go help modules' and 'go help module-get'. ++ ++See also: go build, go install, go clean. ++ `, ++} ++ ++var HelpGopathGet = &base.Command{ ++ UsageLine: "gopath-get", ++ Short: "legacy GOPATH go get", ++ Long: ` ++The 'go get' command changes behavior depending on whether the ++go command is running in module-aware mode or legacy GOPATH mode. ++This help text, accessible as 'go help gopath-get' even in module-aware mode, ++describes 'go get' as it operates in legacy GOPATH mode. ++ ++Usage: ` + CmdGet.UsageLine + ` ++` + CmdGet.Long, ++} ++ ++var ( ++ getD = CmdGet.Flag.Bool("d", false, "") ++ getF = CmdGet.Flag.Bool("f", false, "") ++ getT = CmdGet.Flag.Bool("t", false, "") ++ getU = CmdGet.Flag.Bool("u", false, "") ++ getFix = CmdGet.Flag.Bool("fix", false, "") ++ getInsecure = CmdGet.Flag.Bool("insecure", false, "") ++) ++ ++func init() { ++ work.AddBuildFlags(CmdGet, work.OmitModFlag|work.OmitModCommonFlags) ++ CmdGet.Run = runGet // break init loop ++} ++ ++func runGet(ctx context.Context, cmd *base.Command, args []string) { ++ if cfg.ModulesEnabled { ++ // Should not happen: main.go should install the separate module-enabled get code. ++ base.Fatalf("go: modules not implemented") ++ } ++ ++ work.BuildInit() ++ ++ if *getF && !*getU { ++ base.Fatalf("go: cannot use -f flag without -u") ++ } ++ if *getInsecure { ++ base.Fatalf("go: -insecure flag is no longer supported; use GOINSECURE instead") ++ } ++ ++ // Disable any prompting for passwords by Git itself. ++ // Only has an effect for 2.3.0 or later, but avoiding ++ // the prompt in earlier versions is just too hard. ++ // If user has explicitly set GIT_TERMINAL_PROMPT=1, keep ++ // prompting. ++ // See golang.org/issue/9341 and golang.org/issue/12706. ++ if os.Getenv("GIT_TERMINAL_PROMPT") == "" { ++ os.Setenv("GIT_TERMINAL_PROMPT", "0") ++ } ++ ++ // Also disable prompting for passwords by the 'ssh' subprocess spawned by ++ // Git, because apparently GIT_TERMINAL_PROMPT isn't sufficient to do that. ++ // Adding '-o BatchMode=yes' should do the trick. ++ // ++ // If a Git subprocess forks a child into the background to cache a new connection, ++ // that child keeps stdout/stderr open. After the Git subprocess exits, ++ // os /exec expects to be able to read from the stdout/stderr pipe ++ // until EOF to get all the data that the Git subprocess wrote before exiting. ++ // The EOF doesn't come until the child exits too, because the child ++ // is holding the write end of the pipe. ++ // This is unfortunate, but it has come up at least twice ++ // (see golang.org/issue/13453 and golang.org/issue/16104) ++ // and confuses users when it does. ++ // If the user has explicitly set GIT_SSH or GIT_SSH_COMMAND, ++ // assume they know what they are doing and don't step on it. ++ // But default to turning off ControlMaster. ++ if os.Getenv("GIT_SSH") == "" && os.Getenv("GIT_SSH_COMMAND") == "" { ++ os.Setenv("GIT_SSH_COMMAND", "ssh -o ControlMaster=no -o BatchMode=yes") ++ } ++ ++ // And one more source of Git prompts: the Git Credential Manager Core for Windows. ++ // ++ // See https://github.com/microsoft/Git-Credential-Manager-Core/blob/master/docs/environment.md#gcm_interactive. ++ if os.Getenv("GCM_INTERACTIVE") == "" { ++ os.Setenv("GCM_INTERACTIVE", "never") ++ } ++ ++ // Phase 1. Download/update. ++ var stk load.ImportStack ++ mode := 0 ++ if *getT { ++ mode |= load.GetTestDeps ++ } ++ for _, pkg := range downloadPaths(args) { ++ download(ctx, pkg, nil, &stk, mode) ++ } ++ base.ExitIfErrors() ++ ++ // Phase 2. Rescan packages and re-evaluate args list. ++ ++ // Code we downloaded and all code that depends on it ++ // needs to be evicted from the package cache so that ++ // the information will be recomputed. Instead of keeping ++ // track of the reverse dependency information, evict ++ // everything. ++ load.ClearPackageCache() ++ ++ pkgs := load.PackagesAndErrors(ctx, load.PackageOpts{}, args) ++ load.CheckPackageErrors(pkgs) ++ ++ // Phase 3. Install. ++ if *getD { ++ // Download only. ++ // Check delayed until now so that downloadPaths ++ // and CheckPackageErrors have a chance to print errors. ++ return ++ } ++ ++ work.InstallPackages(ctx, args, pkgs) ++} ++ ++// downloadPaths prepares the list of paths to pass to download. ++// It expands ... patterns that can be expanded. If there is no match ++// for a particular pattern, downloadPaths leaves it in the result list, ++// in the hope that we can figure out the repository from the ++// initial ...-free prefix. ++func downloadPaths(patterns []string) []string { ++ for _, arg := range patterns { ++ if strings.Contains(arg, "@") { ++ base.Fatalf("go: can only use path@version syntax with 'go get' and 'go install' in module-aware mode") ++ } ++ ++ // Guard against 'go get x.go', a common mistake. ++ // Note that package and module paths may end with '.go', so only print an error ++ // if the argument has no slash or refers to an existing file. ++ if strings.HasSuffix(arg, ".go") { ++ if !strings.Contains(arg, "/") { ++ base.Errorf("go: %s: arguments must be package or module paths", arg) ++ continue ++ } ++ if fi, err := os.Stat(arg); err == nil && !fi.IsDir() { ++ base.Errorf("go: %s exists as a file, but 'go get' requires package arguments", arg) ++ } ++ } ++ } ++ base.ExitIfErrors() ++ ++ var pkgs []string ++ noModRoots := []string{} ++ for _, m := range search.ImportPathsQuiet(patterns, noModRoots) { ++ if len(m.Pkgs) == 0 && strings.Contains(m.Pattern(), "...") { ++ pkgs = append(pkgs, m.Pattern()) ++ } else { ++ pkgs = append(pkgs, m.Pkgs...) ++ } ++ } ++ return pkgs ++} ++ ++// downloadCache records the import paths we have already ++// considered during the download, to avoid duplicate work when ++// there is more than one dependency sequence leading to ++// a particular package. ++var downloadCache = map[string]bool{} ++ ++// downloadRootCache records the version control repository ++// root directories we have already considered during the download. ++// For example, all the packages in the github.com/google/codesearch repo ++// share the same root (the directory for that path), and we only need ++// to run the hg commands to consider each repository once. ++var downloadRootCache = map[string]bool{} ++ ++// download runs the download half of the get command ++// for the package or pattern named by the argument. ++func download(ctx context.Context, arg string, parent *load.Package, stk *load.ImportStack, mode int) { ++ if mode&load.ResolveImport != 0 { ++ // Caller is responsible for expanding vendor paths. ++ panic("internal error: download mode has useVendor set") ++ } ++ load1 := func(path string, mode int) *load.Package { ++ if parent == nil { ++ mode := 0 // don't do module or vendor resolution ++ return load.LoadPackage(ctx, load.PackageOpts{}, path, base.Cwd(), stk, nil, mode) ++ } ++ p, err := load.LoadImport(ctx, load.PackageOpts{}, path, parent.Dir, parent, stk, nil, mode|load.ResolveModule) ++ if err != nil { ++ base.Errorf("%s", err) ++ } ++ return p ++ } ++ ++ p := load1(arg, mode) ++ if p.Error != nil && p.Error.Hard { ++ base.Errorf("%s", p.Error) ++ return ++ } ++ ++ // loadPackage inferred the canonical ImportPath from arg. ++ // Use that in the following to prevent hysteresis effects ++ // in e.g. downloadCache and packageCache. ++ // This allows invocations such as: ++ // mkdir -p $GOPATH/src/github.com/user ++ // cd $GOPATH/src/github.com/user ++ // go get ./foo ++ // see: golang.org/issue/9767 ++ arg = p.ImportPath ++ ++ // There's nothing to do if this is a package in the standard library. ++ if p.Standard { ++ return ++ } ++ ++ // Only process each package once. ++ // (Unless we're fetching test dependencies for this package, ++ // in which case we want to process it again.) ++ if downloadCache[arg] && mode&load.GetTestDeps == 0 { ++ return ++ } ++ downloadCache[arg] = true ++ ++ pkgs := []*load.Package{p} ++ wildcardOkay := len(*stk) == 0 ++ isWildcard := false ++ ++ // Download if the package is missing, or update if we're using -u. ++ if p.Dir == "" || *getU { ++ // The actual download. ++ stk.Push(arg) ++ err := downloadPackage(p) ++ if err != nil { ++ base.Errorf("%s", &load.PackageError{ImportStack: stk.Copy(), Err: err}) ++ stk.Pop() ++ return ++ } ++ stk.Pop() ++ ++ args := []string{arg} ++ // If the argument has a wildcard in it, re-evaluate the wildcard. ++ // We delay this until after reloadPackage so that the old entry ++ // for p has been replaced in the package cache. ++ if wildcardOkay && strings.Contains(arg, "...") { ++ match := search.NewMatch(arg) ++ if match.IsLocal() { ++ noModRoots := []string{} // We're in gopath mode, so there are no modroots. ++ match.MatchDirs(noModRoots) ++ args = match.Dirs ++ } else { ++ match.MatchPackages() ++ args = match.Pkgs ++ } ++ for _, err := range match.Errs { ++ base.Errorf("%s", err) ++ } ++ isWildcard = true ++ } ++ ++ // Clear all relevant package cache entries before ++ // doing any new loads. ++ load.ClearPackageCachePartial(args) ++ ++ pkgs = pkgs[:0] ++ for _, arg := range args { ++ // Note: load calls loadPackage or loadImport, ++ // which push arg onto stk already. ++ // Do not push here too, or else stk will say arg imports arg. ++ p := load1(arg, mode) ++ if p.Error != nil { ++ base.Errorf("%s", p.Error) ++ continue ++ } ++ pkgs = append(pkgs, p) ++ } ++ } ++ ++ // Process package, which might now be multiple packages ++ // due to wildcard expansion. ++ for _, p := range pkgs { ++ if *getFix { ++ files := base.RelPaths(p.InternalAllGoFiles()) ++ base.Run(cfg.BuildToolexec, str.StringList(base.Tool("fix"), files)) ++ ++ // The imports might have changed, so reload again. ++ p = load.ReloadPackageNoFlags(arg, stk) ++ if p.Error != nil { ++ base.Errorf("%s", p.Error) ++ return ++ } ++ } ++ ++ if isWildcard { ++ // Report both the real package and the ++ // wildcard in any error message. ++ stk.Push(p.ImportPath) ++ } ++ ++ // Process dependencies, now that we know what they are. ++ imports := p.Imports ++ if mode&load.GetTestDeps != 0 { ++ // Process test dependencies when -t is specified. ++ // (But don't get test dependencies for test dependencies: ++ // we always pass mode 0 to the recursive calls below.) ++ imports = str.StringList(imports, p.TestImports, p.XTestImports) ++ } ++ for i, path := range imports { ++ if path == "C" { ++ continue ++ } ++ // Fail fast on import naming full vendor path. ++ // Otherwise expand path as needed for test imports. ++ // Note that p.Imports can have additional entries beyond p.Internal.Build.Imports. ++ orig := path ++ if i < len(p.Internal.Build.Imports) { ++ orig = p.Internal.Build.Imports[i] ++ } ++ if j, ok := load.FindVendor(orig); ok { ++ stk.Push(path) ++ err := &load.PackageError{ ++ ImportStack: stk.Copy(), ++ Err: load.ImportErrorf(path, "%s must be imported as %s", path, path[j+len("vendor/"):]), ++ } ++ stk.Pop() ++ base.Errorf("%s", err) ++ continue ++ } ++ // If this is a test import, apply module and vendor lookup now. ++ // We cannot pass ResolveImport to download, because ++ // download does caching based on the value of path, ++ // so it must be the fully qualified path already. ++ if i >= len(p.Imports) { ++ path = load.ResolveImportPath(p, path) ++ } ++ download(ctx, path, p, stk, 0) ++ } ++ ++ if isWildcard { ++ stk.Pop() ++ } ++ } ++} ++ ++// downloadPackage runs the create or download command ++// to make the first copy of or update a copy of the given package. ++func downloadPackage(p *load.Package) error { ++ var ( ++ vcsCmd *vcs.Cmd ++ repo, rootPath, repoDir string ++ err error ++ blindRepo bool // set if the repo has unusual configuration ++ ) ++ ++ // p can be either a real package, or a pseudo-package whose “import path” is ++ // actually a wildcard pattern. ++ // Trim the path at the element containing the first wildcard, ++ // and hope that it applies to the wildcarded parts too. ++ // This makes 'go get rsc.io/pdf/...' work in a fresh GOPATH. ++ importPrefix := p.ImportPath ++ if i := strings.Index(importPrefix, "..."); i >= 0 { ++ slash := strings.LastIndexByte(importPrefix[:i], '/') ++ if slash < 0 { ++ return fmt.Errorf("cannot expand ... in %q", p.ImportPath) ++ } ++ importPrefix = importPrefix[:slash] ++ } ++ if err := checkImportPath(importPrefix); err != nil { ++ return fmt.Errorf("%s: invalid import path: %v", p.ImportPath, err) ++ } ++ security := web.SecureOnly ++ if module.MatchPrefixPatterns(cfg.GOINSECURE, importPrefix) { ++ security = web.Insecure ++ } ++ ++ if p.Internal.Build.SrcRoot != "" { ++ // Directory exists. Look for checkout along path to src. ++ const allowNesting = false ++ repoDir, vcsCmd, err = vcs.FromDir(p.Dir, p.Internal.Build.SrcRoot, allowNesting) ++ if err != nil { ++ return err ++ } ++ if !str.HasFilePathPrefix(repoDir, p.Internal.Build.SrcRoot) { ++ panic(fmt.Sprintf("repository %q not in source root %q", repo, p.Internal.Build.SrcRoot)) ++ } ++ rootPath = str.TrimFilePathPrefix(repoDir, p.Internal.Build.SrcRoot) ++ if err := vcs.CheckGOVCS(vcsCmd, rootPath); err != nil { ++ return err ++ } ++ ++ repo = "" // should be unused; make distinctive ++ ++ // Double-check where it came from. ++ if *getU && vcsCmd.RemoteRepo != nil { ++ dir := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath)) ++ remote, err := vcsCmd.RemoteRepo(vcsCmd, dir) ++ if err != nil { ++ // Proceed anyway. The package is present; we likely just don't understand ++ // the repo configuration (e.g. unusual remote protocol). ++ blindRepo = true ++ } ++ repo = remote ++ if !*getF && err == nil { ++ if rr, err := vcs.RepoRootForImportPath(importPrefix, vcs.IgnoreMod, security); err == nil { ++ repo := rr.Repo ++ if rr.VCS.ResolveRepo != nil { ++ resolved, err := rr.VCS.ResolveRepo(rr.VCS, dir, repo) ++ if err == nil { ++ repo = resolved ++ } ++ } ++ if remote != repo && rr.IsCustom { ++ return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.Root, repo, dir, remote) ++ } ++ } ++ } ++ } ++ } else { ++ // Analyze the import path to determine the version control system, ++ // repository, and the import path for the root of the repository. ++ rr, err := vcs.RepoRootForImportPath(importPrefix, vcs.IgnoreMod, security) ++ if err != nil { ++ return err ++ } ++ vcsCmd, repo, rootPath = rr.VCS, rr.Repo, rr.Root ++ } ++ if !blindRepo && !vcsCmd.IsSecure(repo) && security != web.Insecure { ++ return fmt.Errorf("cannot download: %v uses insecure protocol", repo) ++ } ++ ++ if p.Internal.Build.SrcRoot == "" { ++ // Package not found. Put in first directory of $GOPATH. ++ list := filepath.SplitList(cfg.BuildContext.GOPATH) ++ if len(list) == 0 { ++ return fmt.Errorf("cannot download: $GOPATH not set. For more details see: 'go help gopath'") ++ } ++ // Guard against people setting GOPATH=$GOROOT. ++ if filepath.Clean(list[0]) == filepath.Clean(cfg.GOROOT) { ++ return fmt.Errorf("cannot download: $GOPATH must not be set to $GOROOT. For more details see: 'go help gopath'") ++ } ++ if _, err := os.Stat(filepath.Join(list[0], "src/cmd/go/alldocs.go")); err == nil { ++ return fmt.Errorf("cannot download: %s is a GOROOT, not a GOPATH. For more details see: 'go help gopath'", list[0]) ++ } ++ p.Internal.Build.Root = list[0] ++ p.Internal.Build.SrcRoot = filepath.Join(list[0], "src") ++ p.Internal.Build.PkgRoot = filepath.Join(list[0], "pkg") ++ } ++ root := filepath.Join(p.Internal.Build.SrcRoot, filepath.FromSlash(rootPath)) ++ ++ if err := vcs.CheckNested(vcsCmd, root, p.Internal.Build.SrcRoot); err != nil { ++ return err ++ } ++ ++ // If we've considered this repository already, don't do it again. ++ if downloadRootCache[root] { ++ return nil ++ } ++ downloadRootCache[root] = true ++ ++ if cfg.BuildV { ++ fmt.Fprintf(os.Stderr, "%s (download)\n", rootPath) ++ } ++ ++ // Check that this is an appropriate place for the repo to be checked out. ++ // The target directory must either not exist or have a repo checked out already. ++ meta := filepath.Join(root, "."+vcsCmd.Cmd) ++ if _, err := os.Stat(meta); err != nil { ++ // Metadata file or directory does not exist. Prepare to checkout new copy. ++ // Some version control tools require the target directory not to exist. ++ // We require that too, just to avoid stepping on existing work. ++ if _, err := os.Stat(root); err == nil { ++ return fmt.Errorf("%s exists but %s does not - stale checkout?", root, meta) ++ } ++ ++ _, err := os.Stat(p.Internal.Build.Root) ++ gopathExisted := err == nil ++ ++ // Some version control tools require the parent of the target to exist. ++ parent, _ := filepath.Split(root) ++ if err = os.MkdirAll(parent, 0777); err != nil { ++ return err ++ } ++ if cfg.BuildV && !gopathExisted && p.Internal.Build.Root == cfg.BuildContext.GOPATH { ++ fmt.Fprintf(os.Stderr, "created GOPATH=%s; see 'go help gopath'\n", p.Internal.Build.Root) ++ } ++ ++ if err = vcsCmd.Create(root, repo); err != nil { ++ return err ++ } ++ } else { ++ // Metadata directory does exist; download incremental updates. ++ if err = vcsCmd.Download(root); err != nil { ++ return err ++ } ++ } ++ ++ if cfg.BuildN { ++ // Do not show tag sync in -n; it's noise more than anything, ++ // and since we're not running commands, no tag will be found. ++ // But avoid printing nothing. ++ fmt.Fprintf(os.Stderr, "# cd %s; %s sync/update\n", root, vcsCmd.Cmd) ++ return nil ++ } ++ ++ // Select and sync to appropriate version of the repository. ++ tags, err := vcsCmd.Tags(root) ++ if err != nil { ++ return err ++ } ++ vers := runtime.Version() ++ if i := strings.Index(vers, " "); i >= 0 { ++ vers = vers[:i] ++ } ++ if err := vcsCmd.TagSync(root, selectTag(vers, tags)); err != nil { ++ return err ++ } ++ ++ return nil ++} ++ ++// selectTag returns the closest matching tag for a given version. ++// Closest means the latest one that is not after the current release. ++// Version "goX" (or "goX.Y" or "goX.Y.Z") matches tags of the same form. ++// Version "release.rN" matches tags of the form "go.rN" (N being a floating-point number). ++// Version "weekly.YYYY-MM-DD" matches tags like "go.weekly.YYYY-MM-DD". ++// ++// NOTE(rsc): Eventually we will need to decide on some logic here. ++// For now, there is only "go1". This matches the docs in go help get. ++func selectTag(goVersion string, tags []string) (match string) { ++ for _, t := range tags { ++ if t == "go1" { ++ return "go1" ++ } ++ } ++ return "" ++} ++ ++// checkImportPath is like module.CheckImportPath, but it forbids leading dots ++// in path elements. This can lead to 'go get' creating .git and other VCS ++// directories in places we might run VCS tools later. ++func checkImportPath(path string) error { ++ if err := module.CheckImportPath(path); err != nil { ++ return err ++ } ++ checkElem := func(elem string) error { ++ if elem[0] == '.' { ++ return fmt.Errorf("malformed import path %q: leading dot in path element", path) ++ } ++ return nil ++ } ++ elemStart := 0 ++ for i, r := range path { ++ if r == '/' { ++ if err := checkElem(path[elemStart:]); err != nil { ++ return err ++ } ++ elemStart = i + 1 ++ } ++ } ++ if err := checkElem(path[elemStart:]); err != nil { ++ return err ++ } ++ return nil ++} +diff --git a/src/cmd/go/internal/get/tag_test.go b/src/cmd/go/internal/get/tag_test.go +new file mode 100644 +index 0000000..9a25dfa +--- /dev/null ++++ b/src/cmd/go/internal/get/tag_test.go +@@ -0,0 +1,100 @@ ++// Copyright 2011 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 get ++ ++import "testing" ++ ++var selectTagTestTags = []string{ ++ "go.r58", ++ "go.r58.1", ++ "go.r59", ++ "go.r59.1", ++ "go.r61", ++ "go.r61.1", ++ "go.weekly.2010-01-02", ++ "go.weekly.2011-10-12", ++ "go.weekly.2011-10-12.1", ++ "go.weekly.2011-10-14", ++ "go.weekly.2011-11-01", ++ "go1", ++ "go1.0.1", ++ "go1.999", ++ "go1.9.2", ++ "go5", ++ ++ // these should be ignored: ++ "release.r59", ++ "release.r59.1", ++ "release", ++ "weekly.2011-10-12", ++ "weekly.2011-10-12.1", ++ "weekly", ++ "foo", ++ "bar", ++ "go.f00", ++ "go!r60", ++ "go.1999-01-01", ++ "go.2x", ++ "go.20000000000000", ++ "go.2.", ++ "go.2.0", ++ "go2x", ++ "go20000000000000", ++ "go2.", ++ "go2.0", ++} ++ ++var selectTagTests = []struct { ++ version string ++ selected string ++}{ ++ /* ++ {"release.r57", ""}, ++ {"release.r58.2", "go.r58.1"}, ++ {"release.r59", "go.r59"}, ++ {"release.r59.1", "go.r59.1"}, ++ {"release.r60", "go.r59.1"}, ++ {"release.r60.1", "go.r59.1"}, ++ {"release.r61", "go.r61"}, ++ {"release.r66", "go.r61.1"}, ++ {"weekly.2010-01-01", ""}, ++ {"weekly.2010-01-02", "go.weekly.2010-01-02"}, ++ {"weekly.2010-01-02.1", "go.weekly.2010-01-02"}, ++ {"weekly.2010-01-03", "go.weekly.2010-01-02"}, ++ {"weekly.2011-10-12", "go.weekly.2011-10-12"}, ++ {"weekly.2011-10-12.1", "go.weekly.2011-10-12.1"}, ++ {"weekly.2011-10-13", "go.weekly.2011-10-12.1"}, ++ {"weekly.2011-10-14", "go.weekly.2011-10-14"}, ++ {"weekly.2011-10-14.1", "go.weekly.2011-10-14"}, ++ {"weekly.2011-11-01", "go.weekly.2011-11-01"}, ++ {"weekly.2014-01-01", "go.weekly.2011-11-01"}, ++ {"weekly.3000-01-01", "go.weekly.2011-11-01"}, ++ {"go1", "go1"}, ++ {"go1.1", "go1.0.1"}, ++ {"go1.998", "go1.9.2"}, ++ {"go1.1000", "go1.999"}, ++ {"go6", "go5"}, ++ ++ // faulty versions: ++ {"release.f00", ""}, ++ {"weekly.1999-01-01", ""}, ++ {"junk", ""}, ++ {"", ""}, ++ {"go2x", ""}, ++ {"go200000000000", ""}, ++ {"go2.", ""}, ++ {"go2.0", ""}, ++ */ ++ {"anything", "go1"}, ++} ++ ++func TestSelectTag(t *testing.T) { ++ for _, c := range selectTagTests { ++ selected := selectTag(c.version, selectTagTestTags) ++ if selected != c.selected { ++ t.Errorf("selectTag(%q) = %q, want %q", c.version, selected, c.selected) ++ } ++ } ++} +diff --git a/src/cmd/go/internal/help/help.go b/src/cmd/go/internal/help/help.go +index 4f2607f..229ebc3 100644 +--- a/src/cmd/go/internal/help/help.go ++++ b/src/cmd/go/internal/help/help.go +@@ -17,6 +17,7 @@ import ( + + "cmd/go/internal/base" + "cmd/internal/telemetry/counter" ++ "cmd/go/internal/modload" + ) + + var counterErrorsHelpUnknownTopic = counter.New("go/errors:help-unknown-topic") +@@ -37,6 +38,12 @@ func Help(w io.Writer, args []string) { + usage := &base.Command{Long: buf.String()} + cmds := []*base.Command{usage} + for _, cmd := range base.Go.Commands { ++ // Avoid duplication of the "get" documentation. ++ if cmd.UsageLine == "module-get" && modload.Enabled() { ++ continue ++ } else if cmd.UsageLine == "gopath-get" && !modload.Enabled() { ++ continue ++ } + cmds = append(cmds, cmd) + cmds = append(cmds, cmd.Commands...) + } +diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go +index 7343128..966c504 100644 +--- a/src/cmd/go/internal/modget/get.go ++++ b/src/cmd/go/internal/modget/get.go +@@ -131,6 +131,23 @@ See also: go build, go install, go clean, go mod. + `, + } + ++// Note that this help text is a stopgap to make the module-aware get help text ++// available even in non-module settings. It should be deleted when the old get ++// is deleted. It should NOT be considered to set a precedent of having hierarchical ++// help names with dashes. ++var HelpModuleGet = &base.Command{ ++ UsageLine: "module-get", ++ Short: "module-aware go get", ++ Long: ` ++The 'go get' command changes behavior depending on whether the ++go command is running in module-aware mode or legacy GOPATH mode. ++This help text, accessible as 'go help module-get' even in legacy GOPATH mode, ++describes 'go get' as it operates in module-aware mode. ++ ++Usage: ` + CmdGet.UsageLine + ` ++` + CmdGet.Long, ++} ++ + var HelpVCS = &base.Command{ + UsageLine: "vcs", + Short: "controlling version control with GOVCS", +diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go +index 1c58232..722ab87 100644 +--- a/src/cmd/go/main.go ++++ b/src/cmd/go/main.go +@@ -27,6 +27,7 @@ import ( + "cmd/go/internal/fix" + "cmd/go/internal/fmtcmd" + "cmd/go/internal/generate" ++ "cmd/go/internal/get" + "cmd/go/internal/help" + "cmd/go/internal/list" + "cmd/go/internal/modcmd" +@@ -78,9 +79,11 @@ func init() { + help.HelpFileType, + modload.HelpGoMod, + help.HelpGopath, ++ get.HelpGopathGet, + modfetch.HelpGoproxy, + help.HelpImportPath, + modload.HelpModules, ++ modget.HelpModuleGet, + modfetch.HelpModuleAuth, + help.HelpPackages, + modfetch.HelpPrivate, +@@ -112,6 +115,13 @@ func main() { + base.Usage() + } + ++ if args[0] == "get" || args[0] == "help" { ++ if !modload.WillBeEnabled() { ++ // Replace module-aware get with GOPATH get if appropriate. ++ *modget.CmdGet = *get.CmdGet ++ } ++ } ++ + cfg.CmdName = args[0] // for error messages + if args[0] == "help" { + counter.Inc("go/subcommand:" + strings.Join(append([]string{"help"}, args[1:]...), "-")) +diff --git a/src/cmd/go/testdata/script/get_404_meta.txt b/src/cmd/go/testdata/script/get_404_meta.txt +index 7665155..4ffbdeb 100644 +--- a/src/cmd/go/testdata/script/get_404_meta.txt ++++ b/src/cmd/go/testdata/script/get_404_meta.txt +@@ -4,6 +4,9 @@ + [!git] skip + + env GONOSUMDB=bazil.org,github.com,golang.org ++env GO111MODULE=off ++go get -d bazil.org/fuse/fs/fstestutil ++ + env GO111MODULE=on + env GOPROXY=direct + go get bazil.org/fuse/fs/fstestutil +diff --git a/src/cmd/go/testdata/script/get_brace.txt b/src/cmd/go/testdata/script/get_brace.txt +new file mode 100644 +index 0000000..34f66a6 +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_brace.txt +@@ -0,0 +1,51 @@ ++env GO111MODULE=off ++ ++[!git] skip ++ ++# Set up some empty repositories. ++cd $WORK/_origin/foo ++exec git init ++exec git config user.name 'Nameless Gopher' ++exec git config user.email 'nobody@golang.org' ++exec git commit --allow-empty -m 'create master branch' ++ ++cd $WORK ++cd '_origin/{confusing}' ++exec git init ++exec git config user.name 'Nameless Gopher' ++exec git config user.email 'nobody@golang.org' ++exec git commit --allow-empty -m 'create master branch' ++ ++# Clone the empty repositories into GOPATH. ++# This tells the Go command where to find them: it takes the place of a user's meta-tag redirector. ++mkdir $GOPATH/src/example.com ++cd $GOPATH/src/example.com ++exec git clone $WORK/_origin/foo ++exec git clone $WORK/_origin/{confusing} ++ ++# Commit contents to the repositories. ++cd $WORK/_origin/foo ++exec git add main.go ++exec git commit -m 'add main' ++ ++cd $WORK ++cd '_origin/{confusing}' ++exec git add confusing.go ++exec git commit -m 'just try to delete this!' ++ ++# 'go get' should refuse to download or update the confusingly-named repo. ++cd $GOPATH/src/example.com/foo ++! go get -u 'example.com/{confusing}' ++stderr 'invalid char' ++! go get -u example.com/foo ++stderr 'invalid import path' ++! exists example.com/{confusing} ++ ++-- $WORK/_origin/foo/main.go -- ++package main ++import _ "example.com/{confusing}" ++ ++func main() {} ++ ++-- $WORK/_origin/{confusing}/confusing.go -- ++package confusing +diff --git a/src/cmd/go/testdata/script/get_custom_domain_wildcard.txt b/src/cmd/go/testdata/script/get_custom_domain_wildcard.txt +new file mode 100644 +index 0000000..45ab524 +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_custom_domain_wildcard.txt +@@ -0,0 +1,6 @@ ++[!net:rsc.io] skip ++[!git] skip ++env GO111MODULE=off ++ ++go get -u rsc.io/pdf/... ++exists $GOPATH/bin/pdfpasswd$GOEXE +diff --git a/src/cmd/go/testdata/script/get_dash_t.txt b/src/cmd/go/testdata/script/get_dash_t.txt +new file mode 100644 +index 0000000..8f3a036 +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_dash_t.txt +@@ -0,0 +1,9 @@ ++# Tests issue 8181 ++ ++[!net:github.com] skip ++[!git] skip ++env GO111MODULE=off ++ ++go get -v -t github.com/rsc/go-get-issue-8181/a github.com/rsc/go-get-issue-8181/b ++go list -test -deps github.com/rsc/go-get-issue-8181/b ++stdout 'x/build/gerrit' +diff --git a/src/cmd/go/testdata/script/get_domain_root.txt b/src/cmd/go/testdata/script/get_domain_root.txt +new file mode 100644 +index 0000000..dfcea86 +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_domain_root.txt +@@ -0,0 +1,20 @@ ++# Tests issue #9357 ++# go get foo.io (not foo.io/subdir) was not working consistently. ++ ++[!net:go-get-issue-9357.appspot.com] skip ++[!git] skip ++env GO111MODULE=off ++ ++# go-get-issue-9357.appspot.com is running ++# the code at github.com/rsc/go-get-issue-9357, ++# a trivial Go on App Engine app that serves a ++# tag for the domain root. ++go get -d go-get-issue-9357.appspot.com ++go get go-get-issue-9357.appspot.com ++go get -u go-get-issue-9357.appspot.com ++ ++rm $GOPATH/src/go-get-issue-9357.appspot.com ++go get go-get-issue-9357.appspot.com ++ ++rm $GOPATH/src/go-get-issue-9357.appspot.com ++go get -u go-get-issue-9357.appspot.com +diff --git a/src/cmd/go/testdata/script/get_dot_slash_download.txt b/src/cmd/go/testdata/script/get_dot_slash_download.txt +new file mode 100644 +index 0000000..6dbd118 +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_dot_slash_download.txt +@@ -0,0 +1,10 @@ ++[!net:rsc.io] skip ++[!git] skip ++env GO111MODULE=off ++ ++# Tests Issues #9797 and #19769 ++ ++mkdir $WORK/tmp/src/rsc.io ++env GOPATH=$WORK/tmp ++cd $WORK/tmp/src/rsc.io ++go get ./pprof_mac_fix +diff --git a/src/cmd/go/testdata/script/get_dotfiles.txt b/src/cmd/go/testdata/script/get_dotfiles.txt +new file mode 100644 +index 0000000..676a044 +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_dotfiles.txt +@@ -0,0 +1,64 @@ ++env GO111MODULE=off ++[short] skip ++ ++[!git] skip ++ ++# Set up a benign repository and a repository with a dotfile name. ++cd $WORK/_origin/foo ++exec git init ++exec git config user.name 'Nameless Gopher' ++exec git config user.email 'nobody@golang.org' ++exec git commit --allow-empty -m 'create master branch' ++ ++cd $WORK/_origin/.hidden ++exec git init ++exec git config user.name 'Nameless Gopher' ++exec git config user.email 'nobody@golang.org' ++exec git commit --allow-empty -m 'create master branch' ++ ++# Clone the empty repositories into GOPATH. ++# This tells the Go command where to find them: it takes the place of a user's meta-tag redirector. ++mkdir $GOPATH/src/example.com ++cd $GOPATH/src/example.com ++exec git clone $WORK/_origin/foo ++exec git clone $WORK/_origin/.hidden ++ ++# Add a benign commit. ++cd $WORK/_origin/foo ++cp _ok/main.go main.go ++exec git add main.go ++exec git commit -m 'add ok' ++ ++# 'go get' should install the benign commit. ++cd $GOPATH ++go get -u example.com/foo ++ ++# Now sneak in an import of a dotfile path. ++cd $WORK/_origin/.hidden ++exec git add hidden.go ++exec git commit -m 'nothing to see here, move along' ++ ++cd $WORK/_origin/foo ++cp _sneaky/main.go main.go ++exec git add main.go ++exec git commit -m 'fix typo (heh heh heh)' ++ ++# 'go get -u' should refuse to download or update the dotfile-named repo. ++cd $GOPATH/src/example.com/foo ++! go get -u example.com/foo ++stderr 'leading dot' ++! exists example.com/.hidden/hidden.go ++ ++-- $WORK/_origin/foo/_ok/main.go -- ++package main ++ ++func main() {} ++ ++-- $WORK/_origin/foo/_sneaky/main.go -- ++package main ++import _ "example.com/.hidden" ++ ++func main() {} ++ ++-- $WORK/_origin/.hidden/hidden.go -- ++package hidden +diff --git a/src/cmd/go/testdata/script/get_go_file.txt b/src/cmd/go/testdata/script/get_go_file.txt +new file mode 100644 +index 0000000..f6d0de4 +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_go_file.txt +@@ -0,0 +1,60 @@ ++# Tests Issue #38478 ++# Tests that go get in GOPATH mode returns a specific error if the argument ++# ends with '.go', and either has no slash or refers to an existing file. ++ ++env GO111MODULE=off ++ ++# argument doesn't have .go suffix ++go get -d test ++ ++# argument has .go suffix, is a file and exists ++! go get -d test.go ++stderr 'go: test.go: arguments must be package or module paths' ++ ++# argument has .go suffix, doesn't exist and has no slashes ++! go get -d test_missing.go ++stderr 'go: test_missing.go: arguments must be package or module paths' ++ ++# argument has .go suffix, is a file and exists in sub-directory ++! go get -d test/test.go ++stderr 'go: test/test.go exists as a file, but ''go get'' requires package arguments' ++ ++# argument has .go suffix, doesn't exist and has slashes ++! go get -d test/test_missing.go ++! stderr 'arguments must be package or module paths' ++! stderr 'exists as a file, but ''go get'' requires package arguments' ++ ++# argument has .go suffix, is a symlink and exists ++[symlink] symlink test_sym.go -> test.go ++[symlink] ! go get -d test_sym.go ++[symlink] stderr 'go: test_sym.go: arguments must be package or module paths' ++[symlink] rm test_sym.go ++ ++# argument has .go suffix, is a symlink and exists in sub-directory ++[symlink] symlink test/test_sym.go -> test.go ++[symlink] ! go get -d test/test_sym.go ++[symlink] stderr 'go: test/test_sym.go exists as a file, but ''go get'' requires package arguments' ++[symlink] rm test_sym.go ++ ++# argument has .go suffix, is a directory and exists ++mkdir test_dir.go ++! go get -d test_dir.go ++stderr 'go: test_dir.go: arguments must be package or module paths' ++rm test_dir.go ++ ++# argument has .go suffix, is a directory and exists in sub-directory ++mkdir test/test_dir.go ++! go get -d test/test_dir.go ++! stderr 'arguments must be package or module paths' ++! stderr 'exists as a file, but ''go get'' requires package arguments' ++rm test/test_dir.go ++ ++ ++-- test.go -- ++package main ++func main() {println("test")} ++ ++ ++-- test/test.go -- ++package main ++func main() {println("test")} +diff --git a/src/cmd/go/testdata/script/get_goroot.txt b/src/cmd/go/testdata/script/get_goroot.txt +new file mode 100644 +index 0000000..7510692 +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_goroot.txt +@@ -0,0 +1,53 @@ ++[!net:github.com] skip ++env GO111MODULE=off ++ ++# Issue 4186. go get cannot be used to download packages to $GOROOT. ++# Test that without GOPATH set, go get should fail. ++ ++# Fails because GOROOT=GOPATH ++env GOPATH=$WORK/tmp ++env GOROOT=$WORK/tmp ++! go get -d github.com/golang/example/hello ++stderr 'warning: GOPATH set to GOROOT' ++stderr '\$GOPATH must not be set to \$GOROOT' ++ ++# Fails because GOROOT=GOPATH after cleaning. ++env GOPATH=$WORK/tmp/ ++env GOROOT=$WORK/tmp ++! go get -d github.com/golang/example/hello ++stderr 'warning: GOPATH set to GOROOT' ++stderr '\$GOPATH must not be set to \$GOROOT' ++ ++env GOPATH=$WORK/tmp ++env GOROOT=$WORK/tmp/ ++! go get -d github.com/golang/example/hello ++stderr 'warning: GOPATH set to GOROOT' ++stderr '\$GOPATH must not be set to \$GOROOT' ++ ++# Make a home directory ++mkdir $WORK/home/go ++ ++# Fails because GOROOT=$HOME/go so default GOPATH unset. ++[GOOS:windows] env USERPROFILE=$WORK/home ++[GOOS:plan9] env home=$WORK/home ++[!GOOS:windows] [!GOOS:plan9] env HOME=$WORK/home ++env GOPATH= ++env GOROOT=$WORK/home/go ++! go get -d github.com/golang/example/hello ++stderr '\$GOPATH not set' ++ ++[GOOS:windows] env USERPROFILE=$WORK/home/ ++[GOOS:plan9] env home=$WORK/home/ ++[!GOOS:windows] [!GOOS:plan9] env HOME=$WORK/home/ ++env GOPATH= ++env GOROOT=$WORK/home/go ++! go get -d github.com/golang/example/hello ++stderr '\$GOPATH not set' ++ ++[GOOS:windows] env USERPROFILE=$WORK/home ++[GOOS:plan9] env home=$WORK/home ++[!GOOS:windows] [!GOOS:plan9] env HOME=$WORK/home ++env GOPATH= ++env GOROOT=$WORK/home/go/ ++! go get -d github.com/golang/example/hello ++stderr '\$GOPATH not set' +diff --git a/src/cmd/go/testdata/script/get_insecure.txt b/src/cmd/go/testdata/script/get_insecure.txt +index f29ec2d..afe64b8 100644 +--- a/src/cmd/go/testdata/script/get_insecure.txt ++++ b/src/cmd/go/testdata/script/get_insecure.txt +@@ -1,9 +1,25 @@ ++# TODO(matloob): Split this test into two? It's one of the slowest tests we have. ++ + [!net:insecure.go-get-issue-15410.appspot.com] skip + [!git] skip + + env PATH=$WORK/tmp/bin${:}$PATH + go build -o $WORK/tmp/bin/ssh ssh.go + ++# GOPATH: Set up ++env GO111MODULE=off ++ ++# GOPATH: Try go get -d of HTTP-only repo (should fail). ++! go get -d insecure.go-get-issue-15410.appspot.com/pkg/p ++ ++# GOPATH: Try again with GOINSECURE (should succeed). ++env GOINSECURE=insecure.go-get-issue-15410.appspot.com ++go get -d insecure.go-get-issue-15410.appspot.com/pkg/p ++ ++# GOPATH: Try updating without GOINSECURE (should fail). ++env GOINSECURE='' ++! go get -d -u -f insecure.go-get-issue-15410.appspot.com/pkg/p ++ + # Modules: Set up + env GOPATH=$WORK/m/gp + mkdir $WORK/m +diff --git a/src/cmd/go/testdata/script/get_insecure_custom_domain.txt b/src/cmd/go/testdata/script/get_insecure_custom_domain.txt +new file mode 100644 +index 0000000..4b3c9d6 +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_insecure_custom_domain.txt +@@ -0,0 +1,8 @@ ++[!net:insecure.go-get-issue-15410.appspot.com] skip ++[!git] skip ++env GO111MODULE=off ++ ++! go get -d insecure.go-get-issue-15410.appspot.com/pkg/p ++ ++env GOINSECURE=insecure.go-get-issue-15410.appspot.com ++go get -d insecure.go-get-issue-15410.appspot.com/pkg/p +diff --git a/src/cmd/go/testdata/script/get_insecure_env.txt b/src/cmd/go/testdata/script/get_insecure_env.txt +new file mode 100644 +index 0000000..98e7053 +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_insecure_env.txt +@@ -0,0 +1,29 @@ ++[!net:insecure.go-get-issue-15410.appspot.com] skip ++[!git] skip ++ ++# GOPATH: Set up ++env GO111MODULE=off ++ ++# GOPATH: Try go get -d of HTTP-only repo (should fail). ++! go get -d insecure.go-get-issue-15410.appspot.com/pkg/p ++ ++# GOPATH: Try again with invalid GOINSECURE (should fail). ++env GOINSECURE=insecure.go-get-issue-15410.appspot.com/pkg/q ++! go get -d insecure.go-get-issue-15410.appspot.com/pkg/p ++ ++# GOPATH: Try with correct GOINSECURE (should succeed). ++env GOINSECURE=insecure.go-get-issue-15410.appspot.com/pkg/p ++go get -d insecure.go-get-issue-15410.appspot.com/pkg/p ++ ++# GOPATH: Try updating without GOINSECURE (should fail). ++env GOINSECURE= ++! go get -d -u -f insecure.go-get-issue-15410.appspot.com/pkg/p ++ ++# GOPATH: Try updating with GOINSECURE glob (should succeed). ++env GOINSECURE=*.go-get-*.appspot.com ++go get -d -u -f insecure.go-get-issue-15410.appspot.com/pkg/p ++ ++# GOPATH: Try updating with GOINSECURE base URL (should succeed). ++env GOINSECURE=insecure.go-get-issue-15410.appspot.com ++go get -d -u -f insecure.go-get-issue-15410.appspot.com/pkg/p ++ +diff --git a/src/cmd/go/testdata/script/get_insecure_redirect.txt b/src/cmd/go/testdata/script/get_insecure_redirect.txt +new file mode 100644 +index 0000000..2e53c58 +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_insecure_redirect.txt +@@ -0,0 +1,14 @@ ++# golang.org/issue/29591: 'go get' was following plain-HTTP redirects even without -insecure (now replaced by GOINSECURE). ++# golang.org/issue/34049: 'go get' would panic in case of an insecure redirect in GOPATH mode ++ ++[!git] skip ++ ++env GO111MODULE=off ++ ++! go get -d vcs-test.golang.org/insecure/go/insecure ++stderr 'redirected .* to insecure URL' ++ ++[short] stop 'builds a git repo' ++ ++env GOINSECURE=vcs-test.golang.org/insecure/go/insecure ++go get -d vcs-test.golang.org/insecure/go/insecure +diff --git a/src/cmd/go/testdata/script/get_insecure_update.txt b/src/cmd/go/testdata/script/get_insecure_update.txt +new file mode 100644 +index 0000000..7cddd6b +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_insecure_update.txt +@@ -0,0 +1,14 @@ ++[!net:github.com] skip ++[!git] skip ++env GO111MODULE=off ++ ++# Clone the repo via HTTP manually. ++exec git clone -q http://github.com/golang/example github.com/golang/example ++ ++# Update without GOINSECURE should fail. ++# We need -f to ignore import comments. ++! go get -d -u -f github.com/golang/example/hello ++ ++# Update with GOINSECURE should succeed. ++env GOINSECURE=github.com/golang/example/hello ++go get -d -u -f github.com/golang/example/hello +diff --git a/src/cmd/go/testdata/script/get_internal_wildcard.txt b/src/cmd/go/testdata/script/get_internal_wildcard.txt +new file mode 100644 +index 0000000..b25e746 +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_internal_wildcard.txt +@@ -0,0 +1,6 @@ ++[!net:github.com] skip ++[!git] skip ++env GO111MODULE=off ++ ++# This used to fail with errors about internal packages ++go get github.com/rsc/go-get-issue-11960/... +diff --git a/src/cmd/go/testdata/script/get_issue11307.txt b/src/cmd/go/testdata/script/get_issue11307.txt +new file mode 100644 +index 0000000..d490959 +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_issue11307.txt +@@ -0,0 +1,9 @@ ++# go get -u was not working except in checkout directory ++ ++[!net:github.com] skip ++[!git] skip ++env GO111MODULE=off ++ ++env GOPATH=$WORK/tmp/gopath ++go get github.com/rsc/go-get-issue-11307 ++go get -u github.com/rsc/go-get-issue-11307 # was failing +diff --git a/src/cmd/go/testdata/script/get_issue16471.txt b/src/cmd/go/testdata/script/get_issue16471.txt +new file mode 100644 +index 0000000..1aeae58 +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_issue16471.txt +@@ -0,0 +1,23 @@ ++[!net:rsc.io] skip ++[!net:github.com] skip ++[!git] skip ++ ++env GO111MODULE=off ++ ++cd rsc.io/go-get-issue-10952 ++ ++exec git init ++exec git add foo.go ++exec git config user.name Gopher ++exec git config user.email gopher@golang.org ++exec git commit -a -m 'initial commit' ++exec git remote add origin https://github.com/golang/go-get-issue-10952 ++ ++exec git status ++ ++! go get -x -u rsc.io/go-get-issue-10952 ++stderr '^package rsc.io/go-get-issue-10952: rsc\.io/go-get-issue-10952 is a custom import path for https://github.com/rsc/go-get-issue-10952, but .* is checked out from https://github.com/golang/go-get-issue-10952$' ++ ++-- rsc.io/go-get-issue-10952/foo.go -- ++// Junk package to test go get. ++package foo +diff --git a/src/cmd/go/testdata/script/get_issue22125.txt b/src/cmd/go/testdata/script/get_issue22125.txt +new file mode 100644 +index 0000000..086081f +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_issue22125.txt +@@ -0,0 +1,14 @@ ++# This test verifies a fix for a security issue; see https://go.dev/issue/22125. ++ ++[short] skip ++[!git] skip ++[!exec:svn] skip ++ ++env GO111MODULE=off ++ ++cd $GOPATH ++! go get -u vcs-test.golang.org/go/test1-svn-git ++stderr 'src'${/}'vcs-test.* uses git, but parent .*src'${/}'vcs-test.* uses svn' ++ ++[!case-sensitive] ! go get -u vcs-test.golang.org/go/test2-svn-git/test2main ++[!case-sensitive] stderr 'src'${/}'vcs-test.* uses git, but parent .*src'${/}'vcs-test.* uses svn' +diff --git a/src/cmd/go/testdata/script/get_legacy.txt b/src/cmd/go/testdata/script/get_legacy.txt +new file mode 100644 +index 0000000..2909b73 +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_legacy.txt +@@ -0,0 +1,58 @@ ++# This test was converted from a test in vendor_test.go (which no longer exists). ++# That seems to imply that it's about vendoring semantics, but the test doesn't ++# use 'go -mod=vendor' (and none of the fetched repos have vendor folders). ++# The test still seems to be useful as a test of direct-mode go get. ++ ++[short] skip ++[!git] skip ++env GO111MODULE=off ++ ++env GOPATH=$WORK/tmp/d1 ++go get vcs-test.golang.org/git/modlegacy1-old.git/p1 ++go list -f '{{.Deps}}' vcs-test.golang.org/git/modlegacy1-old.git/p1 ++stdout 'new.git/p2' # old/p1 should depend on new/p2 ++! stdout new.git/v2/p2 # old/p1 should NOT depend on new/v2/p2 ++go build vcs-test.golang.org/git/modlegacy1-old.git/p1 vcs-test.golang.org/git/modlegacy1-new.git/p1 ++! stdout . ++ ++env GOPATH=$WORK/tmp/d2 ++ ++rm $GOPATH ++go get github.com/rsc/vgotest5 ++go get github.com/rsc/vgotest4 ++go get github.com/myitcv/vgo_example_compat ++ ++rm $GOPATH ++go get github.com/rsc/vgotest4 ++go get github.com/rsc/vgotest5 ++go get github.com/myitcv/vgo_example_compat ++ ++rm $GOPATH ++go get github.com/rsc/vgotest4 github.com/rsc/vgotest5 ++go get github.com/myitcv/vgo_example_compat ++ ++rm $GOPATH ++go get github.com/rsc/vgotest5 github.com/rsc/vgotest4 ++go get github.com/myitcv/vgo_example_compat ++ ++rm $GOPATH ++go get github.com/myitcv/vgo_example_compat ++go get github.com/rsc/vgotest5 github.com/rsc/vgotest4 ++ ++rm $GOPATH ++go get github.com/myitcv/vgo_example_compat github.com/rsc/vgotest4 github.com/rsc/vgotest5 ++ ++rm $GOPATH ++go get github.com/myitcv/vgo_example_compat github.com/rsc/vgotest5 github.com/rsc/vgotest4 ++ ++rm $GOPATH ++go get github.com/rsc/vgotest4 github.com/myitcv/vgo_example_compat github.com/rsc/vgotest5 ++ ++rm $GOPATH ++go get github.com/rsc/vgotest4 github.com/rsc/vgotest5 github.com/myitcv/vgo_example_compat ++ ++rm $GOPATH ++go get github.com/rsc/vgotest5 github.com/myitcv/vgo_example_compat github.com/rsc/vgotest4 ++ ++rm $GOPATH ++go get github.com/rsc/vgotest5 github.com/rsc/vgotest4 github.com/myitcv/vgo_example_compat +diff --git a/src/cmd/go/testdata/script/get_non_pkg.txt b/src/cmd/go/testdata/script/get_non_pkg.txt +new file mode 100644 +index 0000000..5202e88 +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_non_pkg.txt +@@ -0,0 +1,14 @@ ++[!net:golang.org] skip ++[!git] skip ++ ++env GOBIN=$WORK/tmp/gobin ++env GO111MODULE=off ++ ++! go get -d golang.org/x/tools ++stderr 'golang.org/x/tools: no Go files' ++ ++! go get -d -u golang.org/x/tools ++stderr 'golang.org/x/tools: no Go files' ++ ++! go get -d golang.org/x/tools ++stderr 'golang.org/x/tools: no Go files' +diff --git a/src/cmd/go/testdata/script/get_race.txt b/src/cmd/go/testdata/script/get_race.txt +new file mode 100644 +index 0000000..1e06c80 +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_race.txt +@@ -0,0 +1,8 @@ ++# Tests issue #20502 ++ ++[!net:github.com] skip ++[!git] skip ++[!race] skip ++env GO111MODULE=off ++ ++go get -race github.com/rsc/go-get-issue-9224-cmd +diff --git a/src/cmd/go/testdata/script/get_test_only.txt b/src/cmd/go/testdata/script/get_test_only.txt +new file mode 100644 +index 0000000..af90f74 +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_test_only.txt +@@ -0,0 +1,6 @@ ++[!net:golang.org] skip ++[!git] skip ++env GO111MODULE=off ++ ++go get golang.org/x/tour/content... ++go get -t golang.org/x/tour/content... +diff --git a/src/cmd/go/testdata/script/get_tilde.txt b/src/cmd/go/testdata/script/get_tilde.txt +new file mode 100644 +index 0000000..1c3a029 +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_tilde.txt +@@ -0,0 +1,25 @@ ++env GO111MODULE=off ++ ++# Paths containing windows short names should be rejected before attempting to fetch. ++! go get vcs-test.golang.org/longna~1.dir/thing ++stderr 'trailing tilde and digits' ++! go get vcs-test.golang.org/longna~1/thing ++stderr 'trailing tilde and digits' ++! go get vcs-test.golang.org/~9999999/thing ++stderr 'trailing tilde and digits' ++ ++[short] stop ++ ++# A path containing an element that is just a tilde, or a tilde followed by non-digits, ++# should attempt to resolve. ++! go get vcs-test.golang.org/~glenda/notfound ++! stderr 'trailing tilde and digits' ++stderr 'unrecognized import path' ++ ++! go get vcs-test.golang.org/~glenda2/notfound ++! stderr 'trailing tilde and digits' ++stderr 'unrecognized import path' ++ ++! go get vcs-test.golang.org/~/notfound ++! stderr 'trailing tilde and digits' ++stderr 'unrecognized import path' +diff --git a/src/cmd/go/testdata/script/get_update.txt b/src/cmd/go/testdata/script/get_update.txt +new file mode 100644 +index 0000000..a70a80d +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_update.txt +@@ -0,0 +1,25 @@ ++# Tests Issue #9224 ++# The recursive updating was trying to walk to ++# former dependencies, not current ones. ++ ++[!net:github.com] skip ++[!git] skip ++env GO111MODULE=off ++ ++# Rewind ++go get github.com/rsc/go-get-issue-9224-cmd ++cd $GOPATH/src/github.com/rsc/go-get-issue-9224-lib ++exec git reset --hard HEAD~ ++cd $GOPATH/src ++ ++# Run get ++go get -u 'github.com/rsc/go-get-issue-9224-cmd' ++ ++# (Again with -d -u) Rewind ++go get github.com/rsc/go-get-issue-9224-cmd ++cd $GOPATH/src/github.com/rsc/go-get-issue-9224-lib ++exec git reset --hard HEAD~ ++cd $GOPATH/src ++ ++# (Again with -d -u) Run get ++go get -d -u 'github.com/rsc/go-get-issue-9224-cmd' +diff --git a/src/cmd/go/testdata/script/get_update_all.txt b/src/cmd/go/testdata/script/get_update_all.txt +new file mode 100644 +index 0000000..22fe3ed +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_update_all.txt +@@ -0,0 +1,7 @@ ++# Issue 14444: go get -u .../ duplicate loads errors ++# Check that go get update -u ... does not try to load duplicates ++ ++env GO111MODULE=off ++ ++go get -u -n .../ ++! stderr 'duplicate loads of' # make sure old packages are removed from cache +diff --git a/src/cmd/go/testdata/script/get_update_unknown_protocol.txt b/src/cmd/go/testdata/script/get_update_unknown_protocol.txt +new file mode 100644 +index 0000000..714ed6a +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_update_unknown_protocol.txt +@@ -0,0 +1,14 @@ ++[!net:github.com] skip ++[!git] skip ++env GO111MODULE=off ++ ++# Clone the repo via HTTPS manually. ++exec git clone -q https://github.com/golang/example github.com/golang/example ++ ++# Configure the repo to use a protocol unknown to cmd/go ++# that still actually works. ++cd github.com/golang/example ++exec git remote set-url origin xyz://github.com/golang/example ++exec git config --local url.https://github.com/.insteadOf xyz://github.com/ ++ ++go get -d -u -f github.com/golang/example/hello +diff --git a/src/cmd/go/testdata/script/get_update_wildcard.txt b/src/cmd/go/testdata/script/get_update_wildcard.txt +new file mode 100644 +index 0000000..c833783 +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_update_wildcard.txt +@@ -0,0 +1,16 @@ ++# Issue 14450: go get -u .../ tried to import not downloaded package ++ ++[!net:github.com] skip ++[!git] skip ++env GO111MODULE=off ++ ++go get github.com/tmwh/go-get-issue-14450/a ++! go get -u .../ ++stderr 'cannot find package.*d-dependency/e' ++ ++# Even though get -u failed, the source for others should be downloaded. ++exists github.com/tmwh/go-get-issue-14450/b ++exists github.com/tmwh/go-get-issue-14450-b-dependency/c ++exists github.com/tmwh/go-get-issue-14450-b-dependency/d ++ ++! exists github.com/tmwh/go-get-issue-14450-c-dependency/e +diff --git a/src/cmd/go/testdata/script/get_vcs_error_message.txt b/src/cmd/go/testdata/script/get_vcs_error_message.txt +new file mode 100644 +index 0000000..8dc84fc +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_vcs_error_message.txt +@@ -0,0 +1,9 @@ ++# Test that the Version Control error message includes the correct directory ++env GO111MODULE=off ++! go get -u foo ++stderr gopath(\\\\|/)src(\\\\|/)foo ++ ++-- foo/foo.go -- ++package foo ++-- math/math.go -- ++package math +diff --git a/src/cmd/go/testdata/script/get_vendor.txt b/src/cmd/go/testdata/script/get_vendor.txt +new file mode 100644 +index 0000000..179456d +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_vendor.txt +@@ -0,0 +1,95 @@ ++[short] skip ++env GO111MODULE=off ++ ++cd $GOPATH/src/v ++go run m.go ++go test ++go list -f '{{.Imports}}' ++stdout 'v/vendor/vendor.org/p' ++go list -f '{{.TestImports}}' ++stdout 'v/vendor/vendor.org/p' ++go get -d ++go get -t -d ++ ++[!net:github.com] stop ++[!git] stop ++ ++cd $GOPATH/src ++ ++# Update ++go get 'github.com/rsc/go-get-issue-11864' ++go get -u 'github.com/rsc/go-get-issue-11864' ++exists github.com/rsc/go-get-issue-11864/vendor ++ ++# get -u ++rm $GOPATH ++mkdir $GOPATH/src ++go get -u 'github.com/rsc/go-get-issue-11864' ++exists github.com/rsc/go-get-issue-11864/vendor ++ ++# get -t -u ++rm $GOPATH ++mkdir $GOPATH/src ++go get -t -u 'github.com/rsc/go-get-issue-11864/...' ++exists github.com/rsc/go-get-issue-11864/vendor ++ ++# Submodules ++rm $GOPATH ++mkdir $GOPATH/src ++go get -d 'github.com/rsc/go-get-issue-12612' ++go get -u -d 'github.com/rsc/go-get-issue-12612' ++exists github.com/rsc/go-get-issue-12612/vendor/golang.org/x/crypto/.git ++ ++# Bad vendor (bad/imp) ++rm $GOPATH ++mkdir $GOPATH/src ++! go get -t -u 'github.com/rsc/go-get-issue-18219/bad/imp' ++stderr 'must be imported as' ++! exists github.com/rsc/go-get-issue-11864/vendor ++ ++# Bad vendor (bad/imp2) ++rm $GOPATH ++mkdir $GOPATH/src ++! go get -t -u 'github.com/rsc/go-get-issue-18219/bad/imp2' ++stderr 'must be imported as' ++! exists github.com/rsc/go-get-issue-11864/vendor ++ ++# Bad vendor (bad/imp3) ++rm $GOPATH ++mkdir $GOPATH/src ++! go get -t -u 'github.com/rsc/go-get-issue-18219/bad/imp3' ++stderr 'must be imported as' ++! exists github.com/rsc/go-get-issue-11864/vendor ++ ++# Bad vendor (bad/...) ++rm $GOPATH ++mkdir $GOPATH/src ++! go get -t -u 'github.com/rsc/go-get-issue-18219/bad/...' ++stderr 'must be imported as' ++! exists github.com/rsc/go-get-issue-11864/vendor ++ ++-- v/m.go -- ++package main ++ ++import ( ++ "fmt" ++ "vendor.org/p" ++) ++ ++func main() { ++ fmt.Println(p.C) ++} ++-- v/m_test.go -- ++package main ++import ( ++ "fmt" ++ "testing" ++ "vendor.org/p" ++) ++ ++func TestNothing(t *testing.T) { ++ fmt.Println(p.C) ++} ++-- v/vendor/vendor.org/p/p.go -- ++package p ++const C = 1 +diff --git a/src/cmd/go/testdata/script/get_with_git_trace.txt b/src/cmd/go/testdata/script/get_with_git_trace.txt +new file mode 100644 +index 0000000..6f1305a +--- /dev/null ++++ b/src/cmd/go/testdata/script/get_with_git_trace.txt +@@ -0,0 +1,9 @@ ++env GO111MODULE=off ++ ++env GIT_TRACE=1 ++ ++[!net:golang.org] skip ++[!git] skip ++ ++# go get should be success when GIT_TRACE set ++go get golang.org/x/text +diff --git a/src/cmd/go/testdata/script/gopath_moved_repo.txt b/src/cmd/go/testdata/script/gopath_moved_repo.txt +new file mode 100644 +index 0000000..8108d9b +--- /dev/null ++++ b/src/cmd/go/testdata/script/gopath_moved_repo.txt +@@ -0,0 +1,67 @@ ++env GO111MODULE=off ++ ++# Test that 'go get -u' reports packages whose VCS configurations do not ++# match their import paths. ++ ++[!net:rsc.io] skip ++[short] skip ++ ++# We need to execute a custom Go program to break the config files. ++# ++# git will ask for a username and password when we run 'go get -d -f -u', ++# so we also need to set GIT_ASKPASS. Conveniently, a single binary can ++# perform both tasks! ++ ++go build -o replace.exe replace ++env GIT_ASKPASS=$PWD/replace.exe ++ ++ ++# Test that 'go get -u' reports moved git packages. ++ ++[git] go get -d rsc.io/pdf ++[git] go get -d -u rsc.io/pdf ++[git] exec ./replace.exe pdf rsc.io/pdf/.git/config ++ ++[git] ! go get -d -u rsc.io/pdf ++[git] stderr 'is a custom import path for' ++[git] ! go get -d -f -u rsc.io/pdf ++[git] stderr 'validating server certificate|[nN]ot [fF]ound' ++ ++ ++# Test that 'go get -u' reports moved Mercurial packages. ++ ++[exec:hg] go get -d vcs-test.golang.org/go/custom-hg-hello ++[exec:hg] go get -d -u vcs-test.golang.org/go/custom-hg-hello ++[exec:hg] exec ./replace.exe custom-hg-hello vcs-test.golang.org/go/custom-hg-hello/.hg/hgrc ++ ++[exec:hg] ! go get -d -u vcs-test.golang.org/go/custom-hg-hello ++[exec:hg] stderr 'is a custom import path for' ++[exec:hg] ! go get -d -f -u vcs-test.golang.org/go/custom-hg-hello ++[exec:hg] stderr 'validating server certificate|[nN]ot [fF]ound' ++ ++ ++-- replace/replace.go -- ++package main ++ ++import ( ++ "bytes" ++ "log" ++ "os" ++) ++ ++func main() { ++ if len(os.Args) < 3 { ++ return ++ } ++ ++ base := []byte(os.Args[1]) ++ path := os.Args[2] ++ data, err := os.ReadFile(path) ++ if err != nil { ++ log.Fatal(err) ++ } ++ err = os.WriteFile(path, bytes.ReplaceAll(data, base, append(base, "XXX"...)), 0644) ++ if err != nil { ++ log.Fatal(err) ++ } ++} +diff --git a/src/cmd/go/testdata/script/govcs.txt b/src/cmd/go/testdata/script/govcs.txt +index 876f606..dd128cc 100644 +--- a/src/cmd/go/testdata/script/govcs.txt ++++ b/src/cmd/go/testdata/script/govcs.txt +@@ -84,6 +84,89 @@ env GOVCS=public:git + ! go get rsc.io/nonexist.hg/hello + stderr '^go: rsc.io/nonexist.hg/hello: GOVCS disallows using hg for public rsc.io/nonexist.hg; see ''go help vcs''$' + ++# Repeat in GOPATH mode. Error texts slightly different. ++ ++env GO111MODULE=off ++ ++# GOVCS stops go get ++env GOVCS='*:none' ++! go get github.com/google/go-cmp ++stderr '^package github.com/google/go-cmp: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$' ++env GOPRIVATE='github.com/google' ++! go get github.com/google/go-cmp ++stderr '^package github.com/google/go-cmp: GOVCS disallows using git for private github.com/google/go-cmp; see ''go help vcs''$' ++ ++# public pattern works ++env GOPRIVATE='github.com/google' ++env GOVCS='public:all,private:none' ++! go get github.com/google/go-cmp ++stderr '^package github.com/google/go-cmp: GOVCS disallows using git for private github.com/google/go-cmp; see ''go help vcs''$' ++ ++# private pattern works ++env GOPRIVATE='hubgit.com/google' ++env GOVCS='private:all,public:none' ++! go get github.com/google/go-cmp ++stderr '^package github.com/google/go-cmp: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$' ++ ++# other patterns work (for more patterns, see TestGOVCS) ++env GOPRIVATE= ++env GOVCS='github.com:svn|hg' ++! go get github.com/google/go-cmp ++stderr '^package github.com/google/go-cmp: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$' ++env GOVCS='github.com/google/go-cmp/inner:git,github.com:svn|hg' ++! go get github.com/google/go-cmp ++stderr '^package github.com/google/go-cmp: GOVCS disallows using git for public github.com/google/go-cmp; see ''go help vcs''$' ++ ++# bad patterns are reported (for more bad patterns, see TestGOVCSErrors) ++env GOVCS='git' ++! go get github.com/google/go-cmp ++stderr '^package github.com/google/go-cmp: malformed entry in GOVCS \(missing colon\): "git"$' ++ ++env GOVCS=github.com:hg,github.com:git ++! go get github.com/google/go-cmp ++stderr '^package github.com/google/go-cmp: unreachable pattern in GOVCS: "github.com:git" after "github.com:hg"$' ++ ++# bad GOVCS patterns do not stop commands that do not need to check VCS ++go list ++ ++# svn is disallowed by default ++env GOPRIVATE= ++env GOVCS= ++! go get rsc.io/nonexist.svn/hello ++stderr '^package rsc.io/nonexist.svn/hello: GOVCS disallows using svn for public rsc.io/nonexist.svn; see ''go help vcs''$' ++ ++# fossil is disallowed by default ++env GOPRIVATE= ++env GOVCS= ++! go get rsc.io/nonexist.fossil/hello ++stderr '^package rsc.io/nonexist.fossil/hello: GOVCS disallows using fossil for public rsc.io/nonexist.fossil; see ''go help vcs''$' ++ ++# bzr is disallowed by default ++env GOPRIVATE= ++env GOVCS= ++! go get rsc.io/nonexist.bzr/hello ++stderr '^package rsc.io/nonexist.bzr/hello: GOVCS disallows using bzr for public rsc.io/nonexist.bzr; see ''go help vcs''$' ++ ++# git is OK by default ++env GOVCS= ++env GONOSUMDB='*' ++[net:rsc.io] [git] [!short] go get rsc.io/sampler ++ ++# hg is OK by default ++env GOVCS= ++env GONOSUMDB='*' ++[exec:hg] [!short] go get vcs-test.golang.org/go/custom-hg-hello ++ ++# git can be disallowed ++env GOVCS=public:hg ++! go get rsc.io/nonexist.git/hello ++stderr '^package rsc.io/nonexist.git/hello: GOVCS disallows using git for public rsc.io/nonexist.git; see ''go help vcs''$' ++ ++# hg can be disallowed ++env GOVCS=public:git ++! go get rsc.io/nonexist.hg/hello ++stderr '^package rsc.io/nonexist.hg/hello: GOVCS disallows using hg for public rsc.io/nonexist.hg; see ''go help vcs''$' ++ + -- go.mod -- + module m + +diff --git a/src/cmd/go/testdata/script/help.txt b/src/cmd/go/testdata/script/help.txt +index fb15e93..26a0194 100644 +--- a/src/cmd/go/testdata/script/help.txt ++++ b/src/cmd/go/testdata/script/help.txt +@@ -48,4 +48,4 @@ stderr 'Run ''go help test'' and ''go help testflag'' for details.' + # go help get shows usage for get + go help get + stdout 'usage: go get' +-stdout 'specific module versions' ++stdout 'get when using GOPATH' +diff --git a/src/cmd/go/testdata/script/mod_versions.txt b/src/cmd/go/testdata/script/mod_versions.txt +index aaa4216..9e6322b 100644 +--- a/src/cmd/go/testdata/script/mod_versions.txt ++++ b/src/cmd/go/testdata/script/mod_versions.txt +@@ -1,7 +1,7 @@ + # Test rejection of pkg@version in GOPATH mode. + env GO111MODULE=off + ! go get rsc.io/quote@v1.5.1 +-stderr '^go: modules disabled by GO111MODULE=off' ++stderr '^go: can only use path@version syntax with ''go get'' and ''go install'' in module-aware mode$' + ! go build rsc.io/quote@v1.5.1 + stderr '^package rsc.io/quote@v1.5.1: can only use path@version syntax with ''go get'' and ''go install'' in module-aware mode$' + +diff --git a/src/cmd/go/testdata/script/vendor_list_issue11977.txt b/src/cmd/go/testdata/script/vendor_list_issue11977.txt +index f1ed613..f519175 100644 +--- a/src/cmd/go/testdata/script/vendor_list_issue11977.txt ++++ b/src/cmd/go/testdata/script/vendor_list_issue11977.txt +@@ -1,5 +1,9 @@ ++[!net:github.com] skip ++[!git] skip + env GO111MODULE=off + ++go get github.com/rsc/go-get-issue-11864 ++ + go list -f '{{join .TestImports "\n"}}' github.com/rsc/go-get-issue-11864/t + stdout 'go-get-issue-11864/vendor/vendor.org/p' + +@@ -11,77 +15,3 @@ stdout 'go-get-issue-11864/vendor/vendor.org/tx2' + + go list -f '{{join .XTestImports "\n"}}' github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx3 + stdout 'go-get-issue-11864/vendor/vendor.org/tx3' +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/m.go -- +-package g +- +-import _ "vendor.org/p" +-import _ "vendor.org/p1" +- +-func main() {} +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/t/t_test.go -- +-package t +- +-import _ "vendor.org/p" +-import _ "vendor.org/p1" +-import "testing" +- +-func TestNop(t *testing.T) {} +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/t/t.go -- +-package t +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/tx/tx_test.go -- +-package tx_test +- +-import _ "vendor.org/p" +-import _ "vendor.org/p1" +-import "testing" +- +-func TestNop(t *testing.T) {} +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/tx/tx.go -- +-package tx +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/p1/p1.go -- +-package p1 // import "vendor.org/p1" +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx3/tx3_test.go -- +-package tx3_test +- +-import "vendor.org/tx3" +-import "testing" +- +-var Found = tx3.Exported +- +-func TestNop(t *testing.T) {} +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx3/export_test.go -- +-package tx3 +- +-var Exported = true +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx3/tx3.go -- +-package tx3 +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2/tx2_test.go -- +-package tx2_test +- +-import . "vendor.org/tx2" +-import "testing" +- +-var Found = Exported +- +-func TestNop(t *testing.T) {} +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2/export_test.go -- +-package tx2 +- +-var Exported = true +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2/tx2.go -- +-package tx2 +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/p/p.go -- +-package p +diff --git a/src/cmd/go/testdata/script/vendor_test_issue11864.txt b/src/cmd/go/testdata/script/vendor_test_issue11864.txt +index 90c9c59..9e34811 100644 +--- a/src/cmd/go/testdata/script/vendor_test_issue11864.txt ++++ b/src/cmd/go/testdata/script/vendor_test_issue11864.txt +@@ -1,83 +1,12 @@ +-[short] skip ++[!net:github.com] skip ++[!git] skip + env GO111MODULE=off + ++go get github.com/rsc/go-get-issue-11864 ++ + # test should work too + go test github.com/rsc/go-get-issue-11864 + go test github.com/rsc/go-get-issue-11864/t + + # external tests should observe internal test exports (golang.org/issue/11977) + go test github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2 +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/m.go -- +-package g +- +-import _ "vendor.org/p" +-import _ "vendor.org/p1" +- +-func main() {} +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/t/t_test.go -- +-package t +- +-import _ "vendor.org/p" +-import _ "vendor.org/p1" +-import "testing" +- +-func TestNop(t *testing.T) {} +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/t/t.go -- +-package t +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/tx/tx_test.go -- +-package tx_test +- +-import _ "vendor.org/p" +-import _ "vendor.org/p1" +-import "testing" +- +-func TestNop(t *testing.T) {} +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/tx/tx.go -- +-package tx +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/p1/p1.go -- +-package p1 // import "vendor.org/p1" +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx3/tx3_test.go -- +-package tx3_test +- +-import "vendor.org/tx3" +-import "testing" +- +-var Found = tx3.Exported +- +-func TestNop(t *testing.T) {} +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx3/export_test.go -- +-package tx3 +- +-var Exported = true +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx3/tx3.go -- +-package tx3 +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2/tx2_test.go -- +-package tx2_test +- +-import . "vendor.org/tx2" +-import "testing" +- +-var Found = Exported +- +-func TestNop(t *testing.T) {} +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2/export_test.go -- +-package tx2 +- +-var Exported = true +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2/tx2.go -- +-package tx2 +- +--- $GOPATH/src/github.com/rsc/go-get-issue-11864/vendor/vendor.org/p/p.go -- +-package p +diff --git a/src/cmd/go/testdata/script/vendor_test_issue14613.txt b/src/cmd/go/testdata/script/vendor_test_issue14613.txt +index d2f05c9..9535fc1 100644 +--- a/src/cmd/go/testdata/script/vendor_test_issue14613.txt ++++ b/src/cmd/go/testdata/script/vendor_test_issue14613.txt +@@ -1,6 +1,11 @@ +-[short] skip ++[!net:github.com] skip ++[!git] skip + env GO111MODULE=off + ++cd $GOPATH ++ ++go get github.com/clsung/go-vendor-issue-14613 ++ + # test folder should work + go test github.com/clsung/go-vendor-issue-14613 + +@@ -11,42 +16,3 @@ go test github.com/clsung/go-vendor-issue-14613/vendor_test.go + # test with imported and not used + ! go test github.com/clsung/go-vendor-issue-14613/vendor/mylibtesttest/myapp/myapp_test.go + stderr 'imported and not used' +- +--- $GOPATH/src/github.com/clsung/go-vendor-issue-14613/./vendor_test.go -- +-package main +- +-import ( +- "testing" +- +- "github.com/clsung/fake" +-) +- +-func TestVendor(t *testing.T) { +- ret := fake.DoNothing() +- expected := "Ok" +- if expected != ret { +- t.Errorf("fake returned %q, expected %q", ret, expected) +- } +-} +- +--- $GOPATH/src/github.com/clsung/go-vendor-issue-14613/./vendor/mylibtesttest/myapp/myapp_test.go -- +-package myapp +-import ( +- "mylibtesttest/rds" +-) +- +--- $GOPATH/src/github.com/clsung/go-vendor-issue-14613/./vendor/mylibtesttest/rds/rds.go -- +-package rds +- +--- $GOPATH/src/github.com/clsung/go-vendor-issue-14613/./vendor/github.com/clsung/fake/fake.go -- +-package fake +- +-func DoNothing() string { +- return "Ok" +-} +- +--- $GOPATH/src/github.com/clsung/go-vendor-issue-14613/./m.go -- +-package main +- +-func main() {} +- +-- +2.47.0 + diff --git a/patches/0003-Restore-related-GOPATH-mode-go-get-functions.patch b/patches/0003-Restore-related-GOPATH-mode-go-get-functions.patch new file mode 100644 index 00000000..efb2e8bb --- /dev/null +++ b/patches/0003-Restore-related-GOPATH-mode-go-get-functions.patch @@ -0,0 +1,211 @@ +From 3593bfc89de341818aefadf365ca615b78a8c958 Mon Sep 17 00:00:00 2001 +From: Vorapol Rinsatitnon +Date: Sun, 22 Sep 2024 00:34:20 +1000 +Subject: [PATCH] Restore related GOPATH-mode go get functions + +--- + src/cmd/go/internal/load/pkg.go | 59 +++++++++++++++++++++++++++++++++ + src/cmd/go/internal/par/work.go | 38 +++++++++++++++++++++ + src/cmd/go/internal/vcs/vcs.go | 39 +++++++++++++++++++--- + 3 files changed, 132 insertions(+), 4 deletions(-) + +diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go +index 7c402b4..cb38b53 100644 +--- a/src/cmd/go/internal/load/pkg.go ++++ b/src/cmd/go/internal/load/pkg.go +@@ -604,6 +604,51 @@ func (sp *ImportStack) shorterThan(t []string) bool { + // we return the same pointer each time. + var packageCache = map[string]*Package{} + ++// ClearPackageCache clears the in-memory package cache and the preload caches. ++// It is only for use by GOPATH-based "go get". ++// TODO(jayconrod): When GOPATH-based "go get" is removed, delete this function. ++func ClearPackageCache() { ++ clear(packageCache) ++ resolvedImportCache.Clear() ++ packageDataCache.Clear() ++} ++ ++// ClearPackageCachePartial clears packages with the given import paths from the ++// in-memory package cache and the preload caches. It is only for use by ++// GOPATH-based "go get". ++// TODO(jayconrod): When GOPATH-based "go get" is removed, delete this function. ++func ClearPackageCachePartial(args []string) { ++ shouldDelete := make(map[string]bool) ++ for _, arg := range args { ++ shouldDelete[arg] = true ++ if p := packageCache[arg]; p != nil { ++ delete(packageCache, arg) ++ } ++ } ++ resolvedImportCache.DeleteIf(func(key importSpec) bool { ++ return shouldDelete[key.path] ++ }) ++ packageDataCache.DeleteIf(func(key string) bool { ++ return shouldDelete[key] ++ }) ++} ++ ++// ReloadPackageNoFlags is like LoadImport but makes sure ++// not to use the package cache. ++// It is only for use by GOPATH-based "go get". ++// TODO(rsc): When GOPATH-based "go get" is removed, delete this function. ++func ReloadPackageNoFlags(arg string, stk *ImportStack) *Package { ++ p := packageCache[arg] ++ if p != nil { ++ delete(packageCache, arg) ++ resolvedImportCache.DeleteIf(func(key importSpec) bool { ++ return key.path == p.ImportPath ++ }) ++ packageDataCache.Delete(p.ImportPath) ++ } ++ return LoadPackage(context.TODO(), PackageOpts{}, arg, base.Cwd(), stk, nil, 0) ++} ++ + // dirToImportPath returns the pseudo-import path we use for a package + // outside the Go path. It begins with _/ and then contains the full path + // to the directory. If the package lives in c:\home\gopher\my\pkg then +@@ -655,6 +700,20 @@ const ( + cmdlinePkgLiteral + ) + ++// LoadImport scans the directory named by path, which must be an import path, ++// but possibly a local import path (an absolute file system path or one beginning ++// with ./ or ../). A local relative path is interpreted relative to srcDir. ++// It returns a *Package describing the package found in that directory. ++// LoadImport does not set tool flags and should only be used by ++// this package, as part of a bigger load operation, and by GOPATH-based "go get". ++// TODO(rsc): When GOPATH-based "go get" is removed, unexport this function. ++// The returned PackageError, if any, describes why parent is not allowed ++// to import the named package, with the error referring to importPos. ++// The PackageError can only be non-nil when parent is not nil. ++func LoadImport(ctx context.Context, opts PackageOpts, path, srcDir string, parent *Package, stk *ImportStack, importPos []token.Position, mode int) (*Package, *PackageError) { ++ return loadImport(ctx, opts, nil, path, srcDir, parent, stk, importPos, mode) ++} ++ + // LoadPackage does Load import, but without a parent package load contezt + func LoadPackage(ctx context.Context, opts PackageOpts, path, srcDir string, stk *ImportStack, importPos []token.Position, mode int) *Package { + p, err := loadImport(ctx, opts, nil, path, srcDir, nil, stk, importPos, mode) +diff --git a/src/cmd/go/internal/par/work.go b/src/cmd/go/internal/par/work.go +index 881b51b..3f1e69a 100644 +--- a/src/cmd/go/internal/par/work.go ++++ b/src/cmd/go/internal/par/work.go +@@ -180,3 +180,41 @@ func (c *Cache[K, V]) Get(key K) (V, bool) { + } + return e.result, true + } ++ ++// Clear removes all entries in the cache. ++// ++// Concurrent calls to Get may return old values. Concurrent calls to Do ++// may return old values or store results in entries that have been deleted. ++// ++// TODO(jayconrod): Delete this after the package cache clearing functions ++// in internal/load have been removed. ++func (c *Cache[K, V]) Clear() { ++ c.m.Clear() ++} ++ ++// Delete removes an entry from the map. It is safe to call Delete for an ++// entry that does not exist. Delete will return quickly, even if the result ++// for a key is still being computed; the computation will finish, but the ++// result won't be accessible through the cache. ++// ++// TODO(jayconrod): Delete this after the package cache clearing functions ++// in internal/load have been removed. ++func (c *Cache[K, V]) Delete(key K) { ++ c.m.Delete(key) ++} ++ ++// DeleteIf calls pred for each key in the map. If pred returns true for a key, ++// DeleteIf removes the corresponding entry. If the result for a key is ++// still being computed, DeleteIf will remove the entry without waiting for ++// the computation to finish. The result won't be accessible through the cache. ++// ++// TODO(jayconrod): Delete this after the package cache clearing functions ++// in internal/load have been removed. ++func (c *Cache[K, V]) DeleteIf(pred func(key K) bool) { ++ c.m.Range(func(key, _ any) bool { ++ if key := key.(K); pred(key) { ++ c.Delete(key) ++ } ++ return true ++ }) ++} +diff --git a/src/cmd/go/internal/vcs/vcs.go b/src/cmd/go/internal/vcs/vcs.go +index 19a6a5e..044d02e 100644 +--- a/src/cmd/go/internal/vcs/vcs.go ++++ b/src/cmd/go/internal/vcs/vcs.go +@@ -1013,11 +1013,11 @@ var defaultGOVCS = govcsConfig{ + {"public", []string{"git", "hg"}}, + } + +-// checkGOVCS checks whether the policy defined by the environment variable ++// CheckGOVCS checks whether the policy defined by the environment variable + // GOVCS allows the given vcs command to be used with the given repository + // root path. Note that root may not be a real package or module path; it's + // the same as the root path in the go-import meta tag. +-func checkGOVCS(vcs *Cmd, root string) error { ++func CheckGOVCS(vcs *Cmd, root string) error { + if vcs == vcsMod { + // Direct module (proxy protocol) fetches don't + // involve an external version control system +@@ -1045,6 +1045,37 @@ func checkGOVCS(vcs *Cmd, root string) error { + return nil + } + ++// CheckNested checks for an incorrectly-nested VCS-inside-VCS ++// situation for dir, checking parents up until srcRoot. ++func CheckNested(vcs *Cmd, dir, srcRoot string) error { ++ if len(dir) <= len(srcRoot) || dir[len(srcRoot)] != filepath.Separator { ++ return fmt.Errorf("directory %q is outside source root %q", dir, srcRoot) ++ } ++ ++ otherDir := dir ++ for len(otherDir) > len(srcRoot) { ++ for _, otherVCS := range vcsList { ++ if isVCSRoot(otherDir, otherVCS.RootNames) { ++ // Allow expected vcs in original dir. ++ if otherDir == dir && otherVCS == vcs { ++ continue ++ } ++ // Otherwise, we have one VCS inside a different VCS. ++ return fmt.Errorf("directory %q uses %s, but parent %q uses %s", dir, vcs.Cmd, otherDir, otherVCS.Cmd) ++ } ++ } ++ // Move to parent. ++ newDir := filepath.Dir(otherDir) ++ if len(newDir) >= len(otherDir) { ++ // Shouldn't happen, but just in case, stop. ++ break ++ } ++ otherDir = newDir ++ } ++ ++ return nil ++} ++ + // RepoRoot describes the repository root for a tree of source code. + type RepoRoot struct { + Repo string // repository URL, including scheme +@@ -1160,7 +1191,7 @@ func repoRootFromVCSPaths(importPath string, security web.SecurityMode, vcsPaths + if vcs == nil { + return nil, fmt.Errorf("unknown version control system %q", match["vcs"]) + } +- if err := checkGOVCS(vcs, match["root"]); err != nil { ++ if err := CheckGOVCS(vcs, match["root"]); err != nil { + return nil, err + } + var repoURL string +@@ -1349,7 +1380,7 @@ func repoRootForImportDynamic(importPath string, mod ModuleMode, security web.Se + } + } + +- if err := checkGOVCS(vcs, mmi.Prefix); err != nil { ++ if err := CheckGOVCS(vcs, mmi.Prefix); err != nil { + return nil, err + } + +-- +2.47.0 + diff --git a/patches/0004-Add-back-LoadLibraryA-fallback.patch b/patches/0004-Add-back-LoadLibraryA-fallback.patch new file mode 100644 index 00000000..bf2b6507 --- /dev/null +++ b/patches/0004-Add-back-LoadLibraryA-fallback.patch @@ -0,0 +1,307 @@ +From 4945989aba36baee4cdc72e61bdc4484c81d9ea0 Mon Sep 17 00:00:00 2001 +From: Vorapol Rinsatitnon +Date: Fri, 27 Sep 2024 04:05:44 +1000 +Subject: [PATCH] Add back LoadLibraryA fallback + +--- + src/runtime/export_windows_test.go | 4 ++ + src/runtime/os_windows.go | 60 ++++++++++++++++++++++++++++- + src/runtime/syscall_windows.go | 17 +++++++- + src/runtime/syscall_windows_test.go | 23 ++++++++++- + src/syscall/dll_windows.go | 28 +++++++++++++- + src/syscall/security_windows.go | 1 + + src/syscall/zsyscall_windows.go | 10 +++++ + 7 files changed, 136 insertions(+), 7 deletions(-) + +diff --git a/src/runtime/export_windows_test.go b/src/runtime/export_windows_test.go +index 4880e62..8bfff0b 100644 +--- a/src/runtime/export_windows_test.go ++++ b/src/runtime/export_windows_test.go +@@ -36,3 +36,7 @@ func NewContextStub() *ContextStub { + ctx.set_fp(getcallerfp()) + return &ContextStub{ctx} + } ++ ++func LoadLibraryExStatus() (useEx, haveEx, haveFlags bool) { ++ return useLoadLibraryEx, _LoadLibraryExW != nil, _AddDllDirectory != nil ++} +diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go +index 0273580..c76df9d 100644 +--- a/src/runtime/os_windows.go ++++ b/src/runtime/os_windows.go +@@ -41,6 +41,7 @@ const ( + //go:cgo_import_dynamic runtime._SetThreadContext SetThreadContext%2 "kernel32.dll" + //go:cgo_import_dynamic runtime._LoadLibraryExW LoadLibraryExW%3 "kernel32.dll" + //go:cgo_import_dynamic runtime._LoadLibraryW LoadLibraryW%1 "kernel32.dll" ++//go:cgo_import_dynamic runtime._LoadLibraryA LoadLibraryA%1 "kernel32.dll" + //go:cgo_import_dynamic runtime._PostQueuedCompletionStatus PostQueuedCompletionStatus%4 "kernel32.dll" + //go:cgo_import_dynamic runtime._QueryPerformanceCounter QueryPerformanceCounter%1 "kernel32.dll" + //go:cgo_import_dynamic runtime._QueryPerformanceFrequency QueryPerformanceFrequency%1 "kernel32.dll" +@@ -74,6 +75,7 @@ var ( + // Following syscalls are available on every Windows PC. + // All these variables are set by the Windows executable + // loader before the Go program starts. ++ _AddDllDirectory, + _AddVectoredContinueHandler, + _AddVectoredExceptionHandler, + _CloseHandle, +@@ -99,6 +101,7 @@ var ( + _SetThreadContext, + _LoadLibraryExW, + _LoadLibraryW, ++ _LoadLibraryA, + _PostQueuedCompletionStatus, + _QueryPerformanceCounter, + _QueryPerformanceFrequency, +@@ -157,7 +160,6 @@ var ( + ntdlldll = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0} + powrprofdll = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0} + winmmdll = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0} +- ws2_32dll = [...]uint16{'w', 's', '2', '_', '3', '2', '.', 'd', 'l', 'l', 0} + ) + + // Function to be called by windows CreateThread +@@ -253,7 +255,36 @@ func windows_GetSystemDirectory() string { + } + + func windowsLoadSystemLib(name []uint16) uintptr { +- return stdcall3(_LoadLibraryExW, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32) ++ if useLoadLibraryEx { ++ return stdcall3(_LoadLibraryExW, uintptr(unsafe.Pointer(&name[0])), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32) ++ } else { ++ var nameBytes [_MAX_PATH]byte ++ n := len(name) ++ if n > len(nameBytes) { ++ n = len(nameBytes) ++ } ++ for i := 0; i < n && name[i] != 0; i++ { ++ nameBytes[i] = byte(name[i]) ++ } ++ ++ // Construct the full path ++ var fullPath [_MAX_PATH]byte ++ copy(fullPath[:], sysDirectory[:sysDirectoryLen]) ++ pathLen := sysDirectoryLen ++ for i := 0; i < len(nameBytes) && nameBytes[i] != 0 && pathLen < _MAX_PATH; i++ { ++ fullPath[pathLen] = nameBytes[i] ++ pathLen++ ++ } ++ ++ // Ensure null-termination ++ if pathLen < _MAX_PATH { ++ fullPath[pathLen] = 0 ++ } else { ++ fullPath[_MAX_PATH-1] = 0 ++ } ++ ++ return stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&fullPath[0]))) ++ } + } + + //go:linkname windows_QueryPerformanceCounter internal/syscall/windows.QueryPerformanceCounter +@@ -271,6 +302,15 @@ func windows_QueryPerformanceFrequency() int64 { + } + + func loadOptionalSyscalls() { ++ var kernel32dll = []byte("kernel32.dll\000") ++ k32 := stdcall1(_LoadLibraryA, uintptr(unsafe.Pointer(&kernel32dll[0]))) ++ if k32 == 0 { ++ throw("kernel32.dll not found") ++ } ++ _AddDllDirectory = windowsFindfunc(k32, []byte("AddDllDirectory\000")) ++ _LoadLibraryExW = windowsFindfunc(k32, []byte("LoadLibraryExW\000")) ++ useLoadLibraryEx = (_LoadLibraryExW != nil && _AddDllDirectory != nil) ++ + a32 := windowsLoadSystemLib(advapi32dll[:]) + if a32 == 0 { + throw("advapi32.dll not found") +@@ -365,6 +405,22 @@ const ( + // in sys_windows_386.s and sys_windows_amd64.s: + func getlasterror() uint32 + ++// When loading DLLs, we prefer to use LoadLibraryEx with ++// LOAD_LIBRARY_SEARCH_* flags, if available. LoadLibraryEx is not ++// available on old Windows, though, and the LOAD_LIBRARY_SEARCH_* ++// flags are not available on some versions of Windows without a ++// security patch. ++// ++// https://msdn.microsoft.com/en-us/library/ms684179(v=vs.85).aspx says: ++// "Windows 7, Windows Server 2008 R2, Windows Vista, and Windows ++// Server 2008: The LOAD_LIBRARY_SEARCH_* flags are available on ++// systems that have KB2533623 installed. To determine whether the ++// flags are available, use GetProcAddress to get the address of the ++// AddDllDirectory, RemoveDllDirectory, or SetDefaultDllDirectories ++// function. If GetProcAddress succeeds, the LOAD_LIBRARY_SEARCH_* ++// flags can be used with LoadLibraryEx." ++var useLoadLibraryEx bool ++ + var timeBeginPeriodRetValue uint32 + + // osRelaxMinNS indicates that sysmon shouldn't osRelax if the next +diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go +index 69d720a..973fd9c 100644 +--- a/src/runtime/syscall_windows.go ++++ b/src/runtime/syscall_windows.go +@@ -413,10 +413,23 @@ func callbackWrap(a *callbackArgs) { + + const _LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800 + ++// When available, this function will use LoadLibraryEx with the filename ++// parameter and the important SEARCH_SYSTEM32 argument. But on systems that ++// do not have that option, absoluteFilepath should contain a fallback ++// to the full path inside of system32 for use with vanilla LoadLibrary. ++// + //go:linkname syscall_loadsystemlibrary syscall.loadsystemlibrary +-func syscall_loadsystemlibrary(filename *uint16) (handle, err uintptr) { +- handle, _, err = syscall_SyscallN(uintptr(unsafe.Pointer(_LoadLibraryExW)), uintptr(unsafe.Pointer(filename)), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32) ++func syscall_loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (handle, err uintptr) { ++ if useLoadLibraryEx { ++ handle, _, err = syscall_SyscallN(uintptr(unsafe.Pointer(_LoadLibraryExW)), uintptr(unsafe.Pointer(filename)), 0, _LOAD_LIBRARY_SEARCH_SYSTEM32) ++ } else { ++ handle, _, err = syscall_SyscallN( ++ uintptr(unsafe.Pointer(_LoadLibraryW)), ++ uintptr(unsafe.Pointer(absoluteFilepath)), ++ ) ++ } + KeepAlive(filename) ++ KeepAlive(absoluteFilepath) + if handle != 0 { + err = 0 + } +diff --git a/src/runtime/syscall_windows_test.go b/src/runtime/syscall_windows_test.go +index 6a056c8..2c91cd9 100644 +--- a/src/runtime/syscall_windows_test.go ++++ b/src/runtime/syscall_windows_test.go +@@ -1166,7 +1166,10 @@ uintptr_t cfunc(void) { + dll, err = syscall.LoadDLL(name) + if err == nil { + dll.Release() +- t.Fatalf("Bad: insecure load of DLL by base name %q before sysdll registration: %v", name, err) ++ if wantLoadLibraryEx() { ++ t.Fatalf("Bad: insecure load of DLL by base name %q before sysdll registration: %v", name, err) ++ } ++ t.Skip("insecure load of DLL, but expected") + } + } + +@@ -1212,6 +1215,24 @@ func TestBigStackCallbackSyscall(t *testing.T) { + } + } + ++// wantLoadLibraryEx reports whether we expect LoadLibraryEx to work for tests. ++func wantLoadLibraryEx() bool { ++ return testenv.Builder() != "" && (runtime.GOARCH == "amd64" || runtime.GOARCH == "386") ++} ++ ++func TestLoadLibraryEx(t *testing.T) { ++ use, have, flags := runtime.LoadLibraryExStatus() ++ if use { ++ return // success. ++ } ++ if wantLoadLibraryEx() { ++ t.Fatalf("Expected LoadLibraryEx+flags to be available. (LoadLibraryEx=%v; flags=%v)", ++ have, flags) ++ } ++ t.Skipf("LoadLibraryEx not usable, but not expected. (LoadLibraryEx=%v; flags=%v)", ++ have, flags) ++} ++ + var ( + modwinmm = syscall.NewLazyDLL("winmm.dll") + modkernel32 = syscall.NewLazyDLL("kernel32.dll") +diff --git a/src/syscall/dll_windows.go b/src/syscall/dll_windows.go +index 81134cb..b3554d3 100644 +--- a/src/syscall/dll_windows.go ++++ b/src/syscall/dll_windows.go +@@ -44,7 +44,7 @@ func Syscall18(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a + + func SyscallN(trap uintptr, args ...uintptr) (r1, r2 uintptr, err Errno) + func loadlibrary(filename *uint16) (handle uintptr, err Errno) +-func loadsystemlibrary(filename *uint16) (handle uintptr, err Errno) ++func loadsystemlibrary(filename *uint16, absoluteFilepath *uint16) (handle uintptr, err Errno) + func getprocaddress(handle uintptr, procname *uint8) (proc uintptr, err Errno) + + // A DLL implements access to a single DLL. +@@ -53,6 +53,26 @@ type DLL struct { + Handle Handle + } + ++// We use this for computing the absolute path for system DLLs on systems ++// where SEARCH_SYSTEM32 is not available. ++var systemDirectoryPrefix string ++ ++func init() { ++ n := uint32(MAX_PATH) ++ for { ++ b := make([]uint16, n) ++ l, e := getSystemDirectory(&b[0], n) ++ if e != nil { ++ panic("Unable to determine system directory: " + e.Error()) ++ } ++ if l <= n { ++ systemDirectoryPrefix = UTF16ToString(b[:l]) + "\\" ++ break ++ } ++ n = l ++ } ++} ++ + // LoadDLL loads the named DLL file into memory. + // + // If name is not an absolute path and is not a known system DLL used by +@@ -69,7 +89,11 @@ func LoadDLL(name string) (*DLL, error) { + var h uintptr + var e Errno + if sysdll.IsSystemDLL[name] { +- h, e = loadsystemlibrary(namep) ++ absoluteFilepathp, err := UTF16PtrFromString(systemDirectoryPrefix + name) ++ if err != nil { ++ return nil, err ++ } ++ h, e = loadsystemlibrary(namep, absoluteFilepathp) + } else { + h, e = loadlibrary(namep) + } +diff --git a/src/syscall/security_windows.go b/src/syscall/security_windows.go +index 4e988c4..45b1908 100644 +--- a/src/syscall/security_windows.go ++++ b/src/syscall/security_windows.go +@@ -290,6 +290,7 @@ type Tokenprimarygroup struct { + //sys OpenProcessToken(h Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken + //sys GetTokenInformation(t Token, infoClass uint32, info *byte, infoLen uint32, returnedLen *uint32) (err error) = advapi32.GetTokenInformation + //sys GetUserProfileDirectory(t Token, dir *uint16, dirLen *uint32) (err error) = userenv.GetUserProfileDirectoryW ++//sys getSystemDirectory(dir *uint16, dirLen uint32) (len uint32, err error) = kernel32.GetSystemDirectoryW + + // An access token contains the security information for a logon session. + // The system creates an access token when a user logs on, and every +diff --git a/src/syscall/zsyscall_windows.go b/src/syscall/zsyscall_windows.go +index d8d8594..28369e3 100644 +--- a/src/syscall/zsyscall_windows.go ++++ b/src/syscall/zsyscall_windows.go +@@ -128,6 +128,7 @@ var ( + procGetShortPathNameW = modkernel32.NewProc("GetShortPathNameW") + procGetStartupInfoW = modkernel32.NewProc("GetStartupInfoW") + procGetStdHandle = modkernel32.NewProc("GetStdHandle") ++ procGetSystemDirectoryW = modkernel32.NewProc("GetSystemDirectoryW") + procGetSystemTimeAsFileTime = modkernel32.NewProc("GetSystemTimeAsFileTime") + procGetTempPathW = modkernel32.NewProc("GetTempPathW") + procGetTimeZoneInformation = modkernel32.NewProc("GetTimeZoneInformation") +@@ -870,6 +871,15 @@ func GetStdHandle(stdhandle int) (handle Handle, err error) { + return + } + ++func getSystemDirectory(dir *uint16, dirLen uint32) (len uint32, err error) { ++ r0, _, e1 := Syscall(procGetSystemDirectoryW.Addr(), 2, uintptr(unsafe.Pointer(dir)), uintptr(dirLen), 0) ++ len = uint32(r0) ++ if len == 0 { ++ err = errnoErr(e1) ++ } ++ return ++} ++ + func GetSystemTimeAsFileTime(time *Filetime) { + Syscall(procGetSystemTimeAsFileTime.Addr(), 1, uintptr(unsafe.Pointer(time)), 0, 0) + return +-- +2.47.0 + diff --git a/patches/0005-Add-Windows-7-console-handle-workaround.patch b/patches/0005-Add-Windows-7-console-handle-workaround.patch new file mode 100644 index 00000000..e93fff92 --- /dev/null +++ b/patches/0005-Add-Windows-7-console-handle-workaround.patch @@ -0,0 +1,66 @@ +From 60f9e8454df41affe07266e795f8a1d22567fd3e Mon Sep 17 00:00:00 2001 +From: Vorapol Rinsatitnon +Date: Sat, 5 Oct 2024 14:17:43 +1000 +Subject: [PATCH] Add Windows 7 console handle workaround (revert 48042aa) + +--- + src/syscall/exec_windows.go | 29 ++++++++++++++++++++++++++++- + 1 file changed, 28 insertions(+), 1 deletion(-) + +diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go +index 1220de4..815dfd6 100644 +--- a/src/syscall/exec_windows.go ++++ b/src/syscall/exec_windows.go +@@ -317,6 +317,17 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle + } + } + ++ var maj, min, build uint32 ++ rtlGetNtVersionNumbers(&maj, &min, &build) ++ isWin7 := maj < 6 || (maj == 6 && min <= 1) ++ // NT kernel handles are divisible by 4, with the bottom 3 bits left as ++ // a tag. The fully set tag correlates with the types of handles we're ++ // concerned about here. Except, the kernel will interpret some ++ // special handle values, like -1, -2, and so forth, so kernelbase.dll ++ // checks to see that those bottom three bits are checked, but that top ++ // bit is not checked. ++ isLegacyWin7ConsoleHandle := func(handle Handle) bool { return isWin7 && handle&0x10000003 == 3 } ++ + p, _ := GetCurrentProcess() + parentProcess := p + if sys.ParentProcess != 0 { +@@ -325,7 +336,15 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle + fd := make([]Handle, len(attr.Files)) + for i := range attr.Files { + if attr.Files[i] > 0 { +- err := DuplicateHandle(p, Handle(attr.Files[i]), parentProcess, &fd[i], 0, true, DUPLICATE_SAME_ACCESS) ++ destinationProcessHandle := parentProcess ++ ++ // On Windows 7, console handles aren't real handles, and can only be duplicated ++ // into the current process, not a parent one, which amounts to the same thing. ++ if parentProcess != p && isLegacyWin7ConsoleHandle(Handle(attr.Files[i])) { ++ destinationProcessHandle = p ++ } ++ ++ err := DuplicateHandle(p, Handle(attr.Files[i]), destinationProcessHandle, &fd[i], 0, true, DUPLICATE_SAME_ACCESS) + if err != nil { + return 0, 0, err + } +@@ -356,6 +375,14 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle + + fd = append(fd, sys.AdditionalInheritedHandles...) + ++ // On Windows 7, console handles aren't real handles, so don't pass them ++ // through to PROC_THREAD_ATTRIBUTE_HANDLE_LIST. ++ for i := range fd { ++ if isLegacyWin7ConsoleHandle(fd[i]) { ++ fd[i] = 0 ++ } ++ } ++ + // The presence of a NULL handle in the list is enough to cause PROC_THREAD_ATTRIBUTE_HANDLE_LIST + // to treat the entire list as empty, so remove NULL handles. + j := 0 +-- +2.47.0 + diff --git a/patches/0006-Add-sysSocket-fallback.patch b/patches/0006-Add-sysSocket-fallback.patch new file mode 100644 index 00000000..3d4dc4aa --- /dev/null +++ b/patches/0006-Add-sysSocket-fallback.patch @@ -0,0 +1,177 @@ +From 0468b8b0addf825a274d81630087d62db495a562 Mon Sep 17 00:00:00 2001 +From: Vorapol Rinsatitnon +Date: Sat, 5 Oct 2024 14:27:19 +1000 +Subject: [PATCH] Add sysSocket fallback (revert 7c1157f) + +--- + src/net/hook_windows.go | 1 + + src/net/internal/socktest/main_test.go | 2 +- + .../internal/socktest/main_windows_test.go | 22 ++++++++++++++ + src/net/internal/socktest/sys_windows.go | 29 +++++++++++++++++++ + src/net/main_windows_test.go | 3 ++ + src/net/sock_windows.go | 14 +++++++++ + src/syscall/exec_windows.go | 1 - + 7 files changed, 70 insertions(+), 2 deletions(-) + create mode 100644 src/net/internal/socktest/main_windows_test.go + +diff --git a/src/net/hook_windows.go b/src/net/hook_windows.go +index f7c5b5a..6b82be5 100644 +--- a/src/net/hook_windows.go ++++ b/src/net/hook_windows.go +@@ -13,6 +13,7 @@ var ( + hostsFilePath = windows.GetSystemDirectory() + "/Drivers/etc/hosts" + + // Placeholders for socket system calls. ++ socketFunc func(int, int, int) (syscall.Handle, error) = syscall.Socket + wsaSocketFunc func(int32, int32, int32, *syscall.WSAProtocolInfo, uint32, uint32) (syscall.Handle, error) = windows.WSASocket + connectFunc func(syscall.Handle, syscall.Sockaddr) error = syscall.Connect + listenFunc func(syscall.Handle, int) error = syscall.Listen +diff --git a/src/net/internal/socktest/main_test.go b/src/net/internal/socktest/main_test.go +index 967ce67..0197feb 100644 +--- a/src/net/internal/socktest/main_test.go ++++ b/src/net/internal/socktest/main_test.go +@@ -2,7 +2,7 @@ + // Use of this source code is governed by a BSD-style + // license that can be found in the LICENSE file. + +-//go:build !js && !plan9 && !wasip1 && !windows ++//go:build !js && !plan9 && !wasip1 + + package socktest_test + +diff --git a/src/net/internal/socktest/main_windows_test.go b/src/net/internal/socktest/main_windows_test.go +new file mode 100644 +index 0000000..df1cb97 +--- /dev/null ++++ b/src/net/internal/socktest/main_windows_test.go +@@ -0,0 +1,22 @@ ++// Copyright 2015 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 socktest_test ++ ++import "syscall" ++ ++var ( ++ socketFunc func(int, int, int) (syscall.Handle, error) ++ closeFunc func(syscall.Handle) error ++) ++ ++func installTestHooks() { ++ socketFunc = sw.Socket ++ closeFunc = sw.Closesocket ++} ++ ++func uninstallTestHooks() { ++ socketFunc = syscall.Socket ++ closeFunc = syscall.Closesocket ++} +diff --git a/src/net/internal/socktest/sys_windows.go b/src/net/internal/socktest/sys_windows.go +index 2f02446..2b89362 100644 +--- a/src/net/internal/socktest/sys_windows.go ++++ b/src/net/internal/socktest/sys_windows.go +@@ -9,6 +9,35 @@ import ( + "syscall" + ) + ++// Socket wraps syscall.Socket. ++func (sw *Switch) Socket(family, sotype, proto int) (s syscall.Handle, err error) { ++ sw.once.Do(sw.init) ++ so := &Status{Cookie: cookie(family, sotype, proto)} ++ sw.fmu.RLock() ++ f, _ := sw.fltab[FilterSocket] ++ sw.fmu.RUnlock() ++ af, err := f.apply(so) ++ if err != nil { ++ return syscall.InvalidHandle, err ++ } ++ s, so.Err = syscall.Socket(family, sotype, proto) ++ if err = af.apply(so); err != nil { ++ if so.Err == nil { ++ syscall.Closesocket(s) ++ } ++ return syscall.InvalidHandle, err ++ } ++ sw.smu.Lock() ++ defer sw.smu.Unlock() ++ if so.Err != nil { ++ sw.stats.getLocked(so.Cookie).OpenFailed++ ++ return syscall.InvalidHandle, so.Err ++ } ++ nso := sw.addLocked(s, family, sotype, proto) ++ sw.stats.getLocked(nso.Cookie).Opened++ ++ return s, nil ++} ++ + // WSASocket wraps [syscall.WSASocket]. + func (sw *Switch) WSASocket(family, sotype, proto int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (s syscall.Handle, err error) { + sw.once.Do(sw.init) +diff --git a/src/net/main_windows_test.go b/src/net/main_windows_test.go +index bc024c0..07f21b7 100644 +--- a/src/net/main_windows_test.go ++++ b/src/net/main_windows_test.go +@@ -8,6 +8,7 @@ import "internal/poll" + + var ( + // Placeholders for saving original socket system calls. ++ origSocket = socketFunc + origWSASocket = wsaSocketFunc + origClosesocket = poll.CloseFunc + origConnect = connectFunc +@@ -17,6 +18,7 @@ var ( + ) + + func installTestHooks() { ++ socketFunc = sw.Socket + wsaSocketFunc = sw.WSASocket + poll.CloseFunc = sw.Closesocket + connectFunc = sw.Connect +@@ -26,6 +28,7 @@ func installTestHooks() { + } + + func uninstallTestHooks() { ++ socketFunc = origSocket + wsaSocketFunc = origWSASocket + poll.CloseFunc = origClosesocket + connectFunc = origConnect +diff --git a/src/net/sock_windows.go b/src/net/sock_windows.go +index a519909..ebdf4c3 100644 +--- a/src/net/sock_windows.go ++++ b/src/net/sock_windows.go +@@ -20,6 +20,20 @@ func maxListenerBacklog() int { + func sysSocket(family, sotype, proto int) (syscall.Handle, error) { + s, err := wsaSocketFunc(int32(family), int32(sotype), int32(proto), + nil, 0, windows.WSA_FLAG_OVERLAPPED|windows.WSA_FLAG_NO_HANDLE_INHERIT) ++ if err == nil { ++ return s, nil ++ } ++ // WSA_FLAG_NO_HANDLE_INHERIT flag is not supported on some ++ // old versions of Windows, see ++ // https://msdn.microsoft.com/en-us/library/windows/desktop/ms742212(v=vs.85).aspx ++ // for details. Just use syscall.Socket, if windows.WSASocket failed. ++ // See ../syscall/exec_unix.go for description of ForkLock. ++ syscall.ForkLock.RLock() ++ s, err = socketFunc(family, sotype, proto) ++ if err == nil { ++ syscall.CloseOnExec(s) ++ } ++ syscall.ForkLock.RUnlock() + if err != nil { + return syscall.InvalidHandle, os.NewSyscallError("socket", err) + } +diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go +index 815dfd6..d197380 100644 +--- a/src/syscall/exec_windows.go ++++ b/src/syscall/exec_windows.go +@@ -14,7 +14,6 @@ import ( + "unsafe" + ) + +-// ForkLock is not used on Windows. + var ForkLock sync.RWMutex + + // EscapeArg rewrites command line argument s as prescribed +-- +2.47.0 + diff --git a/patches/0007-Add-Windows-version-info-to-syscall.patch b/patches/0007-Add-Windows-version-info-to-syscall.patch new file mode 100644 index 00000000..6c141508 --- /dev/null +++ b/patches/0007-Add-Windows-version-info-to-syscall.patch @@ -0,0 +1,82 @@ +From d97201a53d5ec76fa81b091bc0d4d64f6ff6ff8c Mon Sep 17 00:00:00 2001 +From: Vorapol Rinsatitnon +Date: Sat, 5 Oct 2024 15:10:54 +1000 +Subject: [PATCH] Add Windows version info to syscall + +--- + src/syscall/exec_windows.go | 7 ++++--- + src/syscall/types_windows.go | 10 ++++++++++ + src/syscall/zsyscall_windows.go | 7 +++++++ + 3 files changed, 21 insertions(+), 3 deletions(-) + +diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go +index d197380..f099a6f 100644 +--- a/src/syscall/exec_windows.go ++++ b/src/syscall/exec_windows.go +@@ -316,9 +316,10 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle + } + } + +- var maj, min, build uint32 +- rtlGetNtVersionNumbers(&maj, &min, &build) +- isWin7 := maj < 6 || (maj == 6 && min <= 1) ++ info := _OSVERSIONINFOW{} ++ info.osVersionInfoSize = uint32(unsafe.Sizeof(info)) ++ rtlGetVersion(&info) ++ isWin7 := info.majorVersion < 6 || (info.majorVersion == 6 && info.minorVersion <= 1) + // NT kernel handles are divisible by 4, with the bottom 3 bits left as + // a tag. The fully set tag correlates with the types of handles we're + // concerned about here. Except, the kernel will interpret some +diff --git a/src/syscall/types_windows.go b/src/syscall/types_windows.go +index 6743675..37d0eff 100644 +--- a/src/syscall/types_windows.go ++++ b/src/syscall/types_windows.go +@@ -1169,3 +1169,13 @@ const ( + ) + + const UNIX_PATH_MAX = 108 // defined in afunix.h ++ ++// https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_osversioninfow ++type _OSVERSIONINFOW struct { ++ osVersionInfoSize uint32 ++ majorVersion uint32 ++ minorVersion uint32 ++ buildNumber uint32 ++ platformId uint32 ++ csdVersion [128]uint16 ++} +diff --git a/src/syscall/zsyscall_windows.go b/src/syscall/zsyscall_windows.go +index 28369e3..a47b090 100644 +--- a/src/syscall/zsyscall_windows.go ++++ b/src/syscall/zsyscall_windows.go +@@ -43,6 +43,7 @@ var ( + modkernel32 = NewLazyDLL(sysdll.Add("kernel32.dll")) + modmswsock = NewLazyDLL(sysdll.Add("mswsock.dll")) + modnetapi32 = NewLazyDLL(sysdll.Add("netapi32.dll")) ++ modntdll = NewLazyDLL(sysdll.Add("ntdll.dll")) + modsecur32 = NewLazyDLL(sysdll.Add("secur32.dll")) + modshell32 = NewLazyDLL(sysdll.Add("shell32.dll")) + moduserenv = NewLazyDLL(sysdll.Add("userenv.dll")) +@@ -169,6 +170,7 @@ var ( + procNetGetJoinInformation = modnetapi32.NewProc("NetGetJoinInformation") + procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo") + procGetUserNameExW = modsecur32.NewProc("GetUserNameExW") ++ procRtlGetVersion = modntdll.NewProc("RtlGetVersion") + procTranslateNameW = modsecur32.NewProc("TranslateNameW") + procCommandLineToArgvW = modshell32.NewProc("CommandLineToArgvW") + procGetUserProfileDirectoryW = moduserenv.NewProc("GetUserProfileDirectoryW") +@@ -1228,6 +1230,11 @@ func GetUserNameEx(nameFormat uint32, nameBuffre *uint16, nSize *uint32) (err er + return + } + ++func rtlGetVersion(info *_OSVERSIONINFOW) { ++ Syscall(procRtlGetVersion.Addr(), 1, uintptr(unsafe.Pointer(info)), 0, 0) ++ return ++} ++ + func TranslateName(accName *uint16, accNameFormat uint32, desiredNameFormat uint32, translatedName *uint16, nSize *uint32) (err error) { + r1, _, e1 := Syscall6(procTranslateNameW.Addr(), 5, uintptr(unsafe.Pointer(accName)), uintptr(accNameFormat), uintptr(desiredNameFormat), uintptr(unsafe.Pointer(translatedName)), uintptr(unsafe.Pointer(nSize)), 0) + if r1&0xff == 0 { +-- +2.47.0 +