Commit 04862afe by Ian Lance Taylor

libgo: update to Go 1.12.2

    
    Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/170706

From-SVN: r270214
parent 8108dfde
392e9b3da473070f24dbe6c12c282a0e06e73b54 a69f7c05f1880bb90544fb0c3577109cb1d7f3ab
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
0380c9ad38843d523d9c9804fe300cb7edd7cd3c ac02fdec7cd16ea8d3de1fc33def9cfabec5170d
The first line of this file holds the git revision number of the The first line of this file holds the git revision number of the
last merge done from the master library sources. last merge done from the master library sources.
...@@ -1184,6 +1184,36 @@ var cgoSyscallExclude = map[string]bool{ ...@@ -1184,6 +1184,36 @@ var cgoSyscallExclude = map[string]bool{
var foldPath = make(map[string]string) var foldPath = make(map[string]string)
// DefaultExecName returns the default executable name
// for a package with the import path importPath.
//
// The default executable name is the last element of the import path.
// In module-aware mode, an additional rule is used. If the last element
// is a vN path element specifying the major version, then the second last
// element of the import path is used instead.
func DefaultExecName(importPath string) string {
_, elem := pathpkg.Split(importPath)
if cfg.ModulesEnabled {
// If this is example.com/mycmd/v2, it's more useful to install it as mycmd than as v2.
// See golang.org/issue/24667.
isVersion := func(v string) bool {
if len(v) < 2 || v[0] != 'v' || v[1] < '1' || '9' < v[1] {
return false
}
for i := 2; i < len(v); i++ {
if c := v[i]; c < '0' || '9' < c {
return false
}
}
return true
}
if isVersion(elem) {
_, elem = pathpkg.Split(pathpkg.Dir(importPath))
}
}
return elem
}
// load populates p using information from bp, err, which should // load populates p using information from bp, err, which should
// be the result of calling build.Context.Import. // be the result of calling build.Context.Import.
func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
...@@ -1226,7 +1256,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { ...@@ -1226,7 +1256,7 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
} }
_, elem := filepath.Split(p.Dir) _, elem := filepath.Split(p.Dir)
if cfg.ModulesEnabled { if cfg.ModulesEnabled {
// NOTE(rsc): Using p.ImportPath instead of p.Dir // NOTE(rsc,dmitshur): Using p.ImportPath instead of p.Dir
// makes sure we install a package in the root of a // makes sure we install a package in the root of a
// cached module directory as that package name // cached module directory as that package name
// not name@v1.2.3. // not name@v1.2.3.
...@@ -1235,26 +1265,9 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) { ...@@ -1235,26 +1265,9 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
// even for non-module-enabled code, // even for non-module-enabled code,
// but I'm not brave enough to change the // but I'm not brave enough to change the
// non-module behavior this late in the // non-module behavior this late in the
// release cycle. Maybe for Go 1.12. // release cycle. Can be done for Go 1.13.
// See golang.org/issue/26869. // See golang.org/issue/26869.
_, elem = pathpkg.Split(p.ImportPath) elem = DefaultExecName(p.ImportPath)
// If this is example.com/mycmd/v2, it's more useful to install it as mycmd than as v2.
// See golang.org/issue/24667.
isVersion := func(v string) bool {
if len(v) < 2 || v[0] != 'v' || v[1] < '1' || '9' < v[1] {
return false
}
for i := 2; i < len(v); i++ {
if c := v[i]; c < '0' || '9' < c {
return false
}
}
return true
}
if isVersion(elem) {
_, elem = pathpkg.Split(pathpkg.Dir(p.ImportPath))
}
} }
full := cfg.BuildContext.GOOS + "_" + cfg.BuildContext.GOARCH + "/" + elem full := cfg.BuildContext.GOOS + "_" + cfg.BuildContext.GOARCH + "/" + elem
if cfg.BuildContext.GOOS != base.ToolGOOS || cfg.BuildContext.GOARCH != base.ToolGOARCH { if cfg.BuildContext.GOOS != base.ToolGOOS || cfg.BuildContext.GOARCH != base.ToolGOARCH {
......
...@@ -268,17 +268,8 @@ func GetTestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Pac ...@@ -268,17 +268,8 @@ func GetTestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Pac
pmain.Imports = pmain.Imports[:w] pmain.Imports = pmain.Imports[:w]
pmain.Internal.RawImports = str.StringList(pmain.Imports) pmain.Internal.RawImports = str.StringList(pmain.Imports)
if ptest != p { // Replace pmain's transitive dependencies with test copies, as necessary.
// We have made modifications to the package p being tested recompileForTest(pmain, p, ptest, pxtest)
// and are rebuilding p (as ptest).
// Arrange to rebuild all packages q such that
// the test depends on q and q depends on p.
// This makes sure that q sees the modifications to p.
// Strictly speaking, the rebuild is only necessary if the
// modifications to p change its export metadata, but
// determining that is a bit tricky, so we rebuild always.
recompileForTest(pmain, p, ptest, pxtest)
}
// Should we apply coverage analysis locally, // Should we apply coverage analysis locally,
// only for this package and only for this test? // only for this package and only for this test?
...@@ -325,6 +316,14 @@ Search: ...@@ -325,6 +316,14 @@ Search:
return stk return stk
} }
// recompileForTest copies and replaces certain packages in pmain's dependency
// graph. This is necessary for two reasons. First, if ptest is different than
// preal, packages that import the package under test should get ptest instead
// of preal. This is particularly important if pxtest depends on functionality
// exposed in test sources in ptest. Second, if there is a main package
// (other than pmain) anywhere, we need to clear p.Internal.BuildInfo in
// the test copy to prevent link conflicts. This may happen if both -coverpkg
// and the command line patterns include multiple main packages.
func recompileForTest(pmain, preal, ptest, pxtest *Package) { func recompileForTest(pmain, preal, ptest, pxtest *Package) {
// The "test copy" of preal is ptest. // The "test copy" of preal is ptest.
// For each package that depends on preal, make a "test copy" // For each package that depends on preal, make a "test copy"
...@@ -367,7 +366,7 @@ func recompileForTest(pmain, preal, ptest, pxtest *Package) { ...@@ -367,7 +366,7 @@ func recompileForTest(pmain, preal, ptest, pxtest *Package) {
// Don't compile build info from a main package. This can happen // Don't compile build info from a main package. This can happen
// if -coverpkg patterns include main packages, since those packages // if -coverpkg patterns include main packages, since those packages
// are imported by pmain. // are imported by pmain. See golang.org/issue/30907.
if p.Internal.BuildInfo != "" && p != pmain { if p.Internal.BuildInfo != "" && p != pmain {
split() split()
} }
......
...@@ -805,7 +805,7 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin ...@@ -805,7 +805,7 @@ func builderTest(b *work.Builder, p *load.Package) (buildAction, runAction, prin
if p.ImportPath == "command-line-arguments" { if p.ImportPath == "command-line-arguments" {
elem = p.Name elem = p.Name
} else { } else {
_, elem = path.Split(p.ImportPath) elem = load.DefaultExecName(p.ImportPath)
} }
testBinary := elem + ".test" testBinary := elem + ".test"
......
...@@ -10,7 +10,6 @@ import ( ...@@ -10,7 +10,6 @@ import (
"go/build" "go/build"
"os" "os"
"os/exec" "os/exec"
"path"
"path/filepath" "path/filepath"
"runtime" "runtime"
"strings" "strings"
...@@ -285,7 +284,7 @@ func runBuild(cmd *base.Command, args []string) { ...@@ -285,7 +284,7 @@ func runBuild(cmd *base.Command, args []string) {
pkgs := load.PackagesForBuild(args) pkgs := load.PackagesForBuild(args)
if len(pkgs) == 1 && pkgs[0].Name == "main" && cfg.BuildO == "" { if len(pkgs) == 1 && pkgs[0].Name == "main" && cfg.BuildO == "" {
_, cfg.BuildO = path.Split(pkgs[0].ImportPath) cfg.BuildO = load.DefaultExecName(pkgs[0].ImportPath)
cfg.BuildO += cfg.ExeSuffix cfg.BuildO += cfg.ExeSuffix
} }
...@@ -518,7 +517,7 @@ func InstallPackages(patterns []string, pkgs []*load.Package) { ...@@ -518,7 +517,7 @@ func InstallPackages(patterns []string, pkgs []*load.Package) {
if len(patterns) == 0 && len(pkgs) == 1 && pkgs[0].Name == "main" { if len(patterns) == 0 && len(pkgs) == 1 && pkgs[0].Name == "main" {
// Compute file 'go build' would have created. // Compute file 'go build' would have created.
// If it exists and is an executable file, remove it. // If it exists and is an executable file, remove it.
_, targ := filepath.Split(pkgs[0].ImportPath) targ := load.DefaultExecName(pkgs[0].ImportPath)
targ += cfg.ExeSuffix targ += cfg.ExeSuffix
if filepath.Join(pkgs[0].Dir, targ) != pkgs[0].Target { // maybe $GOBIN is the current directory if filepath.Join(pkgs[0].Dir, targ) != pkgs[0].Target { // maybe $GOBIN is the current directory
fi, err := os.Stat(targ) fi, err := os.Stat(targ)
......
...@@ -214,6 +214,7 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID { ...@@ -214,6 +214,7 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID {
if p.Internal.CoverMode != "" { if p.Internal.CoverMode != "" {
fmt.Fprintf(h, "cover %q %q\n", p.Internal.CoverMode, b.toolID("cover")) fmt.Fprintf(h, "cover %q %q\n", p.Internal.CoverMode, b.toolID("cover"))
} }
fmt.Fprintf(h, "modinfo %q\n", p.Internal.BuildInfo)
// Configuration specific to compiler toolchain. // Configuration specific to compiler toolchain.
switch cfg.BuildToolchainName { switch cfg.BuildToolchainName {
......
...@@ -13,3 +13,9 @@ import "rsc.io/quote" ...@@ -13,3 +13,9 @@ import "rsc.io/quote"
func main() { func main() {
println(quote.Hello()) println(quote.Hello())
} }
-- fortune_test.go --
package main
import "testing"
func TestFortuneV2(t *testing.T) {}
# This test checks that multiple main packages can be tested
# with -coverpkg=all without duplicate symbol errors.
# Verifies golang.org/issue/30374.
env GO111MODULE=on
[short] skip
go test -coverpkg=all ./...
-- go.mod --
module example.com/cov
-- mainonly/mainonly.go --
package main
func main() {}
-- mainwithtest/mainwithtest.go --
package main
func main() {}
func Foo() {}
-- mainwithtest/mainwithtest_test.go --
package main
import "testing"
func TestFoo(t *testing.T) {
Foo()
}
-- xtest/x.go --
package x
-- xtest/x_test.go --
package x_test
import "testing"
func TestX(t *testing.T) {}
...@@ -660,6 +660,10 @@ func (fd *FD) Write(buf []byte) (int, error) { ...@@ -660,6 +660,10 @@ func (fd *FD) Write(buf []byte) (int, error) {
return 0, err return 0, err
} }
defer fd.writeUnlock() defer fd.writeUnlock()
if fd.isFile || fd.isDir || fd.isConsole {
fd.l.Lock()
defer fd.l.Unlock()
}
ntotal := 0 ntotal := 0
for len(buf) > 0 { for len(buf) > 0 {
...@@ -670,8 +674,6 @@ func (fd *FD) Write(buf []byte) (int, error) { ...@@ -670,8 +674,6 @@ func (fd *FD) Write(buf []byte) (int, error) {
var n int var n int
var err error var err error
if fd.isFile || fd.isDir || fd.isConsole { if fd.isFile || fd.isDir || fd.isConsole {
fd.l.Lock()
defer fd.l.Unlock()
if fd.isConsole { if fd.isConsole {
n, err = fd.writeConsole(b) n, err = fd.writeConsole(b)
} else { } else {
......
...@@ -389,6 +389,11 @@ func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader, flushInterval ...@@ -389,6 +389,11 @@ func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader, flushInterval
latency: flushInterval, latency: flushInterval,
} }
defer mlw.stop() defer mlw.stop()
// set up initial timer so headers get flushed even if body writes are delayed
mlw.flushPending = true
mlw.t = time.AfterFunc(flushInterval, mlw.delayedFlush)
dst = mlw dst = mlw
} }
} }
......
...@@ -9,6 +9,7 @@ package httputil ...@@ -9,6 +9,7 @@ package httputil
import ( import (
"bufio" "bufio"
"bytes" "bytes"
"context"
"errors" "errors"
"fmt" "fmt"
"io" "io"
...@@ -317,6 +318,47 @@ func TestReverseProxyFlushInterval(t *testing.T) { ...@@ -317,6 +318,47 @@ func TestReverseProxyFlushInterval(t *testing.T) {
} }
} }
func TestReverseProxyFlushIntervalHeaders(t *testing.T) {
const expected = "hi"
stopCh := make(chan struct{})
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Add("MyHeader", expected)
w.WriteHeader(200)
w.(http.Flusher).Flush()
<-stopCh
}))
defer backend.Close()
defer close(stopCh)
backendURL, err := url.Parse(backend.URL)
if err != nil {
t.Fatal(err)
}
proxyHandler := NewSingleHostReverseProxy(backendURL)
proxyHandler.FlushInterval = time.Microsecond
frontend := httptest.NewServer(proxyHandler)
defer frontend.Close()
req, _ := http.NewRequest("GET", frontend.URL, nil)
req.Close = true
ctx, cancel := context.WithTimeout(req.Context(), 10*time.Second)
defer cancel()
req = req.WithContext(ctx)
res, err := frontend.Client().Do(req)
if err != nil {
t.Fatalf("Get: %v", err)
}
defer res.Body.Close()
if res.Header.Get("MyHeader") != expected {
t.Errorf("got header %q; expected %q", res.Header.Get("MyHeader"), expected)
}
}
func TestReverseProxyCancelation(t *testing.T) { func TestReverseProxyCancelation(t *testing.T) {
const backendResponse = "I am the backend" const backendResponse = "I am the backend"
......
...@@ -262,8 +262,9 @@ func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IP ...@@ -262,8 +262,9 @@ func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IP
// only the values in context. See Issue 28600. // only the values in context. See Issue 28600.
lookupGroupCtx, lookupGroupCancel := context.WithCancel(withUnexpiredValuesPreserved(ctx)) lookupGroupCtx, lookupGroupCancel := context.WithCancel(withUnexpiredValuesPreserved(ctx))
lookupKey := network + "\000" + host
dnsWaitGroup.Add(1) dnsWaitGroup.Add(1)
ch, called := r.getLookupGroup().DoChan(host, func() (interface{}, error) { ch, called := r.getLookupGroup().DoChan(lookupKey, func() (interface{}, error) {
defer dnsWaitGroup.Done() defer dnsWaitGroup.Done()
return testHookLookupIP(lookupGroupCtx, resolverFunc, network, host) return testHookLookupIP(lookupGroupCtx, resolverFunc, network, host)
}) })
...@@ -280,7 +281,7 @@ func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IP ...@@ -280,7 +281,7 @@ func (r *Resolver) lookupIPAddr(ctx context.Context, network, host string) ([]IP
// let the lookup continue uncanceled, and let later // let the lookup continue uncanceled, and let later
// lookups with the same key share the result. // lookups with the same key share the result.
// See issues 8602, 20703, 22724. // See issues 8602, 20703, 22724.
if r.getLookupGroup().ForgetUnshared(host) { if r.getLookupGroup().ForgetUnshared(lookupKey) {
lookupGroupCancel() lookupGroupCancel()
} else { } else {
go func() { go func() {
......
...@@ -16,6 +16,7 @@ import ( ...@@ -16,6 +16,7 @@ import (
"sort" "sort"
"strings" "strings"
"sync" "sync"
"sync/atomic"
"testing" "testing"
"time" "time"
) )
...@@ -253,14 +254,11 @@ func TestLookupGmailTXT(t *testing.T) { ...@@ -253,14 +254,11 @@ func TestLookupGmailTXT(t *testing.T) {
} }
} }
var lookupGooglePublicDNSAddrTests = []struct { var lookupGooglePublicDNSAddrTests = []string{
addr, name string "8.8.8.8",
}{ "8.8.4.4",
{"8.8.8.8", ".google.com."}, "2001:4860:4860::8888",
{"8.8.4.4", ".google.com."}, "2001:4860:4860::8844",
{"2001:4860:4860::8888", ".google.com."},
{"2001:4860:4860::8844", ".google.com."},
} }
func TestLookupGooglePublicDNSAddr(t *testing.T) { func TestLookupGooglePublicDNSAddr(t *testing.T) {
...@@ -272,8 +270,8 @@ func TestLookupGooglePublicDNSAddr(t *testing.T) { ...@@ -272,8 +270,8 @@ func TestLookupGooglePublicDNSAddr(t *testing.T) {
defer dnsWaitGroup.Wait() defer dnsWaitGroup.Wait()
for _, tt := range lookupGooglePublicDNSAddrTests { for _, ip := range lookupGooglePublicDNSAddrTests {
names, err := LookupAddr(tt.addr) names, err := LookupAddr(ip)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
...@@ -281,8 +279,8 @@ func TestLookupGooglePublicDNSAddr(t *testing.T) { ...@@ -281,8 +279,8 @@ func TestLookupGooglePublicDNSAddr(t *testing.T) {
t.Error("got no record") t.Error("got no record")
} }
for _, name := range names { for _, name := range names {
if !strings.HasSuffix(name, tt.name) { if !strings.HasSuffix(name, ".google.com.") && !strings.HasSuffix(name, ".google.") {
t.Errorf("got %s; want a record containing %s", name, tt.name) t.Errorf("got %q; want a record ending in .google.com. or .google.", name)
} }
} }
} }
...@@ -658,8 +656,8 @@ func testDots(t *testing.T, mode string) { ...@@ -658,8 +656,8 @@ func testDots(t *testing.T, mode string) {
t.Errorf("LookupAddr(8.8.8.8): %v (mode=%v)", err, mode) t.Errorf("LookupAddr(8.8.8.8): %v (mode=%v)", err, mode)
} else { } else {
for _, name := range names { for _, name := range names {
if !strings.HasSuffix(name, ".google.com.") { if !strings.HasSuffix(name, ".google.com.") && !strings.HasSuffix(name, ".google.") {
t.Errorf("LookupAddr(8.8.8.8) = %v, want names ending in .google.com. with trailing dot (mode=%v)", names, mode) t.Errorf("LookupAddr(8.8.8.8) = %v, want names ending in .google.com or .google with trailing dot (mode=%v)", names, mode)
break break
} }
} }
...@@ -1096,6 +1094,69 @@ func TestLookupIPAddrPreservesContextValues(t *testing.T) { ...@@ -1096,6 +1094,69 @@ func TestLookupIPAddrPreservesContextValues(t *testing.T) {
} }
} }
// Issue 30521: The lookup group should call the resolver for each network.
func TestLookupIPAddrConcurrentCallsForNetworks(t *testing.T) {
origTestHookLookupIP := testHookLookupIP
defer func() { testHookLookupIP = origTestHookLookupIP }()
queries := [][]string{
{"udp", "golang.org"},
{"udp4", "golang.org"},
{"udp6", "golang.org"},
{"udp", "golang.org"},
{"udp", "golang.org"},
}
results := map[[2]string][]IPAddr{
{"udp", "golang.org"}: {
{IP: IPv4(127, 0, 0, 1)},
{IP: IPv6loopback},
},
{"udp4", "golang.org"}: {
{IP: IPv4(127, 0, 0, 1)},
},
{"udp6", "golang.org"}: {
{IP: IPv6loopback},
},
}
calls := int32(0)
waitCh := make(chan struct{})
testHookLookupIP = func(ctx context.Context, fn func(context.Context, string, string) ([]IPAddr, error), network, host string) ([]IPAddr, error) {
// We'll block until this is called one time for each different
// expected result. This will ensure that the lookup group would wait
// for the existing call if it was to be reused.
if atomic.AddInt32(&calls, 1) == int32(len(results)) {
close(waitCh)
}
select {
case <-waitCh:
case <-ctx.Done():
return nil, ctx.Err()
}
return results[[2]string{network, host}], nil
}
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
wg := sync.WaitGroup{}
for _, q := range queries {
network := q[0]
host := q[1]
wg.Add(1)
go func() {
defer wg.Done()
gotIPs, err := DefaultResolver.lookupIPAddr(ctx, network, host)
if err != nil {
t.Errorf("lookupIPAddr(%v, %v): unexpected error: %v", network, host, err)
}
wantIPs := results[[2]string{network, host}]
if !reflect.DeepEqual(gotIPs, wantIPs) {
t.Errorf("lookupIPAddr(%v, %v): mismatched IPAddr results\n\tGot: %v\n\tWant: %v", network, host, gotIPs, wantIPs)
}
}()
}
wg.Wait()
}
func TestWithUnexpiredValuesPreserved(t *testing.T) { func TestWithUnexpiredValuesPreserved(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
......
...@@ -62,6 +62,7 @@ func MkdirAll(path string, perm FileMode) error { ...@@ -62,6 +62,7 @@ func MkdirAll(path string, perm FileMode) error {
// It removes everything it can but returns the first error // It removes everything it can but returns the first error
// it encounters. If the path does not exist, RemoveAll // it encounters. If the path does not exist, RemoveAll
// returns nil (no error). // returns nil (no error).
// If there is an error, it will be of type *PathError.
func RemoveAll(path string) error { func RemoveAll(path string) error {
return removeAll(path) return removeAll(path)
} }
......
...@@ -51,7 +51,7 @@ func splitPath(path string) (string, string) { ...@@ -51,7 +51,7 @@ func splitPath(path string) (string, string) {
// Remove leading directory path // Remove leading directory path
for i--; i >= 0; i-- { for i--; i >= 0; i-- {
if path[i] == '/' { if path[i] == '/' {
dirname = path[:i+1] dirname = path[:i]
basename = path[i+1:] basename = path[i+1:]
break break
} }
......
...@@ -46,13 +46,20 @@ func removeAll(path string) error { ...@@ -46,13 +46,20 @@ func removeAll(path string) error {
} }
defer parent.Close() defer parent.Close()
return removeAllFrom(parent, base) if err := removeAllFrom(parent, base); err != nil {
if pathErr, ok := err.(*PathError); ok {
pathErr.Path = parentDir + string(PathSeparator) + pathErr.Path
err = pathErr
}
return err
}
return nil
} }
func removeAllFrom(parent *File, path string) error { func removeAllFrom(parent *File, base string) error {
parentFd := int(parent.Fd()) parentFd := int(parent.Fd())
// Simple case: if Unlink (aka remove) works, we're done. // Simple case: if Unlink (aka remove) works, we're done.
err := unix.Unlinkat(parentFd, path, 0) err := unix.Unlinkat(parentFd, base, 0)
if err == nil || IsNotExist(err) { if err == nil || IsNotExist(err) {
return nil return nil
} }
...@@ -64,21 +71,21 @@ func removeAllFrom(parent *File, path string) error { ...@@ -64,21 +71,21 @@ func removeAllFrom(parent *File, path string) error {
// whose contents need to be removed. // whose contents need to be removed.
// Otherwise just return the error. // Otherwise just return the error.
if err != syscall.EISDIR && err != syscall.EPERM && err != syscall.EACCES { if err != syscall.EISDIR && err != syscall.EPERM && err != syscall.EACCES {
return err return &PathError{"unlinkat", base, err}
} }
// Is this a directory we need to recurse into? // Is this a directory we need to recurse into?
var statInfo syscall.Stat_t var statInfo syscall.Stat_t
statErr := unix.Fstatat(parentFd, path, &statInfo, unix.AT_SYMLINK_NOFOLLOW) statErr := unix.Fstatat(parentFd, base, &statInfo, unix.AT_SYMLINK_NOFOLLOW)
if statErr != nil { if statErr != nil {
if IsNotExist(statErr) { if IsNotExist(statErr) {
return nil return nil
} }
return statErr return &PathError{"fstatat", base, statErr}
} }
if statInfo.Mode&syscall.S_IFMT != syscall.S_IFDIR { if statInfo.Mode&syscall.S_IFMT != syscall.S_IFDIR {
// Not a directory; return the error from the Remove. // Not a directory; return the error from the unix.Unlinkat.
return err return &PathError{"unlinkat", base, err}
} }
// Remove the directory's entries. // Remove the directory's entries.
...@@ -87,12 +94,12 @@ func removeAllFrom(parent *File, path string) error { ...@@ -87,12 +94,12 @@ func removeAllFrom(parent *File, path string) error {
const request = 1024 const request = 1024
// Open the directory to recurse into // Open the directory to recurse into
file, err := openFdAt(parentFd, path) file, err := openFdAt(parentFd, base)
if err != nil { if err != nil {
if IsNotExist(err) { if IsNotExist(err) {
return nil return nil
} }
recurseErr = err recurseErr = &PathError{"openfdat", base, err}
break break
} }
...@@ -103,12 +110,15 @@ func removeAllFrom(parent *File, path string) error { ...@@ -103,12 +110,15 @@ func removeAllFrom(parent *File, path string) error {
if IsNotExist(readErr) { if IsNotExist(readErr) {
return nil return nil
} }
return readErr return &PathError{"readdirnames", base, readErr}
} }
for _, name := range names { for _, name := range names {
err := removeAllFrom(file, name) err := removeAllFrom(file, name)
if err != nil { if err != nil {
if pathErr, ok := err.(*PathError); ok {
pathErr.Path = base + string(PathSeparator) + pathErr.Path
}
recurseErr = err recurseErr = err
} }
} }
...@@ -127,7 +137,7 @@ func removeAllFrom(parent *File, path string) error { ...@@ -127,7 +137,7 @@ func removeAllFrom(parent *File, path string) error {
} }
// Remove the directory itself. // Remove the directory itself.
unlinkError := unix.Unlinkat(parentFd, path, unix.AT_REMOVEDIR) unlinkError := unix.Unlinkat(parentFd, base, unix.AT_REMOVEDIR)
if unlinkError == nil || IsNotExist(unlinkError) { if unlinkError == nil || IsNotExist(unlinkError) {
return nil return nil
} }
...@@ -135,7 +145,7 @@ func removeAllFrom(parent *File, path string) error { ...@@ -135,7 +145,7 @@ func removeAllFrom(parent *File, path string) error {
if recurseErr != nil { if recurseErr != nil {
return recurseErr return recurseErr
} }
return unlinkError return &PathError{"unlinkat", base, unlinkError}
} }
// openFdAt opens path relative to the directory in fd. // openFdAt opens path relative to the directory in fd.
...@@ -157,7 +167,7 @@ func openFdAt(dirfd int, name string) (*File, error) { ...@@ -157,7 +167,7 @@ func openFdAt(dirfd int, name string) (*File, error) {
continue continue
} }
return nil, &PathError{"openat", name, e} return nil, e
} }
if !supportsCloseOnExec { if !supportsCloseOnExec {
......
...@@ -294,7 +294,7 @@ func TestRemoveReadOnlyDir(t *testing.T) { ...@@ -294,7 +294,7 @@ func TestRemoveReadOnlyDir(t *testing.T) {
} }
// Issue #29983. // Issue #29983.
func TestRemoveAllButReadOnly(t *testing.T) { func TestRemoveAllButReadOnlyAndPathError(t *testing.T) {
switch runtime.GOOS { switch runtime.GOOS {
case "nacl", "js", "windows": case "nacl", "js", "windows":
t.Skipf("skipping test on %s", runtime.GOOS) t.Skipf("skipping test on %s", runtime.GOOS)
...@@ -355,10 +355,21 @@ func TestRemoveAllButReadOnly(t *testing.T) { ...@@ -355,10 +355,21 @@ func TestRemoveAllButReadOnly(t *testing.T) {
defer Chmod(d, 0777) defer Chmod(d, 0777)
} }
if err := RemoveAll(tempDir); err == nil { err = RemoveAll(tempDir)
if err == nil {
t.Fatal("RemoveAll succeeded unexpectedly") t.Fatal("RemoveAll succeeded unexpectedly")
} }
// The error should be of type *PathError.
// see issue 30491 for details.
if pathErr, ok := err.(*PathError); ok {
if g, w := pathErr.Path, filepath.Join(tempDir, "b", "y"); g != w {
t.Errorf("got %q, expected pathErr.path %q", g, w)
}
} else {
t.Errorf("got %T, expected *os.PathError", err)
}
for _, dir := range dirs { for _, dir := range dirs {
_, err := Stat(filepath.Join(tempDir, dir)) _, err := Stat(filepath.Join(tempDir, dir))
if inReadonly(dir) { if inReadonly(dir) {
......
...@@ -139,6 +139,7 @@ func TestLldbPython(t *testing.T) { ...@@ -139,6 +139,7 @@ func TestLldbPython(t *testing.T) {
if final := os.Getenv("GOROOT_FINAL"); final != "" && runtime.GOROOT() != final { if final := os.Getenv("GOROOT_FINAL"); final != "" && runtime.GOROOT() != final {
t.Skip("gdb test can fail with GOROOT_FINAL pending") t.Skip("gdb test can fail with GOROOT_FINAL pending")
} }
testenv.SkipFlaky(t, 31188)
checkLldbPython(t) checkLldbPython(t)
......
...@@ -290,6 +290,7 @@ type Tokenprimarygroup struct { ...@@ -290,6 +290,7 @@ type Tokenprimarygroup struct {
//sys OpenProcessToken(h Handle, access uint32, token *Token) (err error) = advapi32.OpenProcessToken //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 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 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. // An access token contains the security information for a logon session.
// The system creates an access token when a user logs on, and every // The system creates an access token when a user logs on, and every
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment