Commit a60b56ad authored by Wèi Cōngruì's avatar Wèi Cōngruì Committed by Ian Lance Taylor

internal/poll: make FD.isFile mean whether it isn't socket on Windows

Before this change, if a directory was closed twice on Windows,
the returning error would be "use of closed network connection".

Some code assumes FD.isFile means whether the fd isn't a network
socket, which is true on Unix. But isFile reports whether
the fd is a normal file rather than directory or console on Windows.

With this change, isFile will have the same meaning on different
platforms. And the change adds a new field kind to replace isConsole
and isDir.

Change-Id: Ib12265f1e12fa3d0239ae925291128a84be59cc2
GitHub-Last-Rev: 3f031756de6ce0b96c1f102ad280950f4adbf6c2
GitHub-Pull-Request: golang/go#30589
Reviewed-on: https://go-review.googlesource.com/c/go/+/165257
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
parent 029a5af6
...@@ -309,7 +309,6 @@ type FD struct { ...@@ -309,7 +309,6 @@ type FD struct {
l sync.Mutex l sync.Mutex
// For console I/O. // For console I/O.
isConsole bool
lastbits []byte // first few bytes of the last incomplete rune in last write lastbits []byte // first few bytes of the last incomplete rune in last write
readuint16 []uint16 // buffer to hold uint16s obtained with ReadConsole readuint16 []uint16 // buffer to hold uint16s obtained with ReadConsole
readbyte []byte // buffer to hold decoding of readuint16 from utf16 to utf8 readbyte []byte // buffer to hold decoding of readuint16 from utf16 to utf8
...@@ -328,13 +327,23 @@ type FD struct { ...@@ -328,13 +327,23 @@ type FD struct {
// message based socket connection. // message based socket connection.
ZeroReadIsEOF bool ZeroReadIsEOF bool
// Whether this is a normal file. // Whether this is a file rather than a network socket.
isFile bool isFile bool
// Whether this is a directory. // The kind of this file.
isDir bool kind fileKind
} }
// fileKind describes the kind of file.
type fileKind byte
const (
kindNet fileKind = iota
kindFile
kindConsole
kindDir
)
// logInitFD is set by tests to enable file descriptor initialization logging. // logInitFD is set by tests to enable file descriptor initialization logging.
var logInitFD func(net string, fd *FD, err error) var logInitFD func(net string, fd *FD, err error)
...@@ -350,18 +359,20 @@ func (fd *FD) Init(net string, pollable bool) (string, error) { ...@@ -350,18 +359,20 @@ func (fd *FD) Init(net string, pollable bool) (string, error) {
switch net { switch net {
case "file": case "file":
fd.isFile = true fd.kind = kindFile
case "console": case "console":
fd.isConsole = true fd.kind = kindConsole
case "dir": case "dir":
fd.isDir = true fd.kind = kindDir
case "tcp", "tcp4", "tcp6": case "tcp", "tcp4", "tcp6",
case "udp", "udp4", "udp6": "udp", "udp4", "udp6",
case "ip", "ip4", "ip6": "ip", "ip4", "ip6",
case "unix", "unixgram", "unixpacket": "unix", "unixgram", "unixpacket":
fd.kind = kindNet
default: default:
return "", errors.New("internal error: unknown network type " + net) return "", errors.New("internal error: unknown network type " + net)
} }
fd.isFile = fd.kind != kindNet
var err error var err error
if pollable { if pollable {
...@@ -430,13 +441,14 @@ func (fd *FD) destroy() error { ...@@ -430,13 +441,14 @@ func (fd *FD) destroy() error {
// so this must be executed before fd.CloseFunc. // so this must be executed before fd.CloseFunc.
fd.pd.close() fd.pd.close()
var err error var err error
if fd.isFile || fd.isConsole { switch fd.kind {
err = syscall.CloseHandle(fd.Sysfd) case kindNet:
} else if fd.isDir {
err = syscall.FindClose(fd.Sysfd)
} else {
// The net package uses the CloseFunc variable for testing. // The net package uses the CloseFunc variable for testing.
err = CloseFunc(fd.Sysfd) err = CloseFunc(fd.Sysfd)
case kindDir:
err = syscall.FindClose(fd.Sysfd)
default:
err = syscall.CloseHandle(fd.Sysfd)
} }
fd.Sysfd = syscall.InvalidHandle fd.Sysfd = syscall.InvalidHandle
runtime_Semrelease(&fd.csema) runtime_Semrelease(&fd.csema)
...@@ -485,12 +497,13 @@ func (fd *FD) Read(buf []byte) (int, error) { ...@@ -485,12 +497,13 @@ func (fd *FD) Read(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.l.Lock() fd.l.Lock()
defer fd.l.Unlock() defer fd.l.Unlock()
if fd.isConsole { switch fd.kind {
case kindConsole:
n, err = fd.readConsole(buf) n, err = fd.readConsole(buf)
} else { default:
n, err = syscall.Read(fd.Sysfd, buf) n, err = syscall.Read(fd.Sysfd, buf)
} }
if err != nil { if err != nil {
...@@ -669,12 +682,13 @@ func (fd *FD) Write(buf []byte) (int, error) { ...@@ -669,12 +682,13 @@ 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.l.Lock() fd.l.Lock()
defer fd.l.Unlock() defer fd.l.Unlock()
if fd.isConsole { switch fd.kind {
case kindConsole:
n, err = fd.writeConsole(b) n, err = fd.writeConsole(b)
} else { default:
n, err = syscall.Write(fd.Sysfd, b) n, err = syscall.Write(fd.Sysfd, b)
} }
if err != nil { if err != nil {
......
...@@ -2279,8 +2279,7 @@ func TestPipeThreads(t *testing.T) { ...@@ -2279,8 +2279,7 @@ func TestPipeThreads(t *testing.T) {
} }
} }
func TestDoubleCloseError(t *testing.T) { func testDoubleCloseError(t *testing.T, path string) {
path := sfdir + "/" + sfname
file, err := Open(path) file, err := Open(path)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
...@@ -2299,6 +2298,11 @@ func TestDoubleCloseError(t *testing.T) { ...@@ -2299,6 +2298,11 @@ func TestDoubleCloseError(t *testing.T) {
} }
} }
func TestDoubleCloseError(t *testing.T) {
testDoubleCloseError(t, filepath.Join(sfdir, sfname))
testDoubleCloseError(t, sfdir)
}
func TestUserHomeDir(t *testing.T) { func TestUserHomeDir(t *testing.T) {
dir, err := UserHomeDir() dir, err := UserHomeDir()
if dir == "" && err == nil { if dir == "" && err == nil {
......
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