From 9b1518aeda297f87d6d06218ddb744c71fefb80d Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 30 Sep 2020 15:48:14 -0400 Subject: io: make clear that EOF should not be wrapped For #40827. Change-Id: Ifd108421abd8d0988dd7b985e4f9e2bd5356964a Reviewed-on: https://go-review.googlesource.com/c/go/+/258524 Trust: Russ Cox Reviewed-by: Rob Pike --- src/io/io.go | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/io/io.go') diff --git a/src/io/io.go b/src/io/io.go index 3dea70b947..adc0c0d550 100644 --- a/src/io/io.go +++ b/src/io/io.go @@ -31,6 +31,8 @@ var ErrShortWrite = errors.New("short write") var ErrShortBuffer = errors.New("short buffer") // EOF is the error returned by Read when no more input is available. +// (Read must return EOF itself, not an error wrapping EOF, +// because callers will test for EOF using ==.) // Functions should return EOF only to signal a graceful end of input. // If the EOF occurs unexpectedly in a structured data stream, // the appropriate error is either ErrUnexpectedEOF or some other error -- cgit v1.2.1 From ad53103aef09c002c41ea34292cfea359857ae5b Mon Sep 17 00:00:00 2001 From: Tao Qingyun Date: Tue, 13 Oct 2020 05:56:48 +0000 Subject: io: add ErrBadWriteCount Fixes #39978 Change-Id: Ib41459861ba9f7cf0bf1fc95b1479c358c4bdbd8 GitHub-Last-Rev: 19cbb1461ca04a8eb64f0c4f354d8fb81a70d4f3 GitHub-Pull-Request: golang/go#39989 Reviewed-on: https://go-review.googlesource.com/c/go/+/240740 Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Trust: Ian Lance Taylor Reviewed-by: Robert Griesemer --- src/io/io.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src/io/io.go') diff --git a/src/io/io.go b/src/io/io.go index adc0c0d550..87ebe8c147 100644 --- a/src/io/io.go +++ b/src/io/io.go @@ -30,6 +30,9 @@ var ErrShortWrite = errors.New("short write") // ErrShortBuffer means that a read required a longer buffer than was provided. var ErrShortBuffer = errors.New("short buffer") +// ErrBadWriteCount means that a write returned an impossible count. +var ErrBadWriteCount = errors.New("Write returned impossible count") + // EOF is the error returned by Read when no more input is available. // (Read must return EOF itself, not an error wrapping EOF, // because callers will test for EOF using ==.) @@ -411,9 +414,13 @@ func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) { nr, er := src.Read(buf) if nr > 0 { nw, ew := dst.Write(buf[0:nr]) - if nw > 0 { - written += int64(nw) + if nw < 0 || nr < nw { + nw = 0 + if ew == nil { + ew = ErrBadWriteCount + } } + written += int64(nw) if ew != nil { err = ew break -- cgit v1.2.1 From b95f0b123160a67c9e0b1d8c03993fe1e8208800 Mon Sep 17 00:00:00 2001 From: Mohamed Attahri Date: Tue, 13 Oct 2020 02:26:19 +0000 Subject: io: add a new ReadSeekCloser interface Research showed that this interface is defined frequently enough in real-world usage to justify its addition to the standard library. Fixes #40962 Change-Id: I522fe8f9b8753c3fa42ccc1def49611cf88cd340 GitHub-Last-Rev: 6a45be66b42e482a06d9809d9da20c195380988b GitHub-Pull-Request: golang/go#41939 Reviewed-on: https://go-review.googlesource.com/c/go/+/261577 Reviewed-by: Ian Lance Taylor Reviewed-by: Dmitri Shuralyov Trust: Dmitri Shuralyov --- src/io/io.go | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/io/io.go') diff --git a/src/io/io.go b/src/io/io.go index 87ebe8c147..4bd1ae913a 100644 --- a/src/io/io.go +++ b/src/io/io.go @@ -152,6 +152,14 @@ type ReadSeeker interface { Seeker } +// ReadSeekCloser is the interface that groups the basic Read, Seek and Close +// methods. +type ReadSeekCloser interface { + Reader + Seeker + Closer +} + // WriteSeeker is the interface that groups the basic Write and Seek methods. type WriteSeeker interface { Writer -- cgit v1.2.1 From 03f181a90ef4de680a666ca86c7988915e892e8c Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 15 Oct 2020 23:32:51 -0400 Subject: io: unexport ErrBadWriteCount It was added in CL 240740 to fix #39978 but without any discussion of the exported API. The error can still be returned to fix the issue, without adding new public API to package io. Also fix the error message to refer to lower-case write like the other errors in the package. Change-Id: I134de5eaf3ac903d73913c5cadcde904c5255d79 Reviewed-on: https://go-review.googlesource.com/c/go/+/262877 Trust: Russ Cox Run-TryBot: Russ Cox Reviewed-by: Emmanuel Odeke TryBot-Result: Go Bot --- src/io/io.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/io/io.go') diff --git a/src/io/io.go b/src/io/io.go index 4bd1ae913a..a34c39a32a 100644 --- a/src/io/io.go +++ b/src/io/io.go @@ -27,12 +27,12 @@ const ( // but failed to return an explicit error. var ErrShortWrite = errors.New("short write") +// errInvalidWrite means that a write returned an impossible count. +var errInvalidWrite = errors.New("invalid write result") + // ErrShortBuffer means that a read required a longer buffer than was provided. var ErrShortBuffer = errors.New("short buffer") -// ErrBadWriteCount means that a write returned an impossible count. -var ErrBadWriteCount = errors.New("Write returned impossible count") - // EOF is the error returned by Read when no more input is available. // (Read must return EOF itself, not an error wrapping EOF, // because callers will test for EOF using ==.) @@ -425,7 +425,7 @@ func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) { if nw < 0 || nr < nw { nw = 0 if ew == nil { - ew = ErrBadWriteCount + ew = errInvalidWrite } } written += int64(nw) -- cgit v1.2.1 From cb0a0f52e67f128c6ad69027c9a8c7a5caf58446 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 16 Oct 2020 00:41:03 -0400 Subject: io: adopt Discard, NopCloser, ReadAll from io/ioutil As proposed and approved in #40025, Discard, NopCloser, and ReadAll do not really fit into io/ioutil, which exists mainly to hold things that would cause an import cycle if implemented in io itself, which is to say things that import "os". These three do not import "os" - they are generic io helpers like many of the things in io itself, so it makes sense for them to be there. Fixes #40025. Change-Id: I77f47e9b2a72839edf7446997936631980047b67 Reviewed-on: https://go-review.googlesource.com/c/go/+/263141 Trust: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Go Bot Reviewed-by: Rob Pike --- src/io/io.go | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 4 deletions(-) (limited to 'src/io/io.go') diff --git a/src/io/io.go b/src/io/io.go index a34c39a32a..269ebf6ed0 100644 --- a/src/io/io.go +++ b/src/io/io.go @@ -14,6 +14,7 @@ package io import ( "errors" + "sync" ) // Seek whence values. @@ -46,9 +47,9 @@ var EOF = errors.New("EOF") // middle of reading a fixed-size block or data structure. var ErrUnexpectedEOF = errors.New("unexpected EOF") -// ErrNoProgress is returned by some clients of an io.Reader when +// ErrNoProgress is returned by some clients of an Reader when // many calls to Read have failed to return any data or error, -// usually the sign of a broken io.Reader implementation. +// usually the sign of a broken Reader implementation. var ErrNoProgress = errors.New("multiple Read calls return no data or error") // Reader is the interface that wraps the basic Read method. @@ -177,7 +178,7 @@ type ReadWriteSeeker interface { // // ReadFrom reads data from r until EOF or error. // The return value n is the number of bytes read. -// Any error except io.EOF encountered during the read is also returned. +// Any error except EOF encountered during the read is also returned. // // The Copy function uses ReaderFrom if available. type ReaderFrom interface { @@ -390,7 +391,7 @@ func Copy(dst Writer, src Reader) (written int64, err error) { // buf will not be used to perform the copy. func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) { if buf != nil && len(buf) == 0 { - panic("empty buffer in io.CopyBuffer") + panic("empty buffer in CopyBuffer") } return copyBuffer(dst, src, buf) } @@ -564,3 +565,78 @@ func (t *teeReader) Read(p []byte) (n int, err error) { } return } + +// Discard is an Writer on which all Write calls succeed +// without doing anything. +var Discard Writer = discard{} + +type discard struct{} + +// discard implements ReaderFrom as an optimization so Copy to +// ioutil.Discard can avoid doing unnecessary work. +var _ ReaderFrom = discard{} + +func (discard) Write(p []byte) (int, error) { + return len(p), nil +} + +func (discard) WriteString(s string) (int, error) { + return len(s), nil +} + +var blackHolePool = sync.Pool{ + New: func() interface{} { + b := make([]byte, 8192) + return &b + }, +} + +func (discard) ReadFrom(r Reader) (n int64, err error) { + bufp := blackHolePool.Get().(*[]byte) + readSize := 0 + for { + readSize, err = r.Read(*bufp) + n += int64(readSize) + if err != nil { + blackHolePool.Put(bufp) + if err == EOF { + return n, nil + } + return + } + } +} + +// NopCloser returns a ReadCloser with a no-op Close method wrapping +// the provided Reader r. +func NopCloser(r Reader) ReadCloser { + return nopCloser{r} +} + +type nopCloser struct { + Reader +} + +func (nopCloser) Close() error { return nil } + +// ReadAll reads from r until an error or EOF and returns the data it read. +// A successful call returns err == nil, not err == EOF. Because ReadAll is +// defined to read from src until EOF, it does not treat an EOF from Read +// as an error to be reported. +func ReadAll(r Reader) ([]byte, error) { + b := make([]byte, 0, 512) + for { + if len(b) == cap(b) { + // Add more capacity (let append pick how much). + b = append(b, 0)[:len(b)] + } + n, err := r.Read(b[len(b):cap(b)]) + b = b[:len(b)+n] + if err != nil { + if err == EOF { + err = nil + } + return b, err + } + } +} -- cgit v1.2.1 From 1b09d430678d4a6f73b2443463d11f75851aba8a Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Fri, 16 Oct 2020 00:49:02 -0400 Subject: all: update references to symbols moved from io/ioutil to io The old ioutil references are still valid, but update our code to reflect best practices and get used to the new locations. Code compiled with the bootstrap toolchain (cmd/asm, cmd/dist, cmd/compile, debug/elf) must remain Go 1.4-compatible and is excluded. Also excluded vendored code. For #41190. Change-Id: I6d86f2bf7bc37a9d904b6cee3fe0c7af6d94d5b1 Reviewed-on: https://go-review.googlesource.com/c/go/+/263142 Trust: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Go Bot Reviewed-by: Emmanuel Odeke --- src/io/io.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/io/io.go') diff --git a/src/io/io.go b/src/io/io.go index 269ebf6ed0..ffd3cedc25 100644 --- a/src/io/io.go +++ b/src/io/io.go @@ -573,7 +573,7 @@ var Discard Writer = discard{} type discard struct{} // discard implements ReaderFrom as an optimization so Copy to -// ioutil.Discard can avoid doing unnecessary work. +// io.Discard can avoid doing unnecessary work. var _ ReaderFrom = discard{} func (discard) Write(p []byte) (int, error) { -- cgit v1.2.1