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') 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.3 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 +++++++++-- src/io/io_test.go | 28 ++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) (limited to 'src/io') 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 diff --git a/src/io/io_test.go b/src/io/io_test.go index 170513dcc0..a8399bcac6 100644 --- a/src/io/io_test.go +++ b/src/io/io_test.go @@ -429,3 +429,31 @@ func TestSectionReader_Size(t *testing.T) { } } } + +// largeWriter returns an invalid count that is larger than the number +// of bytes provided (issue 39978). +type largeWriter struct { + err error +} + +func (w largeWriter) Write(p []byte) (int, error) { + return len(p) + 1, w.err +} + +func TestCopyLargeWriter(t *testing.T) { + want := ErrBadWriteCount + rb := new(Buffer) + wb := largeWriter{} + rb.WriteString("hello, world.") + if _, err := Copy(wb, rb); err != want { + t.Errorf("Copy error: got %v, want %v", err, want) + } + + want = errors.New("largeWriterError") + rb = new(Buffer) + wb = largeWriter{err: want} + rb.WriteString("hello, world.") + if _, err := Copy(wb, rb); err != want { + t.Errorf("Copy error: got %v, want %v", err, want) + } +} -- cgit v1.3 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') 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.3 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/export_test.go | 8 ++++++++ src/io/io.go | 8 ++++---- src/io/io_test.go | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 src/io/export_test.go (limited to 'src/io') diff --git a/src/io/export_test.go b/src/io/export_test.go new file mode 100644 index 0000000000..fa3e8e76f6 --- /dev/null +++ b/src/io/export_test.go @@ -0,0 +1,8 @@ +// Copyright 2020 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 io + +// exported for test +var ErrInvalidWrite = errInvalidWrite 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) diff --git a/src/io/io_test.go b/src/io/io_test.go index a8399bcac6..5b355e8c55 100644 --- a/src/io/io_test.go +++ b/src/io/io_test.go @@ -441,7 +441,7 @@ func (w largeWriter) Write(p []byte) (int, error) { } func TestCopyLargeWriter(t *testing.T) { - want := ErrBadWriteCount + want := ErrInvalidWrite rb := new(Buffer) wb := largeWriter{} rb.WriteString("hello, world.") -- cgit v1.3 From d4da735091986868015369e01c63794af9cc9b84 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 6 Jul 2020 09:49:20 -0400 Subject: io/fs: move FileInfo, FileMode, PathError, ErrInvalid, ... from os to io/fs First step of creating the new io/fs package. For #41190. Change-Id: I1339b1abdd533b0f1deab283628088b2f706fb5b Reviewed-on: https://go-review.googlesource.com/c/go/+/243906 Trust: Russ Cox Run-TryBot: Russ Cox Run-TryBot: Emmanuel Odeke TryBot-Result: Go Bot Reviewed-by: Rob Pike Reviewed-by: Emmanuel Odeke --- api/except.txt | 228 ++++++++++++++++++++++++++++++--------------------- api/next.txt | 88 +++++++++++++++++++- src/cmd/api/goapi.go | 20 ++++- src/io/fs/fs.go | 140 +++++++++++++++++++++++++++++++ src/os/error.go | 32 ++------ src/os/types.go | 91 ++++---------------- 6 files changed, 406 insertions(+), 193 deletions(-) create mode 100644 src/io/fs/fs.go (limited to 'src/io') diff --git a/api/except.txt b/api/except.txt index 962bb14271..6f6f839ba6 100644 --- a/api/except.txt +++ b/api/except.txt @@ -2,12 +2,56 @@ pkg encoding/json, method (*RawMessage) MarshalJSON() ([]uint8, error) pkg math/big, const MaxBase = 36 pkg math/big, type Word uintptr pkg net, func ListenUnixgram(string, *UnixAddr) (*UDPConn, error) -pkg os, const ModeType = 2399141888 -pkg os, const ModeType = 2399666176 -pkg os (linux-arm), const O_SYNC = 4096 -pkg os (linux-arm-cgo), const O_SYNC = 4096 pkg os (linux-arm), const O_SYNC = 1052672 +pkg os (linux-arm), const O_SYNC = 4096 pkg os (linux-arm-cgo), const O_SYNC = 1052672 +pkg os (linux-arm-cgo), const O_SYNC = 4096 +pkg os, const ModeAppend FileMode +pkg os, const ModeCharDevice FileMode +pkg os, const ModeDevice FileMode +pkg os, const ModeDir FileMode +pkg os, const ModeExclusive FileMode +pkg os, const ModeIrregular FileMode +pkg os, const ModeNamedPipe FileMode +pkg os, const ModePerm FileMode +pkg os, const ModeSetgid FileMode +pkg os, const ModeSetuid FileMode +pkg os, const ModeSocket FileMode +pkg os, const ModeSticky FileMode +pkg os, const ModeSymlink FileMode +pkg os, const ModeTemporary FileMode +pkg os, const ModeType = 2399141888 +pkg os, const ModeType = 2399666176 +pkg os, const ModeType FileMode +pkg os, func Chmod(string, FileMode) error +pkg os, func Lstat(string) (FileInfo, error) +pkg os, func Mkdir(string, FileMode) error +pkg os, func MkdirAll(string, FileMode) error +pkg os, func OpenFile(string, int, FileMode) (*File, error) +pkg os, func SameFile(FileInfo, FileInfo) bool +pkg os, func Stat(string) (FileInfo, error) +pkg os, method (*File) Chmod(FileMode) error +pkg os, method (*File) Readdir(int) ([]FileInfo, error) +pkg os, method (*File) Stat() (FileInfo, error) +pkg os, method (*PathError) Error() string +pkg os, method (*PathError) Timeout() bool +pkg os, method (*PathError) Unwrap() error +pkg os, method (FileMode) IsDir() bool +pkg os, method (FileMode) IsRegular() bool +pkg os, method (FileMode) Perm() FileMode +pkg os, method (FileMode) String() string +pkg os, type FileInfo interface { IsDir, ModTime, Mode, Name, Size, Sys } +pkg os, type FileInfo interface, IsDir() bool +pkg os, type FileInfo interface, ModTime() time.Time +pkg os, type FileInfo interface, Mode() FileMode +pkg os, type FileInfo interface, Name() string +pkg os, type FileInfo interface, Size() int64 +pkg os, type FileInfo interface, Sys() interface{} +pkg os, type FileMode uint32 +pkg os, type PathError struct +pkg os, type PathError struct, Err error +pkg os, type PathError struct, Op string +pkg os, type PathError struct, Path string pkg syscall (darwin-amd64), const ImplementsGetwd = false pkg syscall (darwin-amd64), func Fchflags(string, int) error pkg syscall (darwin-amd64-cgo), const ImplementsGetwd = false @@ -18,22 +62,72 @@ pkg syscall (freebsd-386), const ELAST = 94 pkg syscall (freebsd-386), const ImplementsGetwd = false pkg syscall (freebsd-386), const O_CLOEXEC = 0 pkg syscall (freebsd-386), func Fchflags(string, int) error +pkg syscall (freebsd-386), func Mknod(string, uint32, int) error +pkg syscall (freebsd-386), type Dirent struct, Fileno uint32 +pkg syscall (freebsd-386), type Dirent struct, Namlen uint8 +pkg syscall (freebsd-386), type Stat_t struct, Blksize uint32 +pkg syscall (freebsd-386), type Stat_t struct, Dev uint32 +pkg syscall (freebsd-386), type Stat_t struct, Gen uint32 +pkg syscall (freebsd-386), type Stat_t struct, Ino uint32 +pkg syscall (freebsd-386), type Stat_t struct, Lspare int32 +pkg syscall (freebsd-386), type Stat_t struct, Nlink uint16 +pkg syscall (freebsd-386), type Stat_t struct, Pad_cgo_0 [8]uint8 +pkg syscall (freebsd-386), type Stat_t struct, Rdev uint32 +pkg syscall (freebsd-386), type Statfs_t struct, Mntfromname [88]int8 +pkg syscall (freebsd-386), type Statfs_t struct, Mntonname [88]int8 pkg syscall (freebsd-386-cgo), const AF_MAX = 38 pkg syscall (freebsd-386-cgo), const DLT_MATCHING_MAX = 242 pkg syscall (freebsd-386-cgo), const ELAST = 94 pkg syscall (freebsd-386-cgo), const ImplementsGetwd = false pkg syscall (freebsd-386-cgo), const O_CLOEXEC = 0 +pkg syscall (freebsd-386-cgo), func Mknod(string, uint32, int) error +pkg syscall (freebsd-386-cgo), type Dirent struct, Fileno uint32 +pkg syscall (freebsd-386-cgo), type Dirent struct, Namlen uint8 +pkg syscall (freebsd-386-cgo), type Stat_t struct, Blksize uint32 +pkg syscall (freebsd-386-cgo), type Stat_t struct, Dev uint32 +pkg syscall (freebsd-386-cgo), type Stat_t struct, Gen uint32 +pkg syscall (freebsd-386-cgo), type Stat_t struct, Ino uint32 +pkg syscall (freebsd-386-cgo), type Stat_t struct, Lspare int32 +pkg syscall (freebsd-386-cgo), type Stat_t struct, Nlink uint16 +pkg syscall (freebsd-386-cgo), type Stat_t struct, Pad_cgo_0 [8]uint8 +pkg syscall (freebsd-386-cgo), type Stat_t struct, Rdev uint32 +pkg syscall (freebsd-386-cgo), type Statfs_t struct, Mntfromname [88]int8 +pkg syscall (freebsd-386-cgo), type Statfs_t struct, Mntonname [88]int8 pkg syscall (freebsd-amd64), const AF_MAX = 38 pkg syscall (freebsd-amd64), const DLT_MATCHING_MAX = 242 pkg syscall (freebsd-amd64), const ELAST = 94 pkg syscall (freebsd-amd64), const ImplementsGetwd = false pkg syscall (freebsd-amd64), const O_CLOEXEC = 0 pkg syscall (freebsd-amd64), func Fchflags(string, int) error +pkg syscall (freebsd-amd64), func Mknod(string, uint32, int) error +pkg syscall (freebsd-amd64), type Dirent struct, Fileno uint32 +pkg syscall (freebsd-amd64), type Dirent struct, Namlen uint8 +pkg syscall (freebsd-amd64), type Stat_t struct, Blksize uint32 +pkg syscall (freebsd-amd64), type Stat_t struct, Dev uint32 +pkg syscall (freebsd-amd64), type Stat_t struct, Gen uint32 +pkg syscall (freebsd-amd64), type Stat_t struct, Ino uint32 +pkg syscall (freebsd-amd64), type Stat_t struct, Lspare int32 +pkg syscall (freebsd-amd64), type Stat_t struct, Nlink uint16 +pkg syscall (freebsd-amd64), type Stat_t struct, Rdev uint32 +pkg syscall (freebsd-amd64), type Statfs_t struct, Mntfromname [88]int8 +pkg syscall (freebsd-amd64), type Statfs_t struct, Mntonname [88]int8 pkg syscall (freebsd-amd64-cgo), const AF_MAX = 38 pkg syscall (freebsd-amd64-cgo), const DLT_MATCHING_MAX = 242 pkg syscall (freebsd-amd64-cgo), const ELAST = 94 pkg syscall (freebsd-amd64-cgo), const ImplementsGetwd = false pkg syscall (freebsd-amd64-cgo), const O_CLOEXEC = 0 +pkg syscall (freebsd-amd64-cgo), func Mknod(string, uint32, int) error +pkg syscall (freebsd-amd64-cgo), type Dirent struct, Fileno uint32 +pkg syscall (freebsd-amd64-cgo), type Dirent struct, Namlen uint8 +pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Blksize uint32 +pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Dev uint32 +pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Gen uint32 +pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Ino uint32 +pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Lspare int32 +pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Nlink uint16 +pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Rdev uint32 +pkg syscall (freebsd-amd64-cgo), type Statfs_t struct, Mntfromname [88]int8 +pkg syscall (freebsd-amd64-cgo), type Statfs_t struct, Mntonname [88]int8 pkg syscall (freebsd-arm), const AF_MAX = 38 pkg syscall (freebsd-arm), const BIOCGRTIMEOUT = 1074545262 pkg syscall (freebsd-arm), const BIOCSRTIMEOUT = 2148287085 @@ -62,10 +156,22 @@ pkg syscall (freebsd-arm), const SizeofSockaddrDatalink = 56 pkg syscall (freebsd-arm), const SizeofSockaddrUnix = 108 pkg syscall (freebsd-arm), const TIOCTIMESTAMP = 1074558041 pkg syscall (freebsd-arm), func Fchflags(string, int) error +pkg syscall (freebsd-arm), func Mknod(string, uint32, int) error pkg syscall (freebsd-arm), type BpfHdr struct, Pad_cgo_0 [2]uint8 +pkg syscall (freebsd-arm), type Dirent struct, Fileno uint32 +pkg syscall (freebsd-arm), type Dirent struct, Namlen uint8 pkg syscall (freebsd-arm), type RawSockaddrDatalink struct, Pad_cgo_0 [2]uint8 pkg syscall (freebsd-arm), type RawSockaddrUnix struct, Pad_cgo_0 [2]uint8 +pkg syscall (freebsd-arm), type Stat_t struct, Blksize uint32 +pkg syscall (freebsd-arm), type Stat_t struct, Dev uint32 +pkg syscall (freebsd-arm), type Stat_t struct, Gen uint32 +pkg syscall (freebsd-arm), type Stat_t struct, Ino uint32 +pkg syscall (freebsd-arm), type Stat_t struct, Lspare int32 +pkg syscall (freebsd-arm), type Stat_t struct, Nlink uint16 pkg syscall (freebsd-arm), type Stat_t struct, Pad_cgo_0 [4]uint8 +pkg syscall (freebsd-arm), type Stat_t struct, Rdev uint32 +pkg syscall (freebsd-arm), type Statfs_t struct, Mntfromname [88]int8 +pkg syscall (freebsd-arm), type Statfs_t struct, Mntonname [88]int8 pkg syscall (freebsd-arm-cgo), const AF_MAX = 38 pkg syscall (freebsd-arm-cgo), const BIOCGRTIMEOUT = 1074545262 pkg syscall (freebsd-arm-cgo), const BIOCSRTIMEOUT = 2148287085 @@ -94,10 +200,22 @@ pkg syscall (freebsd-arm-cgo), const SizeofSockaddrDatalink = 56 pkg syscall (freebsd-arm-cgo), const SizeofSockaddrUnix = 108 pkg syscall (freebsd-arm-cgo), const TIOCTIMESTAMP = 1074558041 pkg syscall (freebsd-arm-cgo), func Fchflags(string, int) error +pkg syscall (freebsd-arm-cgo), func Mknod(string, uint32, int) error pkg syscall (freebsd-arm-cgo), type BpfHdr struct, Pad_cgo_0 [2]uint8 +pkg syscall (freebsd-arm-cgo), type Dirent struct, Fileno uint32 +pkg syscall (freebsd-arm-cgo), type Dirent struct, Namlen uint8 pkg syscall (freebsd-arm-cgo), type RawSockaddrDatalink struct, Pad_cgo_0 [2]uint8 pkg syscall (freebsd-arm-cgo), type RawSockaddrUnix struct, Pad_cgo_0 [2]uint8 +pkg syscall (freebsd-arm-cgo), type Stat_t struct, Blksize uint32 +pkg syscall (freebsd-arm-cgo), type Stat_t struct, Dev uint32 +pkg syscall (freebsd-arm-cgo), type Stat_t struct, Gen uint32 +pkg syscall (freebsd-arm-cgo), type Stat_t struct, Ino uint32 +pkg syscall (freebsd-arm-cgo), type Stat_t struct, Lspare int32 +pkg syscall (freebsd-arm-cgo), type Stat_t struct, Nlink uint16 pkg syscall (freebsd-arm-cgo), type Stat_t struct, Pad_cgo_0 [4]uint8 +pkg syscall (freebsd-arm-cgo), type Stat_t struct, Rdev uint32 +pkg syscall (freebsd-arm-cgo), type Statfs_t struct, Mntfromname [88]int8 +pkg syscall (freebsd-arm-cgo), type Statfs_t struct, Mntonname [88]int8 pkg syscall (linux-386), type Cmsghdr struct, X__cmsg_data [0]uint8 pkg syscall (linux-386-cgo), type Cmsghdr struct, X__cmsg_data [0]uint8 pkg syscall (linux-amd64), type Cmsghdr struct, X__cmsg_data [0]uint8 @@ -109,10 +227,10 @@ pkg syscall (netbsd-386-cgo), const ImplementsGetwd = false pkg syscall (netbsd-amd64), const ImplementsGetwd = false pkg syscall (netbsd-amd64-cgo), const ImplementsGetwd = false pkg syscall (netbsd-arm), const ImplementsGetwd = false -pkg syscall (netbsd-arm-cgo), const ImplementsGetwd = false pkg syscall (netbsd-arm), const SizeofIfData = 132 pkg syscall (netbsd-arm), func Fchflags(string, int) error pkg syscall (netbsd-arm), type IfMsghdr struct, Pad_cgo_1 [4]uint8 +pkg syscall (netbsd-arm-cgo), const ImplementsGetwd = false pkg syscall (netbsd-arm-cgo), const SizeofIfData = 132 pkg syscall (netbsd-arm-cgo), func Fchflags(string, int) error pkg syscall (netbsd-arm-cgo), type IfMsghdr struct, Pad_cgo_1 [4]uint8 @@ -140,6 +258,7 @@ pkg syscall (openbsd-386), const SYS_GETITIMER = 86 pkg syscall (openbsd-386), const SYS_GETRUSAGE = 117 pkg syscall (openbsd-386), const SYS_GETTIMEOFDAY = 116 pkg syscall (openbsd-386), const SYS_KEVENT = 270 +pkg syscall (openbsd-386), const SYS_KILL = 37 pkg syscall (openbsd-386), const SYS_LSTAT = 293 pkg syscall (openbsd-386), const SYS_NANOSLEEP = 240 pkg syscall (openbsd-386), const SYS_SELECT = 93 @@ -193,6 +312,7 @@ pkg syscall (openbsd-386-cgo), const SYS_GETITIMER = 86 pkg syscall (openbsd-386-cgo), const SYS_GETRUSAGE = 117 pkg syscall (openbsd-386-cgo), const SYS_GETTIMEOFDAY = 116 pkg syscall (openbsd-386-cgo), const SYS_KEVENT = 270 +pkg syscall (openbsd-386-cgo), const SYS_KILL = 37 pkg syscall (openbsd-386-cgo), const SYS_LSTAT = 293 pkg syscall (openbsd-386-cgo), const SYS_NANOSLEEP = 240 pkg syscall (openbsd-386-cgo), const SYS_SELECT = 93 @@ -257,6 +377,7 @@ pkg syscall (openbsd-amd64), const SYS_GETITIMER = 86 pkg syscall (openbsd-amd64), const SYS_GETRUSAGE = 117 pkg syscall (openbsd-amd64), const SYS_GETTIMEOFDAY = 116 pkg syscall (openbsd-amd64), const SYS_KEVENT = 270 +pkg syscall (openbsd-amd64), const SYS_KILL = 37 pkg syscall (openbsd-amd64), const SYS_LSTAT = 293 pkg syscall (openbsd-amd64), const SYS_NANOSLEEP = 240 pkg syscall (openbsd-amd64), const SYS_SELECT = 93 @@ -320,6 +441,7 @@ pkg syscall (openbsd-amd64-cgo), const SYS_GETITIMER = 86 pkg syscall (openbsd-amd64-cgo), const SYS_GETRUSAGE = 117 pkg syscall (openbsd-amd64-cgo), const SYS_GETTIMEOFDAY = 116 pkg syscall (openbsd-amd64-cgo), const SYS_KEVENT = 270 +pkg syscall (openbsd-amd64-cgo), const SYS_KILL = 37 pkg syscall (openbsd-amd64-cgo), const SYS_LSTAT = 293 pkg syscall (openbsd-amd64-cgo), const SYS_NANOSLEEP = 240 pkg syscall (openbsd-amd64-cgo), const SYS_SELECT = 93 @@ -348,19 +470,6 @@ pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, F_spare [3]uint32 pkg syscall (openbsd-amd64-cgo), type Statfs_t struct, Pad_cgo_1 [4]uint8 pkg syscall (openbsd-amd64-cgo), type Timespec struct, Pad_cgo_0 [4]uint8 pkg syscall (openbsd-amd64-cgo), type Timespec struct, Sec int32 -pkg testing, func RegisterCover(Cover) -pkg testing, func MainStart(func(string, string) (bool, error), []InternalTest, []InternalBenchmark, []InternalExample) *M -pkg text/template/parse, type DotNode bool -pkg text/template/parse, type Node interface { Copy, String, Type } -pkg unicode, const Version = "6.2.0" -pkg unicode, const Version = "6.3.0" -pkg unicode, const Version = "7.0.0" -pkg unicode, const Version = "8.0.0" -pkg syscall (openbsd-386), const SYS_KILL = 37 -pkg syscall (openbsd-386-cgo), const SYS_KILL = 37 -pkg syscall (openbsd-amd64), const SYS_KILL = 37 -pkg syscall (openbsd-amd64-cgo), const SYS_KILL = 37 -pkg unicode, const Version = "9.0.0" pkg syscall (windows-386), const TOKEN_ALL_ACCESS = 983295 pkg syscall (windows-386), type AddrinfoW struct, Addr uintptr pkg syscall (windows-386), type CertChainPolicyPara struct, ExtraPolicyPara uintptr @@ -379,81 +488,16 @@ pkg syscall (windows-amd64), type CertRevocationInfo struct, CrlInfo uintptr pkg syscall (windows-amd64), type CertRevocationInfo struct, OidSpecificInfo uintptr pkg syscall (windows-amd64), type CertSimpleChain struct, TrustListInfo uintptr pkg syscall (windows-amd64), type RawSockaddrAny struct, Pad [96]int8 -pkg syscall (freebsd-386), func Mknod(string, uint32, int) error -pkg syscall (freebsd-386), type Dirent struct, Fileno uint32 -pkg syscall (freebsd-386), type Dirent struct, Namlen uint8 -pkg syscall (freebsd-386), type Stat_t struct, Blksize uint32 -pkg syscall (freebsd-386), type Stat_t struct, Dev uint32 -pkg syscall (freebsd-386), type Stat_t struct, Gen uint32 -pkg syscall (freebsd-386), type Stat_t struct, Ino uint32 -pkg syscall (freebsd-386), type Stat_t struct, Lspare int32 -pkg syscall (freebsd-386), type Stat_t struct, Nlink uint16 -pkg syscall (freebsd-386), type Stat_t struct, Pad_cgo_0 [8]uint8 -pkg syscall (freebsd-386), type Stat_t struct, Rdev uint32 -pkg syscall (freebsd-386), type Statfs_t struct, Mntfromname [88]int8 -pkg syscall (freebsd-386), type Statfs_t struct, Mntonname [88]int8 -pkg syscall (freebsd-386-cgo), func Mknod(string, uint32, int) error -pkg syscall (freebsd-386-cgo), type Dirent struct, Fileno uint32 -pkg syscall (freebsd-386-cgo), type Dirent struct, Namlen uint8 -pkg syscall (freebsd-386-cgo), type Stat_t struct, Blksize uint32 -pkg syscall (freebsd-386-cgo), type Stat_t struct, Dev uint32 -pkg syscall (freebsd-386-cgo), type Stat_t struct, Gen uint32 -pkg syscall (freebsd-386-cgo), type Stat_t struct, Ino uint32 -pkg syscall (freebsd-386-cgo), type Stat_t struct, Lspare int32 -pkg syscall (freebsd-386-cgo), type Stat_t struct, Nlink uint16 -pkg syscall (freebsd-386-cgo), type Stat_t struct, Pad_cgo_0 [8]uint8 -pkg syscall (freebsd-386-cgo), type Stat_t struct, Rdev uint32 -pkg syscall (freebsd-386-cgo), type Statfs_t struct, Mntfromname [88]int8 -pkg syscall (freebsd-386-cgo), type Statfs_t struct, Mntonname [88]int8 -pkg syscall (freebsd-amd64), func Mknod(string, uint32, int) error -pkg syscall (freebsd-amd64), type Dirent struct, Fileno uint32 -pkg syscall (freebsd-amd64), type Dirent struct, Namlen uint8 -pkg syscall (freebsd-amd64), type Stat_t struct, Blksize uint32 -pkg syscall (freebsd-amd64), type Stat_t struct, Dev uint32 -pkg syscall (freebsd-amd64), type Stat_t struct, Gen uint32 -pkg syscall (freebsd-amd64), type Stat_t struct, Ino uint32 -pkg syscall (freebsd-amd64), type Stat_t struct, Lspare int32 -pkg syscall (freebsd-amd64), type Stat_t struct, Nlink uint16 -pkg syscall (freebsd-amd64), type Stat_t struct, Rdev uint32 -pkg syscall (freebsd-amd64), type Statfs_t struct, Mntfromname [88]int8 -pkg syscall (freebsd-amd64), type Statfs_t struct, Mntonname [88]int8 -pkg syscall (freebsd-amd64-cgo), func Mknod(string, uint32, int) error -pkg syscall (freebsd-amd64-cgo), type Dirent struct, Fileno uint32 -pkg syscall (freebsd-amd64-cgo), type Dirent struct, Namlen uint8 -pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Blksize uint32 -pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Dev uint32 -pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Gen uint32 -pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Ino uint32 -pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Lspare int32 -pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Nlink uint16 -pkg syscall (freebsd-amd64-cgo), type Stat_t struct, Rdev uint32 -pkg syscall (freebsd-amd64-cgo), type Statfs_t struct, Mntfromname [88]int8 -pkg syscall (freebsd-amd64-cgo), type Statfs_t struct, Mntonname [88]int8 -pkg syscall (freebsd-arm), func Mknod(string, uint32, int) error -pkg syscall (freebsd-arm), type Dirent struct, Fileno uint32 -pkg syscall (freebsd-arm), type Dirent struct, Namlen uint8 -pkg syscall (freebsd-arm), type Stat_t struct, Blksize uint32 -pkg syscall (freebsd-arm), type Stat_t struct, Dev uint32 -pkg syscall (freebsd-arm), type Stat_t struct, Gen uint32 -pkg syscall (freebsd-arm), type Stat_t struct, Ino uint32 -pkg syscall (freebsd-arm), type Stat_t struct, Lspare int32 -pkg syscall (freebsd-arm), type Stat_t struct, Nlink uint16 -pkg syscall (freebsd-arm), type Stat_t struct, Rdev uint32 -pkg syscall (freebsd-arm), type Statfs_t struct, Mntfromname [88]int8 -pkg syscall (freebsd-arm), type Statfs_t struct, Mntonname [88]int8 -pkg syscall (freebsd-arm-cgo), func Mknod(string, uint32, int) error -pkg syscall (freebsd-arm-cgo), type Dirent struct, Fileno uint32 -pkg syscall (freebsd-arm-cgo), type Dirent struct, Namlen uint8 -pkg syscall (freebsd-arm-cgo), type Stat_t struct, Blksize uint32 -pkg syscall (freebsd-arm-cgo), type Stat_t struct, Dev uint32 -pkg syscall (freebsd-arm-cgo), type Stat_t struct, Gen uint32 -pkg syscall (freebsd-arm-cgo), type Stat_t struct, Ino uint32 -pkg syscall (freebsd-arm-cgo), type Stat_t struct, Lspare int32 -pkg syscall (freebsd-arm-cgo), type Stat_t struct, Nlink uint16 -pkg syscall (freebsd-arm-cgo), type Stat_t struct, Rdev uint32 -pkg syscall (freebsd-arm-cgo), type Statfs_t struct, Mntfromname [88]int8 -pkg syscall (freebsd-arm-cgo), type Statfs_t struct, Mntonname [88]int8 +pkg testing, func MainStart(func(string, string) (bool, error), []InternalTest, []InternalBenchmark, []InternalExample) *M +pkg testing, func RegisterCover(Cover) pkg text/scanner, const GoTokens = 1012 +pkg text/template/parse, type DotNode bool +pkg text/template/parse, type Node interface { Copy, String, Type } pkg unicode, const Version = "10.0.0" pkg unicode, const Version = "11.0.0" pkg unicode, const Version = "12.0.0" +pkg unicode, const Version = "6.2.0" +pkg unicode, const Version = "6.3.0" +pkg unicode, const Version = "7.0.0" +pkg unicode, const Version = "8.0.0" +pkg unicode, const Version = "9.0.0" diff --git a/api/next.txt b/api/next.txt index 59422cca4d..3184a8ceae 100644 --- a/api/next.txt +++ b/api/next.txt @@ -223,15 +223,97 @@ pkg io, type ReadSeekCloser interface { Close, Read, Seek } pkg io, type ReadSeekCloser interface, Close() error pkg io, type ReadSeekCloser interface, Read([]uint8) (int, error) pkg io, type ReadSeekCloser interface, Seek(int64, int) (int64, error) +pkg io/fs, const ModeAppend = 1073741824 +pkg io/fs, const ModeAppend FileMode +pkg io/fs, const ModeCharDevice = 2097152 +pkg io/fs, const ModeCharDevice FileMode +pkg io/fs, const ModeDevice = 67108864 +pkg io/fs, const ModeDevice FileMode +pkg io/fs, const ModeDir = 2147483648 +pkg io/fs, const ModeDir FileMode +pkg io/fs, const ModeExclusive = 536870912 +pkg io/fs, const ModeExclusive FileMode +pkg io/fs, const ModeIrregular = 524288 +pkg io/fs, const ModeIrregular FileMode +pkg io/fs, const ModeNamedPipe = 33554432 +pkg io/fs, const ModeNamedPipe FileMode +pkg io/fs, const ModePerm = 511 +pkg io/fs, const ModePerm FileMode +pkg io/fs, const ModeSetgid = 4194304 +pkg io/fs, const ModeSetgid FileMode +pkg io/fs, const ModeSetuid = 8388608 +pkg io/fs, const ModeSetuid FileMode +pkg io/fs, const ModeSocket = 16777216 +pkg io/fs, const ModeSocket FileMode +pkg io/fs, const ModeSticky = 1048576 +pkg io/fs, const ModeSticky FileMode +pkg io/fs, const ModeSymlink = 134217728 +pkg io/fs, const ModeSymlink FileMode +pkg io/fs, const ModeTemporary = 268435456 +pkg io/fs, const ModeTemporary FileMode +pkg io/fs, const ModeType = 2401763328 +pkg io/fs, const ModeType FileMode +pkg io/fs, method (*PathError) Error() string +pkg io/fs, method (*PathError) Timeout() bool +pkg io/fs, method (*PathError) Unwrap() error +pkg io/fs, method (FileMode) IsDir() bool +pkg io/fs, method (FileMode) IsRegular() bool +pkg io/fs, method (FileMode) Perm() FileMode +pkg io/fs, method (FileMode) String() string +pkg io/fs, method (FileMode) Type() FileMode +pkg io/fs, type FileInfo interface { IsDir, ModTime, Mode, Name, Size, Sys } +pkg io/fs, type FileInfo interface, IsDir() bool +pkg io/fs, type FileInfo interface, ModTime() time.Time +pkg io/fs, type FileInfo interface, Mode() FileMode +pkg io/fs, type FileInfo interface, Name() string +pkg io/fs, type FileInfo interface, Size() int64 +pkg io/fs, type FileInfo interface, Sys() interface{} +pkg io/fs, type FileMode uint32 +pkg io/fs, type PathError struct +pkg io/fs, type PathError struct, Err error +pkg io/fs, type PathError struct, Op string +pkg io/fs, type PathError struct, Path string +pkg io/fs, var ErrClosed error +pkg io/fs, var ErrExist error +pkg io/fs, var ErrInvalid error +pkg io/fs, var ErrNotExist error +pkg io/fs, var ErrPermission error pkg net, var ErrClosed error pkg net/http, type Transport struct, GetProxyConnectHeader func(context.Context, *url.URL, string) (Header, error) +pkg os, const ModeAppend fs.FileMode +pkg os, const ModeCharDevice fs.FileMode +pkg os, const ModeDevice fs.FileMode +pkg os, const ModeDir fs.FileMode +pkg os, const ModeExclusive fs.FileMode +pkg os, const ModeIrregular fs.FileMode +pkg os, const ModeNamedPipe fs.FileMode +pkg os, const ModePerm fs.FileMode +pkg os, const ModeSetgid fs.FileMode +pkg os, const ModeSetuid fs.FileMode +pkg os, const ModeSocket fs.FileMode +pkg os, const ModeSticky fs.FileMode +pkg os, const ModeSymlink fs.FileMode +pkg os, const ModeTemporary fs.FileMode +pkg os, const ModeType fs.FileMode +pkg os, func Chmod(string, fs.FileMode) error +pkg os, func Lstat(string) (fs.FileInfo, error) +pkg os, func Mkdir(string, fs.FileMode) error +pkg os, func MkdirAll(string, fs.FileMode) error +pkg os, func OpenFile(string, int, fs.FileMode) (*File, error) +pkg os, func SameFile(fs.FileInfo, fs.FileInfo) bool +pkg os, func Stat(string) (fs.FileInfo, error) +pkg os, method (*File) Chmod(fs.FileMode) error pkg os, method (*File) ReadDir(int) ([]DirEntry, error) -pkg os, method (FileMode) Type() FileMode +pkg os, method (*File) Readdir(int) ([]fs.FileInfo, error) +pkg os, method (*File) Stat() (fs.FileInfo, error) pkg os, type DirEntry interface { Info, IsDir, Name, Type } -pkg os, type DirEntry interface, Info() (FileInfo, error) +pkg os, type DirEntry interface, Info() (fs.FileInfo, error) pkg os, type DirEntry interface, IsDir() bool pkg os, type DirEntry interface, Name() string -pkg os, type DirEntry interface, Type() FileMode +pkg os, type DirEntry interface, Type() fs.FileMode +pkg os, type FileInfo = fs.FileInfo +pkg os, type FileMode = fs.FileMode +pkg os, type PathError = fs.PathError pkg os/signal, func NotifyContext(context.Context, ...os.Signal) (context.Context, context.CancelFunc) pkg testing/iotest, func ErrReader(error) io.Reader pkg text/template/parse, const NodeComment = 20 diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go index 6a80ed269b..b14d57c236 100644 --- a/src/cmd/api/goapi.go +++ b/src/cmd/api/goapi.go @@ -326,6 +326,18 @@ func compareAPI(w io.Writer, features, required, optional, exception []string, a return } +// aliasReplacer applies type aliases to earlier API files, +// to avoid misleading negative results. +// This makes all the references to os.FileInfo in go1.txt +// be read as if they said fs.FileInfo, since os.FileInfo is now an alias. +// If there are many of these, we could do a more general solution, +// but for now the replacer is fine. +var aliasReplacer = strings.NewReplacer( + "os.FileInfo", "fs.FileInfo", + "os.FileMode", "fs.FileMode", + "os.PathError", "fs.PathError", +) + func fileFeatures(filename string) []string { if filename == "" { return nil @@ -334,7 +346,9 @@ func fileFeatures(filename string) []string { if err != nil { log.Fatalf("Error reading file %s: %v", filename, err) } - lines := strings.Split(string(bs), "\n") + s := string(bs) + s = aliasReplacer.Replace(s) + lines := strings.Split(s, "\n") var nonblank []string for _, line := range lines { line = strings.TrimSpace(line) @@ -856,6 +870,10 @@ func (w *Walker) emitObj(obj types.Object) { func (w *Walker) emitType(obj *types.TypeName) { name := obj.Name() typ := obj.Type() + if obj.IsAlias() { + w.emitf("type %s = %s", name, w.typeString(typ)) + return + } switch typ := typ.Underlying().(type) { case *types.Struct: w.emitStructType(name, typ) diff --git a/src/io/fs/fs.go b/src/io/fs/fs.go new file mode 100644 index 0000000000..de5c465d9d --- /dev/null +++ b/src/io/fs/fs.go @@ -0,0 +1,140 @@ +// Copyright 2020 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 fs defines basic interfaces to a file system. +// A file system can be provided by the host operating system +// but also by other packages. +package fs + +import ( + "internal/oserror" + "time" +) + +// Generic file system errors. +// Errors returned by file systems can be tested against these errors +// using errors.Is. +var ( + ErrInvalid = errInvalid() // "invalid argument" + ErrPermission = errPermission() // "permission denied" + ErrExist = errExist() // "file already exists" + ErrNotExist = errNotExist() // "file does not exist" + ErrClosed = errClosed() // "file already closed" +) + +func errInvalid() error { return oserror.ErrInvalid } +func errPermission() error { return oserror.ErrPermission } +func errExist() error { return oserror.ErrExist } +func errNotExist() error { return oserror.ErrNotExist } +func errClosed() error { return oserror.ErrClosed } + +// A FileInfo describes a file and is returned by Stat. +type FileInfo interface { + Name() string // base name of the file + Size() int64 // length in bytes for regular files; system-dependent for others + Mode() FileMode // file mode bits + ModTime() time.Time // modification time + IsDir() bool // abbreviation for Mode().IsDir() + Sys() interface{} // underlying data source (can return nil) +} + +// A FileMode represents a file's mode and permission bits. +// The bits have the same definition on all systems, so that +// information about files can be moved from one system +// to another portably. Not all bits apply to all systems. +// The only required bit is ModeDir for directories. +type FileMode uint32 + +// The defined file mode bits are the most significant bits of the FileMode. +// The nine least-significant bits are the standard Unix rwxrwxrwx permissions. +// The values of these bits should be considered part of the public API and +// may be used in wire protocols or disk representations: they must not be +// changed, although new bits might be added. +const ( + // The single letters are the abbreviations + // used by the String method's formatting. + ModeDir FileMode = 1 << (32 - 1 - iota) // d: is a directory + ModeAppend // a: append-only + ModeExclusive // l: exclusive use + ModeTemporary // T: temporary file; Plan 9 only + ModeSymlink // L: symbolic link + ModeDevice // D: device file + ModeNamedPipe // p: named pipe (FIFO) + ModeSocket // S: Unix domain socket + ModeSetuid // u: setuid + ModeSetgid // g: setgid + ModeCharDevice // c: Unix character device, when ModeDevice is set + ModeSticky // t: sticky + ModeIrregular // ?: non-regular file; nothing else is known about this file + + // Mask for the type bits. For regular files, none will be set. + ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice | ModeCharDevice | ModeIrregular + + ModePerm FileMode = 0777 // Unix permission bits +) + +func (m FileMode) String() string { + const str = "dalTLDpSugct?" + var buf [32]byte // Mode is uint32. + w := 0 + for i, c := range str { + if m&(1< Date: Tue, 7 Jul 2020 13:49:21 -0400 Subject: all: update references to symbols moved from os to io/fs The old os 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. For #41190. Change-Id: I8f9526977867c10a221e2f392f78d7dec073f1bd Reviewed-on: https://go-review.googlesource.com/c/go/+/243907 Trust: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Go Bot Reviewed-by: Rob Pike --- src/archive/tar/common.go | 68 ++++++++++---------- src/archive/tar/stat_unix.go | 4 +- src/archive/tar/tar_test.go | 19 +++--- src/archive/zip/reader_test.go | 11 ++-- src/archive/zip/struct.go | 72 +++++++++++----------- src/archive/zip/writer_test.go | 10 +-- src/cmd/doc/pkg.go | 10 +-- src/cmd/fix/main.go | 5 +- src/cmd/go/go_test.go | 7 ++- src/cmd/go/internal/cache/cache.go | 3 +- src/cmd/go/internal/fsys/fsys.go | 41 ++++++------ src/cmd/go/internal/fsys/fsys_test.go | 39 ++++++------ src/cmd/go/internal/imports/scan.go | 3 +- src/cmd/go/internal/load/pkg.go | 5 +- .../lockedfile/internal/filelock/filelock.go | 5 +- .../lockedfile/internal/filelock/filelock_fcntl.go | 6 +- .../lockedfile/internal/filelock/filelock_other.go | 6 +- .../lockedfile/internal/filelock/filelock_plan9.go | 8 +-- .../lockedfile/internal/filelock/filelock_unix.go | 4 +- .../internal/filelock/filelock_windows.go | 6 +- src/cmd/go/internal/lockedfile/lockedfile.go | 9 +-- .../go/internal/lockedfile/lockedfile_filelock.go | 3 +- src/cmd/go/internal/lockedfile/lockedfile_plan9.go | 9 +-- src/cmd/go/internal/modcmd/vendor.go | 7 ++- src/cmd/go/internal/modcmd/verify.go | 9 +-- src/cmd/go/internal/modfetch/cache.go | 7 ++- src/cmd/go/internal/modfetch/codehost/codehost.go | 9 +-- src/cmd/go/internal/modfetch/codehost/git.go | 15 ++--- src/cmd/go/internal/modfetch/codehost/git_test.go | 3 +- src/cmd/go/internal/modfetch/codehost/vcs.go | 3 +- src/cmd/go/internal/modfetch/coderepo.go | 7 ++- src/cmd/go/internal/modfetch/fetch.go | 11 ++-- src/cmd/go/internal/modfetch/proxy.go | 8 +-- src/cmd/go/internal/modfetch/repo.go | 5 +- src/cmd/go/internal/modfetch/sumdb.go | 7 ++- src/cmd/go/internal/modload/import.go | 3 +- src/cmd/go/internal/modload/load.go | 3 +- src/cmd/go/internal/modload/query.go | 11 ++-- src/cmd/go/internal/modload/search.go | 5 +- src/cmd/go/internal/modload/stat_openfile.go | 3 +- src/cmd/go/internal/modload/stat_unix.go | 3 +- src/cmd/go/internal/modload/stat_windows.go | 6 +- src/cmd/go/internal/modload/vendor.go | 4 +- src/cmd/go/internal/renameio/renameio.go | 7 ++- src/cmd/go/internal/renameio/umask_test.go | 5 +- src/cmd/go/internal/search/search.go | 7 ++- src/cmd/go/internal/test/test.go | 3 +- src/cmd/go/internal/vcs/vcs.go | 5 +- src/cmd/go/internal/version/version.go | 11 ++-- src/cmd/go/internal/web/api.go | 6 +- src/cmd/go/internal/web/file_test.go | 5 +- src/cmd/go/internal/work/build_test.go | 3 +- src/cmd/go/internal/work/exec.go | 9 +-- src/cmd/go/proxy_test.go | 5 +- src/cmd/go/script_test.go | 7 ++- src/cmd/go/testdata/addmod.go | 3 +- src/cmd/go/testdata/savedir.go | 3 +- src/cmd/gofmt/gofmt.go | 9 +-- src/cmd/gofmt/long_test.go | 3 +- src/cmd/internal/buildid/buildid.go | 9 +-- src/cmd/internal/buildid/note.go | 7 ++- src/cmd/internal/moddeps/moddeps_test.go | 3 +- src/cmd/pack/pack.go | 3 +- src/cmd/pack/pack_test.go | 11 ++-- src/compress/gzip/issue14937_test.go | 3 +- src/crypto/rand/eagain.go | 4 +- src/crypto/x509/root_unix.go | 7 ++- src/errors/errors.go | 12 ++-- src/errors/wrap.go | 4 +- src/errors/wrap_test.go | 11 ++-- src/go/build/build.go | 9 +-- src/go/build/deps_test.go | 3 +- src/go/doc/doc_test.go | 6 +- src/go/doc/headscan.go | 5 +- src/go/parser/interface.go | 6 +- src/go/parser/parser_test.go | 4 +- src/index/suffixarray/suffixarray_test.go | 4 +- src/internal/poll/error_test.go | 3 +- src/internal/reflectlite/reflect_mirror_test.go | 3 +- src/io/ioutil/ioutil.go | 5 +- src/io/ioutil/tempfile_test.go | 3 +- src/net/conf_test.go | 8 +-- src/net/dnsconfig_unix_test.go | 3 +- src/net/error_test.go | 13 ++-- src/net/http/example_filesystem_test.go | 14 ++--- src/net/http/fs.go | 9 +-- src/net/http/fs_test.go | 27 ++++---- src/net/ipsock_plan9.go | 3 +- src/os/error_test.go | 55 +++++++++-------- src/os/error_unix_test.go | 11 ++-- src/os/error_windows_test.go | 11 ++-- src/os/example_test.go | 5 +- src/os/exec/exec_plan9.go | 4 +- src/os/exec/exec_unix.go | 4 +- src/os/exec/exec_windows.go | 4 +- src/os/exec/lp_plan9.go | 3 +- src/os/exec/lp_unix.go | 3 +- src/os/exec/lp_windows.go | 5 +- src/os/os_test.go | 2 +- src/os/os_windows_test.go | 11 ++-- src/os/pipe_test.go | 17 ++--- src/os/removeall_test.go | 2 +- src/os/signal/signal_cgo_test.go | 3 +- src/os/stat_test.go | 19 +++--- src/path/filepath/example_unix_walk_test.go | 3 +- src/path/filepath/path.go | 7 ++- src/path/filepath/path_test.go | 15 ++--- src/path/filepath/path_windows_test.go | 3 +- src/path/filepath/symlink.go | 3 +- src/runtime/testdata/testprogcgo/exec.go | 3 +- src/syscall/syscall_js.go | 2 +- src/syscall/syscall_linux_test.go | 3 +- src/syscall/syscall_plan9.go | 2 +- src/syscall/syscall_unix.go | 2 +- src/syscall/syscall_windows.go | 2 +- 115 files changed, 529 insertions(+), 450 deletions(-) (limited to 'src/io') diff --git a/src/archive/tar/common.go b/src/archive/tar/common.go index dee9e47e4a..c667cfc872 100644 --- a/src/archive/tar/common.go +++ b/src/archive/tar/common.go @@ -13,8 +13,8 @@ package tar import ( "errors" "fmt" + "io/fs" "math" - "os" "path" "reflect" "strconv" @@ -525,12 +525,12 @@ func (h Header) allowedFormats() (format Format, paxHdrs map[string]string, err return format, paxHdrs, err } -// FileInfo returns an os.FileInfo for the Header. -func (h *Header) FileInfo() os.FileInfo { +// FileInfo returns an fs.FileInfo for the Header. +func (h *Header) FileInfo() fs.FileInfo { return headerFileInfo{h} } -// headerFileInfo implements os.FileInfo. +// headerFileInfo implements fs.FileInfo. type headerFileInfo struct { h *Header } @@ -549,57 +549,57 @@ func (fi headerFileInfo) Name() string { } // Mode returns the permission and mode bits for the headerFileInfo. -func (fi headerFileInfo) Mode() (mode os.FileMode) { +func (fi headerFileInfo) Mode() (mode fs.FileMode) { // Set file permission bits. - mode = os.FileMode(fi.h.Mode).Perm() + mode = fs.FileMode(fi.h.Mode).Perm() // Set setuid, setgid and sticky bits. if fi.h.Mode&c_ISUID != 0 { - mode |= os.ModeSetuid + mode |= fs.ModeSetuid } if fi.h.Mode&c_ISGID != 0 { - mode |= os.ModeSetgid + mode |= fs.ModeSetgid } if fi.h.Mode&c_ISVTX != 0 { - mode |= os.ModeSticky + mode |= fs.ModeSticky } // Set file mode bits; clear perm, setuid, setgid, and sticky bits. - switch m := os.FileMode(fi.h.Mode) &^ 07777; m { + switch m := fs.FileMode(fi.h.Mode) &^ 07777; m { case c_ISDIR: - mode |= os.ModeDir + mode |= fs.ModeDir case c_ISFIFO: - mode |= os.ModeNamedPipe + mode |= fs.ModeNamedPipe case c_ISLNK: - mode |= os.ModeSymlink + mode |= fs.ModeSymlink case c_ISBLK: - mode |= os.ModeDevice + mode |= fs.ModeDevice case c_ISCHR: - mode |= os.ModeDevice - mode |= os.ModeCharDevice + mode |= fs.ModeDevice + mode |= fs.ModeCharDevice case c_ISSOCK: - mode |= os.ModeSocket + mode |= fs.ModeSocket } switch fi.h.Typeflag { case TypeSymlink: - mode |= os.ModeSymlink + mode |= fs.ModeSymlink case TypeChar: - mode |= os.ModeDevice - mode |= os.ModeCharDevice + mode |= fs.ModeDevice + mode |= fs.ModeCharDevice case TypeBlock: - mode |= os.ModeDevice + mode |= fs.ModeDevice case TypeDir: - mode |= os.ModeDir + mode |= fs.ModeDir case TypeFifo: - mode |= os.ModeNamedPipe + mode |= fs.ModeNamedPipe } return mode } // sysStat, if non-nil, populates h from system-dependent fields of fi. -var sysStat func(fi os.FileInfo, h *Header) error +var sysStat func(fi fs.FileInfo, h *Header) error const ( // Mode constants from the USTAR spec: @@ -623,10 +623,10 @@ const ( // If fi describes a symlink, FileInfoHeader records link as the link target. // If fi describes a directory, a slash is appended to the name. // -// Since os.FileInfo's Name method only returns the base name of +// Since fs.FileInfo's Name method only returns the base name of // the file it describes, it may be necessary to modify Header.Name // to provide the full path name of the file. -func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) { +func FileInfoHeader(fi fs.FileInfo, link string) (*Header, error) { if fi == nil { return nil, errors.New("archive/tar: FileInfo is nil") } @@ -643,29 +643,29 @@ func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) { case fi.IsDir(): h.Typeflag = TypeDir h.Name += "/" - case fm&os.ModeSymlink != 0: + case fm&fs.ModeSymlink != 0: h.Typeflag = TypeSymlink h.Linkname = link - case fm&os.ModeDevice != 0: - if fm&os.ModeCharDevice != 0 { + case fm&fs.ModeDevice != 0: + if fm&fs.ModeCharDevice != 0 { h.Typeflag = TypeChar } else { h.Typeflag = TypeBlock } - case fm&os.ModeNamedPipe != 0: + case fm&fs.ModeNamedPipe != 0: h.Typeflag = TypeFifo - case fm&os.ModeSocket != 0: + case fm&fs.ModeSocket != 0: return nil, fmt.Errorf("archive/tar: sockets not supported") default: return nil, fmt.Errorf("archive/tar: unknown file mode %v", fm) } - if fm&os.ModeSetuid != 0 { + if fm&fs.ModeSetuid != 0 { h.Mode |= c_ISUID } - if fm&os.ModeSetgid != 0 { + if fm&fs.ModeSetgid != 0 { h.Mode |= c_ISGID } - if fm&os.ModeSticky != 0 { + if fm&fs.ModeSticky != 0 { h.Mode |= c_ISVTX } // If possible, populate additional fields from OS-specific diff --git a/src/archive/tar/stat_unix.go b/src/archive/tar/stat_unix.go index 8df3616990..581d87dca9 100644 --- a/src/archive/tar/stat_unix.go +++ b/src/archive/tar/stat_unix.go @@ -7,7 +7,7 @@ package tar import ( - "os" + "io/fs" "os/user" "runtime" "strconv" @@ -23,7 +23,7 @@ func init() { // The downside is that renaming uname or gname by the OS never takes effect. var userMap, groupMap sync.Map // map[int]string -func statUnix(fi os.FileInfo, h *Header) error { +func statUnix(fi fs.FileInfo, h *Header) error { sys, ok := fi.Sys().(*syscall.Stat_t) if !ok { return nil diff --git a/src/archive/tar/tar_test.go b/src/archive/tar/tar_test.go index 2676853122..f605dae904 100644 --- a/src/archive/tar/tar_test.go +++ b/src/archive/tar/tar_test.go @@ -10,6 +10,7 @@ import ( "fmt" "internal/testenv" "io" + "io/fs" "io/ioutil" "math" "os" @@ -338,7 +339,7 @@ func TestRoundTrip(t *testing.T) { type headerRoundTripTest struct { h *Header - fm os.FileMode + fm fs.FileMode } func TestHeaderRoundTrip(t *testing.T) { @@ -361,7 +362,7 @@ func TestHeaderRoundTrip(t *testing.T) { ModTime: time.Unix(1360600852, 0), Typeflag: TypeSymlink, }, - fm: 0777 | os.ModeSymlink, + fm: 0777 | fs.ModeSymlink, }, { // character device node. h: &Header{ @@ -371,7 +372,7 @@ func TestHeaderRoundTrip(t *testing.T) { ModTime: time.Unix(1360578951, 0), Typeflag: TypeChar, }, - fm: 0666 | os.ModeDevice | os.ModeCharDevice, + fm: 0666 | fs.ModeDevice | fs.ModeCharDevice, }, { // block device node. h: &Header{ @@ -381,7 +382,7 @@ func TestHeaderRoundTrip(t *testing.T) { ModTime: time.Unix(1360578954, 0), Typeflag: TypeBlock, }, - fm: 0660 | os.ModeDevice, + fm: 0660 | fs.ModeDevice, }, { // directory. h: &Header{ @@ -391,7 +392,7 @@ func TestHeaderRoundTrip(t *testing.T) { ModTime: time.Unix(1360601116, 0), Typeflag: TypeDir, }, - fm: 0755 | os.ModeDir, + fm: 0755 | fs.ModeDir, }, { // fifo node. h: &Header{ @@ -401,7 +402,7 @@ func TestHeaderRoundTrip(t *testing.T) { ModTime: time.Unix(1360578949, 0), Typeflag: TypeFifo, }, - fm: 0600 | os.ModeNamedPipe, + fm: 0600 | fs.ModeNamedPipe, }, { // setuid. h: &Header{ @@ -411,7 +412,7 @@ func TestHeaderRoundTrip(t *testing.T) { ModTime: time.Unix(1355405093, 0), Typeflag: TypeReg, }, - fm: 0755 | os.ModeSetuid, + fm: 0755 | fs.ModeSetuid, }, { // setguid. h: &Header{ @@ -421,7 +422,7 @@ func TestHeaderRoundTrip(t *testing.T) { ModTime: time.Unix(1360602346, 0), Typeflag: TypeReg, }, - fm: 0750 | os.ModeSetgid, + fm: 0750 | fs.ModeSetgid, }, { // sticky. h: &Header{ @@ -431,7 +432,7 @@ func TestHeaderRoundTrip(t *testing.T) { ModTime: time.Unix(1360602540, 0), Typeflag: TypeReg, }, - fm: 0600 | os.ModeSticky, + fm: 0600 | fs.ModeSticky, }, { // hard link. h: &Header{ diff --git a/src/archive/zip/reader_test.go b/src/archive/zip/reader_test.go index adca87a8b3..8a32d9c7dc 100644 --- a/src/archive/zip/reader_test.go +++ b/src/archive/zip/reader_test.go @@ -10,6 +10,7 @@ import ( "encoding/hex" "internal/obscuretestdata" "io" + "io/fs" "io/ioutil" "os" "path/filepath" @@ -30,7 +31,7 @@ type ZipTest struct { type ZipTestFile struct { Name string - Mode os.FileMode + Mode fs.FileMode NonUTF8 bool ModTime time.Time Modified time.Time @@ -107,7 +108,7 @@ var tests = []ZipTest{ Name: "symlink", Content: []byte("../target"), Modified: time.Date(2012, 2, 3, 19, 56, 48, 0, timeZone(-2*time.Hour)), - Mode: 0777 | os.ModeSymlink, + Mode: 0777 | fs.ModeSymlink, }, }, }, @@ -149,7 +150,7 @@ var tests = []ZipTest{ Name: "dir/empty/", Content: []byte{}, Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, time.UTC), - Mode: os.ModeDir | 0777, + Mode: fs.ModeDir | 0777, }, { Name: "readonly", @@ -179,7 +180,7 @@ var tests = []ZipTest{ Name: "dir/empty/", Content: []byte{}, Modified: time.Date(2011, 12, 8, 10, 8, 6, 0, timeZone(0)), - Mode: os.ModeDir | 0777, + Mode: fs.ModeDir | 0777, }, { Name: "readonly", @@ -645,7 +646,7 @@ func readTestFile(t *testing.T, zt ZipTest, ft ZipTestFile, f *File) { } } -func testFileMode(t *testing.T, f *File, want os.FileMode) { +func testFileMode(t *testing.T, f *File, want fs.FileMode) { mode := f.Mode() if want == 0 { t.Errorf("%s mode: got %v, want none", f.Name, mode) diff --git a/src/archive/zip/struct.go b/src/archive/zip/struct.go index 686e79781a..355c57051b 100644 --- a/src/archive/zip/struct.go +++ b/src/archive/zip/struct.go @@ -20,7 +20,7 @@ fields must be used instead. package zip import ( - "os" + "io/fs" "path" "time" ) @@ -137,12 +137,12 @@ type FileHeader struct { ExternalAttrs uint32 // Meaning depends on CreatorVersion } -// FileInfo returns an os.FileInfo for the FileHeader. -func (h *FileHeader) FileInfo() os.FileInfo { +// FileInfo returns an fs.FileInfo for the FileHeader. +func (h *FileHeader) FileInfo() fs.FileInfo { return headerFileInfo{h} } -// headerFileInfo implements os.FileInfo. +// headerFileInfo implements fs.FileInfo. type headerFileInfo struct { fh *FileHeader } @@ -161,17 +161,17 @@ func (fi headerFileInfo) ModTime() time.Time { } return fi.fh.Modified.UTC() } -func (fi headerFileInfo) Mode() os.FileMode { return fi.fh.Mode() } +func (fi headerFileInfo) Mode() fs.FileMode { return fi.fh.Mode() } func (fi headerFileInfo) Sys() interface{} { return fi.fh } // FileInfoHeader creates a partially-populated FileHeader from an -// os.FileInfo. -// Because os.FileInfo's Name method returns only the base name of +// fs.FileInfo. +// Because fs.FileInfo's Name method returns only the base name of // the file it describes, it may be necessary to modify the Name field // of the returned header to provide the full path name of the file. // If compression is desired, callers should set the FileHeader.Method // field; it is unset by default. -func FileInfoHeader(fi os.FileInfo) (*FileHeader, error) { +func FileInfoHeader(fi fs.FileInfo) (*FileHeader, error) { size := fi.Size() fh := &FileHeader{ Name: fi.Name(), @@ -280,7 +280,7 @@ const ( ) // Mode returns the permission and mode bits for the FileHeader. -func (h *FileHeader) Mode() (mode os.FileMode) { +func (h *FileHeader) Mode() (mode fs.FileMode) { switch h.CreatorVersion >> 8 { case creatorUnix, creatorMacOSX: mode = unixModeToFileMode(h.ExternalAttrs >> 16) @@ -288,18 +288,18 @@ func (h *FileHeader) Mode() (mode os.FileMode) { mode = msdosModeToFileMode(h.ExternalAttrs) } if len(h.Name) > 0 && h.Name[len(h.Name)-1] == '/' { - mode |= os.ModeDir + mode |= fs.ModeDir } return mode } // SetMode changes the permission and mode bits for the FileHeader. -func (h *FileHeader) SetMode(mode os.FileMode) { +func (h *FileHeader) SetMode(mode fs.FileMode) { h.CreatorVersion = h.CreatorVersion&0xff | creatorUnix<<8 h.ExternalAttrs = fileModeToUnixMode(mode) << 16 // set MSDOS attributes too, as the original zip does. - if mode&os.ModeDir != 0 { + if mode&fs.ModeDir != 0 { h.ExternalAttrs |= msdosDir } if mode&0200 == 0 { @@ -312,9 +312,9 @@ func (h *FileHeader) isZip64() bool { return h.CompressedSize64 >= uint32max || h.UncompressedSize64 >= uint32max } -func msdosModeToFileMode(m uint32) (mode os.FileMode) { +func msdosModeToFileMode(m uint32) (mode fs.FileMode) { if m&msdosDir != 0 { - mode = os.ModeDir | 0777 + mode = fs.ModeDir | 0777 } else { mode = 0666 } @@ -324,64 +324,64 @@ func msdosModeToFileMode(m uint32) (mode os.FileMode) { return mode } -func fileModeToUnixMode(mode os.FileMode) uint32 { +func fileModeToUnixMode(mode fs.FileMode) uint32 { var m uint32 - switch mode & os.ModeType { + switch mode & fs.ModeType { default: m = s_IFREG - case os.ModeDir: + case fs.ModeDir: m = s_IFDIR - case os.ModeSymlink: + case fs.ModeSymlink: m = s_IFLNK - case os.ModeNamedPipe: + case fs.ModeNamedPipe: m = s_IFIFO - case os.ModeSocket: + case fs.ModeSocket: m = s_IFSOCK - case os.ModeDevice: - if mode&os.ModeCharDevice != 0 { + case fs.ModeDevice: + if mode&fs.ModeCharDevice != 0 { m = s_IFCHR } else { m = s_IFBLK } } - if mode&os.ModeSetuid != 0 { + if mode&fs.ModeSetuid != 0 { m |= s_ISUID } - if mode&os.ModeSetgid != 0 { + if mode&fs.ModeSetgid != 0 { m |= s_ISGID } - if mode&os.ModeSticky != 0 { + if mode&fs.ModeSticky != 0 { m |= s_ISVTX } return m | uint32(mode&0777) } -func unixModeToFileMode(m uint32) os.FileMode { - mode := os.FileMode(m & 0777) +func unixModeToFileMode(m uint32) fs.FileMode { + mode := fs.FileMode(m & 0777) switch m & s_IFMT { case s_IFBLK: - mode |= os.ModeDevice + mode |= fs.ModeDevice case s_IFCHR: - mode |= os.ModeDevice | os.ModeCharDevice + mode |= fs.ModeDevice | fs.ModeCharDevice case s_IFDIR: - mode |= os.ModeDir + mode |= fs.ModeDir case s_IFIFO: - mode |= os.ModeNamedPipe + mode |= fs.ModeNamedPipe case s_IFLNK: - mode |= os.ModeSymlink + mode |= fs.ModeSymlink case s_IFREG: // nothing to do case s_IFSOCK: - mode |= os.ModeSocket + mode |= fs.ModeSocket } if m&s_ISGID != 0 { - mode |= os.ModeSetgid + mode |= fs.ModeSetgid } if m&s_ISUID != 0 { - mode |= os.ModeSetuid + mode |= fs.ModeSetuid } if m&s_ISVTX != 0 { - mode |= os.ModeSticky + mode |= fs.ModeSticky } return mode } diff --git a/src/archive/zip/writer_test.go b/src/archive/zip/writer_test.go index 1fedfd85e8..282f9ec216 100644 --- a/src/archive/zip/writer_test.go +++ b/src/archive/zip/writer_test.go @@ -9,9 +9,9 @@ import ( "encoding/binary" "fmt" "io" + "io/fs" "io/ioutil" "math/rand" - "os" "strings" "testing" "time" @@ -23,7 +23,7 @@ type WriteTest struct { Name string Data []byte Method uint16 - Mode os.FileMode + Mode fs.FileMode } var writeTests = []WriteTest{ @@ -43,19 +43,19 @@ var writeTests = []WriteTest{ Name: "setuid", Data: []byte("setuid file"), Method: Deflate, - Mode: 0755 | os.ModeSetuid, + Mode: 0755 | fs.ModeSetuid, }, { Name: "setgid", Data: []byte("setgid file"), Method: Deflate, - Mode: 0755 | os.ModeSetgid, + Mode: 0755 | fs.ModeSetgid, }, { Name: "symlink", Data: []byte("../link/target"), Method: Deflate, - Mode: 0755 | os.ModeSymlink, + Mode: 0755 | fs.ModeSymlink, }, } diff --git a/src/cmd/doc/pkg.go b/src/cmd/doc/pkg.go index ffc302c78c..c2e06ebc8b 100644 --- a/src/cmd/doc/pkg.go +++ b/src/cmd/doc/pkg.go @@ -16,8 +16,8 @@ import ( "go/printer" "go/token" "io" + "io/fs" "log" - "os" "path/filepath" "strings" "unicode" @@ -129,11 +129,10 @@ func (pkg *Package) Fatalf(format string, args ...interface{}) { // parsePackage turns the build package we found into a parsed package // we can then use to generate documentation. func parsePackage(writer io.Writer, pkg *build.Package, userPath string) *Package { - fs := token.NewFileSet() // include tells parser.ParseDir which files to include. // That means the file must be in the build package's GoFiles or CgoFiles // list only (no tag-ignored files, tests, swig or other non-Go files). - include := func(info os.FileInfo) bool { + include := func(info fs.FileInfo) bool { for _, name := range pkg.GoFiles { if name == info.Name() { return true @@ -146,7 +145,8 @@ func parsePackage(writer io.Writer, pkg *build.Package, userPath string) *Packag } return false } - pkgs, err := parser.ParseDir(fs, pkg.Dir, include, parser.ParseComments) + fset := token.NewFileSet() + pkgs, err := parser.ParseDir(fset, pkg.Dir, include, parser.ParseComments) if err != nil { log.Fatal(err) } @@ -203,7 +203,7 @@ func parsePackage(writer io.Writer, pkg *build.Package, userPath string) *Packag typedValue: typedValue, constructor: constructor, build: pkg, - fs: fs, + fs: fset, } p.buf.pkg = p return p diff --git a/src/cmd/fix/main.go b/src/cmd/fix/main.go index d19dde6b4a..dfba902f48 100644 --- a/src/cmd/fix/main.go +++ b/src/cmd/fix/main.go @@ -13,6 +13,7 @@ import ( "go/parser" "go/scanner" "go/token" + "io/fs" "io/ioutil" "os" "path/filepath" @@ -235,7 +236,7 @@ func walkDir(path string) { filepath.Walk(path, visitFile) } -func visitFile(path string, f os.FileInfo, err error) error { +func visitFile(path string, f fs.FileInfo, err error) error { if err == nil && isGoFile(f) { err = processFile(path, false) } @@ -245,7 +246,7 @@ func visitFile(path string, f os.FileInfo, err error) error { return nil } -func isGoFile(f os.FileInfo) bool { +func isGoFile(f fs.FileInfo) bool { // ignore non-Go files name := f.Name() return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index 093ea2ffa1..2c11d16959 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -15,6 +15,7 @@ import ( "internal/race" "internal/testenv" "io" + "io/fs" "io/ioutil" "log" "os" @@ -813,7 +814,7 @@ func (tg *testgoData) cleanup() { func removeAll(dir string) error { // module cache has 0444 directories; // make them writable in order to remove content. - filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error { // chmod not only directories, but also things that we couldn't even stat // due to permission errors: they may also be unreadable directories. if err != nil || info.IsDir() { @@ -860,7 +861,7 @@ func TestNewReleaseRebuildsStalePackagesInGOPATH(t *testing.T) { srcdir := filepath.Join(testGOROOT, copydir) tg.tempDir(filepath.Join("goroot", copydir)) err := filepath.Walk(srcdir, - func(path string, info os.FileInfo, err error) error { + func(path string, info fs.FileInfo, err error) error { if err != nil { return err } @@ -2018,7 +2019,7 @@ func main() { tg.run("build", "-o", exe, "p") } -func copyFile(src, dst string, perm os.FileMode) error { +func copyFile(src, dst string, perm fs.FileMode) error { sf, err := os.Open(src) if err != nil { return err diff --git a/src/cmd/go/internal/cache/cache.go b/src/cmd/go/internal/cache/cache.go index 15545ac31f..5464fe5685 100644 --- a/src/cmd/go/internal/cache/cache.go +++ b/src/cmd/go/internal/cache/cache.go @@ -12,6 +12,7 @@ import ( "errors" "fmt" "io" + "io/fs" "io/ioutil" "os" "path/filepath" @@ -54,7 +55,7 @@ func Open(dir string) (*Cache, error) { return nil, err } if !info.IsDir() { - return nil, &os.PathError{Op: "open", Path: dir, Err: fmt.Errorf("not a directory")} + return nil, &fs.PathError{Op: "open", Path: dir, Err: fmt.Errorf("not a directory")} } for i := 0; i < 256; i++ { name := filepath.Join(dir, fmt.Sprintf("%02x", i)) diff --git a/src/cmd/go/internal/fsys/fsys.go b/src/cmd/go/internal/fsys/fsys.go index 489af93496..67359ffb6d 100644 --- a/src/cmd/go/internal/fsys/fsys.go +++ b/src/cmd/go/internal/fsys/fsys.go @@ -6,6 +6,7 @@ import ( "encoding/json" "errors" "fmt" + "io/fs" "io/ioutil" "os" "path/filepath" @@ -240,7 +241,7 @@ var errNotDir = errors.New("not a directory") // readDir reads a dir on disk, returning an error that is errNotDir if the dir is not a directory. // Unfortunately, the error returned by ioutil.ReadDir if dir is not a directory // can vary depending on the OS (Linux, Mac, Windows return ENOTDIR; BSD returns EINVAL). -func readDir(dir string) ([]os.FileInfo, error) { +func readDir(dir string) ([]fs.FileInfo, error) { fis, err := ioutil.ReadDir(dir) if err == nil { return fis, nil @@ -249,25 +250,25 @@ func readDir(dir string) ([]os.FileInfo, error) { if os.IsNotExist(err) { return nil, err } else if dirfi, staterr := os.Stat(dir); staterr == nil && !dirfi.IsDir() { - return nil, &os.PathError{Op: "ReadDir", Path: dir, Err: errNotDir} + return nil, &fs.PathError{Op: "ReadDir", Path: dir, Err: errNotDir} } else { return nil, err } } -// ReadDir provides a slice of os.FileInfo entries corresponding +// ReadDir provides a slice of fs.FileInfo entries corresponding // to the overlaid files in the directory. -func ReadDir(dir string) ([]os.FileInfo, error) { +func ReadDir(dir string) ([]fs.FileInfo, error) { dir = canonicalize(dir) if _, ok := parentIsOverlayFile(dir); ok { - return nil, &os.PathError{Op: "ReadDir", Path: dir, Err: errNotDir} + return nil, &fs.PathError{Op: "ReadDir", Path: dir, Err: errNotDir} } dirNode := overlay[dir] if dirNode == nil { return readDir(dir) } else if dirNode.isDeleted() { - return nil, &os.PathError{Op: "ReadDir", Path: dir, Err: os.ErrNotExist} + return nil, &fs.PathError{Op: "ReadDir", Path: dir, Err: fs.ErrNotExist} } diskfis, err := readDir(dir) if err != nil && !os.IsNotExist(err) && !errors.Is(err, errNotDir) { @@ -275,7 +276,7 @@ func ReadDir(dir string) ([]os.FileInfo, error) { } // Stat files in overlay to make composite list of fileinfos - files := make(map[string]os.FileInfo) + files := make(map[string]fs.FileInfo) for _, f := range diskfis { files[f.Name()] = f } @@ -327,14 +328,14 @@ func Open(path string) (*os.File, error) { cpath := canonicalize(path) if node, ok := overlay[cpath]; ok { if node.isDir() { - return nil, &os.PathError{Op: "Open", Path: path, Err: errors.New("fsys.Open doesn't support opening directories yet")} + return nil, &fs.PathError{Op: "Open", Path: path, Err: errors.New("fsys.Open doesn't support opening directories yet")} } return os.Open(node.actualFilePath) } else if parent, ok := parentIsOverlayFile(filepath.Dir(cpath)); ok { // The file is deleted explicitly in the Replace map, // or implicitly because one of its parent directories was // replaced by a file. - return nil, &os.PathError{ + return nil, &fs.PathError{ Op: "Open", Path: path, Err: fmt.Errorf("file %s does not exist: parent directory %s is replaced by a file in overlay", path, parent)} @@ -387,7 +388,7 @@ func IsDirWithGoFiles(dir string) (bool, error) { // walk recursively descends path, calling walkFn. Copied, with some // modifications from path/filepath.walk. -func walk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error { +func walk(path string, info fs.FileInfo, walkFn filepath.WalkFunc) error { if !info.IsDir() { return walkFn(path, info, nil) } @@ -432,11 +433,11 @@ func Walk(root string, walkFn filepath.WalkFunc) error { } // lstat implements a version of os.Lstat that operates on the overlay filesystem. -func lstat(path string) (os.FileInfo, error) { +func lstat(path string) (fs.FileInfo, error) { cpath := canonicalize(path) if _, ok := parentIsOverlayFile(filepath.Dir(cpath)); ok { - return nil, &os.PathError{Op: "lstat", Path: cpath, Err: os.ErrNotExist} + return nil, &fs.PathError{Op: "lstat", Path: cpath, Err: fs.ErrNotExist} } node, ok := overlay[cpath] @@ -447,7 +448,7 @@ func lstat(path string) (os.FileInfo, error) { switch { case node.isDeleted(): - return nil, &os.PathError{Op: "lstat", Path: cpath, Err: os.ErrNotExist} + return nil, &fs.PathError{Op: "lstat", Path: cpath, Err: fs.ErrNotExist} case node.isDir(): return fakeDir(filepath.Base(cpath)), nil default: @@ -459,22 +460,22 @@ func lstat(path string) (os.FileInfo, error) { } } -// fakeFile provides an os.FileInfo implementation for an overlaid file, +// fakeFile provides an fs.FileInfo implementation for an overlaid file, // so that the file has the name of the overlaid file, but takes all // other characteristics of the replacement file. type fakeFile struct { name string - real os.FileInfo + real fs.FileInfo } func (f fakeFile) Name() string { return f.name } func (f fakeFile) Size() int64 { return f.real.Size() } -func (f fakeFile) Mode() os.FileMode { return f.real.Mode() } +func (f fakeFile) Mode() fs.FileMode { return f.real.Mode() } func (f fakeFile) ModTime() time.Time { return f.real.ModTime() } func (f fakeFile) IsDir() bool { return f.real.IsDir() } func (f fakeFile) Sys() interface{} { return f.real.Sys() } -// missingFile provides an os.FileInfo for an overlaid file where the +// missingFile provides an fs.FileInfo for an overlaid file where the // destination file in the overlay doesn't exist. It returns zero values // for the fileInfo methods other than Name, set to the file's name, and Mode // set to ModeIrregular. @@ -482,19 +483,19 @@ type missingFile string func (f missingFile) Name() string { return string(f) } func (f missingFile) Size() int64 { return 0 } -func (f missingFile) Mode() os.FileMode { return os.ModeIrregular } +func (f missingFile) Mode() fs.FileMode { return fs.ModeIrregular } func (f missingFile) ModTime() time.Time { return time.Unix(0, 0) } func (f missingFile) IsDir() bool { return false } func (f missingFile) Sys() interface{} { return nil } -// fakeDir provides an os.FileInfo implementation for directories that are +// fakeDir provides an fs.FileInfo implementation for directories that are // implicitly created by overlaid files. Each directory in the // path of an overlaid file is considered to exist in the overlay filesystem. type fakeDir string func (f fakeDir) Name() string { return string(f) } func (f fakeDir) Size() int64 { return 0 } -func (f fakeDir) Mode() os.FileMode { return os.ModeDir | 0500 } +func (f fakeDir) Mode() fs.FileMode { return fs.ModeDir | 0500 } func (f fakeDir) ModTime() time.Time { return time.Unix(0, 0) } func (f fakeDir) IsDir() bool { return true } func (f fakeDir) Sys() interface{} { return nil } diff --git a/src/cmd/go/internal/fsys/fsys_test.go b/src/cmd/go/internal/fsys/fsys_test.go index 6cf59fba47..ba9f05d00b 100644 --- a/src/cmd/go/internal/fsys/fsys_test.go +++ b/src/cmd/go/internal/fsys/fsys_test.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "internal/testenv" + "io/fs" "io/ioutil" "os" "path/filepath" @@ -291,8 +292,8 @@ x _, gotErr := ReadDir(dir) if gotErr == nil { t.Errorf("ReadDir(%q): got no error, want error", dir) - } else if _, ok := gotErr.(*os.PathError); !ok { - t.Errorf("ReadDir(%q): got error with string %q and type %T, want os.PathError", dir, gotErr.Error(), gotErr) + } else if _, ok := gotErr.(*fs.PathError); !ok { + t.Errorf("ReadDir(%q): got error with string %q and type %T, want fs.PathError", dir, gotErr.Error(), gotErr) } } } @@ -489,7 +490,7 @@ func TestWalk(t *testing.T) { path string name string size int64 - mode os.FileMode + mode fs.FileMode isDir bool } testCases := []struct { @@ -504,7 +505,7 @@ func TestWalk(t *testing.T) { `, ".", []file{ - {".", "root", 0, os.ModeDir | 0700, true}, + {".", "root", 0, fs.ModeDir | 0700, true}, {"file.txt", "file.txt", 0, 0600, false}, }, }, @@ -520,7 +521,7 @@ contents of other file `, ".", []file{ - {".", "root", 0, os.ModeDir | 0500, true}, + {".", "root", 0, fs.ModeDir | 0500, true}, {"file.txt", "file.txt", 23, 0600, false}, {"other.txt", "other.txt", 23, 0600, false}, }, @@ -536,7 +537,7 @@ contents of other file `, ".", []file{ - {".", "root", 0, os.ModeDir | 0500, true}, + {".", "root", 0, fs.ModeDir | 0500, true}, {"file.txt", "file.txt", 23, 0600, false}, {"other.txt", "other.txt", 23, 0600, false}, }, @@ -552,8 +553,8 @@ contents of other file `, ".", []file{ - {".", "root", 0, os.ModeDir | 0500, true}, - {"dir", "dir", 0, os.ModeDir | 0500, true}, + {".", "root", 0, fs.ModeDir | 0500, true}, + {"dir", "dir", 0, fs.ModeDir | 0500, true}, {"dir" + string(filepath.Separator) + "file.txt", "file.txt", 23, 0600, false}, {"other.txt", "other.txt", 23, 0600, false}, }, @@ -565,7 +566,7 @@ contents of other file initOverlay(t, tc.overlay) var got []file - Walk(tc.root, func(path string, info os.FileInfo, err error) error { + Walk(tc.root, func(path string, info fs.FileInfo, err error) error { got = append(got, file{path, info.Name(), info.Size(), info.Mode(), info.IsDir()}) return nil }) @@ -580,8 +581,8 @@ contents of other file if got[i].name != tc.wantFiles[i].name { t.Errorf("name of file #%v in walk, got %q, want %q", i, got[i].name, tc.wantFiles[i].name) } - if got[i].mode&(os.ModeDir|0700) != tc.wantFiles[i].mode { - t.Errorf("mode&(os.ModeDir|0700) for mode of file #%v in walk, got %v, want %v", i, got[i].mode&(os.ModeDir|0700), tc.wantFiles[i].mode) + if got[i].mode&(fs.ModeDir|0700) != tc.wantFiles[i].mode { + t.Errorf("mode&(fs.ModeDir|0700) for mode of file #%v in walk, got %v, want %v", i, got[i].mode&(fs.ModeDir|0700), tc.wantFiles[i].mode) } if got[i].isDir != tc.wantFiles[i].isDir { t.Errorf("isDir for file #%v in walk, got %v, want %v", i, got[i].isDir, tc.wantFiles[i].isDir) @@ -610,7 +611,7 @@ func TestWalk_SkipDir(t *testing.T) { `) var seen []string - Walk(".", func(path string, info os.FileInfo, err error) error { + Walk(".", func(path string, info fs.FileInfo, err error) error { seen = append(seen, path) if path == "skipthisdir" || path == filepath.Join("dontskip", "skip") { return filepath.SkipDir @@ -635,7 +636,7 @@ func TestWalk_Error(t *testing.T) { initOverlay(t, "{}") alreadyCalled := false - err := Walk("foo", func(path string, info os.FileInfo, err error) error { + err := Walk("foo", func(path string, info fs.FileInfo, err error) error { if alreadyCalled { t.Fatal("expected walk function to be called exactly once, but it was called more than once") } @@ -683,7 +684,7 @@ func TestWalk_Symlink(t *testing.T) { t.Run(tc.name, func(t *testing.T) { var got []string - err := Walk(tc.dir, func(path string, info os.FileInfo, err error) error { + err := Walk(tc.dir, func(path string, info fs.FileInfo, err error) error { got = append(got, path) if err != nil { t.Errorf("walkfn: got non nil err argument: %v, want nil err argument", err) @@ -706,7 +707,7 @@ func TestLstat(t *testing.T) { type file struct { name string size int64 - mode os.FileMode // mode & (os.ModeDir|0x700): only check 'user' permissions + mode fs.FileMode // mode & (fs.ModeDir|0x700): only check 'user' permissions isDir bool } @@ -771,7 +772,7 @@ contents`, -- dir/foo.txt -- `, "dir", - file{"dir", 0, 0700 | os.ModeDir, true}, + file{"dir", 0, 0700 | fs.ModeDir, true}, false, }, { @@ -780,7 +781,7 @@ contents`, -- dummy.txt -- `, "dir", - file{"dir", 0, 0500 | os.ModeDir, true}, + file{"dir", 0, 0500 | fs.ModeDir, true}, false, }, } @@ -801,8 +802,8 @@ contents`, if got.Name() != tc.want.name { t.Errorf("lstat(%q).Name(): got %q, want %q", tc.path, got.Name(), tc.want.name) } - if got.Mode()&(os.ModeDir|0700) != tc.want.mode { - t.Errorf("lstat(%q).Mode()&(os.ModeDir|0700): got %v, want %v", tc.path, got.Mode()&(os.ModeDir|0700), tc.want.mode) + if got.Mode()&(fs.ModeDir|0700) != tc.want.mode { + t.Errorf("lstat(%q).Mode()&(fs.ModeDir|0700): got %v, want %v", tc.path, got.Mode()&(fs.ModeDir|0700), tc.want.mode) } if got.IsDir() != tc.want.isDir { t.Errorf("lstat(%q).IsDir(): got %v, want %v", tc.path, got.IsDir(), tc.want.isDir) diff --git a/src/cmd/go/internal/imports/scan.go b/src/cmd/go/internal/imports/scan.go index 42ee49aaaa..d45393f36c 100644 --- a/src/cmd/go/internal/imports/scan.go +++ b/src/cmd/go/internal/imports/scan.go @@ -6,6 +6,7 @@ package imports import ( "fmt" + "io/fs" "os" "path/filepath" "sort" @@ -26,7 +27,7 @@ func ScanDir(dir string, tags map[string]bool) ([]string, []string, error) { // If the directory entry is a symlink, stat it to obtain the info for the // link target instead of the link itself. - if info.Mode()&os.ModeSymlink != 0 { + if info.Mode()&fs.ModeSymlink != 0 { info, err = os.Stat(filepath.Join(dir, name)) if err != nil { continue // Ignore broken symlinks. diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index f73b79d089..066ff6c981 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -14,6 +14,7 @@ import ( "go/build" "go/scanner" "go/token" + "io/fs" "io/ioutil" "os" pathpkg "path" @@ -2300,7 +2301,7 @@ func GoFilesPackage(ctx context.Context, gofiles []string) *Package { // to make it look like this is a standard package or // command directory. So that local imports resolve // consistently, the files must all be in the same directory. - var dirent []os.FileInfo + var dirent []fs.FileInfo var dir string for _, file := range gofiles { fi, err := os.Stat(file) @@ -2321,7 +2322,7 @@ func GoFilesPackage(ctx context.Context, gofiles []string) *Package { } dirent = append(dirent, fi) } - ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil } + ctxt.ReadDir = func(string) ([]fs.FileInfo, error) { return dirent, nil } if cfg.ModulesEnabled { modload.ImportFromFiles(ctx, gofiles) diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock.go index aba3eed776..05f27c321a 100644 --- a/src/cmd/go/internal/lockedfile/internal/filelock/filelock.go +++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock.go @@ -9,6 +9,7 @@ package filelock import ( "errors" + "io/fs" "os" ) @@ -24,7 +25,7 @@ type File interface { Fd() uintptr // Stat returns the FileInfo structure describing file. - Stat() (os.FileInfo, error) + Stat() (fs.FileInfo, error) } // Lock places an advisory write lock on the file, blocking until it can be @@ -87,7 +88,7 @@ var ErrNotSupported = errors.New("operation not supported") // underlyingError returns the underlying error for known os error types. func underlyingError(err error) error { switch err := err.(type) { - case *os.PathError: + case *fs.PathError: return err.Err case *os.LinkError: return err.Err diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go index 8776c5741c..1fa4327a89 100644 --- a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go +++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_fcntl.go @@ -18,8 +18,8 @@ package filelock import ( "errors" "io" + "io/fs" "math/rand" - "os" "sync" "syscall" "time" @@ -61,7 +61,7 @@ func lock(f File, lt lockType) (err error) { mu.Lock() if i, dup := inodes[f]; dup && i != ino { mu.Unlock() - return &os.PathError{ + return &fs.PathError{ Op: lt.String(), Path: f.Name(), Err: errors.New("inode for file changed since last Lock or RLock"), @@ -152,7 +152,7 @@ func lock(f File, lt lockType) (err error) { if err != nil { unlock(f) - return &os.PathError{ + return &fs.PathError{ Op: lt.String(), Path: f.Name(), Err: err, diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_other.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_other.go index 107611e1ce..bc480343fc 100644 --- a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_other.go +++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_other.go @@ -6,7 +6,7 @@ package filelock -import "os" +import "io/fs" type lockType int8 @@ -16,7 +16,7 @@ const ( ) func lock(f File, lt lockType) error { - return &os.PathError{ + return &fs.PathError{ Op: lt.String(), Path: f.Name(), Err: ErrNotSupported, @@ -24,7 +24,7 @@ func lock(f File, lt lockType) error { } func unlock(f File) error { - return &os.PathError{ + return &fs.PathError{ Op: "Unlock", Path: f.Name(), Err: ErrNotSupported, diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_plan9.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_plan9.go index afdffe323f..0798ee469a 100644 --- a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_plan9.go +++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_plan9.go @@ -6,9 +6,7 @@ package filelock -import ( - "os" -) +import "io/fs" type lockType int8 @@ -18,7 +16,7 @@ const ( ) func lock(f File, lt lockType) error { - return &os.PathError{ + return &fs.PathError{ Op: lt.String(), Path: f.Name(), Err: ErrNotSupported, @@ -26,7 +24,7 @@ func lock(f File, lt lockType) error { } func unlock(f File) error { - return &os.PathError{ + return &fs.PathError{ Op: "Unlock", Path: f.Name(), Err: ErrNotSupported, diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_unix.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_unix.go index 78f2c51129..ed07bac608 100644 --- a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_unix.go +++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_unix.go @@ -7,7 +7,7 @@ package filelock import ( - "os" + "io/fs" "syscall" ) @@ -26,7 +26,7 @@ func lock(f File, lt lockType) (err error) { } } if err != nil { - return &os.PathError{ + return &fs.PathError{ Op: lt.String(), Path: f.Name(), Err: err, diff --git a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_windows.go b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_windows.go index 43e85e450e..19de27eb9b 100644 --- a/src/cmd/go/internal/lockedfile/internal/filelock/filelock_windows.go +++ b/src/cmd/go/internal/lockedfile/internal/filelock/filelock_windows.go @@ -8,7 +8,7 @@ package filelock import ( "internal/syscall/windows" - "os" + "io/fs" "syscall" ) @@ -34,7 +34,7 @@ func lock(f File, lt lockType) error { err := windows.LockFileEx(syscall.Handle(f.Fd()), uint32(lt), reserved, allBytes, allBytes, ol) if err != nil { - return &os.PathError{ + return &fs.PathError{ Op: lt.String(), Path: f.Name(), Err: err, @@ -47,7 +47,7 @@ func unlock(f File) error { ol := new(syscall.Overlapped) err := windows.UnlockFileEx(syscall.Handle(f.Fd()), reserved, allBytes, allBytes, ol) if err != nil { - return &os.PathError{ + return &fs.PathError{ Op: "Unlock", Path: f.Name(), Err: err, diff --git a/src/cmd/go/internal/lockedfile/lockedfile.go b/src/cmd/go/internal/lockedfile/lockedfile.go index 59b2dba44c..503024da4b 100644 --- a/src/cmd/go/internal/lockedfile/lockedfile.go +++ b/src/cmd/go/internal/lockedfile/lockedfile.go @@ -9,6 +9,7 @@ package lockedfile import ( "fmt" "io" + "io/fs" "io/ioutil" "os" "runtime" @@ -35,7 +36,7 @@ type osFile struct { // OpenFile is like os.OpenFile, but returns a locked file. // If flag includes os.O_WRONLY or os.O_RDWR, the file is write-locked; // otherwise, it is read-locked. -func OpenFile(name string, flag int, perm os.FileMode) (*File, error) { +func OpenFile(name string, flag int, perm fs.FileMode) (*File, error) { var ( f = new(File) err error @@ -82,10 +83,10 @@ func Edit(name string) (*File, error) { // non-nil error. func (f *File) Close() error { if f.closed { - return &os.PathError{ + return &fs.PathError{ Op: "close", Path: f.Name(), - Err: os.ErrClosed, + Err: fs.ErrClosed, } } f.closed = true @@ -108,7 +109,7 @@ func Read(name string) ([]byte, error) { // Write opens the named file (creating it with the given permissions if needed), // then write-locks it and overwrites it with the given content. -func Write(name string, content io.Reader, perm os.FileMode) (err error) { +func Write(name string, content io.Reader, perm fs.FileMode) (err error) { f, err := OpenFile(name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) if err != nil { return err diff --git a/src/cmd/go/internal/lockedfile/lockedfile_filelock.go b/src/cmd/go/internal/lockedfile/lockedfile_filelock.go index f63dd8664b..10e1240efd 100644 --- a/src/cmd/go/internal/lockedfile/lockedfile_filelock.go +++ b/src/cmd/go/internal/lockedfile/lockedfile_filelock.go @@ -7,12 +7,13 @@ package lockedfile import ( + "io/fs" "os" "cmd/go/internal/lockedfile/internal/filelock" ) -func openFile(name string, flag int, perm os.FileMode) (*os.File, error) { +func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) { // On BSD systems, we could add the O_SHLOCK or O_EXLOCK flag to the OpenFile // call instead of locking separately, but we have to support separate locking // calls for Linux and Windows anyway, so it's simpler to use that approach diff --git a/src/cmd/go/internal/lockedfile/lockedfile_plan9.go b/src/cmd/go/internal/lockedfile/lockedfile_plan9.go index 4a52c94976..51681381d7 100644 --- a/src/cmd/go/internal/lockedfile/lockedfile_plan9.go +++ b/src/cmd/go/internal/lockedfile/lockedfile_plan9.go @@ -7,6 +7,7 @@ package lockedfile import ( + "io/fs" "math/rand" "os" "strings" @@ -41,7 +42,7 @@ func isLocked(err error) bool { return false } -func openFile(name string, flag int, perm os.FileMode) (*os.File, error) { +func openFile(name string, flag int, perm fs.FileMode) (*os.File, error) { // Plan 9 uses a mode bit instead of explicit lock/unlock syscalls. // // Per http://man.cat-v.org/plan_9/5/stat: “Exclusive use files may be open @@ -56,8 +57,8 @@ func openFile(name string, flag int, perm os.FileMode) (*os.File, error) { // have the ModeExclusive bit set. Set it before we call OpenFile, so that we // can be confident that a successful OpenFile implies exclusive use. if fi, err := os.Stat(name); err == nil { - if fi.Mode()&os.ModeExclusive == 0 { - if err := os.Chmod(name, fi.Mode()|os.ModeExclusive); err != nil { + if fi.Mode()&fs.ModeExclusive == 0 { + if err := os.Chmod(name, fi.Mode()|fs.ModeExclusive); err != nil { return nil, err } } @@ -68,7 +69,7 @@ func openFile(name string, flag int, perm os.FileMode) (*os.File, error) { nextSleep := 1 * time.Millisecond const maxSleep = 500 * time.Millisecond for { - f, err := os.OpenFile(name, flag, perm|os.ModeExclusive) + f, err := os.OpenFile(name, flag, perm|fs.ModeExclusive) if err == nil { return f, nil } diff --git a/src/cmd/go/internal/modcmd/vendor.go b/src/cmd/go/internal/modcmd/vendor.go index 1bc4ab3def..1b9ce60529 100644 --- a/src/cmd/go/internal/modcmd/vendor.go +++ b/src/cmd/go/internal/modcmd/vendor.go @@ -9,6 +9,7 @@ import ( "context" "fmt" "io" + "io/fs" "io/ioutil" "os" "path/filepath" @@ -232,7 +233,7 @@ var metaPrefixes = []string{ } // matchMetadata reports whether info is a metadata file. -func matchMetadata(dir string, info os.FileInfo) bool { +func matchMetadata(dir string, info fs.FileInfo) bool { name := info.Name() for _, p := range metaPrefixes { if strings.HasPrefix(name, p) { @@ -243,7 +244,7 @@ func matchMetadata(dir string, info os.FileInfo) bool { } // matchPotentialSourceFile reports whether info may be relevant to a build operation. -func matchPotentialSourceFile(dir string, info os.FileInfo) bool { +func matchPotentialSourceFile(dir string, info fs.FileInfo) bool { if strings.HasSuffix(info.Name(), "_test.go") { return false } @@ -269,7 +270,7 @@ func matchPotentialSourceFile(dir string, info os.FileInfo) bool { } // copyDir copies all regular files satisfying match(info) from src to dst. -func copyDir(dst, src string, match func(dir string, info os.FileInfo) bool) { +func copyDir(dst, src string, match func(dir string, info fs.FileInfo) bool) { files, err := ioutil.ReadDir(src) if err != nil { base.Fatalf("go mod vendor: %v", err) diff --git a/src/cmd/go/internal/modcmd/verify.go b/src/cmd/go/internal/modcmd/verify.go index bd591d3f32..ce24793929 100644 --- a/src/cmd/go/internal/modcmd/verify.go +++ b/src/cmd/go/internal/modcmd/verify.go @@ -9,6 +9,7 @@ import ( "context" "errors" "fmt" + "io/fs" "io/ioutil" "os" "runtime" @@ -88,8 +89,8 @@ func verifyMod(mod module.Version) []error { dir, dirErr := modfetch.DownloadDir(mod) data, err := ioutil.ReadFile(zip + "hash") if err != nil { - if zipErr != nil && errors.Is(zipErr, os.ErrNotExist) && - dirErr != nil && errors.Is(dirErr, os.ErrNotExist) { + if zipErr != nil && errors.Is(zipErr, fs.ErrNotExist) && + dirErr != nil && errors.Is(dirErr, fs.ErrNotExist) { // Nothing downloaded yet. Nothing to verify. return nil } @@ -98,7 +99,7 @@ func verifyMod(mod module.Version) []error { } h := string(bytes.TrimSpace(data)) - if zipErr != nil && errors.Is(zipErr, os.ErrNotExist) { + if zipErr != nil && errors.Is(zipErr, fs.ErrNotExist) { // ok } else { hZ, err := dirhash.HashZip(zip, dirhash.DefaultHash) @@ -109,7 +110,7 @@ func verifyMod(mod module.Version) []error { errs = append(errs, fmt.Errorf("%s %s: zip has been modified (%v)", mod.Path, mod.Version, zip)) } } - if dirErr != nil && errors.Is(dirErr, os.ErrNotExist) { + if dirErr != nil && errors.Is(dirErr, fs.ErrNotExist) { // ok } else { hD, err := dirhash.HashDir(dir, mod.Path+"@"+mod.Version, dirhash.DefaultHash) diff --git a/src/cmd/go/internal/modfetch/cache.go b/src/cmd/go/internal/modfetch/cache.go index 6eadb026c9..b7aa670250 100644 --- a/src/cmd/go/internal/modfetch/cache.go +++ b/src/cmd/go/internal/modfetch/cache.go @@ -10,6 +10,7 @@ import ( "errors" "fmt" "io" + "io/fs" "io/ioutil" "os" "path/filepath" @@ -60,7 +61,7 @@ func CachePath(m module.Version, suffix string) (string, error) { // DownloadDir returns the directory to which m should have been downloaded. // An error will be returned if the module path or version cannot be escaped. -// An error satisfying errors.Is(err, os.ErrNotExist) will be returned +// An error satisfying errors.Is(err, fs.ErrNotExist) will be returned // along with the directory if the directory does not exist or if the directory // is not completely populated. func DownloadDir(m module.Version) (string, error) { @@ -107,14 +108,14 @@ func DownloadDir(m module.Version) (string, error) { // DownloadDirPartialError is returned by DownloadDir if a module directory // exists but was not completely populated. // -// DownloadDirPartialError is equivalent to os.ErrNotExist. +// DownloadDirPartialError is equivalent to fs.ErrNotExist. type DownloadDirPartialError struct { Dir string Err error } func (e *DownloadDirPartialError) Error() string { return fmt.Sprintf("%s: %v", e.Dir, e.Err) } -func (e *DownloadDirPartialError) Is(err error) bool { return err == os.ErrNotExist } +func (e *DownloadDirPartialError) Is(err error) bool { return err == fs.ErrNotExist } // lockVersion locks a file within the module cache that guards the downloading // and extraction of the zipfile for the given module version. diff --git a/src/cmd/go/internal/modfetch/codehost/codehost.go b/src/cmd/go/internal/modfetch/codehost/codehost.go index df4cfdab1a..c5fbb31b2b 100644 --- a/src/cmd/go/internal/modfetch/codehost/codehost.go +++ b/src/cmd/go/internal/modfetch/codehost/codehost.go @@ -11,6 +11,7 @@ import ( "crypto/sha256" "fmt" "io" + "io/fs" "io/ioutil" "os" "os/exec" @@ -105,7 +106,7 @@ type FileRev struct { Err error // error if any; os.IsNotExist(Err)==true if rev exists but file does not exist in that rev } -// UnknownRevisionError is an error equivalent to os.ErrNotExist, but for a +// UnknownRevisionError is an error equivalent to fs.ErrNotExist, but for a // revision rather than a file. type UnknownRevisionError struct { Rev string @@ -115,10 +116,10 @@ func (e *UnknownRevisionError) Error() string { return "unknown revision " + e.Rev } func (UnknownRevisionError) Is(err error) bool { - return err == os.ErrNotExist + return err == fs.ErrNotExist } -// ErrNoCommits is an error equivalent to os.ErrNotExist indicating that a given +// ErrNoCommits is an error equivalent to fs.ErrNotExist indicating that a given // repository or module contains no commits. var ErrNoCommits error = noCommitsError{} @@ -128,7 +129,7 @@ func (noCommitsError) Error() string { return "no commits" } func (noCommitsError) Is(err error) bool { - return err == os.ErrNotExist + return err == fs.ErrNotExist } // AllHex reports whether the revision rev is entirely lower-case hexadecimal digits. diff --git a/src/cmd/go/internal/modfetch/codehost/git.go b/src/cmd/go/internal/modfetch/codehost/git.go index 5a35829c98..58b4b2f2d3 100644 --- a/src/cmd/go/internal/modfetch/codehost/git.go +++ b/src/cmd/go/internal/modfetch/codehost/git.go @@ -9,6 +9,7 @@ import ( "errors" "fmt" "io" + "io/fs" "io/ioutil" "net/url" "os" @@ -34,13 +35,13 @@ func LocalGitRepo(remote string) (Repo, error) { } // A notExistError wraps another error to retain its original text -// but makes it opaquely equivalent to os.ErrNotExist. +// but makes it opaquely equivalent to fs.ErrNotExist. type notExistError struct { err error } func (e notExistError) Error() string { return e.err.Error() } -func (notExistError) Is(err error) bool { return err == os.ErrNotExist } +func (notExistError) Is(err error) bool { return err == fs.ErrNotExist } const gitWorkDirType = "git3" @@ -188,7 +189,7 @@ func (r *gitRepo) loadRefs() { // For HTTP and HTTPS, that's easy to detect: we'll try to fetch the URL // ourselves and see what code it serves. if u, err := url.Parse(r.remoteURL); err == nil && (u.Scheme == "http" || u.Scheme == "https") { - if _, err := web.GetBytes(u); errors.Is(err, os.ErrNotExist) { + if _, err := web.GetBytes(u); errors.Is(err, fs.ErrNotExist) { gitErr = notExistError{gitErr} } } @@ -505,7 +506,7 @@ func (r *gitRepo) ReadFile(rev, file string, maxSize int64) ([]byte, error) { } out, err := Run(r.dir, "git", "cat-file", "blob", info.Name+":"+file) if err != nil { - return nil, os.ErrNotExist + return nil, fs.ErrNotExist } return out, nil } @@ -629,9 +630,9 @@ func (r *gitRepo) readFileRevs(tags []string, file string, fileMap map[string]*F case "tag", "commit": switch fileType { default: - f.Err = &os.PathError{Path: tag + ":" + file, Op: "read", Err: fmt.Errorf("unexpected non-blob type %q", fileType)} + f.Err = &fs.PathError{Path: tag + ":" + file, Op: "read", Err: fmt.Errorf("unexpected non-blob type %q", fileType)} case "missing": - f.Err = &os.PathError{Path: tag + ":" + file, Op: "read", Err: os.ErrNotExist} + f.Err = &fs.PathError{Path: tag + ":" + file, Op: "read", Err: fs.ErrNotExist} case "blob": f.Data = fileData } @@ -826,7 +827,7 @@ func (r *gitRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser, archive, err := Run(r.dir, "git", "-c", "core.autocrlf=input", "-c", "core.eol=lf", "archive", "--format=zip", "--prefix=prefix/", info.Name, args) if err != nil { if bytes.Contains(err.(*RunError).Stderr, []byte("did not match any files")) { - return nil, os.ErrNotExist + return nil, fs.ErrNotExist } return nil, err } diff --git a/src/cmd/go/internal/modfetch/codehost/git_test.go b/src/cmd/go/internal/modfetch/codehost/git_test.go index ba27c70f5a..16908b3e84 100644 --- a/src/cmd/go/internal/modfetch/codehost/git_test.go +++ b/src/cmd/go/internal/modfetch/codehost/git_test.go @@ -10,6 +10,7 @@ import ( "flag" "fmt" "internal/testenv" + "io/fs" "io/ioutil" "log" "os" @@ -210,7 +211,7 @@ var readFileTests = []struct { repo: gitrepo1, rev: "v2.3.4", file: "another.txt", - err: os.ErrNotExist.Error(), + err: fs.ErrNotExist.Error(), }, } diff --git a/src/cmd/go/internal/modfetch/codehost/vcs.go b/src/cmd/go/internal/modfetch/codehost/vcs.go index 6278cb21e1..ec97fc7e1b 100644 --- a/src/cmd/go/internal/modfetch/codehost/vcs.go +++ b/src/cmd/go/internal/modfetch/codehost/vcs.go @@ -9,6 +9,7 @@ import ( "fmt" "internal/lazyregexp" "io" + "io/fs" "io/ioutil" "os" "path/filepath" @@ -377,7 +378,7 @@ func (r *vcsRepo) ReadFile(rev, file string, maxSize int64) ([]byte, error) { out, err := Run(r.dir, r.cmd.readFile(rev, file, r.remote)) if err != nil { - return nil, os.ErrNotExist + return nil, fs.ErrNotExist } return out, nil } diff --git a/src/cmd/go/internal/modfetch/coderepo.go b/src/cmd/go/internal/modfetch/coderepo.go index d99a31d360..7f44e18a70 100644 --- a/src/cmd/go/internal/modfetch/coderepo.go +++ b/src/cmd/go/internal/modfetch/coderepo.go @@ -10,6 +10,7 @@ import ( "errors" "fmt" "io" + "io/fs" "io/ioutil" "os" "path" @@ -1040,7 +1041,7 @@ type zipFile struct { } func (f zipFile) Path() string { return f.name } -func (f zipFile) Lstat() (os.FileInfo, error) { return f.f.FileInfo(), nil } +func (f zipFile) Lstat() (fs.FileInfo, error) { return f.f.FileInfo(), nil } func (f zipFile) Open() (io.ReadCloser, error) { return f.f.Open() } type dataFile struct { @@ -1049,7 +1050,7 @@ type dataFile struct { } func (f dataFile) Path() string { return f.name } -func (f dataFile) Lstat() (os.FileInfo, error) { return dataFileInfo{f}, nil } +func (f dataFile) Lstat() (fs.FileInfo, error) { return dataFileInfo{f}, nil } func (f dataFile) Open() (io.ReadCloser, error) { return ioutil.NopCloser(bytes.NewReader(f.data)), nil } @@ -1060,7 +1061,7 @@ type dataFileInfo struct { func (fi dataFileInfo) Name() string { return path.Base(fi.f.name) } func (fi dataFileInfo) Size() int64 { return int64(len(fi.f.data)) } -func (fi dataFileInfo) Mode() os.FileMode { return 0644 } +func (fi dataFileInfo) Mode() fs.FileMode { return 0644 } func (fi dataFileInfo) ModTime() time.Time { return time.Time{} } func (fi dataFileInfo) IsDir() bool { return false } func (fi dataFileInfo) Sys() interface{} { return nil } diff --git a/src/cmd/go/internal/modfetch/fetch.go b/src/cmd/go/internal/modfetch/fetch.go index 599419977a..6ff455e89c 100644 --- a/src/cmd/go/internal/modfetch/fetch.go +++ b/src/cmd/go/internal/modfetch/fetch.go @@ -11,6 +11,7 @@ import ( "errors" "fmt" "io" + "io/fs" "io/ioutil" "os" "path/filepath" @@ -67,7 +68,7 @@ func download(ctx context.Context, mod module.Version) (dir string, err error) { if err == nil { // The directory has already been completely extracted (no .partial file exists). return dir, nil - } else if dir == "" || !errors.Is(err, os.ErrNotExist) { + } else if dir == "" || !errors.Is(err, fs.ErrNotExist) { return "", err } @@ -314,10 +315,10 @@ func downloadZip(ctx context.Context, mod module.Version, zipfile string) (err e func makeDirsReadOnly(dir string) { type pathMode struct { path string - mode os.FileMode + mode fs.FileMode } var dirs []pathMode // in lexical order - filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error { if err == nil && info.Mode()&0222 != 0 { if info.IsDir() { dirs = append(dirs, pathMode{path, info.Mode()}) @@ -336,7 +337,7 @@ func makeDirsReadOnly(dir string) { // any permission changes needed to do so. func RemoveAll(dir string) error { // Module cache has 0555 directories; make them writable in order to remove content. - filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error { if err != nil { return nil // ignore errors walking in file system } @@ -441,7 +442,7 @@ func checkMod(mod module.Version) { } data, err := renameio.ReadFile(ziphash) if err != nil { - if errors.Is(err, os.ErrNotExist) { + if errors.Is(err, fs.ErrNotExist) { // This can happen if someone does rm -rf GOPATH/src/cache/download. So it goes. return } diff --git a/src/cmd/go/internal/modfetch/proxy.go b/src/cmd/go/internal/modfetch/proxy.go index 4ac26650a9..819990b403 100644 --- a/src/cmd/go/internal/modfetch/proxy.go +++ b/src/cmd/go/internal/modfetch/proxy.go @@ -9,9 +9,9 @@ import ( "errors" "fmt" "io" + "io/fs" "io/ioutil" "net/url" - "os" "path" pathpkg "path" "path/filepath" @@ -186,7 +186,7 @@ func proxyList() ([]proxySpec, error) { // TryProxies iterates f over each configured proxy (including "noproxy" and // "direct" if applicable) until f returns no error or until f returns an -// error that is not equivalent to os.ErrNotExist on a proxy configured +// error that is not equivalent to fs.ErrNotExist on a proxy configured // not to fall back on errors. // // TryProxies then returns that final error. @@ -222,7 +222,7 @@ func TryProxies(f func(proxy string) error) error { if err == nil { return nil } - isNotExistErr := errors.Is(err, os.ErrNotExist) + isNotExistErr := errors.Is(err, fs.ErrNotExist) if proxy.url == "direct" || (proxy.url == "noproxy" && err != errUseProxy) { bestErr = err @@ -428,7 +428,7 @@ func (p *proxyRepo) Stat(rev string) (*RevInfo, error) { func (p *proxyRepo) Latest() (*RevInfo, error) { data, err := p.getBytes("@latest") if err != nil { - if !errors.Is(err, os.ErrNotExist) { + if !errors.Is(err, fs.ErrNotExist) { return nil, p.versionError("", err) } return p.latest() diff --git a/src/cmd/go/internal/modfetch/repo.go b/src/cmd/go/internal/modfetch/repo.go index c7cf5595bd..af9e24cefd 100644 --- a/src/cmd/go/internal/modfetch/repo.go +++ b/src/cmd/go/internal/modfetch/repo.go @@ -7,6 +7,7 @@ package modfetch import ( "fmt" "io" + "io/fs" "os" "sort" "strconv" @@ -432,7 +433,7 @@ func (r errRepo) Latest() (*RevInfo, error) { return nil func (r errRepo) GoMod(version string) ([]byte, error) { return nil, r.err } func (r errRepo) Zip(dst io.Writer, version string) error { return r.err } -// A notExistError is like os.ErrNotExist, but with a custom message +// A notExistError is like fs.ErrNotExist, but with a custom message type notExistError struct { err error } @@ -446,7 +447,7 @@ func (e notExistError) Error() string { } func (notExistError) Is(target error) bool { - return target == os.ErrNotExist + return target == fs.ErrNotExist } func (e notExistError) Unwrap() error { diff --git a/src/cmd/go/internal/modfetch/sumdb.go b/src/cmd/go/internal/modfetch/sumdb.go index 47a2571531..5108961a33 100644 --- a/src/cmd/go/internal/modfetch/sumdb.go +++ b/src/cmd/go/internal/modfetch/sumdb.go @@ -12,6 +12,7 @@ import ( "bytes" "errors" "fmt" + "io/fs" "io/ioutil" "net/url" "os" @@ -182,7 +183,7 @@ func (c *dbClient) initBase() { return nil } }) - if errors.Is(err, os.ErrNotExist) { + if errors.Is(err, fs.ErrNotExist) { // No proxies, or all proxies failed (with 404, 410, or were were allowed // to fall back), or we reached an explicit "direct" or "off". c.base = c.direct @@ -203,7 +204,7 @@ func (c *dbClient) ReadConfig(file string) (data []byte, err error) { } targ := filepath.Join(cfg.SumdbDir, file) data, err = lockedfile.Read(targ) - if errors.Is(err, os.ErrNotExist) { + if errors.Is(err, fs.ErrNotExist) { // Treat non-existent as empty, to bootstrap the "latest" file // the first time we connect to a given database. return []byte{}, nil @@ -257,7 +258,7 @@ func (*dbClient) ReadCache(file string) ([]byte, error) { // during which the empty file can be locked for reading. // Treat observing an empty file as file not found. if err == nil && len(data) == 0 { - err = &os.PathError{Op: "read", Path: targ, Err: os.ErrNotExist} + err = &fs.PathError{Op: "read", Path: targ, Err: fs.ErrNotExist} } return data, err } diff --git a/src/cmd/go/internal/modload/import.go b/src/cmd/go/internal/modload/import.go index 6d0d8de944..bcbc9b0c3a 100644 --- a/src/cmd/go/internal/modload/import.go +++ b/src/cmd/go/internal/modload/import.go @@ -10,6 +10,7 @@ import ( "fmt" "go/build" "internal/goroot" + "io/fs" "os" "path/filepath" "sort" @@ -347,7 +348,7 @@ func queryImport(ctx context.Context, path string) (module.Version, error) { candidates, err := QueryPattern(ctx, path, "latest", Selected, CheckAllowed) if err != nil { - if errors.Is(err, os.ErrNotExist) { + if errors.Is(err, fs.ErrNotExist) { // Return "cannot find module providing package […]" instead of whatever // low-level error QueryPattern produced. return module.Version{}, &ImportMissingError{Path: path, QueryErr: err} diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go index 4ddb817cf1..4b3ded8326 100644 --- a/src/cmd/go/internal/modload/load.go +++ b/src/cmd/go/internal/modload/load.go @@ -98,6 +98,7 @@ import ( "errors" "fmt" "go/build" + "io/fs" "os" "path" pathpkg "path" @@ -364,7 +365,7 @@ func resolveLocalPackage(dir string) (string, error) { if os.IsNotExist(err) { // Canonicalize OS-specific errors to errDirectoryNotFound so that error // messages will be easier for users to search for. - return "", &os.PathError{Op: "stat", Path: absDir, Err: errDirectoryNotFound} + return "", &fs.PathError{Op: "stat", Path: absDir, Err: errDirectoryNotFound} } return "", err } diff --git a/src/cmd/go/internal/modload/query.go b/src/cmd/go/internal/modload/query.go index 3b27e66d01..6b14768388 100644 --- a/src/cmd/go/internal/modload/query.go +++ b/src/cmd/go/internal/modload/query.go @@ -8,6 +8,7 @@ import ( "context" "errors" "fmt" + "io/fs" "os" pathpkg "path" "path/filepath" @@ -145,7 +146,7 @@ func queryProxy(ctx context.Context, proxy, path, query, current string, allowed canonicalQuery := module.CanonicalVersion(query) if canonicalQuery != "" && query != canonicalQuery { info, err = repo.Stat(canonicalQuery) - if err != nil && !errors.Is(err, os.ErrNotExist) { + if err != nil && !errors.Is(err, fs.ErrNotExist) { return info, err } } @@ -230,7 +231,7 @@ func queryProxy(ctx context.Context, proxy, path, query, current string, allowed if qm.allowsVersion(ctx, latest.Version) { return lookup(latest.Version) } - } else if !errors.Is(err, os.ErrNotExist) { + } else if !errors.Is(err, fs.ErrNotExist) { return nil, err } } @@ -701,7 +702,7 @@ func queryPrefixModules(ctx context.Context, candidateModules []string, queryMod noVersion = rErr } default: - if errors.Is(rErr, os.ErrNotExist) { + if errors.Is(rErr, fs.ErrNotExist) { if notExistErr == nil { notExistErr = rErr } @@ -744,7 +745,7 @@ func queryPrefixModules(ctx context.Context, candidateModules []string, queryMod // A NoMatchingVersionError indicates that Query found a module at the requested // path, but not at any versions satisfying the query string and allow-function. // -// NOTE: NoMatchingVersionError MUST NOT implement Is(os.ErrNotExist). +// NOTE: NoMatchingVersionError MUST NOT implement Is(fs.ErrNotExist). // // If the module came from a proxy, that proxy had to return a successful status // code for the versions it knows about, and thus did not have the opportunity @@ -765,7 +766,7 @@ func (e *NoMatchingVersionError) Error() string { // module at the requested version, but that module did not contain any packages // matching the requested pattern. // -// NOTE: PackageNotInModuleError MUST NOT implement Is(os.ErrNotExist). +// NOTE: PackageNotInModuleError MUST NOT implement Is(fs.ErrNotExist). // // If the module came from a proxy, that proxy had to return a successful status // code for the versions it knows about, and thus did not have the opportunity diff --git a/src/cmd/go/internal/modload/search.go b/src/cmd/go/internal/modload/search.go index 0f82026732..19289ceb9c 100644 --- a/src/cmd/go/internal/modload/search.go +++ b/src/cmd/go/internal/modload/search.go @@ -7,6 +7,7 @@ package modload import ( "context" "fmt" + "io/fs" "os" "path/filepath" "strings" @@ -54,7 +55,7 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f walkPkgs := func(root, importPathRoot string, prune pruning) { root = filepath.Clean(root) - err := fsys.Walk(root, func(path string, fi os.FileInfo, err error) error { + err := fsys.Walk(root, func(path string, fi fs.FileInfo, err error) error { if err != nil { m.AddError(err) return nil @@ -85,7 +86,7 @@ func matchPackages(ctx context.Context, m *search.Match, tags map[string]bool, f } if !fi.IsDir() { - if fi.Mode()&os.ModeSymlink != 0 && want { + if fi.Mode()&fs.ModeSymlink != 0 && want { if target, err := os.Stat(path); err == nil && target.IsDir() { fmt.Fprintf(os.Stderr, "warning: ignoring symlink %s\n", path) } diff --git a/src/cmd/go/internal/modload/stat_openfile.go b/src/cmd/go/internal/modload/stat_openfile.go index 931aaf1577..7cdeaf47a2 100644 --- a/src/cmd/go/internal/modload/stat_openfile.go +++ b/src/cmd/go/internal/modload/stat_openfile.go @@ -13,12 +13,13 @@ package modload import ( + "io/fs" "os" ) // hasWritePerm reports whether the current user has permission to write to the // file with the given info. -func hasWritePerm(path string, _ os.FileInfo) bool { +func hasWritePerm(path string, _ fs.FileInfo) bool { if f, err := os.OpenFile(path, os.O_WRONLY, 0); err == nil { f.Close() return true diff --git a/src/cmd/go/internal/modload/stat_unix.go b/src/cmd/go/internal/modload/stat_unix.go index ea3b801f2c..65068444d0 100644 --- a/src/cmd/go/internal/modload/stat_unix.go +++ b/src/cmd/go/internal/modload/stat_unix.go @@ -7,6 +7,7 @@ package modload import ( + "io/fs" "os" "syscall" ) @@ -17,7 +18,7 @@ import ( // Although the root user on most Unix systems can write to files even without // permission, hasWritePerm reports false if no appropriate permission bit is // set even if the current user is root. -func hasWritePerm(path string, fi os.FileInfo) bool { +func hasWritePerm(path string, fi fs.FileInfo) bool { if os.Getuid() == 0 { // The root user can access any file, but we still want to default to // read-only mode if the go.mod file is marked as globally non-writable. diff --git a/src/cmd/go/internal/modload/stat_windows.go b/src/cmd/go/internal/modload/stat_windows.go index d7826cfc6b..0ac2391347 100644 --- a/src/cmd/go/internal/modload/stat_windows.go +++ b/src/cmd/go/internal/modload/stat_windows.go @@ -6,13 +6,11 @@ package modload -import ( - "os" -) +import "io/fs" // hasWritePerm reports whether the current user has permission to write to the // file with the given info. -func hasWritePerm(_ string, fi os.FileInfo) bool { +func hasWritePerm(_ string, fi fs.FileInfo) bool { // Windows has a read-only attribute independent of ACLs, so use that to // determine whether the file is intended to be overwritten. // diff --git a/src/cmd/go/internal/modload/vendor.go b/src/cmd/go/internal/modload/vendor.go index 9f34b829fc..ab29d4d014 100644 --- a/src/cmd/go/internal/modload/vendor.go +++ b/src/cmd/go/internal/modload/vendor.go @@ -7,8 +7,8 @@ package modload import ( "errors" "fmt" + "io/fs" "io/ioutil" - "os" "path/filepath" "strings" "sync" @@ -42,7 +42,7 @@ func readVendorList() { vendorMeta = make(map[module.Version]vendorMetadata) data, err := ioutil.ReadFile(filepath.Join(ModRoot(), "vendor/modules.txt")) if err != nil { - if !errors.Is(err, os.ErrNotExist) { + if !errors.Is(err, fs.ErrNotExist) { base.Fatalf("go: %s", err) } return diff --git a/src/cmd/go/internal/renameio/renameio.go b/src/cmd/go/internal/renameio/renameio.go index d573cc690d..60a7138a76 100644 --- a/src/cmd/go/internal/renameio/renameio.go +++ b/src/cmd/go/internal/renameio/renameio.go @@ -8,6 +8,7 @@ package renameio import ( "bytes" "io" + "io/fs" "math/rand" "os" "path/filepath" @@ -29,13 +30,13 @@ func Pattern(filename string) string { // final name. // // That ensures that the final location, if it exists, is always a complete file. -func WriteFile(filename string, data []byte, perm os.FileMode) (err error) { +func WriteFile(filename string, data []byte, perm fs.FileMode) (err error) { return WriteToFile(filename, bytes.NewReader(data), perm) } // WriteToFile is a variant of WriteFile that accepts the data as an io.Reader // instead of a slice. -func WriteToFile(filename string, data io.Reader, perm os.FileMode) (err error) { +func WriteToFile(filename string, data io.Reader, perm fs.FileMode) (err error) { f, err := tempFile(filepath.Dir(filename), filepath.Base(filename), perm) if err != nil { return err @@ -80,7 +81,7 @@ func ReadFile(filename string) ([]byte, error) { } // tempFile creates a new temporary file with given permission bits. -func tempFile(dir, prefix string, perm os.FileMode) (f *os.File, err error) { +func tempFile(dir, prefix string, perm fs.FileMode) (f *os.File, err error) { for i := 0; i < 10000; i++ { name := filepath.Join(dir, prefix+strconv.Itoa(rand.Intn(1000000000))+patternSuffix) f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, perm) diff --git a/src/cmd/go/internal/renameio/umask_test.go b/src/cmd/go/internal/renameio/umask_test.go index d75d67c9a9..19e217c548 100644 --- a/src/cmd/go/internal/renameio/umask_test.go +++ b/src/cmd/go/internal/renameio/umask_test.go @@ -7,6 +7,7 @@ package renameio import ( + "io/fs" "io/ioutil" "os" "path/filepath" @@ -36,7 +37,7 @@ func TestWriteFileModeAppliesUmask(t *testing.T) { t.Fatalf("Stat %q (looking for mode %#o): %s", file, mode, err) } - if fi.Mode()&os.ModePerm != 0640 { - t.Errorf("Stat %q: mode %#o want %#o", file, fi.Mode()&os.ModePerm, 0640) + if fi.Mode()&fs.ModePerm != 0640 { + t.Errorf("Stat %q: mode %#o want %#o", file, fi.Mode()&fs.ModePerm, 0640) } } diff --git a/src/cmd/go/internal/search/search.go b/src/cmd/go/internal/search/search.go index b1d2a9376b..e4784e9478 100644 --- a/src/cmd/go/internal/search/search.go +++ b/src/cmd/go/internal/search/search.go @@ -10,6 +10,7 @@ import ( "cmd/go/internal/fsys" "fmt" "go/build" + "io/fs" "os" "path" "path/filepath" @@ -128,7 +129,7 @@ func (m *Match) MatchPackages() { if m.pattern == "cmd" { root += "cmd" + string(filepath.Separator) } - err := fsys.Walk(root, func(path string, fi os.FileInfo, err error) error { + err := fsys.Walk(root, func(path string, fi fs.FileInfo, err error) error { if err != nil { return err // Likely a permission error, which could interfere with matching. } @@ -154,7 +155,7 @@ func (m *Match) MatchPackages() { } if !fi.IsDir() { - if fi.Mode()&os.ModeSymlink != 0 && want { + if fi.Mode()&fs.ModeSymlink != 0 && want { if target, err := os.Stat(path); err == nil && target.IsDir() { fmt.Fprintf(os.Stderr, "warning: ignoring symlink %s\n", path) } @@ -264,7 +265,7 @@ func (m *Match) MatchDirs() { } } - err := fsys.Walk(dir, func(path string, fi os.FileInfo, err error) error { + err := fsys.Walk(dir, func(path string, fi fs.FileInfo, err error) error { if err != nil { return err // Likely a permission error, which could interfere with matching. } diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go index 51d333d866..00da9770df 100644 --- a/src/cmd/go/internal/test/test.go +++ b/src/cmd/go/internal/test/test.go @@ -12,6 +12,7 @@ import ( "fmt" "go/build" "io" + "io/fs" "io/ioutil" "os" "os/exec" @@ -1598,7 +1599,7 @@ func hashStat(name string) cache.ActionID { return h.Sum() } -func hashWriteStat(h io.Writer, info os.FileInfo) { +func hashWriteStat(h io.Writer, info fs.FileInfo) { fmt.Fprintf(h, "stat %d %x %v %v\n", info.Size(), uint64(info.Mode()), info.ModTime(), info.IsDir()) } diff --git a/src/cmd/go/internal/vcs/vcs.go b/src/cmd/go/internal/vcs/vcs.go index 90bf10244d..7812afd488 100644 --- a/src/cmd/go/internal/vcs/vcs.go +++ b/src/cmd/go/internal/vcs/vcs.go @@ -10,6 +10,7 @@ import ( "fmt" "internal/lazyregexp" "internal/singleflight" + "io/fs" "log" urlpkg "net/url" "os" @@ -404,9 +405,9 @@ func (v *Cmd) run1(dir string, cmdline string, keyval []string, verbose bool) ([ if len(args) >= 2 && args[0] == "-go-internal-mkdir" { var err error if filepath.IsAbs(args[1]) { - err = os.Mkdir(args[1], os.ModePerm) + err = os.Mkdir(args[1], fs.ModePerm) } else { - err = os.Mkdir(filepath.Join(dir, args[1]), os.ModePerm) + err = os.Mkdir(filepath.Join(dir, args[1]), fs.ModePerm) } if err != nil { return nil, err diff --git a/src/cmd/go/internal/version/version.go b/src/cmd/go/internal/version/version.go index 5aa0f8e7ed..44ac24c62d 100644 --- a/src/cmd/go/internal/version/version.go +++ b/src/cmd/go/internal/version/version.go @@ -10,6 +10,7 @@ import ( "context" "encoding/binary" "fmt" + "io/fs" "os" "path/filepath" "runtime" @@ -87,8 +88,8 @@ func runVersion(ctx context.Context, cmd *base.Command, args []string) { // scanDir scans a directory for executables to run scanFile on. func scanDir(dir string) { - filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { - if info.Mode().IsRegular() || info.Mode()&os.ModeSymlink != 0 { + filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error { + if info.Mode().IsRegular() || info.Mode()&fs.ModeSymlink != 0 { scanFile(path, info, *versionV) } return nil @@ -96,7 +97,7 @@ func scanDir(dir string) { } // isExe reports whether the file should be considered executable. -func isExe(file string, info os.FileInfo) bool { +func isExe(file string, info fs.FileInfo) bool { if runtime.GOOS == "windows" { return strings.HasSuffix(strings.ToLower(file), ".exe") } @@ -107,8 +108,8 @@ func isExe(file string, info os.FileInfo) bool { // If mustPrint is true, scanFile will report any error reading file. // Otherwise (mustPrint is false, because scanFile is being called // by scanDir) scanFile prints nothing for non-Go executables. -func scanFile(file string, info os.FileInfo, mustPrint bool) { - if info.Mode()&os.ModeSymlink != 0 { +func scanFile(file string, info fs.FileInfo, mustPrint bool) { + if info.Mode()&fs.ModeSymlink != 0 { // Accept file symlinks only. i, err := os.Stat(file) if err != nil || !i.Mode().IsRegular() { diff --git a/src/cmd/go/internal/web/api.go b/src/cmd/go/internal/web/api.go index 570818843b..f7d3ed60f6 100644 --- a/src/cmd/go/internal/web/api.go +++ b/src/cmd/go/internal/web/api.go @@ -13,9 +13,9 @@ import ( "bytes" "fmt" "io" + "io/fs" "io/ioutil" "net/url" - "os" "strings" "unicode" "unicode/utf8" @@ -56,7 +56,7 @@ func (e *HTTPError) Error() string { } if err := e.Err; err != nil { - if pErr, ok := e.Err.(*os.PathError); ok && strings.HasSuffix(e.URL, pErr.Path) { + if pErr, ok := e.Err.(*fs.PathError); ok && strings.HasSuffix(e.URL, pErr.Path) { // Remove the redundant copy of the path. err = pErr.Err } @@ -67,7 +67,7 @@ func (e *HTTPError) Error() string { } func (e *HTTPError) Is(target error) bool { - return target == os.ErrNotExist && (e.StatusCode == 404 || e.StatusCode == 410) + return target == fs.ErrNotExist && (e.StatusCode == 404 || e.StatusCode == 410) } func (e *HTTPError) Unwrap() error { diff --git a/src/cmd/go/internal/web/file_test.go b/src/cmd/go/internal/web/file_test.go index 6339469045..a1bb080e07 100644 --- a/src/cmd/go/internal/web/file_test.go +++ b/src/cmd/go/internal/web/file_test.go @@ -6,6 +6,7 @@ package web import ( "errors" + "io/fs" "io/ioutil" "os" "path/filepath" @@ -54,7 +55,7 @@ func TestGetNonexistentFile(t *testing.T) { } b, err := GetBytes(u) - if !errors.Is(err, os.ErrNotExist) { - t.Fatalf("GetBytes(%v) = %q, %v; want _, os.ErrNotExist", u, b, err) + if !errors.Is(err, fs.ErrNotExist) { + t.Fatalf("GetBytes(%v) = %q, %v; want _, fs.ErrNotExist", u, b, err) } } diff --git a/src/cmd/go/internal/work/build_test.go b/src/cmd/go/internal/work/build_test.go index 904aee0684..e941729734 100644 --- a/src/cmd/go/internal/work/build_test.go +++ b/src/cmd/go/internal/work/build_test.go @@ -7,6 +7,7 @@ package work import ( "bytes" "fmt" + "io/fs" "io/ioutil" "os" "path/filepath" @@ -253,7 +254,7 @@ func TestRespectSetgidDir(t *testing.T) { } // Change setgiddir's permissions to include the SetGID bit. - if err := os.Chmod(setgiddir, 0755|os.ModeSetgid); err != nil { + if err := os.Chmod(setgiddir, 0755|fs.ModeSetgid); err != nil { t.Fatal(err) } diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index 824a4b5a0a..717b0cc3af 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -14,6 +14,7 @@ import ( "fmt" "internal/lazyregexp" "io" + "io/fs" "io/ioutil" "log" "math/rand" @@ -1560,7 +1561,7 @@ func BuildInstallFunc(b *Builder, ctx context.Context, a *Action) (err error) { return err } - perm := os.FileMode(0666) + perm := fs.FileMode(0666) if a1.Mode == "link" { switch cfg.BuildBuildmode { case "c-archive", "c-shared", "plugin": @@ -1609,7 +1610,7 @@ func (b *Builder) cleanup(a *Action) { } // moveOrCopyFile is like 'mv src dst' or 'cp src dst'. -func (b *Builder) moveOrCopyFile(dst, src string, perm os.FileMode, force bool) error { +func (b *Builder) moveOrCopyFile(dst, src string, perm fs.FileMode, force bool) error { if cfg.BuildN { b.Showcmd("", "mv %s %s", src, dst) return nil @@ -1635,7 +1636,7 @@ func (b *Builder) moveOrCopyFile(dst, src string, perm os.FileMode, force bool) // we have to copy the file to retain the correct permissions. // https://golang.org/issue/18878 if fi, err := os.Stat(filepath.Dir(dst)); err == nil { - if fi.IsDir() && (fi.Mode()&os.ModeSetgid) != 0 { + if fi.IsDir() && (fi.Mode()&fs.ModeSetgid) != 0 { return b.copyFile(dst, src, perm, force) } } @@ -1670,7 +1671,7 @@ func (b *Builder) moveOrCopyFile(dst, src string, perm os.FileMode, force bool) } // copyFile is like 'cp src dst'. -func (b *Builder) copyFile(dst, src string, perm os.FileMode, force bool) error { +func (b *Builder) copyFile(dst, src string, perm fs.FileMode, force bool) error { if cfg.BuildN || cfg.BuildX { b.Showcmd("", "cp %s %s", src, dst) if cfg.BuildN { diff --git a/src/cmd/go/proxy_test.go b/src/cmd/go/proxy_test.go index 42972f5b2a..8b0dbb74b2 100644 --- a/src/cmd/go/proxy_test.go +++ b/src/cmd/go/proxy_test.go @@ -12,6 +12,7 @@ import ( "flag" "fmt" "io" + "io/fs" "io/ioutil" "log" "net" @@ -335,7 +336,7 @@ func proxyHandler(w http.ResponseWriter, r *http.Request) { if testing.Verbose() { fmt.Fprintf(os.Stderr, "go proxy: no archive %s %s: %v\n", path, vers, err) } - if errors.Is(err, os.ErrNotExist) { + if errors.Is(err, fs.ErrNotExist) { http.NotFound(w, r) } else { http.Error(w, "cannot load archive", 500) @@ -443,7 +444,7 @@ func readArchive(path, vers string) (*txtar.Archive, error) { return a }).(*txtar.Archive) if a == nil { - return nil, os.ErrNotExist + return nil, fs.ErrNotExist } return a, nil } diff --git a/src/cmd/go/script_test.go b/src/cmd/go/script_test.go index 986646252a..a31561cd86 100644 --- a/src/cmd/go/script_test.go +++ b/src/cmd/go/script_test.go @@ -14,6 +14,7 @@ import ( "fmt" "go/build" "internal/testenv" + "io/fs" "io/ioutil" "os" "os/exec" @@ -500,7 +501,7 @@ func (ts *testScript) cmdChmod(want simpleStatus, args []string) { ts.fatalf("usage: chmod perm paths...") } perm, err := strconv.ParseUint(args[0], 0, 32) - if err != nil || perm&uint64(os.ModePerm) != perm { + if err != nil || perm&uint64(fs.ModePerm) != perm { ts.fatalf("invalid mode: %s", args[0]) } for _, arg := range args[1:] { @@ -508,7 +509,7 @@ func (ts *testScript) cmdChmod(want simpleStatus, args []string) { if !filepath.IsAbs(path) { path = filepath.Join(ts.cd, arg) } - err := os.Chmod(path, os.FileMode(perm)) + err := os.Chmod(path, fs.FileMode(perm)) ts.check(err) } } @@ -595,7 +596,7 @@ func (ts *testScript) cmdCp(want simpleStatus, args []string) { var ( src string data []byte - mode os.FileMode + mode fs.FileMode ) switch arg { case "stdout": diff --git a/src/cmd/go/testdata/addmod.go b/src/cmd/go/testdata/addmod.go index d9c3aab9c4..d1b6467c5d 100644 --- a/src/cmd/go/testdata/addmod.go +++ b/src/cmd/go/testdata/addmod.go @@ -22,6 +22,7 @@ import ( "bytes" "flag" "fmt" + "io/fs" "io/ioutil" "log" "os" @@ -121,7 +122,7 @@ func main() { {Name: ".info", Data: info}, } dir = filepath.Clean(dir) - err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + err = filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error { if !info.Mode().IsRegular() { return nil } diff --git a/src/cmd/go/testdata/savedir.go b/src/cmd/go/testdata/savedir.go index 48a6318860..04902df61e 100644 --- a/src/cmd/go/testdata/savedir.go +++ b/src/cmd/go/testdata/savedir.go @@ -17,6 +17,7 @@ package main import ( "flag" "fmt" + "io/fs" "io/ioutil" "log" "os" @@ -48,7 +49,7 @@ func main() { a := new(txtar.Archive) dir = filepath.Clean(dir) - filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { + filepath.Walk(dir, func(path string, info fs.FileInfo, err error) error { if path == dir { return nil } diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go index 8c56af7559..48b6ad6f53 100644 --- a/src/cmd/gofmt/gofmt.go +++ b/src/cmd/gofmt/gofmt.go @@ -14,6 +14,7 @@ import ( "go/scanner" "go/token" "io" + "io/fs" "io/ioutil" "os" "path/filepath" @@ -73,7 +74,7 @@ func initParserMode() { } } -func isGoFile(f os.FileInfo) bool { +func isGoFile(f fs.FileInfo) bool { // ignore non-Go files name := f.Name() return !f.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") @@ -81,7 +82,7 @@ func isGoFile(f os.FileInfo) bool { // If in == nil, the source is the contents of the file with the given filename. func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error { - var perm os.FileMode = 0644 + var perm fs.FileMode = 0644 if in == nil { f, err := os.Open(filename) if err != nil { @@ -163,7 +164,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error return err } -func visitFile(path string, f os.FileInfo, err error) error { +func visitFile(path string, f fs.FileInfo, err error) error { if err == nil && isGoFile(f) { err = processFile(path, nil, os.Stdout, false) } @@ -275,7 +276,7 @@ const chmodSupported = runtime.GOOS != "windows" // backupFile writes data to a new file named filename with permissions perm, // with 0 && name[0] != '.' && // ignore .files @@ -86,7 +86,7 @@ func test(t *testing.T, mode Mode) { if err != nil { t.Fatal(err) } - filter = func(fi os.FileInfo) bool { + filter = func(fi fs.FileInfo) bool { return isGoFile(fi) && rx.MatchString(fi.Name()) } } diff --git a/src/go/doc/headscan.go b/src/go/doc/headscan.go index 3f782cc1b4..8ea462366e 100644 --- a/src/go/doc/headscan.go +++ b/src/go/doc/headscan.go @@ -23,6 +23,7 @@ import ( "go/parser" "go/token" "internal/lazyregexp" + "io/fs" "os" "path/filepath" "runtime" @@ -39,7 +40,7 @@ var html_h = lazyregexp.New(`

`) const html_endh = "

\n" -func isGoFile(fi os.FileInfo) bool { +func isGoFile(fi fs.FileInfo) bool { return strings.HasSuffix(fi.Name(), ".go") && !strings.HasSuffix(fi.Name(), "_test.go") } @@ -68,7 +69,7 @@ func main() { flag.Parse() fset := token.NewFileSet() nheadings := 0 - err := filepath.Walk(*root, func(path string, fi os.FileInfo, err error) error { + err := filepath.Walk(*root, func(path string, fi fs.FileInfo, err error) error { if !fi.IsDir() { return nil } diff --git a/src/go/parser/interface.go b/src/go/parser/interface.go index 54f9d7b80a..b2d834fdec 100644 --- a/src/go/parser/interface.go +++ b/src/go/parser/interface.go @@ -12,8 +12,8 @@ import ( "go/ast" "go/token" "io" + "io/fs" "io/ioutil" - "os" "path/filepath" "strings" ) @@ -123,7 +123,7 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode) // directory specified by path and returns a map of package name -> package // AST with all the packages found. // -// If filter != nil, only the files with os.FileInfo entries passing through +// If filter != nil, only the files with fs.FileInfo entries passing through // the filter (and ending in ".go") are considered. The mode bits are passed // to ParseFile unchanged. Position information is recorded in fset, which // must not be nil. @@ -132,7 +132,7 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode) // returned. If a parse error occurred, a non-nil but incomplete map and the // first error encountered are returned. // -func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, mode Mode) (pkgs map[string]*ast.Package, first error) { +func ParseDir(fset *token.FileSet, path string, filter func(fs.FileInfo) bool, mode Mode) (pkgs map[string]*ast.Package, first error) { list, err := ioutil.ReadDir(path) if err != nil { return nil, err diff --git a/src/go/parser/parser_test.go b/src/go/parser/parser_test.go index 25a374eeef..7193a329fe 100644 --- a/src/go/parser/parser_test.go +++ b/src/go/parser/parser_test.go @@ -9,7 +9,7 @@ import ( "fmt" "go/ast" "go/token" - "os" + "io/fs" "strings" "testing" ) @@ -40,7 +40,7 @@ func nameFilter(filename string) bool { return false } -func dirFilter(f os.FileInfo) bool { return nameFilter(f.Name()) } +func dirFilter(f fs.FileInfo) bool { return nameFilter(f.Name()) } func TestParseFile(t *testing.T) { src := "package p\nvar _=s[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]+\ns[::]" diff --git a/src/index/suffixarray/suffixarray_test.go b/src/index/suffixarray/suffixarray_test.go index 28090de9aa..b6a81123b7 100644 --- a/src/index/suffixarray/suffixarray_test.go +++ b/src/index/suffixarray/suffixarray_test.go @@ -7,9 +7,9 @@ package suffixarray import ( "bytes" "fmt" + "io/fs" "io/ioutil" "math/rand" - "os" "path/filepath" "regexp" "sort" @@ -503,7 +503,7 @@ func makeText(name string) ([]byte, error) { return nil, err } case "go": - err := filepath.Walk("../..", func(path string, info os.FileInfo, err error) error { + err := filepath.Walk("../..", func(path string, info fs.FileInfo, err error) error { if err == nil && strings.HasSuffix(path, ".go") && !info.IsDir() { file, err := ioutil.ReadFile(path) if err != nil { diff --git a/src/internal/poll/error_test.go b/src/internal/poll/error_test.go index 06b96f635a..abc8b1684f 100644 --- a/src/internal/poll/error_test.go +++ b/src/internal/poll/error_test.go @@ -6,6 +6,7 @@ package poll_test import ( "fmt" + "io/fs" "net" "os" "testing" @@ -37,7 +38,7 @@ func parseReadError(nestedErr error, verify func(error) (string, bool)) error { if nerr, ok := err.(*net.OpError); ok { err = nerr.Err } - if nerr, ok := err.(*os.PathError); ok { + if nerr, ok := err.(*fs.PathError); ok { err = nerr.Err } if nerr, ok := err.(*os.SyscallError); ok { diff --git a/src/internal/reflectlite/reflect_mirror_test.go b/src/internal/reflectlite/reflect_mirror_test.go index fbb6fb397e..9b28b13550 100644 --- a/src/internal/reflectlite/reflect_mirror_test.go +++ b/src/internal/reflectlite/reflect_mirror_test.go @@ -9,6 +9,7 @@ import ( "go/ast" "go/parser" "go/token" + "io/fs" "os" "path/filepath" "runtime" @@ -71,7 +72,7 @@ func (v visitor) Visit(n ast.Node) ast.Visitor { func loadTypes(path, pkgName string, v visitor) { fset := token.NewFileSet() - filter := func(fi os.FileInfo) bool { + filter := func(fi fs.FileInfo) bool { return strings.HasSuffix(fi.Name(), ".go") } pkgs, err := parser.ParseDir(fset, path, filter, 0) diff --git a/src/io/ioutil/ioutil.go b/src/io/ioutil/ioutil.go index acc6ec3a40..cae41f0018 100644 --- a/src/io/ioutil/ioutil.go +++ b/src/io/ioutil/ioutil.go @@ -8,6 +8,7 @@ package ioutil import ( "bytes" "io" + "io/fs" "os" "sort" "sync" @@ -76,7 +77,7 @@ func ReadFile(filename string) ([]byte, error) { // WriteFile writes data to a file named by filename. // If the file does not exist, WriteFile creates it with permissions perm // (before umask); otherwise WriteFile truncates it before writing, without changing permissions. -func WriteFile(filename string, data []byte, perm os.FileMode) error { +func WriteFile(filename string, data []byte, perm fs.FileMode) error { f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) if err != nil { return err @@ -90,7 +91,7 @@ func WriteFile(filename string, data []byte, perm os.FileMode) error { // ReadDir reads the directory named by dirname and returns // a list of directory entries sorted by filename. -func ReadDir(dirname string) ([]os.FileInfo, error) { +func ReadDir(dirname string) ([]fs.FileInfo, error) { f, err := os.Open(dirname) if err != nil { return nil, err diff --git a/src/io/ioutil/tempfile_test.go b/src/io/ioutil/tempfile_test.go index fcc5101fcc..440c7cffc6 100644 --- a/src/io/ioutil/tempfile_test.go +++ b/src/io/ioutil/tempfile_test.go @@ -5,6 +5,7 @@ package ioutil_test import ( + "io/fs" . "io/ioutil" "os" "path/filepath" @@ -151,7 +152,7 @@ func TestTempDir_BadDir(t *testing.T) { badDir := filepath.Join(dir, "not-exist") _, err = TempDir(badDir, "foo") - if pe, ok := err.(*os.PathError); !ok || !os.IsNotExist(err) || pe.Path != badDir { + if pe, ok := err.(*fs.PathError); !ok || !os.IsNotExist(err) || pe.Path != badDir { t.Errorf("TempDir error = %#v; want PathError for path %q satisifying os.IsNotExist", err, badDir) } } diff --git a/src/net/conf_test.go b/src/net/conf_test.go index 3c7403eccc..4c21d56ba0 100644 --- a/src/net/conf_test.go +++ b/src/net/conf_test.go @@ -7,7 +7,7 @@ package net import ( - "os" + "io/fs" "strings" "testing" ) @@ -26,7 +26,7 @@ var defaultResolvConf = &dnsConfig{ ndots: 1, timeout: 5, attempts: 2, - err: os.ErrNotExist, + err: fs.ErrNotExist, } func TestConfHostLookupOrder(t *testing.T) { @@ -106,7 +106,7 @@ func TestConfHostLookupOrder(t *testing.T) { name: "solaris_no_nsswitch", c: &conf{ goos: "solaris", - nss: &nssConf{err: os.ErrNotExist}, + nss: &nssConf{err: fs.ErrNotExist}, resolv: defaultResolvConf, }, hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupCgo}}, @@ -176,7 +176,7 @@ func TestConfHostLookupOrder(t *testing.T) { name: "linux_no_nsswitch.conf", c: &conf{ goos: "linux", - nss: &nssConf{err: os.ErrNotExist}, + nss: &nssConf{err: fs.ErrNotExist}, resolv: defaultResolvConf, }, hostTests: []nssHostTest{{"google.com", "myhostname", hostLookupDNSFiles}}, diff --git a/src/net/dnsconfig_unix_test.go b/src/net/dnsconfig_unix_test.go index 42880123c5..0d7897a813 100644 --- a/src/net/dnsconfig_unix_test.go +++ b/src/net/dnsconfig_unix_test.go @@ -8,6 +8,7 @@ package net import ( "errors" + "io/fs" "os" "reflect" "strings" @@ -183,7 +184,7 @@ func TestDNSReadMissingFile(t *testing.T) { conf := dnsReadConfig("a-nonexistent-file") if !os.IsNotExist(conf.err) { - t.Errorf("missing resolv.conf:\ngot: %v\nwant: %v", conf.err, os.ErrNotExist) + t.Errorf("missing resolv.conf:\ngot: %v\nwant: %v", conf.err, fs.ErrNotExist) } conf.err = nil want := &dnsConfig{ diff --git a/src/net/error_test.go b/src/net/error_test.go index 62dfb9c15d..7823fdf9d8 100644 --- a/src/net/error_test.go +++ b/src/net/error_test.go @@ -12,6 +12,7 @@ import ( "fmt" "internal/poll" "io" + "io/fs" "io/ioutil" "net/internal/socktest" "os" @@ -97,7 +98,7 @@ second: case *os.SyscallError: nestedErr = err.Err goto third - case *os.PathError: // for Plan 9 + case *fs.PathError: // for Plan 9 nestedErr = err.Err goto third } @@ -531,7 +532,7 @@ second: case *os.SyscallError: nestedErr = err.Err goto third - case *os.PathError: // for Plan 9 + case *fs.PathError: // for Plan 9 nestedErr = err.Err goto third } @@ -546,7 +547,7 @@ third: return nil } switch nestedErr { - case os.ErrClosed: // for Plan 9 + case fs.ErrClosed: // for Plan 9 return nil } return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr) @@ -627,7 +628,7 @@ second: case *os.SyscallError: nestedErr = err.Err goto third - case *os.PathError: // for Plan 9 + case *fs.PathError: // for Plan 9 nestedErr = err.Err goto third } @@ -706,7 +707,7 @@ second: case *os.LinkError: nestedErr = err.Err goto third - case *os.PathError: + case *fs.PathError: nestedErr = err.Err goto third } @@ -799,7 +800,7 @@ func parseLookupPortError(nestedErr error) error { switch nestedErr.(type) { case *AddrError, *DNSError: return nil - case *os.PathError: // for Plan 9 + case *fs.PathError: // for Plan 9 return nil } return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr) diff --git a/src/net/http/example_filesystem_test.go b/src/net/http/example_filesystem_test.go index e1fd42d049..0e81458a07 100644 --- a/src/net/http/example_filesystem_test.go +++ b/src/net/http/example_filesystem_test.go @@ -5,9 +5,9 @@ package http_test import ( + "io/fs" "log" "net/http" - "os" "strings" ) @@ -33,7 +33,7 @@ type dotFileHidingFile struct { // Readdir is a wrapper around the Readdir method of the embedded File // that filters out all files that start with a period in their name. -func (f dotFileHidingFile) Readdir(n int) (fis []os.FileInfo, err error) { +func (f dotFileHidingFile) Readdir(n int) (fis []fs.FileInfo, err error) { files, err := f.File.Readdir(n) for _, file := range files { // Filters out the dot files if !strings.HasPrefix(file.Name(), ".") { @@ -52,12 +52,12 @@ type dotFileHidingFileSystem struct { // Open is a wrapper around the Open method of the embedded FileSystem // that serves a 403 permission error when name has a file or directory // with whose name starts with a period in its path. -func (fs dotFileHidingFileSystem) Open(name string) (http.File, error) { +func (fsys dotFileHidingFileSystem) Open(name string) (http.File, error) { if containsDotFile(name) { // If dot file, return 403 response - return nil, os.ErrPermission + return nil, fs.ErrPermission } - file, err := fs.FileSystem.Open(name) + file, err := fsys.FileSystem.Open(name) if err != nil { return nil, err } @@ -65,7 +65,7 @@ func (fs dotFileHidingFileSystem) Open(name string) (http.File, error) { } func ExampleFileServer_dotFileHiding() { - fs := dotFileHidingFileSystem{http.Dir(".")} - http.Handle("/", http.FileServer(fs)) + fsys := dotFileHidingFileSystem{http.Dir(".")} + http.Handle("/", http.FileServer(fsys)) log.Fatal(http.ListenAndServe(":8080", nil)) } diff --git a/src/net/http/fs.go b/src/net/http/fs.go index d718fffba0..0743b5b621 100644 --- a/src/net/http/fs.go +++ b/src/net/http/fs.go @@ -10,6 +10,7 @@ import ( "errors" "fmt" "io" + "io/fs" "mime" "mime/multipart" "net/textproto" @@ -43,7 +44,7 @@ type Dir string // mapDirOpenError maps the provided non-nil error from opening name // to a possibly better non-nil error. In particular, it turns OS-specific errors -// about opening files in non-directories into os.ErrNotExist. See Issue 18984. +// about opening files in non-directories into fs.ErrNotExist. See Issue 18984. func mapDirOpenError(originalErr error, name string) error { if os.IsNotExist(originalErr) || os.IsPermission(originalErr) { return originalErr @@ -59,7 +60,7 @@ func mapDirOpenError(originalErr error, name string) error { return originalErr } if !fi.IsDir() { - return os.ErrNotExist + return fs.ErrNotExist } } return originalErr @@ -98,8 +99,8 @@ type File interface { io.Closer io.Reader io.Seeker - Readdir(count int) ([]os.FileInfo, error) - Stat() (os.FileInfo, error) + Readdir(count int) ([]fs.FileInfo, error) + Stat() (fs.FileInfo, error) } func dirList(w ResponseWriter, r *Request, f File) { diff --git a/src/net/http/fs_test.go b/src/net/http/fs_test.go index 4ac73b728f..de793b331e 100644 --- a/src/net/http/fs_test.go +++ b/src/net/http/fs_test.go @@ -10,6 +10,7 @@ import ( "errors" "fmt" "io" + "io/fs" "io/ioutil" "mime" "mime/multipart" @@ -629,9 +630,9 @@ func (f *fakeFileInfo) Sys() interface{} { return nil } func (f *fakeFileInfo) ModTime() time.Time { return f.modtime } func (f *fakeFileInfo) IsDir() bool { return f.dir } func (f *fakeFileInfo) Size() int64 { return int64(len(f.contents)) } -func (f *fakeFileInfo) Mode() os.FileMode { +func (f *fakeFileInfo) Mode() fs.FileMode { if f.dir { - return 0755 | os.ModeDir + return 0755 | fs.ModeDir } return 0644 } @@ -644,12 +645,12 @@ type fakeFile struct { } func (f *fakeFile) Close() error { return nil } -func (f *fakeFile) Stat() (os.FileInfo, error) { return f.fi, nil } -func (f *fakeFile) Readdir(count int) ([]os.FileInfo, error) { +func (f *fakeFile) Stat() (fs.FileInfo, error) { return f.fi, nil } +func (f *fakeFile) Readdir(count int) ([]fs.FileInfo, error) { if !f.fi.dir { - return nil, os.ErrInvalid + return nil, fs.ErrInvalid } - var fis []os.FileInfo + var fis []fs.FileInfo limit := f.entpos + count if count <= 0 || limit > len(f.fi.ents) { @@ -668,11 +669,11 @@ func (f *fakeFile) Readdir(count int) ([]os.FileInfo, error) { type fakeFS map[string]*fakeFileInfo -func (fs fakeFS) Open(name string) (File, error) { +func (fsys fakeFS) Open(name string) (File, error) { name = path.Clean(name) - f, ok := fs[name] + f, ok := fsys[name] if !ok { - return nil, os.ErrNotExist + return nil, fs.ErrNotExist } if f.err != nil { return nil, f.err @@ -747,7 +748,7 @@ func TestDirectoryIfNotModified(t *testing.T) { res.Body.Close() } -func mustStat(t *testing.T, fileName string) os.FileInfo { +func mustStat(t *testing.T, fileName string) fs.FileInfo { fi, err := os.Stat(fileName) if err != nil { t.Fatal(err) @@ -1081,7 +1082,7 @@ func (issue12991FS) Open(string) (File, error) { return issue12991File{}, nil } type issue12991File struct{ File } -func (issue12991File) Stat() (os.FileInfo, error) { return nil, os.ErrPermission } +func (issue12991File) Stat() (fs.FileInfo, error) { return nil, fs.ErrPermission } func (issue12991File) Close() error { return nil } func TestServeContentErrorMessages(t *testing.T) { @@ -1091,7 +1092,7 @@ func TestServeContentErrorMessages(t *testing.T) { err: errors.New("random error"), }, "/403": &fakeFileInfo{ - err: &os.PathError{Err: os.ErrPermission}, + err: &fs.PathError{Err: fs.ErrPermission}, }, } ts := httptest.NewServer(FileServer(fs)) @@ -1289,7 +1290,7 @@ func (d fileServerCleanPathDir) Open(path string) (File, error) { // Just return back something that's a directory. return Dir(".").Open(".") } - return nil, os.ErrNotExist + return nil, fs.ErrNotExist } type panicOnSeek struct{ io.ReadSeeker } diff --git a/src/net/ipsock_plan9.go b/src/net/ipsock_plan9.go index 23082366aa..7a4b7a6041 100644 --- a/src/net/ipsock_plan9.go +++ b/src/net/ipsock_plan9.go @@ -7,6 +7,7 @@ package net import ( "context" "internal/bytealg" + "io/fs" "os" "syscall" ) @@ -164,7 +165,7 @@ func fixErr(err error) { if nonNilInterface(oe.Addr) { oe.Addr = nil } - if pe, ok := oe.Err.(*os.PathError); ok { + if pe, ok := oe.Err.(*fs.PathError); ok { if _, ok = pe.Err.(syscall.ErrorString); ok { oe.Err = pe.Err } diff --git a/src/os/error_test.go b/src/os/error_test.go index 3d921578fd..060cf59875 100644 --- a/src/os/error_test.go +++ b/src/os/error_test.go @@ -7,6 +7,7 @@ package os_test import ( "errors" "fmt" + "io/fs" "io/ioutil" "os" "path/filepath" @@ -27,7 +28,7 @@ func TestErrIsExist(t *testing.T) { t.Fatal("Open should have failed") return } - if s := checkErrorPredicate("os.IsExist", os.IsExist, err, os.ErrExist); s != "" { + if s := checkErrorPredicate("os.IsExist", os.IsExist, err, fs.ErrExist); s != "" { t.Fatal(s) return } @@ -39,7 +40,7 @@ func testErrNotExist(name string) string { f.Close() return "Open should have failed" } - if s := checkErrorPredicate("os.IsNotExist", os.IsNotExist, err, os.ErrNotExist); s != "" { + if s := checkErrorPredicate("os.IsNotExist", os.IsNotExist, err, fs.ErrNotExist); s != "" { return s } @@ -47,7 +48,7 @@ func testErrNotExist(name string) string { if err == nil { return "Chdir should have failed" } - if s := checkErrorPredicate("os.IsNotExist", os.IsNotExist, err, os.ErrNotExist); s != "" { + if s := checkErrorPredicate("os.IsNotExist", os.IsNotExist, err, fs.ErrNotExist); s != "" { return s } return "" @@ -91,18 +92,18 @@ type isExistTest struct { } var isExistTests = []isExistTest{ - {&os.PathError{Err: os.ErrInvalid}, false, false}, - {&os.PathError{Err: os.ErrPermission}, false, false}, - {&os.PathError{Err: os.ErrExist}, true, false}, - {&os.PathError{Err: os.ErrNotExist}, false, true}, - {&os.PathError{Err: os.ErrClosed}, false, false}, - {&os.LinkError{Err: os.ErrInvalid}, false, false}, - {&os.LinkError{Err: os.ErrPermission}, false, false}, - {&os.LinkError{Err: os.ErrExist}, true, false}, - {&os.LinkError{Err: os.ErrNotExist}, false, true}, - {&os.LinkError{Err: os.ErrClosed}, false, false}, - {&os.SyscallError{Err: os.ErrNotExist}, false, true}, - {&os.SyscallError{Err: os.ErrExist}, true, false}, + {&fs.PathError{Err: fs.ErrInvalid}, false, false}, + {&fs.PathError{Err: fs.ErrPermission}, false, false}, + {&fs.PathError{Err: fs.ErrExist}, true, false}, + {&fs.PathError{Err: fs.ErrNotExist}, false, true}, + {&fs.PathError{Err: fs.ErrClosed}, false, false}, + {&os.LinkError{Err: fs.ErrInvalid}, false, false}, + {&os.LinkError{Err: fs.ErrPermission}, false, false}, + {&os.LinkError{Err: fs.ErrExist}, true, false}, + {&os.LinkError{Err: fs.ErrNotExist}, false, true}, + {&os.LinkError{Err: fs.ErrClosed}, false, false}, + {&os.SyscallError{Err: fs.ErrNotExist}, false, true}, + {&os.SyscallError{Err: fs.ErrExist}, true, false}, {nil, false, false}, } @@ -111,14 +112,14 @@ func TestIsExist(t *testing.T) { if is := os.IsExist(tt.err); is != tt.is { t.Errorf("os.IsExist(%T %v) = %v, want %v", tt.err, tt.err, is, tt.is) } - if is := errors.Is(tt.err, os.ErrExist); is != tt.is { - t.Errorf("errors.Is(%T %v, os.ErrExist) = %v, want %v", tt.err, tt.err, is, tt.is) + if is := errors.Is(tt.err, fs.ErrExist); is != tt.is { + t.Errorf("errors.Is(%T %v, fs.ErrExist) = %v, want %v", tt.err, tt.err, is, tt.is) } if isnot := os.IsNotExist(tt.err); isnot != tt.isnot { t.Errorf("os.IsNotExist(%T %v) = %v, want %v", tt.err, tt.err, isnot, tt.isnot) } - if isnot := errors.Is(tt.err, os.ErrNotExist); isnot != tt.isnot { - t.Errorf("errors.Is(%T %v, os.ErrNotExist) = %v, want %v", tt.err, tt.err, isnot, tt.isnot) + if isnot := errors.Is(tt.err, fs.ErrNotExist); isnot != tt.isnot { + t.Errorf("errors.Is(%T %v, fs.ErrNotExist) = %v, want %v", tt.err, tt.err, isnot, tt.isnot) } } } @@ -130,8 +131,8 @@ type isPermissionTest struct { var isPermissionTests = []isPermissionTest{ {nil, false}, - {&os.PathError{Err: os.ErrPermission}, true}, - {&os.SyscallError{Err: os.ErrPermission}, true}, + {&fs.PathError{Err: fs.ErrPermission}, true}, + {&os.SyscallError{Err: fs.ErrPermission}, true}, } func TestIsPermission(t *testing.T) { @@ -139,8 +140,8 @@ func TestIsPermission(t *testing.T) { if got := os.IsPermission(tt.err); got != tt.want { t.Errorf("os.IsPermission(%#v) = %v; want %v", tt.err, got, tt.want) } - if got := errors.Is(tt.err, os.ErrPermission); got != tt.want { - t.Errorf("errors.Is(%#v, os.ErrPermission) = %v; want %v", tt.err, got, tt.want) + if got := errors.Is(tt.err, fs.ErrPermission); got != tt.want { + t.Errorf("errors.Is(%#v, fs.ErrPermission) = %v; want %v", tt.err, got, tt.want) } } } @@ -170,8 +171,8 @@ func TestErrPathNUL(t *testing.T) { } func TestPathErrorUnwrap(t *testing.T) { - pe := &os.PathError{Err: os.ErrInvalid} - if !errors.Is(pe, os.ErrInvalid) { + pe := &fs.PathError{Err: fs.ErrInvalid} + if !errors.Is(pe, fs.ErrInvalid) { t.Error("errors.Is failed, wanted success") } } @@ -181,7 +182,7 @@ type myErrorIs struct{ error } func (e myErrorIs) Is(target error) bool { return target == e.error } func TestErrorIsMethods(t *testing.T) { - if os.IsPermission(myErrorIs{os.ErrPermission}) { - t.Error("os.IsPermission(err) = true when err.Is(os.ErrPermission), wanted false") + if os.IsPermission(myErrorIs{fs.ErrPermission}) { + t.Error("os.IsPermission(err) = true when err.Is(fs.ErrPermission), wanted false") } } diff --git a/src/os/error_unix_test.go b/src/os/error_unix_test.go index bfc83c9867..18bcf3f4e4 100644 --- a/src/os/error_unix_test.go +++ b/src/os/error_unix_test.go @@ -7,14 +7,15 @@ package os_test import ( + "io/fs" "os" "syscall" ) func init() { isExistTests = append(isExistTests, - isExistTest{err: &os.PathError{Err: syscall.EEXIST}, is: true, isnot: false}, - isExistTest{err: &os.PathError{Err: syscall.ENOTEMPTY}, is: true, isnot: false}, + isExistTest{err: &fs.PathError{Err: syscall.EEXIST}, is: true, isnot: false}, + isExistTest{err: &fs.PathError{Err: syscall.ENOTEMPTY}, is: true, isnot: false}, isExistTest{err: &os.LinkError{Err: syscall.EEXIST}, is: true, isnot: false}, isExistTest{err: &os.LinkError{Err: syscall.ENOTEMPTY}, is: true, isnot: false}, @@ -23,9 +24,9 @@ func init() { isExistTest{err: &os.SyscallError{Err: syscall.ENOTEMPTY}, is: true, isnot: false}, ) isPermissionTests = append(isPermissionTests, - isPermissionTest{err: &os.PathError{Err: syscall.EACCES}, want: true}, - isPermissionTest{err: &os.PathError{Err: syscall.EPERM}, want: true}, - isPermissionTest{err: &os.PathError{Err: syscall.EEXIST}, want: false}, + isPermissionTest{err: &fs.PathError{Err: syscall.EACCES}, want: true}, + isPermissionTest{err: &fs.PathError{Err: syscall.EPERM}, want: true}, + isPermissionTest{err: &fs.PathError{Err: syscall.EEXIST}, want: false}, isPermissionTest{err: &os.LinkError{Err: syscall.EACCES}, want: true}, isPermissionTest{err: &os.LinkError{Err: syscall.EPERM}, want: true}, diff --git a/src/os/error_windows_test.go b/src/os/error_windows_test.go index 1635c1088e..b8191c5ebc 100644 --- a/src/os/error_windows_test.go +++ b/src/os/error_windows_test.go @@ -7,6 +7,7 @@ package os_test import ( + "io/fs" "os" "syscall" ) @@ -15,24 +16,24 @@ func init() { const _ERROR_BAD_NETPATH = syscall.Errno(53) isExistTests = append(isExistTests, - isExistTest{err: &os.PathError{Err: syscall.ERROR_FILE_NOT_FOUND}, is: false, isnot: true}, + isExistTest{err: &fs.PathError{Err: syscall.ERROR_FILE_NOT_FOUND}, is: false, isnot: true}, isExistTest{err: &os.LinkError{Err: syscall.ERROR_FILE_NOT_FOUND}, is: false, isnot: true}, isExistTest{err: &os.SyscallError{Err: syscall.ERROR_FILE_NOT_FOUND}, is: false, isnot: true}, - isExistTest{err: &os.PathError{Err: _ERROR_BAD_NETPATH}, is: false, isnot: true}, + isExistTest{err: &fs.PathError{Err: _ERROR_BAD_NETPATH}, is: false, isnot: true}, isExistTest{err: &os.LinkError{Err: _ERROR_BAD_NETPATH}, is: false, isnot: true}, isExistTest{err: &os.SyscallError{Err: _ERROR_BAD_NETPATH}, is: false, isnot: true}, - isExistTest{err: &os.PathError{Err: syscall.ERROR_PATH_NOT_FOUND}, is: false, isnot: true}, + isExistTest{err: &fs.PathError{Err: syscall.ERROR_PATH_NOT_FOUND}, is: false, isnot: true}, isExistTest{err: &os.LinkError{Err: syscall.ERROR_PATH_NOT_FOUND}, is: false, isnot: true}, isExistTest{err: &os.SyscallError{Err: syscall.ERROR_PATH_NOT_FOUND}, is: false, isnot: true}, - isExistTest{err: &os.PathError{Err: syscall.ERROR_DIR_NOT_EMPTY}, is: true, isnot: false}, + isExistTest{err: &fs.PathError{Err: syscall.ERROR_DIR_NOT_EMPTY}, is: true, isnot: false}, isExistTest{err: &os.LinkError{Err: syscall.ERROR_DIR_NOT_EMPTY}, is: true, isnot: false}, isExistTest{err: &os.SyscallError{Err: syscall.ERROR_DIR_NOT_EMPTY}, is: true, isnot: false}, ) isPermissionTests = append(isPermissionTests, - isPermissionTest{err: &os.PathError{Err: syscall.ERROR_ACCESS_DENIED}, want: true}, + isPermissionTest{err: &fs.PathError{Err: syscall.ERROR_ACCESS_DENIED}, want: true}, isPermissionTest{err: &os.LinkError{Err: syscall.ERROR_ACCESS_DENIED}, want: true}, isPermissionTest{err: &os.SyscallError{Err: syscall.ERROR_ACCESS_DENIED}, want: true}, ) diff --git a/src/os/example_test.go b/src/os/example_test.go index 822886f70c..fbb277b6f1 100644 --- a/src/os/example_test.go +++ b/src/os/example_test.go @@ -6,6 +6,7 @@ package os_test import ( "fmt" + "io/fs" "log" "os" "time" @@ -62,9 +63,9 @@ func ExampleFileMode() { fmt.Println("regular file") case mode.IsDir(): fmt.Println("directory") - case mode&os.ModeSymlink != 0: + case mode&fs.ModeSymlink != 0: fmt.Println("symbolic link") - case mode&os.ModeNamedPipe != 0: + case mode&fs.ModeNamedPipe != 0: fmt.Println("named pipe") } } diff --git a/src/os/exec/exec_plan9.go b/src/os/exec/exec_plan9.go index d90bd04399..21ac7b765f 100644 --- a/src/os/exec/exec_plan9.go +++ b/src/os/exec/exec_plan9.go @@ -4,14 +4,14 @@ package exec -import "os" +import "io/fs" func init() { skipStdinCopyError = func(err error) bool { // Ignore hungup errors copying to stdin if the program // completed successfully otherwise. // See Issue 35753. - pe, ok := err.(*os.PathError) + pe, ok := err.(*fs.PathError) return ok && pe.Op == "write" && pe.Path == "|1" && pe.Err.Error() == "i/o on hungup channel" diff --git a/src/os/exec/exec_unix.go b/src/os/exec/exec_unix.go index 9c3e17d23a..51c52427c2 100644 --- a/src/os/exec/exec_unix.go +++ b/src/os/exec/exec_unix.go @@ -7,7 +7,7 @@ package exec import ( - "os" + "io/fs" "syscall" ) @@ -16,7 +16,7 @@ func init() { // Ignore EPIPE errors copying to stdin if the program // completed successfully otherwise. // See Issue 9173. - pe, ok := err.(*os.PathError) + pe, ok := err.(*fs.PathError) return ok && pe.Op == "write" && pe.Path == "|1" && pe.Err == syscall.EPIPE diff --git a/src/os/exec/exec_windows.go b/src/os/exec/exec_windows.go index af8cd97218..bb937f8aed 100644 --- a/src/os/exec/exec_windows.go +++ b/src/os/exec/exec_windows.go @@ -5,7 +5,7 @@ package exec import ( - "os" + "io/fs" "syscall" ) @@ -15,7 +15,7 @@ func init() { // to stdin if the program completed successfully otherwise. // See Issue 20445. const _ERROR_NO_DATA = syscall.Errno(0xe8) - pe, ok := err.(*os.PathError) + pe, ok := err.(*fs.PathError) return ok && pe.Op == "write" && pe.Path == "|1" && (pe.Err == syscall.ERROR_BROKEN_PIPE || pe.Err == _ERROR_NO_DATA) diff --git a/src/os/exec/lp_plan9.go b/src/os/exec/lp_plan9.go index 5860cbca4d..e8826a5083 100644 --- a/src/os/exec/lp_plan9.go +++ b/src/os/exec/lp_plan9.go @@ -6,6 +6,7 @@ package exec import ( "errors" + "io/fs" "os" "path/filepath" "strings" @@ -22,7 +23,7 @@ func findExecutable(file string) error { if m := d.Mode(); !m.IsDir() && m&0111 != 0 { return nil } - return os.ErrPermission + return fs.ErrPermission } // LookPath searches for an executable named file in the diff --git a/src/os/exec/lp_unix.go b/src/os/exec/lp_unix.go index 93793e0eee..66c1df76fb 100644 --- a/src/os/exec/lp_unix.go +++ b/src/os/exec/lp_unix.go @@ -8,6 +8,7 @@ package exec import ( "errors" + "io/fs" "os" "path/filepath" "strings" @@ -24,7 +25,7 @@ func findExecutable(file string) error { if m := d.Mode(); !m.IsDir() && m&0111 != 0 { return nil } - return os.ErrPermission + return fs.ErrPermission } // LookPath searches for an executable named file in the diff --git a/src/os/exec/lp_windows.go b/src/os/exec/lp_windows.go index 9ea3d76575..e7a2cdf142 100644 --- a/src/os/exec/lp_windows.go +++ b/src/os/exec/lp_windows.go @@ -6,6 +6,7 @@ package exec import ( "errors" + "io/fs" "os" "path/filepath" "strings" @@ -20,7 +21,7 @@ func chkStat(file string) error { return err } if d.IsDir() { - return os.ErrPermission + return fs.ErrPermission } return nil } @@ -47,7 +48,7 @@ func findExecutable(file string, exts []string) (string, error) { return f, nil } } - return "", os.ErrNotExist + return "", fs.ErrNotExist } // LookPath searches for an executable named file in the diff --git a/src/os/os_test.go b/src/os/os_test.go index c692ba099f..8f14263401 100644 --- a/src/os/os_test.go +++ b/src/os/os_test.go @@ -2526,7 +2526,7 @@ func testDoubleCloseError(t *testing.T, path string) { if err := file.Close(); err == nil { t.Error("second Close did not fail") } else if pe, ok := err.(*PathError); !ok { - t.Errorf("second Close returned unexpected error type %T; expected os.PathError", pe) + t.Errorf("second Close returned unexpected error type %T; expected fs.PathError", pe) } else if pe.Err != ErrClosed { t.Errorf("second Close returned %q, wanted %q", err, ErrClosed) } else { diff --git a/src/os/os_windows_test.go b/src/os/os_windows_test.go index f03ec750d0..e002774844 100644 --- a/src/os/os_windows_test.go +++ b/src/os/os_windows_test.go @@ -12,6 +12,7 @@ import ( "internal/syscall/windows/registry" "internal/testenv" "io" + "io/fs" "io/ioutil" "os" osexec "os/exec" @@ -164,11 +165,11 @@ func testDirLinks(t *testing.T, tests []dirLinkTest) { t.Errorf("failed to lstat link %v: %v", link, err) continue } - if m := fi2.Mode(); m&os.ModeSymlink == 0 { + if m := fi2.Mode(); m&fs.ModeSymlink == 0 { t.Errorf("%q should be a link, but is not (mode=0x%x)", link, uint32(m)) continue } - if m := fi2.Mode(); m&os.ModeDir != 0 { + if m := fi2.Mode(); m&fs.ModeDir != 0 { t.Errorf("%q should be a link, not a directory (mode=0x%x)", link, uint32(m)) continue } @@ -681,7 +682,7 @@ func TestStatSymlinkLoop(t *testing.T) { defer os.Remove("x") _, err = os.Stat("x") - if _, ok := err.(*os.PathError); !ok { + if _, ok := err.(*fs.PathError); !ok { t.Errorf("expected *PathError, got %T: %v\n", err, err) } } @@ -1291,9 +1292,9 @@ func TestWindowsReadlink(t *testing.T) { // os.Mkdir(os.DevNull) fails. func TestMkdirDevNull(t *testing.T) { err := os.Mkdir(os.DevNull, 777) - oserr, ok := err.(*os.PathError) + oserr, ok := err.(*fs.PathError) if !ok { - t.Fatalf("error (%T) is not *os.PathError", err) + t.Fatalf("error (%T) is not *fs.PathError", err) } errno, ok := oserr.Err.(syscall.Errno) if !ok { diff --git a/src/os/pipe_test.go b/src/os/pipe_test.go index 429bd813c2..0593efec75 100644 --- a/src/os/pipe_test.go +++ b/src/os/pipe_test.go @@ -13,6 +13,7 @@ import ( "fmt" "internal/testenv" "io" + "io/fs" "io/ioutil" "os" osexec "os/exec" @@ -46,7 +47,7 @@ func TestEPIPE(t *testing.T) { if err == nil { t.Fatal("unexpected success of Write to broken pipe") } - if pe, ok := err.(*os.PathError); ok { + if pe, ok := err.(*fs.PathError); ok { err = pe.Err } if se, ok := err.(*os.SyscallError); ok { @@ -202,10 +203,10 @@ func testClosedPipeRace(t *testing.T, read bool) { } if err == nil { t.Error("I/O on closed pipe unexpectedly succeeded") - } else if pe, ok := err.(*os.PathError); !ok { - t.Errorf("I/O on closed pipe returned unexpected error type %T; expected os.PathError", pe) - } else if pe.Err != os.ErrClosed { - t.Errorf("got error %q but expected %q", pe.Err, os.ErrClosed) + } else if pe, ok := err.(*fs.PathError); !ok { + t.Errorf("I/O on closed pipe returned unexpected error type %T; expected fs.PathError", pe) + } else if pe.Err != fs.ErrClosed { + t.Errorf("got error %q but expected %q", pe.Err, fs.ErrClosed) } else { t.Logf("I/O returned expected error %q", err) } @@ -233,7 +234,7 @@ func TestReadNonblockingFd(t *testing.T) { defer syscall.SetNonblock(fd, false) _, err := os.Stdin.Read(make([]byte, 1)) if err != nil { - if perr, ok := err.(*os.PathError); !ok || perr.Err != syscall.EAGAIN { + if perr, ok := err.(*fs.PathError); !ok || perr.Err != syscall.EAGAIN { t.Fatalf("read on nonblocking stdin got %q, should have gotten EAGAIN", err) } } @@ -308,10 +309,10 @@ func testCloseWithBlockingRead(t *testing.T, r, w *os.File) { if err == nil { t.Error("I/O on closed pipe unexpectedly succeeded") } - if pe, ok := err.(*os.PathError); ok { + if pe, ok := err.(*fs.PathError); ok { err = pe.Err } - if err != io.EOF && err != os.ErrClosed { + if err != io.EOF && err != fs.ErrClosed { t.Errorf("got %v, expected EOF or closed", err) } }(c2) diff --git a/src/os/removeall_test.go b/src/os/removeall_test.go index 1e5c650fe1..bc9c468ce3 100644 --- a/src/os/removeall_test.go +++ b/src/os/removeall_test.go @@ -359,7 +359,7 @@ func TestRemoveAllButReadOnlyAndPathError(t *testing.T) { t.Errorf("got %q, expected pathErr.path %q", g, w) } } else { - t.Errorf("got %T, expected *os.PathError", err) + t.Errorf("got %T, expected *fs.PathError", err) } for _, dir := range dirs { diff --git a/src/os/signal/signal_cgo_test.go b/src/os/signal/signal_cgo_test.go index a117221400..a8a485613f 100644 --- a/src/os/signal/signal_cgo_test.go +++ b/src/os/signal/signal_cgo_test.go @@ -17,6 +17,7 @@ import ( "context" "fmt" "io" + "io/fs" "os" "os/exec" ptypkg "os/signal/internal/pty" @@ -127,7 +128,7 @@ func TestTerminalSignal(t *testing.T) { if len(line) > 0 || len(handled) > 0 { t.Logf("%q", append(handled, line...)) } - if perr, ok := err.(*os.PathError); ok { + if perr, ok := err.(*fs.PathError); ok { err = perr.Err } // EOF means pty is closed. diff --git a/src/os/stat_test.go b/src/os/stat_test.go index 60f3b4c587..88b789080e 100644 --- a/src/os/stat_test.go +++ b/src/os/stat_test.go @@ -6,6 +6,7 @@ package os_test import ( "internal/testenv" + "io/fs" "io/ioutil" "os" "path/filepath" @@ -14,7 +15,7 @@ import ( ) // testStatAndLstat verifies that all os.Stat, os.Lstat os.File.Stat and os.Readdir work. -func testStatAndLstat(t *testing.T, path string, isLink bool, statCheck, lstatCheck func(*testing.T, string, os.FileInfo)) { +func testStatAndLstat(t *testing.T, path string, isLink bool, statCheck, lstatCheck func(*testing.T, string, fs.FileInfo)) { // test os.Stat sfi, err := os.Stat(path) if err != nil { @@ -70,7 +71,7 @@ func testStatAndLstat(t *testing.T, path string, isLink bool, statCheck, lstatCh } } - // test os.FileInfo returned by os.Readdir + // test fs.FileInfo returned by os.Readdir if len(path) > 0 && os.IsPathSeparator(path[len(path)-1]) { // skip os.Readdir test of directories with slash at the end return @@ -88,7 +89,7 @@ func testStatAndLstat(t *testing.T, path string, isLink bool, statCheck, lstatCh t.Error(err) return } - var lsfi2 os.FileInfo + var lsfi2 fs.FileInfo base := filepath.Base(path) for _, fi2 := range fis { if fi2.Name() == base { @@ -108,34 +109,34 @@ func testStatAndLstat(t *testing.T, path string, isLink bool, statCheck, lstatCh } // testIsDir verifies that fi refers to directory. -func testIsDir(t *testing.T, path string, fi os.FileInfo) { +func testIsDir(t *testing.T, path string, fi fs.FileInfo) { t.Helper() if !fi.IsDir() { t.Errorf("%q should be a directory", path) } - if fi.Mode()&os.ModeSymlink != 0 { + if fi.Mode()&fs.ModeSymlink != 0 { t.Errorf("%q should not be a symlink", path) } } // testIsSymlink verifies that fi refers to symlink. -func testIsSymlink(t *testing.T, path string, fi os.FileInfo) { +func testIsSymlink(t *testing.T, path string, fi fs.FileInfo) { t.Helper() if fi.IsDir() { t.Errorf("%q should not be a directory", path) } - if fi.Mode()&os.ModeSymlink == 0 { + if fi.Mode()&fs.ModeSymlink == 0 { t.Errorf("%q should be a symlink", path) } } // testIsFile verifies that fi refers to file. -func testIsFile(t *testing.T, path string, fi os.FileInfo) { +func testIsFile(t *testing.T, path string, fi fs.FileInfo) { t.Helper() if fi.IsDir() { t.Errorf("%q should not be a directory", path) } - if fi.Mode()&os.ModeSymlink != 0 { + if fi.Mode()&fs.ModeSymlink != 0 { t.Errorf("%q should not be a symlink", path) } } diff --git a/src/path/filepath/example_unix_walk_test.go b/src/path/filepath/example_unix_walk_test.go index fa8b8e393b..66dc7f6b53 100644 --- a/src/path/filepath/example_unix_walk_test.go +++ b/src/path/filepath/example_unix_walk_test.go @@ -8,6 +8,7 @@ package filepath_test import ( "fmt" + "io/fs" "io/ioutil" "os" "path/filepath" @@ -40,7 +41,7 @@ func ExampleWalk() { subDirToSkip := "skip" fmt.Println("On Unix:") - err = filepath.Walk(".", func(path string, info os.FileInfo, err error) error { + err = filepath.Walk(".", func(path string, info fs.FileInfo, err error) error { if err != nil { fmt.Printf("prevent panic by handling failure accessing a path %q: %v\n", path, err) return err diff --git a/src/path/filepath/path.go b/src/path/filepath/path.go index 26f1833189..dffd27db14 100644 --- a/src/path/filepath/path.go +++ b/src/path/filepath/path.go @@ -13,6 +13,7 @@ package filepath import ( "errors" + "io/fs" "os" "sort" "strings" @@ -339,7 +340,7 @@ var SkipDir = errors.New("skip this directory") // visited by Walk. The path argument contains the argument to Walk as a // prefix; that is, if Walk is called with "dir", which is a directory // containing the file "a", the walk function will be called with argument -// "dir/a". The info argument is the os.FileInfo for the named path. +// "dir/a". The info argument is the fs.FileInfo for the named path. // // If there was a problem walking to the file or directory named by path, the // incoming error will describe the problem and the function can decide how @@ -350,12 +351,12 @@ var SkipDir = errors.New("skip this directory") // Walk skips the directory's contents entirely. If the function returns SkipDir // when invoked on a non-directory file, Walk skips the remaining files in the // containing directory. -type WalkFunc func(path string, info os.FileInfo, err error) error +type WalkFunc func(path string, info fs.FileInfo, err error) error var lstat = os.Lstat // for testing // walk recursively descends path, calling walkFn. -func walk(path string, info os.FileInfo, walkFn WalkFunc) error { +func walk(path string, info fs.FileInfo, walkFn WalkFunc) error { if !info.IsDir() { return walkFn(path, info, nil) } diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go index 6a8700e413..7dc8b60c28 100644 --- a/src/path/filepath/path_test.go +++ b/src/path/filepath/path_test.go @@ -8,6 +8,7 @@ import ( "errors" "fmt" "internal/testenv" + "io/fs" "io/ioutil" "os" "path/filepath" @@ -393,7 +394,7 @@ func checkMarks(t *testing.T, report bool) { // Assumes that each node name is unique. Good enough for a test. // If clear is true, any incoming error is cleared before return. The errors // are always accumulated, though. -func mark(info os.FileInfo, err error, errors *[]error, clear bool) error { +func mark(info fs.FileInfo, err error, errors *[]error, clear bool) error { name := info.Name() walkTree(tree, tree.name, func(path string, n *Node) { if n.name == name { @@ -454,7 +455,7 @@ func TestWalk(t *testing.T) { makeTree(t) errors := make([]error, 0, 10) clear := true - markFn := func(path string, info os.FileInfo, err error) error { + markFn := func(path string, info fs.FileInfo, err error) error { return mark(info, err, &errors, clear) } // Expect no errors. @@ -543,7 +544,7 @@ func TestWalkSkipDirOnFile(t *testing.T) { touch(t, filepath.Join(td, "dir/foo2")) sawFoo2 := false - walker := func(path string, info os.FileInfo, err error) error { + walker := func(path string, info fs.FileInfo, err error) error { if strings.HasSuffix(path, "foo2") { sawFoo2 = true } @@ -589,14 +590,14 @@ func TestWalkFileError(t *testing.T) { *filepath.LstatP = os.Lstat }() statErr := errors.New("some stat error") - *filepath.LstatP = func(path string) (os.FileInfo, error) { + *filepath.LstatP = func(path string) (fs.FileInfo, error) { if strings.HasSuffix(path, "stat-error") { return nil, statErr } return os.Lstat(path) } got := map[string]error{} - err = filepath.Walk(td, func(path string, fi os.FileInfo, err error) error { + err = filepath.Walk(td, func(path string, fi fs.FileInfo, err error) error { rel, _ := filepath.Rel(td, path) got[filepath.ToSlash(rel)] = err return nil @@ -1289,7 +1290,7 @@ func TestBug3486(t *testing.T) { // https://golang.org/issue/3486 ken := filepath.Join(root, "ken") seenBugs := false seenKen := false - err = filepath.Walk(root, func(pth string, info os.FileInfo, err error) error { + err = filepath.Walk(root, func(pth string, info fs.FileInfo, err error) error { if err != nil { t.Fatal(err) } @@ -1338,7 +1339,7 @@ func testWalkSymlink(t *testing.T, mklink func(target, link string) error) { } var visited []string - err = filepath.Walk(tmpdir, func(path string, info os.FileInfo, err error) error { + err = filepath.Walk(tmpdir, func(path string, info fs.FileInfo, err error) error { if err != nil { t.Fatal(err) } diff --git a/src/path/filepath/path_windows_test.go b/src/path/filepath/path_windows_test.go index f7c454bf65..990f18614d 100644 --- a/src/path/filepath/path_windows_test.go +++ b/src/path/filepath/path_windows_test.go @@ -8,6 +8,7 @@ import ( "flag" "fmt" "internal/testenv" + "io/fs" "io/ioutil" "os" "os/exec" @@ -34,7 +35,7 @@ func testWinSplitListTestIsValid(t *testing.T, ti int, tt SplitListTest, const ( cmdfile = `printdir.cmd` - perm os.FileMode = 0700 + perm fs.FileMode = 0700 ) tmp, err := ioutil.TempDir("", "testWinSplitListTestIsValid") diff --git a/src/path/filepath/symlink.go b/src/path/filepath/symlink.go index 335b315a20..6fefd15977 100644 --- a/src/path/filepath/symlink.go +++ b/src/path/filepath/symlink.go @@ -6,6 +6,7 @@ package filepath import ( "errors" + "io/fs" "os" "runtime" "syscall" @@ -85,7 +86,7 @@ func walkSymlinks(path string) (string, error) { return "", err } - if fi.Mode()&os.ModeSymlink == 0 { + if fi.Mode()&fs.ModeSymlink == 0 { if !fi.Mode().IsDir() && end < len(path) { return "", syscall.ENOTDIR } diff --git a/src/runtime/testdata/testprogcgo/exec.go b/src/runtime/testdata/testprogcgo/exec.go index 94da5dc526..15723c7369 100644 --- a/src/runtime/testdata/testprogcgo/exec.go +++ b/src/runtime/testdata/testprogcgo/exec.go @@ -31,6 +31,7 @@ import "C" import ( "fmt" + "io/fs" "os" "os/exec" "os/signal" @@ -98,7 +99,7 @@ func CgoExecSignalMask() { // isEAGAIN reports whether err is an EAGAIN error from a process execution. func isEAGAIN(err error) bool { - if p, ok := err.(*os.PathError); ok { + if p, ok := err.(*fs.PathError); ok { err = p.Err } return err == syscall.EAGAIN diff --git a/src/syscall/syscall_js.go b/src/syscall/syscall_js.go index dfb4a275e3..0ab8c3fba4 100644 --- a/src/syscall/syscall_js.go +++ b/src/syscall/syscall_js.go @@ -49,7 +49,7 @@ const PathMax = 256 // using errors.Is. For example: // // _, _, err := syscall.Syscall(...) -// if errors.Is(err, os.ErrNotExist) ... +// if errors.Is(err, fs.ErrNotExist) ... type Errno uintptr func (e Errno) Error() string { diff --git a/src/syscall/syscall_linux_test.go b/src/syscall/syscall_linux_test.go index c5008f2913..93a4d236d8 100644 --- a/src/syscall/syscall_linux_test.go +++ b/src/syscall/syscall_linux_test.go @@ -8,6 +8,7 @@ import ( "bufio" "fmt" "io" + "io/fs" "io/ioutil" "os" "os/exec" @@ -353,7 +354,7 @@ func TestSyscallNoError(t *testing.T) { t.Fatalf("failed to chown test binary %q, %v", tmpBinary, err) } - err = os.Chmod(tmpBinary, 0755|os.ModeSetuid) + err = os.Chmod(tmpBinary, 0755|fs.ModeSetuid) if err != nil { t.Fatalf("failed to set setuid bit on test binary %q, %v", tmpBinary, err) } diff --git a/src/syscall/syscall_plan9.go b/src/syscall/syscall_plan9.go index 1648e409b0..d16cad45d8 100644 --- a/src/syscall/syscall_plan9.go +++ b/src/syscall/syscall_plan9.go @@ -25,7 +25,7 @@ const bitSize16 = 2 // using errors.Is. For example: // // _, _, err := syscall.Syscall(...) -// if errors.Is(err, os.ErrNotExist) ... +// if errors.Is(err, fs.ErrNotExist) ... type ErrorString string func (e ErrorString) Error() string { return string(e) } diff --git a/src/syscall/syscall_unix.go b/src/syscall/syscall_unix.go index 91c939e0ea..786ad34170 100644 --- a/src/syscall/syscall_unix.go +++ b/src/syscall/syscall_unix.go @@ -110,7 +110,7 @@ func (m *mmapper) Munmap(data []byte) (err error) { // using errors.Is. For example: // // _, _, err := syscall.Syscall(...) -// if errors.Is(err, os.ErrNotExist) ... +// if errors.Is(err, fs.ErrNotExist) ... type Errno uintptr func (e Errno) Error() string { diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go index f62c00d72f..40c43de84c 100644 --- a/src/syscall/syscall_windows.go +++ b/src/syscall/syscall_windows.go @@ -106,7 +106,7 @@ func UTF16PtrFromString(s string) (*uint16, error) { // using errors.Is. For example: // // _, _, err := syscall.Syscall(...) -// if errors.Is(err, os.ErrNotExist) ... +// if errors.Is(err, fs.ErrNotExist) ... type Errno uintptr func langid(pri, sub uint16) uint32 { return uint32(sub)<<10 | uint32(pri) } -- cgit v1.3 From fcb9d6b5d0ba6f5606c2b5dfc09f75e2dc5fc1e5 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 6 Jul 2020 09:56:43 -0400 Subject: io/fs: add FS, File, ReadDirFile; move DirEntry from os These are the core interfaces for the io/fs design. See #41190 and https://golang.org/s/draft-iofs-design for details. DirEntry was left behind in the previous move from os but is needed for ReadDirFile, so it moves in this commit. Also apply a couple comment changes suggested in the review of CL 261540. For #41190. Change-Id: I087741545139ed30b9ba5db728a0bad71129500b Reviewed-on: https://go-review.googlesource.com/c/go/+/243908 Trust: Russ Cox Run-TryBot: Russ Cox Reviewed-by: Emmanuel Odeke Reviewed-by: Rob Pike TryBot-Result: Go Bot --- src/io/fs/fs.go | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/io/fs/fs_test.go | 48 ++++++++++++++++++++++ src/os/dir.go | 24 ++--------- 3 files changed, 163 insertions(+), 21 deletions(-) create mode 100644 src/io/fs/fs_test.go (limited to 'src/io') diff --git a/src/io/fs/fs.go b/src/io/fs/fs.go index de5c465d9d..d9f89fc6ee 100644 --- a/src/io/fs/fs.go +++ b/src/io/fs/fs.go @@ -12,6 +12,118 @@ import ( "time" ) +// An FS provides access to a hierarchical file system. +// +// The FS interface is the minimum implementation required of the file system. +// A file system may implement additional interfaces, +// such as fsutil.ReadFileFS, to provide additional or optimized functionality. +// See io/fsutil for details. +type FS interface { + // Open opens the named file. + // + // When Open returns an error, it should be of type *PathError + // with the Op field set to "open", the Path field set to name, + // and the Err field describing the problem. + // + // Open should reject attempts to open names that do not satisfy + // ValidPath(name), returning a *PathError with Err set to + // ErrInvalid or ErrNotExist. + Open(name string) (File, error) +} + +// ValidPath reports whether the given path name +// is valid for use in a call to Open. +// Path names passed to open are unrooted, slash-separated +// sequences of path elements, like “x/y/z”. +// Path names must not contain a “.” or “..” or empty element, +// except for the special case that the root directory is named “.”. +// +// Paths are slash-separated on all systems, even Windows. +// Backslashes must not appear in path names. +func ValidPath(name string) bool { + if name == "." { + // special case + return true + } + + // Iterate over elements in name, checking each. + for { + i := 0 + for i < len(name) && name[i] != '/' { + if name[i] == '\\' { + return false + } + i++ + } + elem := name[:i] + if elem == "" || elem == "." || elem == ".." { + return false + } + if i == len(name) { + return true // reached clean ending + } + name = name[i+1:] + } +} + +// A File provides access to a single file. +// The File interface is the minimum implementation required of the file. +// A file may implement additional interfaces, such as +// ReadDirFile, ReaderAt, or Seeker, to provide additional or optimized functionality. +type File interface { + Stat() (FileInfo, error) + Read([]byte) (int, error) + Close() error +} + +// A DirEntry is an entry read from a directory +// (using the ReadDir function or a ReadDirFile's ReadDir method). +type DirEntry interface { + // Name returns the name of the file (or subdirectory) described by the entry. + // This name is only the final element of the path (the base name), not the entire path. + // For example, Name would return "hello.go" not "/home/gopher/hello.go". + Name() string + + // IsDir reports whether the entry describes a directory. + IsDir() bool + + // Type returns the type bits for the entry. + // The type bits are a subset of the usual FileMode bits, those returned by the FileMode.Type method. + Type() FileMode + + // Info returns the FileInfo for the file or subdirectory described by the entry. + // The returned FileInfo may be from the time of the original directory read + // or from the time of the call to Info. If the file has been removed or renamed + // since the directory read, Info may return an error satisfying errors.Is(err, ErrNotExist). + // If the entry denotes a symbolic link, Info reports the information about the link itself, + // not the link's target. + Info() (FileInfo, error) +} + +// A ReadDirFile is a directory file whose entries can be read with the ReadDir method. +// Every directory file should implement this interface. +// (It is permissible for any file to implement this interface, +// but if so ReadDir should return an error for non-directories.) +type ReadDirFile interface { + File + + // ReadDir reads the contents of the directory and returns + // a slice of up to n DirEntry values in directory order. + // Subsequent calls on the same file will yield further DirEntry values. + // + // If n > 0, ReadDir returns at most n DirEntry structures. + // In this case, if ReadDir returns an empty slice, it will return + // a non-nil error explaining why. + // At the end of a directory, the error is io.EOF. + // + // If n <= 0, ReadDir returns all the DirEntry values from the directory + // in a single slice. In this case, if ReadDir succeeds (reads all the way + // to the end of the directory), it returns the slice and a nil error. + // If it encounters an error before the end of the directory, + // ReadDir returns the DirEntry list read until that point and a non-nil error. + ReadDir(n int) ([]DirEntry, error) +} + // Generic file system errors. // Errors returned by file systems can be tested against these errors // using errors.Is. diff --git a/src/io/fs/fs_test.go b/src/io/fs/fs_test.go new file mode 100644 index 0000000000..8d395fc0db --- /dev/null +++ b/src/io/fs/fs_test.go @@ -0,0 +1,48 @@ +// Copyright 2020 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 fs_test + +import ( + . "io/fs" + "testing" +) + +var isValidPathTests = []struct { + name string + ok bool +}{ + {".", true}, + {"x", true}, + {"x/y", true}, + + {"", false}, + {"..", false}, + {"/", false}, + {"x/", false}, + {"/x", false}, + {"x/y/", false}, + {"/x/y", false}, + {"./", false}, + {"./x", false}, + {"x/.", false}, + {"x/./y", false}, + {"../", false}, + {"../x", false}, + {"x/..", false}, + {"x/../y", false}, + {"x//y", false}, + {`x\`, false}, + {`x\y`, false}, + {`\x`, false}, +} + +func TestValidPath(t *testing.T) { + for _, tt := range isValidPathTests { + ok := ValidPath(tt.name) + if ok != tt.ok { + t.Errorf("ValidPath(%q) = %v, want %v", tt.name, ok, tt.ok) + } + } +} diff --git a/src/os/dir.go b/src/os/dir.go index a312001704..b56d998459 100644 --- a/src/os/dir.go +++ b/src/os/dir.go @@ -4,6 +4,8 @@ package os +import "io/fs" + type readdirMode int const ( @@ -62,27 +64,7 @@ func (f *File) Readdirnames(n int) (names []string, err error) { // A DirEntry is an entry read from a directory // (using the ReadDir function or a File's ReadDir method). -type DirEntry interface { - // Name returns the name of the file (or subdirectory) described by the entry. - // This name is only the final element of the path, not the entire path. - // For example, Name would return "hello.go" not "/home/gopher/hello.go". - Name() string - - // IsDir reports whether the entry describes a subdirectory. - IsDir() bool - - // Type returns the type bits for the entry. - // The type bits are a subset of the usual FileMode bits, those returned by the FileMode.Type method. - Type() FileMode - - // Info returns the FileInfo for the file or subdirectory described by the entry. - // The returned FileInfo may be from the time of the original directory read - // or from the time of the call to Info. If the file has been removed or renamed - // since the directory read, Info may return an error satisfying errors.Is(err, ErrNotExist). - // If the entry denotes a symbolic link, Info reports the information about the link itself, - // not the link's target. - Info() (FileInfo, error) -} +type DirEntry = fs.DirEntry // ReadDir reads the contents of the directory associated with the file f // and returns a slice of DirEntry values in directory order. -- cgit v1.3 From f098ccf04a33e2e4d2dffa2e90fe77ca8a0fcbb4 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 6 Jul 2020 11:26:26 -0400 Subject: io/fs: add ReadFile and ReadFileFS Add ReadFile helper function, ReadFileFS interface, and test. Add ReadFile method to fstest.MapFS. Add testing of ReadFile method to fstest.TestFS. For #41190. Change-Id: I5b6a41e2e582824e570463b698b635abaa436c32 Reviewed-on: https://go-review.googlesource.com/c/go/+/243912 Trust: Russ Cox Reviewed-by: Rob Pike --- src/go/build/deps_test.go | 4 ++- src/io/fs/readfile.go | 63 ++++++++++++++++++++++++++++++++++++++++++++ src/io/fs/readfile_test.go | 43 ++++++++++++++++++++++++++++++ src/testing/fstest/mapfs.go | 12 +++++++++ src/testing/fstest/testfs.go | 39 ++++++++++++++++++++++++--- 5 files changed, 156 insertions(+), 5 deletions(-) create mode 100644 src/io/fs/readfile.go create mode 100644 src/io/fs/readfile_test.go (limited to 'src/io') diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index 4867a5031a..ccee539086 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -165,7 +165,9 @@ var depsRules = ` os/signal, STR < path/filepath - < io/ioutil, os/exec + < io/ioutil, os/exec; + + io/ioutil, os/exec, os/signal < OS; reflect !< OS; diff --git a/src/io/fs/readfile.go b/src/io/fs/readfile.go new file mode 100644 index 0000000000..7ee9eadac4 --- /dev/null +++ b/src/io/fs/readfile.go @@ -0,0 +1,63 @@ +// Copyright 2020 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 fs + +import "io" + +// ReadFileFS is the interface implemented by a file system +// that provides an optimized implementation of ReadFile. +type ReadFileFS interface { + FS + + // ReadFile reads the named file and returns its contents. + // A successful call returns a nil error, not io.EOF. + // (Because ReadFile reads the whole file, the expected EOF + // from the final Read is not treated as an error to be reported.) + ReadFile(name string) ([]byte, error) +} + +// ReadFile reads the named file from the file system fs and returns its contents. +// A successful call returns a nil error, not io.EOF. +// (Because ReadFile reads the whole file, the expected EOF +// from the final Read is not treated as an error to be reported.) +// +// If fs implements ReadFileFS, ReadFile calls fs.ReadFile. +// Otherwise ReadFile calls fs.Open and uses Read and Close +// on the returned file. +func ReadFile(fsys FS, name string) ([]byte, error) { + if fsys, ok := fsys.(ReadFileFS); ok { + return fsys.ReadFile(name) + } + + file, err := fsys.Open(name) + if err != nil { + return nil, err + } + defer file.Close() + + var size int + if info, err := file.Stat(); err == nil { + size64 := info.Size() + if int64(int(size64)) == size64 { + size = int(size64) + } + } + + data := make([]byte, 0, size+1) + for { + if len(data) >= cap(data) { + d := append(data[:cap(data)], 0) + data = d[:len(data)] + } + n, err := file.Read(data[len(data):cap(data)]) + data = data[:len(data)+n] + if err != nil { + if err == io.EOF { + err = nil + } + return data, err + } + } +} diff --git a/src/io/fs/readfile_test.go b/src/io/fs/readfile_test.go new file mode 100644 index 0000000000..0afa334ace --- /dev/null +++ b/src/io/fs/readfile_test.go @@ -0,0 +1,43 @@ +// Copyright 2020 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 fs_test + +import ( + . "io/fs" + "testing" + "testing/fstest" + "time" +) + +var testFsys = fstest.MapFS{ + "hello.txt": { + Data: []byte("hello, world"), + Mode: 0456, + ModTime: time.Now(), + Sys: &sysValue, + }, +} + +var sysValue int + +type readFileOnly struct{ ReadFileFS } + +func (readFileOnly) Open(name string) (File, error) { return nil, ErrNotExist } + +type openOnly struct{ FS } + +func TestReadFile(t *testing.T) { + // Test that ReadFile uses the method when present. + data, err := ReadFile(readFileOnly{testFsys}, "hello.txt") + if string(data) != "hello, world" || err != nil { + t.Fatalf(`ReadFile(readFileOnly, "hello.txt") = %q, %v, want %q, nil`, data, err, "hello, world") + } + + // Test that ReadFile uses Open when the method is not present. + data, err = ReadFile(openOnly{testFsys}, "hello.txt") + if string(data) != "hello, world" || err != nil { + t.Fatalf(`ReadFile(openOnly, "hello.txt") = %q, %v, want %q, nil`, data, err, "hello, world") + } +} diff --git a/src/testing/fstest/mapfs.go b/src/testing/fstest/mapfs.go index 84a943f409..e969ac2bd1 100644 --- a/src/testing/fstest/mapfs.go +++ b/src/testing/fstest/mapfs.go @@ -108,6 +108,18 @@ func (fsys MapFS) Open(name string) (fs.File, error) { return &mapDir{name, mapFileInfo{elem, file}, list, 0}, nil } +// fsOnly is a wrapper that hides all but the fs.FS methods, +// to avoid an infinite recursion when implementing special +// methods in terms of helpers that would use them. +// (In general, implementing these methods using the package fs helpers +// is redundant and unnecessary, but having the methods may make +// MapFS exercise more code paths when used in tests.) +type fsOnly struct{ fs.FS } + +func (fsys MapFS) ReadFile(name string) ([]byte, error) { + return fs.ReadFile(fsOnly{fsys}, name) +} + // A mapFileInfo implements fs.FileInfo and fs.DirEntry for a given map file. type mapFileInfo struct { name string diff --git a/src/testing/fstest/testfs.go b/src/testing/fstest/testfs.go index 2bb2120c19..66725ca2a4 100644 --- a/src/testing/fstest/testfs.go +++ b/src/testing/fstest/testfs.go @@ -310,6 +310,27 @@ func (t *fsTester) checkFile(file string) { // The return value doesn't matter. f.Close() + // Check that ReadFile works if present. + if fsys, ok := t.fsys.(fs.ReadFileFS); ok { + data2, err := fsys.ReadFile(file) + if err != nil { + t.errorf("%s: fsys.ReadFile: %v", file, err) + return + } + t.checkFileRead(file, "ReadAll vs fsys.ReadFile", data, data2) + + t.checkBadPath(file, "ReadFile", + func(name string) error { _, err := fsys.ReadFile(name); return err }) + } + + // Check that fs.ReadFile works with t.fsys. + data2, err := fs.ReadFile(t.fsys, file) + if err != nil { + t.errorf("%s: fs.ReadFile: %v", file, err) + return + } + t.checkFileRead(file, "ReadAll vs fs.ReadFile", data, data2) + // Use iotest.TestReader to check small reads, Seek, ReadAt. f, err = t.fsys.Open(file) if err != nil { @@ -329,8 +350,19 @@ func (t *fsTester) checkFileRead(file, desc string, data1, data2 []byte) { } } -// checkOpen checks that various invalid forms of file's name cannot be opened. +// checkBadPath checks that various invalid forms of file's name cannot be opened using t.fsys.Open. func (t *fsTester) checkOpen(file string) { + t.checkBadPath(file, "Open", func(file string) error { + f, err := t.fsys.Open(file) + if err == nil { + f.Close() + } + return err + }) +} + +// checkBadPath checks that various invalid forms of file's name cannot be opened using open. +func (t *fsTester) checkBadPath(file string, desc string, open func(string) error) { bad := []string{ "/" + file, file + "/.", @@ -356,9 +388,8 @@ func (t *fsTester) checkOpen(file string) { } for _, b := range bad { - if f, err := t.fsys.Open(b); err == nil { - f.Close() - t.errorf("%s: Open(%s) succeeded, want error", file, b) + if err := open(b); err == nil { + t.errorf("%s: %s(%s) succeeded, want error", file, desc, b) } } } -- cgit v1.3 From 10a1a1a37c007adef8425d273e6b276547982889 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 6 Jul 2020 11:26:45 -0400 Subject: io/fs: add Stat and StatFS Add Stat helper function, StatFS interface, and test. Add Stat method to fstest.MapFS. Add testing of Stat method to fstest.TestFS. For #41190. Change-Id: Icf8b6eb1c3fa6f93a9be8405ec5a9468fb1da97b Reviewed-on: https://go-review.googlesource.com/c/go/+/243913 Trust: Russ Cox Reviewed-by: Rob Pike --- src/io/fs/stat.go | 31 +++++++++++++++++++++++++++++++ src/io/fs/stat_test.go | 36 ++++++++++++++++++++++++++++++++++++ src/testing/fstest/mapfs.go | 4 ++++ src/testing/fstest/testfs.go | 25 ++++++++++++++++++++++++- 4 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 src/io/fs/stat.go create mode 100644 src/io/fs/stat_test.go (limited to 'src/io') diff --git a/src/io/fs/stat.go b/src/io/fs/stat.go new file mode 100644 index 0000000000..735a6e3281 --- /dev/null +++ b/src/io/fs/stat.go @@ -0,0 +1,31 @@ +// Copyright 2020 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 fs + +// A StatFS is a file system with a Stat method. +type StatFS interface { + FS + + // Stat returns a FileInfo describing the file. + // If there is an error, it should be of type *PathError. + Stat(name string) (FileInfo, error) +} + +// Stat returns a FileInfo describing the named file from the file system. +// +// If fs implements StatFS, Stat calls fs.Stat. +// Otherwise, Stat opens the file to stat it. +func Stat(fsys FS, name string) (FileInfo, error) { + if fsys, ok := fsys.(StatFS); ok { + return fsys.Stat(name) + } + + file, err := fsys.Open(name) + if err != nil { + return nil, err + } + defer file.Close() + return file.Stat() +} diff --git a/src/io/fs/stat_test.go b/src/io/fs/stat_test.go new file mode 100644 index 0000000000..e312b6fbd9 --- /dev/null +++ b/src/io/fs/stat_test.go @@ -0,0 +1,36 @@ +// Copyright 2020 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 fs_test + +import ( + "fmt" + . "io/fs" + "testing" +) + +type statOnly struct{ StatFS } + +func (statOnly) Open(name string) (File, error) { return nil, ErrNotExist } + +func TestStat(t *testing.T) { + check := func(desc string, info FileInfo, err error) { + t.Helper() + if err != nil || info == nil || info.Mode() != 0456 { + infoStr := "" + if info != nil { + infoStr = fmt.Sprintf("FileInfo(Mode: %#o)", info.Mode()) + } + t.Fatalf("Stat(%s) = %v, %v, want Mode:0456, nil", desc, infoStr, err) + } + } + + // Test that Stat uses the method when present. + info, err := Stat(statOnly{testFsys}, "hello.txt") + check("statOnly", info, err) + + // Test that Stat uses Open when the method is not present. + info, err = Stat(openOnly{testFsys}, "hello.txt") + check("openOnly", info, err) +} diff --git a/src/testing/fstest/mapfs.go b/src/testing/fstest/mapfs.go index e969ac2bd1..b01911e589 100644 --- a/src/testing/fstest/mapfs.go +++ b/src/testing/fstest/mapfs.go @@ -120,6 +120,10 @@ func (fsys MapFS) ReadFile(name string) ([]byte, error) { return fs.ReadFile(fsOnly{fsys}, name) } +func (fsys MapFS) Stat(name string) (fs.FileInfo, error) { + return fs.Stat(fsOnly{fsys}, name) +} + // A mapFileInfo implements fs.FileInfo and fs.DirEntry for a given map file. type mapFileInfo struct { name string diff --git a/src/testing/fstest/testfs.go b/src/testing/fstest/testfs.go index 66725ca2a4..290d2596cc 100644 --- a/src/testing/fstest/testfs.go +++ b/src/testing/fstest/testfs.go @@ -230,7 +230,30 @@ func (t *fsTester) checkStat(path string, entry fs.DirEntry) { fentry := formatEntry(entry) finfo := formatInfoEntry(info) if fentry != finfo { - t.errorf("%s: mismatch:\n\tentry = %v\n\tfile.Stat() = %v", path, fentry, finfo) + t.errorf("%s: mismatch:\n\tentry = %s\n\tfile.Stat() = %s", path, fentry, finfo) + } + + info2, err := fs.Stat(t.fsys, path) + if err != nil { + t.errorf("%s: fs.Stat: %v", path, err) + return + } + finfo = formatInfo(info) + finfo2 := formatInfo(info2) + if finfo2 != finfo { + t.errorf("%s: fs.Stat(...) = %s\n\twant %s", path, finfo2, finfo) + } + + if fsys, ok := t.fsys.(fs.StatFS); ok { + info2, err := fsys.Stat(path) + if err != nil { + t.errorf("%s: fsys.Stat: %v", path, err) + return + } + finfo2 := formatInfo(info2) + if finfo2 != finfo { + t.errorf("%s: fsys.Stat(...) = %s\n\twant %s", path, finfo2, finfo) + } } } -- cgit v1.3 From 7a131acfd142f0fc7612365078b9f00e371fc0e2 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 6 Jul 2020 11:26:56 -0400 Subject: io/fs: add ReadDir and ReadDirFS Add ReadDir helper function, ReadDirFS interface, and test. Add ReadDir method to fstest.MapFS. Add testing of ReadDir method to fstest.TestFS. For #41190. Change-Id: Ib860770ec7433ba77b29e626682b238f1b3bf54f Reviewed-on: https://go-review.googlesource.com/c/go/+/243914 Trust: Russ Cox Reviewed-by: Rob Pike --- src/io/fs/readdir.go | 47 ++++++++++++++++++++++++++++++++++++++++++++ src/io/fs/readdir_test.go | 35 +++++++++++++++++++++++++++++++++ src/testing/fstest/mapfs.go | 4 ++++ src/testing/fstest/testfs.go | 42 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 src/io/fs/readdir.go create mode 100644 src/io/fs/readdir_test.go (limited to 'src/io') diff --git a/src/io/fs/readdir.go b/src/io/fs/readdir.go new file mode 100644 index 0000000000..3a5aa6d86a --- /dev/null +++ b/src/io/fs/readdir.go @@ -0,0 +1,47 @@ +// Copyright 2020 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 fs + +import ( + "errors" + "sort" +) + +// ReadDirFS is the interface implemented by a file system +// that provides an optimized implementation of ReadDir. +type ReadDirFS interface { + FS + + // ReadDir reads the named directory + // and returns a list of directory entries sorted by filename. + ReadDir(name string) ([]DirEntry, error) +} + +// ReadDir reads the named directory +// and returns a list of directory entries sorted by filename. +// +// If fs implements ReadDirFS, ReadDir calls fs.ReadDir. +// Otherwise ReadDir calls fs.Open and uses ReadDir and Close +// on the returned file. +func ReadDir(fsys FS, name string) ([]DirEntry, error) { + if fsys, ok := fsys.(ReadDirFS); ok { + return fsys.ReadDir(name) + } + + file, err := fsys.Open(name) + if err != nil { + return nil, err + } + defer file.Close() + + dir, ok := file.(ReadDirFile) + if !ok { + return nil, &PathError{Op: "readdir", Path: name, Err: errors.New("not implemented")} + } + + list, err := dir.ReadDir(-1) + sort.Slice(list, func(i, j int) bool { return list[i].Name() < list[j].Name() }) + return list, err +} diff --git a/src/io/fs/readdir_test.go b/src/io/fs/readdir_test.go new file mode 100644 index 0000000000..46a4bc2788 --- /dev/null +++ b/src/io/fs/readdir_test.go @@ -0,0 +1,35 @@ +// Copyright 2020 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 fs_test + +import ( + . "io/fs" + "testing" +) + +type readDirOnly struct{ ReadDirFS } + +func (readDirOnly) Open(name string) (File, error) { return nil, ErrNotExist } + +func TestReadDir(t *testing.T) { + check := func(desc string, dirs []DirEntry, err error) { + t.Helper() + if err != nil || len(dirs) != 1 || dirs[0].Name() != "hello.txt" { + var names []string + for _, d := range dirs { + names = append(names, d.Name()) + } + t.Errorf("ReadDir(%s) = %v, %v, want %v, nil", desc, names, err, []string{"hello.txt"}) + } + } + + // Test that ReadDir uses the method when present. + dirs, err := ReadDir(readDirOnly{testFsys}, ".") + check("readDirOnly", dirs, err) + + // Test that ReadDir uses Open when the method is not present. + dirs, err = ReadDir(openOnly{testFsys}, ".") + check("openOnly", dirs, err) +} diff --git a/src/testing/fstest/mapfs.go b/src/testing/fstest/mapfs.go index b01911e589..1eaf8f0040 100644 --- a/src/testing/fstest/mapfs.go +++ b/src/testing/fstest/mapfs.go @@ -124,6 +124,10 @@ func (fsys MapFS) Stat(name string) (fs.FileInfo, error) { return fs.Stat(fsOnly{fsys}, name) } +func (fsys MapFS) ReadDir(name string) ([]fs.DirEntry, error) { + return fs.ReadDir(fsOnly{fsys}, name) +} + // A mapFileInfo implements fs.FileInfo and fs.DirEntry for a given map file. type mapFileInfo struct { name string diff --git a/src/testing/fstest/testfs.go b/src/testing/fstest/testfs.go index 290d2596cc..4ea6ed6095 100644 --- a/src/testing/fstest/testfs.go +++ b/src/testing/fstest/testfs.go @@ -196,6 +196,36 @@ func (t *fsTester) checkDir(dir string) { } } t.checkDirList(dir, "first Open+ReadDir(-1) vs third Open+ReadDir(1,2) loop", list, list2) + + // If fsys has ReadDir, check that it matches and is sorted. + if fsys, ok := t.fsys.(fs.ReadDirFS); ok { + list2, err := fsys.ReadDir(dir) + if err != nil { + t.errorf("%s: fsys.ReadDir: %v", dir, err) + return + } + t.checkDirList(dir, "first Open+ReadDir(-1) vs fsys.ReadDir", list, list2) + + for i := 0; i+1 < len(list2); i++ { + if list2[i].Name() >= list2[i+1].Name() { + t.errorf("%s: fsys.ReadDir: list not sorted: %s before %s", dir, list2[i].Name(), list2[i+1].Name()) + } + } + } + + // Check fs.ReadDir as well. + list2, err = fs.ReadDir(t.fsys, dir) + if err != nil { + t.errorf("%s: fs.ReadDir: %v", dir, err) + return + } + t.checkDirList(dir, "first Open+ReadDir(-1) vs fs.ReadDir", list, list2) + + for i := 0; i+1 < len(list2); i++ { + if list2[i].Name() >= list2[i+1].Name() { + t.errorf("%s: fs.ReadDir: list not sorted: %s before %s", dir, list2[i].Name(), list2[i+1].Name()) + } + } } // formatEntry formats an fs.DirEntry into a string for error messages and comparison. @@ -233,12 +263,22 @@ func (t *fsTester) checkStat(path string, entry fs.DirEntry) { t.errorf("%s: mismatch:\n\tentry = %s\n\tfile.Stat() = %s", path, fentry, finfo) } + einfo, err := entry.Info() + if err != nil { + t.errorf("%s: entry.Info: %v", path, err) + return + } + fentry = formatInfo(einfo) + finfo = formatInfo(info) + if fentry != finfo { + t.errorf("%s: mismatch:\n\tentry.Info() = %s\n\tfile.Stat() = %s\n", path, fentry, finfo) + } + info2, err := fs.Stat(t.fsys, path) if err != nil { t.errorf("%s: fs.Stat: %v", path, err) return } - finfo = formatInfo(info) finfo2 := formatInfo(info2) if finfo2 != finfo { t.errorf("%s: fs.Stat(...) = %s\n\twant %s", path, finfo2, finfo) -- cgit v1.3 From b64202bc29b9c1cf0118878d1c0acc9cdb2308f6 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 6 Jul 2020 11:27:12 -0400 Subject: io/fs: add Glob and GlobFS Add Glob helper function, GlobFS interface, and test. Add Glob method to fstest.MapFS. Add testing of Glob method to fstest.TestFS. For #41190. Change-Id: If89dd7f63e310ba5ca2651340267a9ff39fcc0c7 Reviewed-on: https://go-review.googlesource.com/c/go/+/243915 Trust: Russ Cox Reviewed-by: Rob Pike --- src/go/build/deps_test.go | 2 +- src/io/fs/glob.go | 116 +++++++++++++++++++++++++++++++++++++++++++ src/io/fs/glob_test.go | 82 ++++++++++++++++++++++++++++++ src/testing/fstest/mapfs.go | 4 ++ src/testing/fstest/testfs.go | 96 +++++++++++++++++++++++++++++++++++ 5 files changed, 299 insertions(+), 1 deletion(-) create mode 100644 src/io/fs/glob.go create mode 100644 src/io/fs/glob_test.go (limited to 'src/io') diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go index ccee539086..16a67791cf 100644 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@ -123,7 +123,7 @@ var depsRules = ` < context < TIME; - TIME, io, sort + TIME, io, path, sort < io/fs; # MATH is RUNTIME plus the basic math packages. diff --git a/src/io/fs/glob.go b/src/io/fs/glob.go new file mode 100644 index 0000000000..77f6ebbaaf --- /dev/null +++ b/src/io/fs/glob.go @@ -0,0 +1,116 @@ +// Copyright 2010 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 fs + +import ( + "path" + "runtime" +) + +// A GlobFS is a file system with a Glob method. +type GlobFS interface { + FS + + // Glob returns the names of all files matching pattern, + // providing an implementation of the top-level + // Glob function. + Glob(pattern string) ([]string, error) +} + +// Glob returns the names of all files matching pattern or nil +// if there is no matching file. The syntax of patterns is the same +// as in path.Match. The pattern may describe hierarchical names such as +// /usr/*/bin/ed (assuming the Separator is '/'). +// +// Glob ignores file system errors such as I/O errors reading directories. +// The only possible returned error is path.ErrBadPattern, reporting that +// the pattern is malformed. +// +// If fs implements GlobFS, Glob calls fs.Glob. +// Otherwise, Glob uses ReadDir to traverse the directory tree +// and look for matches for the pattern. +func Glob(fsys FS, pattern string) (matches []string, err error) { + if fsys, ok := fsys.(GlobFS); ok { + return fsys.Glob(pattern) + } + + if !hasMeta(pattern) { + if _, err = Stat(fsys, pattern); err != nil { + return nil, nil + } + return []string{pattern}, nil + } + + dir, file := path.Split(pattern) + dir = cleanGlobPath(dir) + + if !hasMeta(dir) { + return glob(fsys, dir, file, nil) + } + + // Prevent infinite recursion. See issue 15879. + if dir == pattern { + return nil, path.ErrBadPattern + } + + var m []string + m, err = Glob(fsys, dir) + if err != nil { + return + } + for _, d := range m { + matches, err = glob(fsys, d, file, matches) + if err != nil { + return + } + } + return +} + +// cleanGlobPath prepares path for glob matching. +func cleanGlobPath(path string) string { + switch path { + case "": + return "." + default: + return path[0 : len(path)-1] // chop off trailing separator + } +} + +// glob searches for files matching pattern in the directory dir +// and appends them to matches, returning the updated slice. +// If the directory cannot be opened, glob returns the existing matches. +// New matches are added in lexicographical order. +func glob(fs FS, dir, pattern string, matches []string) (m []string, e error) { + m = matches + infos, err := ReadDir(fs, dir) + if err != nil { + return // ignore I/O error + } + + for _, info := range infos { + n := info.Name() + matched, err := path.Match(pattern, n) + if err != nil { + return m, err + } + if matched { + m = append(m, path.Join(dir, n)) + } + } + return +} + +// hasMeta reports whether path contains any of the magic characters +// recognized by path.Match. +func hasMeta(path string) bool { + for i := 0; i < len(path); i++ { + c := path[i] + if c == '*' || c == '?' || c == '[' || runtime.GOOS == "windows" && c == '\\' { + return true + } + } + return false +} diff --git a/src/io/fs/glob_test.go b/src/io/fs/glob_test.go new file mode 100644 index 0000000000..0183a49b6c --- /dev/null +++ b/src/io/fs/glob_test.go @@ -0,0 +1,82 @@ +// Copyright 2009 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 fs_test + +import ( + . "io/fs" + "os" + "testing" +) + +var globTests = []struct { + fs FS + pattern, result string +}{ + {os.DirFS("."), "glob.go", "glob.go"}, + {os.DirFS("."), "gl?b.go", "glob.go"}, + {os.DirFS("."), "*", "glob.go"}, + {os.DirFS(".."), "*/glob.go", "fs/glob.go"}, +} + +func TestGlob(t *testing.T) { + for _, tt := range globTests { + matches, err := Glob(tt.fs, tt.pattern) + if err != nil { + t.Errorf("Glob error for %q: %s", tt.pattern, err) + continue + } + if !contains(matches, tt.result) { + t.Errorf("Glob(%#q) = %#v want %v", tt.pattern, matches, tt.result) + } + } + for _, pattern := range []string{"no_match", "../*/no_match"} { + matches, err := Glob(os.DirFS("."), pattern) + if err != nil { + t.Errorf("Glob error for %q: %s", pattern, err) + continue + } + if len(matches) != 0 { + t.Errorf("Glob(%#q) = %#v want []", pattern, matches) + } + } +} + +func TestGlobError(t *testing.T) { + _, err := Glob(os.DirFS("."), "[]") + if err == nil { + t.Error("expected error for bad pattern; got none") + } +} + +// contains reports whether vector contains the string s. +func contains(vector []string, s string) bool { + for _, elem := range vector { + if elem == s { + return true + } + } + return false +} + +type globOnly struct{ GlobFS } + +func (globOnly) Open(name string) (File, error) { return nil, ErrNotExist } + +func TestGlobMethod(t *testing.T) { + check := func(desc string, names []string, err error) { + t.Helper() + if err != nil || len(names) != 1 || names[0] != "hello.txt" { + t.Errorf("Glob(%s) = %v, %v, want %v, nil", desc, names, err, []string{"hello.txt"}) + } + } + + // Test that ReadDir uses the method when present. + names, err := Glob(globOnly{testFsys}, "*.txt") + check("readDirOnly", names, err) + + // Test that ReadDir uses Open when the method is not present. + names, err = Glob(openOnly{testFsys}, "*.txt") + check("openOnly", names, err) +} diff --git a/src/testing/fstest/mapfs.go b/src/testing/fstest/mapfs.go index 1eaf8f0040..10e56f5b3c 100644 --- a/src/testing/fstest/mapfs.go +++ b/src/testing/fstest/mapfs.go @@ -128,6 +128,10 @@ func (fsys MapFS) ReadDir(name string) ([]fs.DirEntry, error) { return fs.ReadDir(fsOnly{fsys}, name) } +func (fsys MapFS) Glob(pattern string) ([]string, error) { + return fs.Glob(fsOnly{fsys}, pattern) +} + // A mapFileInfo implements fs.FileInfo and fs.DirEntry for a given map file. type mapFileInfo struct { name string diff --git a/src/testing/fstest/testfs.go b/src/testing/fstest/testfs.go index 4ea6ed6095..21cd00e5b6 100644 --- a/src/testing/fstest/testfs.go +++ b/src/testing/fstest/testfs.go @@ -11,6 +11,8 @@ import ( "io" "io/fs" "io/ioutil" + "path" + "reflect" "sort" "strings" "testing/iotest" @@ -226,6 +228,8 @@ func (t *fsTester) checkDir(dir string) { t.errorf("%s: fs.ReadDir: list not sorted: %s before %s", dir, list2[i].Name(), list2[i+1].Name()) } } + + t.checkGlob(dir, list) } // formatEntry formats an fs.DirEntry into a string for error messages and comparison. @@ -243,6 +247,98 @@ func formatInfo(info fs.FileInfo) string { return fmt.Sprintf("%s IsDir=%v Mode=%v Size=%d ModTime=%v", info.Name(), info.IsDir(), info.Mode(), info.Size(), info.ModTime()) } +// checkGlob checks that various glob patterns work if the file system implements GlobFS. +func (t *fsTester) checkGlob(dir string, list []fs.DirEntry) { + if _, ok := t.fsys.(fs.GlobFS); !ok { + return + } + + // Make a complex glob pattern prefix that only matches dir. + var glob string + if dir != "." { + elem := strings.Split(dir, "/") + for i, e := range elem { + var pattern []rune + for j, r := range e { + if r == '*' || r == '?' || r == '\\' || r == '[' { + pattern = append(pattern, '\\', r) + continue + } + switch (i + j) % 5 { + case 0: + pattern = append(pattern, r) + case 1: + pattern = append(pattern, '[', r, ']') + case 2: + pattern = append(pattern, '[', r, '-', r, ']') + case 3: + pattern = append(pattern, '[', '\\', r, ']') + case 4: + pattern = append(pattern, '[', '\\', r, '-', '\\', r, ']') + } + } + elem[i] = string(pattern) + } + glob = strings.Join(elem, "/") + "/" + } + + // Try to find a letter that appears in only some of the final names. + c := rune('a') + for ; c <= 'z'; c++ { + have, haveNot := false, false + for _, d := range list { + if strings.ContainsRune(d.Name(), c) { + have = true + } else { + haveNot = true + } + } + if have && haveNot { + break + } + } + if c > 'z' { + c = 'a' + } + glob += "*" + string(c) + "*" + + var want []string + for _, d := range list { + if strings.ContainsRune(d.Name(), c) { + want = append(want, path.Join(dir, d.Name())) + } + } + + names, err := t.fsys.(fs.GlobFS).Glob(glob) + if err != nil { + t.errorf("%s: Glob(%#q): %v", dir, glob, err) + return + } + if reflect.DeepEqual(want, names) { + return + } + + if !sort.StringsAreSorted(names) { + t.errorf("%s: Glob(%#q): unsorted output:\n%s", dir, glob, strings.Join(names, "\n")) + sort.Strings(names) + } + + var problems []string + for len(want) > 0 || len(names) > 0 { + switch { + case len(want) > 0 && len(names) > 0 && want[0] == names[0]: + want, names = want[1:], names[1:] + case len(want) > 0 && (len(names) == 0 || want[0] < names[0]): + problems = append(problems, "missing: "+want[0]) + want = want[1:] + default: + problems = append(problems, "extra: "+names[0]) + names = names[1:] + } + } + t.errorf("%s: Glob(%#q): wrong output:\n%s", dir, glob, strings.Join(problems, "\n")) +} + // checkStat checks that a direct stat of path matches entry, // which was found in the parent's directory listing. func (t *fsTester) checkStat(path string, entry fs.DirEntry) { -- cgit v1.3 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/example_test.go | 14 +++++++ src/io/io.go | 84 +++++++++++++++++++++++++++++++++++-- src/io/ioutil/ioutil.go | 107 +++++++++++++++--------------------------------- 3 files changed, 126 insertions(+), 79 deletions(-) (limited to 'src/io') diff --git a/src/io/example_test.go b/src/io/example_test.go index 465eed4d5e..4706032429 100644 --- a/src/io/example_test.go +++ b/src/io/example_test.go @@ -241,3 +241,17 @@ func ExamplePipe() { // Output: // some io.Reader stream to be read } + +func ExampleReadAll() { + r := strings.NewReader("Go is a general-purpose language designed with systems programming in mind.") + + b, err := ioutil.ReadAll(r) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("%s", b) + + // Output: + // Go is a general-purpose language designed with systems programming in mind. +} 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 + } + } +} diff --git a/src/io/ioutil/ioutil.go b/src/io/ioutil/ioutil.go index cae41f0018..a001c86b2f 100644 --- a/src/io/ioutil/ioutil.go +++ b/src/io/ioutil/ioutil.go @@ -6,44 +6,20 @@ package ioutil import ( - "bytes" "io" "io/fs" "os" "sort" - "sync" ) -// readAll reads from r until an error or EOF and returns the data it read -// from the internal buffer allocated with a specified capacity. -func readAll(r io.Reader, capacity int64) (b []byte, err error) { - var buf bytes.Buffer - // If the buffer overflows, we will get bytes.ErrTooLarge. - // Return that as an error. Any other panic remains. - defer func() { - e := recover() - if e == nil { - return - } - if panicErr, ok := e.(error); ok && panicErr == bytes.ErrTooLarge { - err = panicErr - } else { - panic(e) - } - }() - if int64(int(capacity)) == capacity { - buf.Grow(int(capacity)) - } - _, err = buf.ReadFrom(r) - return buf.Bytes(), err -} - // 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. +// +// As of Go 1.16, this function simply calls io.ReadAll. func ReadAll(r io.Reader) ([]byte, error) { - return readAll(r, bytes.MinRead) + return io.ReadAll(r) } // ReadFile reads the file named by filename and returns the contents. @@ -58,7 +34,8 @@ func ReadFile(filename string) ([]byte, error) { defer f.Close() // It's a good but not certain bet that FileInfo will tell us exactly how much to // read, so let's try it but be prepared for the answer to be wrong. - var n int64 = bytes.MinRead + const minRead = 512 + var n int64 = minRead if fi, err := f.Stat(); err == nil { // As initial capacity for readAll, use Size + a little extra in case Size @@ -67,11 +44,30 @@ func ReadFile(filename string) ([]byte, error) { // cheaply. If the size was wrong, we'll either waste some space off the end // or reallocate as needed, but in the overwhelmingly common case we'll get // it just right. - if size := fi.Size() + bytes.MinRead; size > n { + if size := fi.Size() + minRead; size > n { n = size } } - return readAll(f, n) + + if int64(int(n)) != n { + n = minRead + } + + b := make([]byte, 0, n) + for { + if len(b) == cap(b) { + // Add more capacity (let append pick how much). + b = append(b, 0)[:len(b)] + } + n, err := f.Read(b[len(b):cap(b)]) + b = b[:len(b)+n] + if err != nil { + if err == io.EOF { + err = nil + } + return b, err + } + } } // WriteFile writes data to a file named by filename. @@ -105,55 +101,16 @@ func ReadDir(dirname string) ([]fs.FileInfo, error) { return list, nil } -type nopCloser struct { - io.Reader -} - -func (nopCloser) Close() error { return nil } - // NopCloser returns a ReadCloser with a no-op Close method wrapping // the provided Reader r. +// +// As of Go 1.16, this function simply calls io.NopCloser. func NopCloser(r io.Reader) io.ReadCloser { - return nopCloser{r} -} - -type devNull int - -// devNull implements ReaderFrom as an optimization so io.Copy to -// ioutil.Discard can avoid doing unnecessary work. -var _ io.ReaderFrom = devNull(0) - -func (devNull) Write(p []byte) (int, error) { - return len(p), nil -} - -func (devNull) WriteString(s string) (int, error) { - return len(s), nil -} - -var blackHolePool = sync.Pool{ - New: func() interface{} { - b := make([]byte, 8192) - return &b - }, -} - -func (devNull) ReadFrom(r io.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 == io.EOF { - return n, nil - } - return - } - } + return io.NopCloser(r) } // Discard is an io.Writer on which all Write calls succeed // without doing anything. -var Discard io.Writer = devNull(0) +// +// As of Go 1.16, this value is simply io.Discard. +var Discard io.Writer = io.Discard -- cgit v1.3 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/archive/tar/reader.go | 7 +- src/archive/tar/reader_test.go | 2 +- src/archive/tar/tar_test.go | 8 +- src/archive/zip/reader_test.go | 6 +- src/archive/zip/register.go | 3 +- src/archive/zip/writer_test.go | 4 +- src/archive/zip/zip_test.go | 3 +- src/bufio/bufio_test.go | 19 ++-- src/bytes/reader_test.go | 9 +- src/cmd/fix/main.go | 3 +- src/cmd/go/internal/clean/clean.go | 3 +- src/cmd/go/internal/fsys/fsys_test.go | 3 +- src/cmd/go/internal/imports/read.go | 4 +- src/cmd/go/internal/lockedfile/lockedfile.go | 5 +- src/cmd/go/internal/modfetch/codehost/git.go | 5 +- src/cmd/go/internal/modfetch/codehost/git_test.go | 3 +- src/cmd/go/internal/modfetch/codehost/shell.go | 3 +- src/cmd/go/internal/modfetch/coderepo.go | 2 +- src/cmd/go/internal/modfetch/fetch.go | 2 +- src/cmd/go/internal/modfetch/proxy.go | 3 +- src/cmd/go/internal/modfetch/sumdb.go | 4 +- src/cmd/go/internal/web/api.go | 5 +- src/cmd/go/proxy_test.go | 4 +- src/cmd/go/testdata/script/test_cache_inputs.txt | 2 +- src/cmd/gofmt/gofmt.go | 2 +- src/cmd/pprof/pprof.go | 4 +- src/cmd/trace/trace_test.go | 10 +- src/cmd/trace/trace_unix_test.go | 4 +- src/compress/bzip2/bzip2_test.go | 6 +- src/compress/flate/deflate_test.go | 24 ++--- src/compress/flate/flate_test.go | 5 +- src/compress/flate/inflate_test.go | 3 +- src/compress/flate/reader_test.go | 4 +- src/compress/flate/writer_test.go | 9 +- src/compress/gzip/gunzip_test.go | 9 +- src/compress/gzip/gzip_test.go | 9 +- src/compress/lzw/reader_test.go | 4 +- src/compress/lzw/writer_test.go | 10 +- src/compress/zlib/writer_test.go | 4 +- src/crypto/tls/handshake_test.go | 2 +- src/crypto/tls/tls_test.go | 7 +- src/crypto/x509/root_ios_gen.go | 2 +- src/debug/gosym/pclntab_test.go | 3 +- src/encoding/ascii85/ascii85_test.go | 7 +- src/encoding/base32/base32_test.go | 13 ++- src/encoding/base64/base64_test.go | 15 ++- src/encoding/binary/binary_test.go | 3 +- src/encoding/gob/encoder_test.go | 4 +- src/encoding/hex/hex_test.go | 3 +- src/encoding/json/bench_test.go | 8 +- src/encoding/json/stream_test.go | 5 +- src/encoding/pem/pem_test.go | 4 +- src/flag/flag_test.go | 5 +- src/go/internal/gccgoimporter/importer.go | 2 +- src/go/internal/gcimporter/gcimporter.go | 3 +- src/go/parser/interface.go | 2 +- src/go/printer/performance_test.go | 2 +- src/go/types/gotype.go | 4 +- src/html/template/clone_test.go | 14 +-- src/html/template/exec_test.go | 8 +- src/image/gif/writer_test.go | 22 ++-- src/image/jpeg/writer_test.go | 6 +- src/image/png/writer_test.go | 17 ++-- src/internal/obscuretestdata/obscuretestdata.go | 2 +- src/internal/profile/profile.go | 5 +- src/io/example_test.go | 5 +- src/io/io.go | 2 +- src/io/multi_test.go | 11 +- src/mime/encodedword_test.go | 3 +- src/mime/example_test.go | 5 +- src/mime/multipart/example_test.go | 3 +- src/mime/multipart/multipart.go | 3 +- src/mime/multipart/multipart_test.go | 13 ++- src/mime/multipart/writer_test.go | 8 +- src/mime/quotedprintable/example_test.go | 4 +- src/mime/quotedprintable/writer_test.go | 6 +- src/net/http/alpn_test.go | 5 +- src/net/http/cgi/child.go | 3 +- src/net/http/client.go | 5 +- src/net/http/client_test.go | 25 +++-- src/net/http/clientserver_test.go | 39 ++++--- src/net/http/doc.go | 2 +- src/net/http/example_test.go | 3 +- src/net/http/fcgi/child.go | 5 +- src/net/http/fcgi/fcgi_test.go | 5 +- src/net/http/filetransport_test.go | 3 +- src/net/http/fs_test.go | 20 ++-- src/net/http/httptest/example_test.go | 9 +- src/net/http/httptest/httptest.go | 3 +- src/net/http/httptest/httptest_test.go | 3 +- src/net/http/httptest/recorder.go | 4 +- src/net/http/httptest/recorder_test.go | 3 +- src/net/http/httptest/server_test.go | 10 +- src/net/http/httputil/dump.go | 9 +- src/net/http/httputil/dump_test.go | 9 +- src/net/http/httputil/example_test.go | 6 +- src/net/http/httputil/reverseproxy_test.go | 49 +++++---- src/net/http/internal/chunked_test.go | 5 +- src/net/http/main_test.go | 4 +- src/net/http/pprof/pprof_test.go | 6 +- src/net/http/readrequest_test.go | 3 +- src/net/http/request.go | 11 +- src/net/http/request_test.go | 22 ++-- src/net/http/requestwrite_test.go | 27 +++-- src/net/http/response_test.go | 5 +- src/net/http/responsewrite_test.go | 20 ++-- src/net/http/roundtrip_js.go | 3 +- src/net/http/serve_test.go | 119 +++++++++++----------- src/net/http/server.go | 5 +- src/net/http/sniff_test.go | 7 +- src/net/http/transfer.go | 11 +- src/net/http/transfer_test.go | 16 +-- src/net/http/transport_internal_test.go | 3 +- src/net/http/transport_test.go | 100 +++++++++--------- src/net/mail/example_test.go | 4 +- src/net/mail/message_test.go | 5 +- src/net/rpc/jsonrpc/all_test.go | 5 +- src/net/sendfile_test.go | 3 +- src/net/splice_test.go | 3 +- src/net/textproto/reader.go | 3 +- src/net/timeout_test.go | 3 +- src/net/writev_test.go | 5 +- src/os/exec/example_test.go | 3 +- src/os/exec/exec_test.go | 4 +- src/os/exec/read3.go | 4 +- src/os/timeout_test.go | 4 +- src/runtime/crash_unix_test.go | 2 +- src/runtime/testdata/testprogcgo/eintr.go | 3 +- src/strings/reader_test.go | 7 +- src/syscall/mkpost.go | 4 +- src/syscall/syscall_unix_test.go | 2 +- src/testing/iotest/reader.go | 9 +- src/text/tabwriter/tabwriter_test.go | 11 +- src/text/template/exec_test.go | 8 +- src/time/genzabbrs.go | 3 +- 135 files changed, 535 insertions(+), 597 deletions(-) (limited to 'src/io') diff --git a/src/archive/tar/reader.go b/src/archive/tar/reader.go index 4f9135b791..1b1d5b4689 100644 --- a/src/archive/tar/reader.go +++ b/src/archive/tar/reader.go @@ -7,7 +7,6 @@ package tar import ( "bytes" "io" - "io/ioutil" "strconv" "strings" "time" @@ -104,7 +103,7 @@ func (tr *Reader) next() (*Header, error) { continue // This is a meta header affecting the next header case TypeGNULongName, TypeGNULongLink: format.mayOnlyBe(FormatGNU) - realname, err := ioutil.ReadAll(tr) + realname, err := io.ReadAll(tr) if err != nil { return nil, err } @@ -294,7 +293,7 @@ func mergePAX(hdr *Header, paxHdrs map[string]string) (err error) { // parsePAX parses PAX headers. // If an extended header (type 'x') is invalid, ErrHeader is returned func parsePAX(r io.Reader) (map[string]string, error) { - buf, err := ioutil.ReadAll(r) + buf, err := io.ReadAll(r) if err != nil { return nil, err } @@ -850,7 +849,7 @@ func discard(r io.Reader, n int64) error { } } - copySkipped, err := io.CopyN(ioutil.Discard, r, n-seekSkipped) + copySkipped, err := io.CopyN(io.Discard, r, n-seekSkipped) if err == io.EOF && seekSkipped+copySkipped < n { err = io.ErrUnexpectedEOF } diff --git a/src/archive/tar/reader_test.go b/src/archive/tar/reader_test.go index f153b668de..411d1e0b99 100644 --- a/src/archive/tar/reader_test.go +++ b/src/archive/tar/reader_test.go @@ -865,7 +865,7 @@ func TestReadTruncation(t *testing.T) { } cnt++ if s2 == "manual" { - if _, err = tr.writeTo(ioutil.Discard); err != nil { + if _, err = tr.writeTo(io.Discard); err != nil { break } } diff --git a/src/archive/tar/tar_test.go b/src/archive/tar/tar_test.go index f605dae904..d4a3d42312 100644 --- a/src/archive/tar/tar_test.go +++ b/src/archive/tar/tar_test.go @@ -328,7 +328,7 @@ func TestRoundTrip(t *testing.T) { if !reflect.DeepEqual(rHdr, hdr) { t.Errorf("Header mismatch.\n got %+v\nwant %+v", rHdr, hdr) } - rData, err := ioutil.ReadAll(tr) + rData, err := io.ReadAll(tr) if err != nil { t.Fatalf("Read: %v", err) } @@ -805,9 +805,9 @@ func Benchmark(b *testing.B) { b.Run(v.label, func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - // Writing to ioutil.Discard because we want to + // Writing to io.Discard because we want to // test purely the writer code and not bring in disk performance into this. - tw := NewWriter(ioutil.Discard) + tw := NewWriter(io.Discard) for _, file := range v.files { if err := tw.WriteHeader(file.hdr); err != nil { b.Errorf("unexpected WriteHeader error: %v", err) @@ -845,7 +845,7 @@ func Benchmark(b *testing.B) { if _, err := tr.Next(); err != nil { b.Errorf("unexpected Next error: %v", err) } - if _, err := io.Copy(ioutil.Discard, tr); err != nil { + if _, err := io.Copy(io.Discard, tr); err != nil { b.Errorf("unexpected Copy error : %v", err) } } diff --git a/src/archive/zip/reader_test.go b/src/archive/zip/reader_test.go index 38ff7badd0..b7a7d7a757 100644 --- a/src/archive/zip/reader_test.go +++ b/src/archive/zip/reader_test.go @@ -930,7 +930,7 @@ func returnBigZipBytes() (r io.ReaderAt, size int64) { if err != nil { panic(err) } - b, err = ioutil.ReadAll(f) + b, err = io.ReadAll(f) if err != nil { panic(err) } @@ -987,7 +987,7 @@ func TestIssue10957(t *testing.T) { continue } if f.UncompressedSize64 < 1e6 { - n, err := io.Copy(ioutil.Discard, r) + n, err := io.Copy(io.Discard, r) if i == 3 && err != io.ErrUnexpectedEOF { t.Errorf("File[3] error = %v; want io.ErrUnexpectedEOF", err) } @@ -1029,7 +1029,7 @@ func TestIssue11146(t *testing.T) { if err != nil { t.Fatal(err) } - _, err = ioutil.ReadAll(r) + _, err = io.ReadAll(r) if err != io.ErrUnexpectedEOF { t.Errorf("File[0] error = %v; want io.ErrUnexpectedEOF", err) } diff --git a/src/archive/zip/register.go b/src/archive/zip/register.go index 51e9c3e4d4..4389246286 100644 --- a/src/archive/zip/register.go +++ b/src/archive/zip/register.go @@ -8,7 +8,6 @@ import ( "compress/flate" "errors" "io" - "io/ioutil" "sync" ) @@ -111,7 +110,7 @@ func init() { compressors.Store(Store, Compressor(func(w io.Writer) (io.WriteCloser, error) { return &nopCloser{w}, nil })) compressors.Store(Deflate, Compressor(func(w io.Writer) (io.WriteCloser, error) { return newFlateWriter(w), nil })) - decompressors.Store(Store, Decompressor(ioutil.NopCloser)) + decompressors.Store(Store, Decompressor(io.NopCloser)) decompressors.Store(Deflate, Decompressor(newFlateReader)) } diff --git a/src/archive/zip/writer_test.go b/src/archive/zip/writer_test.go index 282f9ec216..2c32eaf4a5 100644 --- a/src/archive/zip/writer_test.go +++ b/src/archive/zip/writer_test.go @@ -301,7 +301,7 @@ func TestWriterFlush(t *testing.T) { } func TestWriterDir(t *testing.T) { - w := NewWriter(ioutil.Discard) + w := NewWriter(io.Discard) dw, err := w.Create("dir/") if err != nil { t.Fatal(err) @@ -380,7 +380,7 @@ func testReadFile(t *testing.T, f *File, wt *WriteTest) { if err != nil { t.Fatal("opening:", err) } - b, err := ioutil.ReadAll(rc) + b, err := io.ReadAll(rc) if err != nil { t.Fatal("reading:", err) } diff --git a/src/archive/zip/zip_test.go b/src/archive/zip/zip_test.go index b3a7caac7f..ead9cd3aab 100644 --- a/src/archive/zip/zip_test.go +++ b/src/archive/zip/zip_test.go @@ -13,7 +13,6 @@ import ( "hash" "internal/testenv" "io" - "io/ioutil" "runtime" "sort" "strings" @@ -620,7 +619,7 @@ func testZip64(t testing.TB, size int64) *rleBuffer { t.Fatal("read:", err) } } - gotEnd, err := ioutil.ReadAll(rc) + gotEnd, err := io.ReadAll(rc) if err != nil { t.Fatal("read end:", err) } diff --git a/src/bufio/bufio_test.go b/src/bufio/bufio_test.go index cb68f3ba23..75086f1f24 100644 --- a/src/bufio/bufio_test.go +++ b/src/bufio/bufio_test.go @@ -10,7 +10,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "strings" "testing" "testing/iotest" @@ -886,7 +885,7 @@ func TestReadEmptyBuffer(t *testing.T) { func TestLinesAfterRead(t *testing.T) { l := NewReaderSize(bytes.NewReader([]byte("foo")), minReadBufferSize) - _, err := ioutil.ReadAll(l) + _, err := io.ReadAll(l) if err != nil { t.Error(err) return @@ -1130,7 +1129,7 @@ func TestWriterReadFromCounts(t *testing.T) { } } -// A writeCountingDiscard is like ioutil.Discard and counts the number of times +// A writeCountingDiscard is like io.Discard and counts the number of times // Write is called on it. type writeCountingDiscard int @@ -1300,7 +1299,7 @@ func TestReaderReset(t *testing.T) { t.Errorf("buf = %q; want foo", buf) } r.Reset(strings.NewReader("bar bar")) - all, err := ioutil.ReadAll(r) + all, err := io.ReadAll(r) if err != nil { t.Fatal(err) } @@ -1645,13 +1644,13 @@ func BenchmarkReaderWriteToOptimal(b *testing.B) { buf := make([]byte, bufSize) r := bytes.NewReader(buf) srcReader := NewReaderSize(onlyReader{r}, 1<<10) - if _, ok := ioutil.Discard.(io.ReaderFrom); !ok { - b.Fatal("ioutil.Discard doesn't support ReaderFrom") + if _, ok := io.Discard.(io.ReaderFrom); !ok { + b.Fatal("io.Discard doesn't support ReaderFrom") } for i := 0; i < b.N; i++ { r.Seek(0, io.SeekStart) srcReader.Reset(onlyReader{r}) - n, err := srcReader.WriteTo(ioutil.Discard) + n, err := srcReader.WriteTo(io.Discard) if err != nil { b.Fatal(err) } @@ -1722,7 +1721,7 @@ func BenchmarkReaderEmpty(b *testing.B) { str := strings.Repeat("x", 16<<10) for i := 0; i < b.N; i++ { br := NewReader(strings.NewReader(str)) - n, err := io.Copy(ioutil.Discard, br) + n, err := io.Copy(io.Discard, br) if err != nil { b.Fatal(err) } @@ -1737,7 +1736,7 @@ func BenchmarkWriterEmpty(b *testing.B) { str := strings.Repeat("x", 1<<10) bs := []byte(str) for i := 0; i < b.N; i++ { - bw := NewWriter(ioutil.Discard) + bw := NewWriter(io.Discard) bw.Flush() bw.WriteByte('a') bw.Flush() @@ -1752,7 +1751,7 @@ func BenchmarkWriterEmpty(b *testing.B) { func BenchmarkWriterFlush(b *testing.B) { b.ReportAllocs() - bw := NewWriter(ioutil.Discard) + bw := NewWriter(io.Discard) str := strings.Repeat("x", 50) for i := 0; i < b.N; i++ { bw.WriteString(str) diff --git a/src/bytes/reader_test.go b/src/bytes/reader_test.go index d799e036f0..8baac5046c 100644 --- a/src/bytes/reader_test.go +++ b/src/bytes/reader_test.go @@ -8,7 +8,6 @@ import ( . "bytes" "fmt" "io" - "io/ioutil" "sync" "testing" ) @@ -235,7 +234,7 @@ func TestReaderCopyNothing(t *testing.T) { type justWriter struct { io.Writer } - discard := justWriter{ioutil.Discard} // hide ReadFrom + discard := justWriter{io.Discard} // hide ReadFrom var with, withOut nErr with.n, with.err = io.Copy(discard, NewReader(nil)) @@ -248,7 +247,7 @@ func TestReaderCopyNothing(t *testing.T) { // tests that Len is affected by reads, but Size is not. func TestReaderLenSize(t *testing.T) { r := NewReader([]byte("abc")) - io.CopyN(ioutil.Discard, r, 1) + io.CopyN(io.Discard, r, 1) if r.Len() != 2 { t.Errorf("Len = %d; want 2", r.Len()) } @@ -268,7 +267,7 @@ func TestReaderReset(t *testing.T) { if err := r.UnreadRune(); err == nil { t.Errorf("UnreadRune: expected error, got nil") } - buf, err := ioutil.ReadAll(r) + buf, err := io.ReadAll(r) if err != nil { t.Errorf("ReadAll: unexpected error: %v", err) } @@ -314,7 +313,7 @@ func TestReaderZero(t *testing.T) { t.Errorf("UnreadRune: got nil, want error") } - if n, err := (&Reader{}).WriteTo(ioutil.Discard); n != 0 || err != nil { + if n, err := (&Reader{}).WriteTo(io.Discard); n != 0 || err != nil { t.Errorf("WriteTo: got %d, %v; want 0, nil", n, err) } } diff --git a/src/cmd/fix/main.go b/src/cmd/fix/main.go index dfba902f48..1cea9a876a 100644 --- a/src/cmd/fix/main.go +++ b/src/cmd/fix/main.go @@ -13,6 +13,7 @@ import ( "go/parser" "go/scanner" "go/token" + "io" "io/fs" "io/ioutil" "os" @@ -128,7 +129,7 @@ func processFile(filename string, useStdin bool) error { defer f.Close() } - src, err := ioutil.ReadAll(f) + src, err := io.ReadAll(f) if err != nil { return err } diff --git a/src/cmd/go/internal/clean/clean.go b/src/cmd/go/internal/clean/clean.go index 6bfd7ae21e..095c3cc713 100644 --- a/src/cmd/go/internal/clean/clean.go +++ b/src/cmd/go/internal/clean/clean.go @@ -8,6 +8,7 @@ package clean import ( "context" "fmt" + "io" "io/ioutil" "os" "path/filepath" @@ -172,7 +173,7 @@ func runClean(ctx context.Context, cmd *base.Command, args []string) { f, err := lockedfile.Edit(filepath.Join(dir, "testexpire.txt")) if err == nil { now := time.Now().UnixNano() - buf, _ := ioutil.ReadAll(f) + buf, _ := io.ReadAll(f) prev, _ := strconv.ParseInt(strings.TrimSpace(string(buf)), 10, 64) if now > prev { if err = f.Truncate(0); err == nil { diff --git a/src/cmd/go/internal/fsys/fsys_test.go b/src/cmd/go/internal/fsys/fsys_test.go index ba9f05d00b..28c3f08cb9 100644 --- a/src/cmd/go/internal/fsys/fsys_test.go +++ b/src/cmd/go/internal/fsys/fsys_test.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "internal/testenv" + "io" "io/fs" "io/ioutil" "os" @@ -418,7 +419,7 @@ this can exist because the parent directory is deleted t.Errorf("Open(%q): got error %v, want nil", tc.path, err) continue } - contents, err := ioutil.ReadAll(f) + contents, err := io.ReadAll(f) if err != nil { t.Errorf("unexpected error reading contents of file: %v", err) } diff --git a/src/cmd/go/internal/imports/read.go b/src/cmd/go/internal/imports/read.go index 58c2abdc29..5e270781d7 100644 --- a/src/cmd/go/internal/imports/read.go +++ b/src/cmd/go/internal/imports/read.go @@ -198,7 +198,7 @@ func (r *importReader) readImport(imports *[]string) { r.readString(imports) } -// ReadComments is like ioutil.ReadAll, except that it only reads the leading +// ReadComments is like io.ReadAll, except that it only reads the leading // block of comments in the file. func ReadComments(f io.Reader) ([]byte, error) { r := &importReader{b: bufio.NewReader(f)} @@ -210,7 +210,7 @@ func ReadComments(f io.Reader) ([]byte, error) { return r.buf, r.err } -// ReadImports is like ioutil.ReadAll, except that it expects a Go file as input +// ReadImports is like io.ReadAll, except that it expects a Go file as input // and stops reading the input once the imports have completed. func ReadImports(f io.Reader, reportSyntaxError bool, imports *[]string) ([]byte, error) { r := &importReader{b: bufio.NewReader(f)} diff --git a/src/cmd/go/internal/lockedfile/lockedfile.go b/src/cmd/go/internal/lockedfile/lockedfile.go index 503024da4b..82e1a89675 100644 --- a/src/cmd/go/internal/lockedfile/lockedfile.go +++ b/src/cmd/go/internal/lockedfile/lockedfile.go @@ -10,7 +10,6 @@ import ( "fmt" "io" "io/fs" - "io/ioutil" "os" "runtime" ) @@ -104,7 +103,7 @@ func Read(name string) ([]byte, error) { } defer f.Close() - return ioutil.ReadAll(f) + return io.ReadAll(f) } // Write opens the named file (creating it with the given permissions if needed), @@ -136,7 +135,7 @@ func Transform(name string, t func([]byte) ([]byte, error)) (err error) { } defer f.Close() - old, err := ioutil.ReadAll(f) + old, err := io.ReadAll(f) if err != nil { return err } diff --git a/src/cmd/go/internal/modfetch/codehost/git.go b/src/cmd/go/internal/modfetch/codehost/git.go index 58b4b2f2d3..8abc039e7f 100644 --- a/src/cmd/go/internal/modfetch/codehost/git.go +++ b/src/cmd/go/internal/modfetch/codehost/git.go @@ -10,7 +10,6 @@ import ( "fmt" "io" "io/fs" - "io/ioutil" "net/url" "os" "os/exec" @@ -832,7 +831,7 @@ func (r *gitRepo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser, return nil, err } - return ioutil.NopCloser(bytes.NewReader(archive)), nil + return io.NopCloser(bytes.NewReader(archive)), nil } // ensureGitAttributes makes sure export-subst and export-ignore features are @@ -863,7 +862,7 @@ func ensureGitAttributes(repoDir string) (err error) { } }() - b, err := ioutil.ReadAll(f) + b, err := io.ReadAll(f) if err != nil { return err } diff --git a/src/cmd/go/internal/modfetch/codehost/git_test.go b/src/cmd/go/internal/modfetch/codehost/git_test.go index 16908b3e84..981e3fe91f 100644 --- a/src/cmd/go/internal/modfetch/codehost/git_test.go +++ b/src/cmd/go/internal/modfetch/codehost/git_test.go @@ -10,6 +10,7 @@ import ( "flag" "fmt" "internal/testenv" + "io" "io/fs" "io/ioutil" "log" @@ -433,7 +434,7 @@ func TestReadZip(t *testing.T) { if tt.err != "" { t.Fatalf("ReadZip: no error, wanted %v", tt.err) } - zipdata, err := ioutil.ReadAll(rc) + zipdata, err := io.ReadAll(rc) if err != nil { t.Fatal(err) } diff --git a/src/cmd/go/internal/modfetch/codehost/shell.go b/src/cmd/go/internal/modfetch/codehost/shell.go index 2762c55720..b9525adf5e 100644 --- a/src/cmd/go/internal/modfetch/codehost/shell.go +++ b/src/cmd/go/internal/modfetch/codehost/shell.go @@ -14,6 +14,7 @@ import ( "bytes" "flag" "fmt" + "io" "io/ioutil" "log" "os" @@ -115,7 +116,7 @@ func main() { fmt.Fprintf(os.Stderr, "?%s\n", err) continue } - data, err := ioutil.ReadAll(rc) + data, err := io.ReadAll(rc) rc.Close() if err != nil { fmt.Fprintf(os.Stderr, "?%s\n", err) diff --git a/src/cmd/go/internal/modfetch/coderepo.go b/src/cmd/go/internal/modfetch/coderepo.go index 7f44e18a70..b6bcf83f1a 100644 --- a/src/cmd/go/internal/modfetch/coderepo.go +++ b/src/cmd/go/internal/modfetch/coderepo.go @@ -1052,7 +1052,7 @@ type dataFile struct { func (f dataFile) Path() string { return f.name } func (f dataFile) Lstat() (fs.FileInfo, error) { return dataFileInfo{f}, nil } func (f dataFile) Open() (io.ReadCloser, error) { - return ioutil.NopCloser(bytes.NewReader(f.data)), nil + return io.NopCloser(bytes.NewReader(f.data)), nil } type dataFileInfo struct { diff --git a/src/cmd/go/internal/modfetch/fetch.go b/src/cmd/go/internal/modfetch/fetch.go index 6ff455e89c..40196c4e9a 100644 --- a/src/cmd/go/internal/modfetch/fetch.go +++ b/src/cmd/go/internal/modfetch/fetch.go @@ -461,7 +461,7 @@ func checkMod(mod module.Version) { // goModSum returns the checksum for the go.mod contents. func goModSum(data []byte) (string, error) { return dirhash.Hash1([]string{"go.mod"}, func(string) (io.ReadCloser, error) { - return ioutil.NopCloser(bytes.NewReader(data)), nil + return io.NopCloser(bytes.NewReader(data)), nil }) } diff --git a/src/cmd/go/internal/modfetch/proxy.go b/src/cmd/go/internal/modfetch/proxy.go index 819990b403..d75b4da521 100644 --- a/src/cmd/go/internal/modfetch/proxy.go +++ b/src/cmd/go/internal/modfetch/proxy.go @@ -10,7 +10,6 @@ import ( "fmt" "io" "io/fs" - "io/ioutil" "net/url" "path" pathpkg "path" @@ -305,7 +304,7 @@ func (p *proxyRepo) getBytes(path string) ([]byte, error) { return nil, err } defer body.Close() - return ioutil.ReadAll(body) + return io.ReadAll(body) } func (p *proxyRepo) getBody(path string) (io.ReadCloser, error) { diff --git a/src/cmd/go/internal/modfetch/sumdb.go b/src/cmd/go/internal/modfetch/sumdb.go index 5108961a33..4fbc54d15c 100644 --- a/src/cmd/go/internal/modfetch/sumdb.go +++ b/src/cmd/go/internal/modfetch/sumdb.go @@ -12,8 +12,8 @@ import ( "bytes" "errors" "fmt" + "io" "io/fs" - "io/ioutil" "net/url" "os" "path/filepath" @@ -228,7 +228,7 @@ func (*dbClient) WriteConfig(file string, old, new []byte) error { return err } defer f.Close() - data, err := ioutil.ReadAll(f) + data, err := io.ReadAll(f) if err != nil { return err } diff --git a/src/cmd/go/internal/web/api.go b/src/cmd/go/internal/web/api.go index f7d3ed60f6..9053b16b62 100644 --- a/src/cmd/go/internal/web/api.go +++ b/src/cmd/go/internal/web/api.go @@ -14,7 +14,6 @@ import ( "fmt" "io" "io/fs" - "io/ioutil" "net/url" "strings" "unicode" @@ -87,7 +86,7 @@ func GetBytes(u *url.URL) ([]byte, error) { if err := resp.Err(); err != nil { return nil, err } - b, err := ioutil.ReadAll(resp.Body) + b, err := io.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("reading %s: %v", u.Redacted(), err) } @@ -130,7 +129,7 @@ func (r *Response) formatErrorDetail() string { } // Ensure that r.errorDetail has been populated. - _, _ = io.Copy(ioutil.Discard, r.Body) + _, _ = io.Copy(io.Discard, r.Body) s := r.errorDetail.buf.String() if !utf8.ValidString(s) { diff --git a/src/cmd/go/proxy_test.go b/src/cmd/go/proxy_test.go index 8b0dbb74b2..3ed42face2 100644 --- a/src/cmd/go/proxy_test.go +++ b/src/cmd/go/proxy_test.go @@ -471,13 +471,13 @@ func proxyGoSum(path, vers string) ([]byte, error) { } h1, err := dirhash.Hash1(names, func(name string) (io.ReadCloser, error) { data := files[name] - return ioutil.NopCloser(bytes.NewReader(data)), nil + return io.NopCloser(bytes.NewReader(data)), nil }) if err != nil { return nil, err } h1mod, err := dirhash.Hash1([]string{"go.mod"}, func(string) (io.ReadCloser, error) { - return ioutil.NopCloser(bytes.NewReader(gomod)), nil + return io.NopCloser(bytes.NewReader(gomod)), nil }) if err != nil { return nil, err diff --git a/src/cmd/go/testdata/script/test_cache_inputs.txt b/src/cmd/go/testdata/script/test_cache_inputs.txt index 57602e91dc..97ae4af51f 100644 --- a/src/cmd/go/testdata/script/test_cache_inputs.txt +++ b/src/cmd/go/testdata/script/test_cache_inputs.txt @@ -159,7 +159,7 @@ func TestOddFileContent(t *testing.T) { if err != nil { t.Fatal(err) } - data, err := ioutil.ReadAll(f) + data, err := io.ReadAll(f) f.Close() if err != nil { t.Fatal(err) diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go index 48b6ad6f53..dba2411eed 100644 --- a/src/cmd/gofmt/gofmt.go +++ b/src/cmd/gofmt/gofmt.go @@ -97,7 +97,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error perm = fi.Mode().Perm() } - src, err := ioutil.ReadAll(in) + src, err := io.ReadAll(in) if err != nil { return err } diff --git a/src/cmd/pprof/pprof.go b/src/cmd/pprof/pprof.go index c1ddbe372f..11f91cbedb 100644 --- a/src/cmd/pprof/pprof.go +++ b/src/cmd/pprof/pprof.go @@ -13,7 +13,7 @@ import ( "crypto/tls" "debug/dwarf" "fmt" - "io/ioutil" + "io" "net/http" "net/url" "os" @@ -94,7 +94,7 @@ func getProfile(source string, timeout time.Duration) (*profile.Profile, error) func statusCodeError(resp *http.Response) error { if resp.Header.Get("X-Go-Pprof") != "" && strings.Contains(resp.Header.Get("Content-Type"), "text/plain") { // error is from pprof endpoint - if body, err := ioutil.ReadAll(resp.Body); err == nil { + if body, err := io.ReadAll(resp.Body); err == nil { return fmt.Errorf("server response: %s - %s", resp.Status, body) } } diff --git a/src/cmd/trace/trace_test.go b/src/cmd/trace/trace_test.go index dd12e8cd20..ea0cc6f880 100644 --- a/src/cmd/trace/trace_test.go +++ b/src/cmd/trace/trace_test.go @@ -10,7 +10,7 @@ import ( "cmd/internal/traceviewer" "context" "internal/trace" - "io/ioutil" + "io" rtrace "runtime/trace" "strings" "sync" @@ -78,7 +78,7 @@ func TestGoroutineCount(t *testing.T) { // Use the default viewerDataTraceConsumer but replace // consumeViewerEvent to intercept the ViewerEvents for testing. - c := viewerDataTraceConsumer(ioutil.Discard, 0, 1<<63-1) + c := viewerDataTraceConsumer(io.Discard, 0, 1<<63-1) c.consumeViewerEvent = func(ev *traceviewer.Event, _ bool) { if ev.Name == "Goroutines" { cnt := ev.Arg.(*goroutineCountersArg) @@ -131,7 +131,7 @@ func TestGoroutineFilter(t *testing.T) { gs: map[uint64]bool{10: true}, } - c := viewerDataTraceConsumer(ioutil.Discard, 0, 1<<63-1) + c := viewerDataTraceConsumer(io.Discard, 0, 1<<63-1) if err := generateTrace(params, c); err != nil { t.Fatalf("generateTrace failed: %v", err) } @@ -163,7 +163,7 @@ func TestPreemptedMarkAssist(t *testing.T) { endTime: int64(1<<63 - 1), } - c := viewerDataTraceConsumer(ioutil.Discard, 0, 1<<63-1) + c := viewerDataTraceConsumer(io.Discard, 0, 1<<63-1) marks := 0 c.consumeViewerEvent = func(ev *traceviewer.Event, _ bool) { @@ -214,7 +214,7 @@ func TestFoo(t *testing.T) { tasks: []*taskDesc{task}, } - c := viewerDataTraceConsumer(ioutil.Discard, 0, 1<<63-1) + c := viewerDataTraceConsumer(io.Discard, 0, 1<<63-1) var logBeforeTaskEnd, logAfterTaskEnd bool c.consumeViewerEvent = func(ev *traceviewer.Event, _ bool) { diff --git a/src/cmd/trace/trace_unix_test.go b/src/cmd/trace/trace_unix_test.go index 645978e0f8..c569b40bb2 100644 --- a/src/cmd/trace/trace_unix_test.go +++ b/src/cmd/trace/trace_unix_test.go @@ -10,7 +10,7 @@ import ( "bytes" "cmd/internal/traceviewer" traceparser "internal/trace" - "io/ioutil" + "io" "runtime" "runtime/trace" "sync" @@ -83,7 +83,7 @@ func TestGoroutineInSyscall(t *testing.T) { // Check only one thread for the pipe read goroutine is // considered in-syscall. - c := viewerDataTraceConsumer(ioutil.Discard, 0, 1<<63-1) + c := viewerDataTraceConsumer(io.Discard, 0, 1<<63-1) c.consumeViewerEvent = func(ev *traceviewer.Event, _ bool) { if ev.Name == "Threads" { arg := ev.Arg.(*threadCountersArg) diff --git a/src/compress/bzip2/bzip2_test.go b/src/compress/bzip2/bzip2_test.go index c432bb5226..98477791b3 100644 --- a/src/compress/bzip2/bzip2_test.go +++ b/src/compress/bzip2/bzip2_test.go @@ -133,7 +133,7 @@ func TestReader(t *testing.T) { for i, v := range vectors { rd := NewReader(bytes.NewReader(v.input)) - buf, err := ioutil.ReadAll(rd) + buf, err := io.ReadAll(rd) if fail := bool(err != nil); fail != v.fail { if fail { @@ -220,7 +220,7 @@ var ( func benchmarkDecode(b *testing.B, compressed []byte) { // Determine the uncompressed size of testfile. - uncompressedSize, err := io.Copy(ioutil.Discard, NewReader(bytes.NewReader(compressed))) + uncompressedSize, err := io.Copy(io.Discard, NewReader(bytes.NewReader(compressed))) if err != nil { b.Fatal(err) } @@ -231,7 +231,7 @@ func benchmarkDecode(b *testing.B, compressed []byte) { for i := 0; i < b.N; i++ { r := bytes.NewReader(compressed) - io.Copy(ioutil.Discard, NewReader(r)) + io.Copy(io.Discard, NewReader(r)) } } diff --git a/src/compress/flate/deflate_test.go b/src/compress/flate/deflate_test.go index b19cbec5a9..6fc5abf4d5 100644 --- a/src/compress/flate/deflate_test.go +++ b/src/compress/flate/deflate_test.go @@ -157,7 +157,7 @@ func TestVeryLongSparseChunk(t *testing.T) { if testing.Short() { t.Skip("skipping sparse chunk during short test") } - w, err := NewWriter(ioutil.Discard, 1) + w, err := NewWriter(io.Discard, 1) if err != nil { t.Errorf("NewWriter: %v", err) return @@ -294,7 +294,7 @@ func testSync(t *testing.T, level int, input []byte, name string) { // stream should work for ordinary reader too r = NewReader(buf1) - out, err = ioutil.ReadAll(r) + out, err = io.ReadAll(r) if err != nil { t.Errorf("testSync: read: %s", err) return @@ -322,7 +322,7 @@ func testToFromWithLevelAndLimit(t *testing.T, level int, input []byte, name str t.Logf("level: %d, size:%.2f%%, %d b\n", level, float64(buffer.Len()*100)/float64(limit), buffer.Len()) } r := NewReader(&buffer) - out, err := ioutil.ReadAll(r) + out, err := io.ReadAll(r) if err != nil { t.Errorf("read: %s", err) return @@ -415,7 +415,7 @@ func TestReaderDict(t *testing.T) { w.Close() r := NewReaderDict(&b, []byte(dict)) - data, err := ioutil.ReadAll(r) + data, err := io.ReadAll(r) if err != nil { t.Fatal(err) } @@ -456,7 +456,7 @@ func TestRegression2508(t *testing.T) { t.Logf("test disabled with -short") return } - w, err := NewWriter(ioutil.Discard, 1) + w, err := NewWriter(io.Discard, 1) if err != nil { t.Fatalf("NewWriter: %v", err) } @@ -475,7 +475,7 @@ func TestWriterReset(t *testing.T) { if testing.Short() && level > 1 { break } - w, err := NewWriter(ioutil.Discard, level) + w, err := NewWriter(io.Discard, level) if err != nil { t.Fatalf("NewWriter: %v", err) } @@ -487,9 +487,9 @@ func TestWriterReset(t *testing.T) { for i := 0; i < n; i++ { w.Write(buf) } - w.Reset(ioutil.Discard) + w.Reset(io.Discard) - wref, err := NewWriter(ioutil.Discard, level) + wref, err := NewWriter(io.Discard, level) if err != nil { t.Fatalf("NewWriter: %v", err) } @@ -654,7 +654,7 @@ func TestBestSpeed(t *testing.T) { } r := NewReader(buf) - got, err := ioutil.ReadAll(r) + got, err := io.ReadAll(r) if err != nil { t.Errorf("i=%d, firstN=%d, flush=%t: ReadAll: %v", i, firstN, flush, err) continue @@ -881,7 +881,7 @@ func TestBestSpeedMaxMatchOffset(t *testing.T) { } r := NewReader(buf) - dst, err := ioutil.ReadAll(r) + dst, err := io.ReadAll(r) r.Close() if err != nil { report("ReadAll: ", err) @@ -968,7 +968,7 @@ func TestMaxStackSize(t *testing.T) { wg.Add(1) go func(level int) { defer wg.Done() - zw, err := NewWriter(ioutil.Discard, level) + zw, err := NewWriter(io.Discard, level) if err != nil { t.Errorf("level %d, NewWriter() = %v, want nil", level, err) } @@ -978,7 +978,7 @@ func TestMaxStackSize(t *testing.T) { if err := zw.Close(); err != nil { t.Errorf("level %d, Close() = %v, want nil", level, err) } - zw.Reset(ioutil.Discard) + zw.Reset(io.Discard) }(level) } } diff --git a/src/compress/flate/flate_test.go b/src/compress/flate/flate_test.go index 1e45077bd5..23f4c47b03 100644 --- a/src/compress/flate/flate_test.go +++ b/src/compress/flate/flate_test.go @@ -12,7 +12,6 @@ import ( "bytes" "encoding/hex" "io" - "io/ioutil" "strings" "testing" ) @@ -243,7 +242,7 @@ func TestStreams(t *testing.T) { if err != nil { t.Fatal(err) } - data, err = ioutil.ReadAll(NewReader(bytes.NewReader(data))) + data, err = io.ReadAll(NewReader(bytes.NewReader(data))) if tc.want == "fail" { if err == nil { t.Errorf("#%d (%s): got nil error, want non-nil", i, tc.desc) @@ -266,7 +265,7 @@ func TestTruncatedStreams(t *testing.T) { for i := 0; i < len(data)-1; i++ { r := NewReader(strings.NewReader(data[:i])) - _, err := io.Copy(ioutil.Discard, r) + _, err := io.Copy(io.Discard, r) if err != io.ErrUnexpectedEOF { t.Errorf("io.Copy(%d) on truncated stream: got %v, want %v", i, err, io.ErrUnexpectedEOF) } diff --git a/src/compress/flate/inflate_test.go b/src/compress/flate/inflate_test.go index 951decd775..9575be1cf2 100644 --- a/src/compress/flate/inflate_test.go +++ b/src/compress/flate/inflate_test.go @@ -7,7 +7,6 @@ package flate import ( "bytes" "io" - "io/ioutil" "strings" "testing" ) @@ -57,7 +56,7 @@ func TestReaderTruncated(t *testing.T) { for i, v := range vectors { r := strings.NewReader(v.input) zr := NewReader(r) - b, err := ioutil.ReadAll(zr) + b, err := io.ReadAll(zr) if err != io.ErrUnexpectedEOF { t.Errorf("test %d, error mismatch: got %v, want io.ErrUnexpectedEOF", i, err) } diff --git a/src/compress/flate/reader_test.go b/src/compress/flate/reader_test.go index 9d2943a540..eb32c89184 100644 --- a/src/compress/flate/reader_test.go +++ b/src/compress/flate/reader_test.go @@ -16,7 +16,7 @@ import ( func TestNlitOutOfRange(t *testing.T) { // Trying to decode this bogus flate data, which has a Huffman table // with nlit=288, should not panic. - io.Copy(ioutil.Discard, NewReader(strings.NewReader( + io.Copy(io.Discard, NewReader(strings.NewReader( "\xfc\xfe\x36\xe7\x5e\x1c\xef\xb3\x55\x58\x77\xb6\x56\xb5\x43\xf4"+ "\x6f\xf2\xd2\xe6\x3d\x99\xa0\x85\x8c\x48\xeb\xf8\xda\x83\x04\x2a"+ "\x75\xc4\xf8\x0f\x12\x11\xb9\xb4\x4b\x09\xa0\xbe\x8b\x91\x4c"))) @@ -54,7 +54,7 @@ func BenchmarkDecode(b *testing.B) { runtime.GC() b.StartTimer() for i := 0; i < b.N; i++ { - io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1))) + io.Copy(io.Discard, NewReader(bytes.NewReader(buf1))) } }) } diff --git a/src/compress/flate/writer_test.go b/src/compress/flate/writer_test.go index 881cb71cc3..c413735cd2 100644 --- a/src/compress/flate/writer_test.go +++ b/src/compress/flate/writer_test.go @@ -8,7 +8,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "math/rand" "runtime" "testing" @@ -27,14 +26,14 @@ func BenchmarkEncode(b *testing.B) { copy(buf1[i:], buf0) } buf0 = nil - w, err := NewWriter(ioutil.Discard, level) + w, err := NewWriter(io.Discard, level) if err != nil { b.Fatal(err) } runtime.GC() b.StartTimer() for i := 0; i < b.N; i++ { - w.Reset(ioutil.Discard) + w.Reset(io.Discard) w.Write(buf1) w.Close() } @@ -96,7 +95,7 @@ func TestWriteError(t *testing.T) { t.Fatal("Level", l, "Expected an error on close") } - w.Reset(ioutil.Discard) + w.Reset(io.Discard) n2, err = w.Write([]byte{1, 2, 3, 4, 5, 6}) if err != nil { t.Fatal("Level", l, "Got unexpected error after reset:", err) @@ -206,7 +205,7 @@ func TestDeflateFast_Reset(t *testing.T) { w.Close() for ; offset <= 256; offset *= 2 { - w, err := NewWriter(ioutil.Discard, level) + w, err := NewWriter(io.Discard, level) if err != nil { t.Fatalf("NewWriter: level %d: %v", level, err) } diff --git a/src/compress/gzip/gunzip_test.go b/src/compress/gzip/gunzip_test.go index 1b01404169..17c23e8a9b 100644 --- a/src/compress/gzip/gunzip_test.go +++ b/src/compress/gzip/gunzip_test.go @@ -9,7 +9,6 @@ import ( "compress/flate" "encoding/base64" "io" - "io/ioutil" "os" "strings" "testing" @@ -430,7 +429,7 @@ func TestIssue6550(t *testing.T) { defer gzip.Close() done := make(chan bool, 1) go func() { - _, err := io.Copy(ioutil.Discard, gzip) + _, err := io.Copy(io.Discard, gzip) if err == nil { t.Errorf("Copy succeeded") } else { @@ -467,7 +466,7 @@ Found: const hello = "hello world\n" r.Multistream(false) - data, err := ioutil.ReadAll(&r) + data, err := io.ReadAll(&r) if string(data) != hello || err != nil { t.Fatalf("first stream = %q, %v, want %q, %v", string(data), err, hello, nil) } @@ -476,7 +475,7 @@ Found: t.Fatalf("second reset: %v", err) } r.Multistream(false) - data, err = ioutil.ReadAll(&r) + data, err = io.ReadAll(&r) if string(data) != hello || err != nil { t.Fatalf("second stream = %q, %v, want %q, %v", string(data), err, hello, nil) } @@ -507,7 +506,7 @@ func TestTruncatedStreams(t *testing.T) { } continue } - _, err = io.Copy(ioutil.Discard, r) + _, err = io.Copy(io.Discard, r) if ferr, ok := err.(*flate.ReadError); ok { err = ferr.Err } diff --git a/src/compress/gzip/gzip_test.go b/src/compress/gzip/gzip_test.go index f18c5cb454..12c8e18207 100644 --- a/src/compress/gzip/gzip_test.go +++ b/src/compress/gzip/gzip_test.go @@ -8,7 +8,6 @@ import ( "bufio" "bytes" "io" - "io/ioutil" "reflect" "testing" "time" @@ -29,7 +28,7 @@ func TestEmpty(t *testing.T) { if want := (Header{OS: 255}); !reflect.DeepEqual(r.Header, want) { t.Errorf("Header mismatch:\ngot %#v\nwant %#v", r.Header, want) } - b, err := ioutil.ReadAll(r) + b, err := io.ReadAll(r) if err != nil { t.Fatalf("ReadAll: %v", err) } @@ -62,7 +61,7 @@ func TestRoundTrip(t *testing.T) { if err != nil { t.Fatalf("NewReader: %v", err) } - b, err := ioutil.ReadAll(r) + b, err := io.ReadAll(r) if err != nil { t.Fatalf("ReadAll: %v", err) } @@ -147,7 +146,7 @@ func TestLatin1RoundTrip(t *testing.T) { t.Errorf("NewReader: %v", err) continue } - _, err = ioutil.ReadAll(r) + _, err = io.ReadAll(r) if err != nil { t.Errorf("ReadAll: %v", err) continue @@ -217,7 +216,7 @@ func TestConcat(t *testing.T) { if err != nil { t.Fatal(err) } - data, err := ioutil.ReadAll(r) + data, err := io.ReadAll(r) if string(data) != "hello world\n" || err != nil { t.Fatalf("ReadAll = %q, %v, want %q, nil", data, err, "hello world") } diff --git a/src/compress/lzw/reader_test.go b/src/compress/lzw/reader_test.go index 98bbfbb763..6d91dd806f 100644 --- a/src/compress/lzw/reader_test.go +++ b/src/compress/lzw/reader_test.go @@ -206,7 +206,7 @@ func TestNoLongerSavingPriorExpansions(t *testing.T) { in = append(in, 0x80, 0xff, 0x0f, 0x08) r := NewReader(bytes.NewReader(in), LSB, 8) - nDecoded, err := io.Copy(ioutil.Discard, r) + nDecoded, err := io.Copy(io.Discard, r) if err != nil { t.Fatalf("Copy: %v", err) } @@ -246,7 +246,7 @@ func BenchmarkDecoder(b *testing.B) { runtime.GC() b.StartTimer() for i := 0; i < b.N; i++ { - io.Copy(ioutil.Discard, NewReader(bytes.NewReader(buf1), LSB, 8)) + io.Copy(io.Discard, NewReader(bytes.NewReader(buf1), LSB, 8)) } }) } diff --git a/src/compress/lzw/writer_test.go b/src/compress/lzw/writer_test.go index 4979f8b352..33a28bdd3a 100644 --- a/src/compress/lzw/writer_test.go +++ b/src/compress/lzw/writer_test.go @@ -67,8 +67,8 @@ func testFile(t *testing.T, fn string, order Order, litWidth int) { defer lzwr.Close() // Compare the two. - b0, err0 := ioutil.ReadAll(golden) - b1, err1 := ioutil.ReadAll(lzwr) + b0, err0 := io.ReadAll(golden) + b1, err1 := io.ReadAll(lzwr) if err0 != nil { t.Errorf("%s (order=%d litWidth=%d): %v", fn, order, litWidth, err0) return @@ -107,7 +107,7 @@ func TestWriter(t *testing.T) { } func TestWriterReturnValues(t *testing.T) { - w := NewWriter(ioutil.Discard, LSB, 8) + w := NewWriter(io.Discard, LSB, 8) n, err := w.Write([]byte("asdf")) if n != 4 || err != nil { t.Errorf("got %d, %v, want 4, nil", n, err) @@ -115,7 +115,7 @@ func TestWriterReturnValues(t *testing.T) { } func TestSmallLitWidth(t *testing.T) { - w := NewWriter(ioutil.Discard, LSB, 2) + w := NewWriter(io.Discard, LSB, 2) if _, err := w.Write([]byte{0x03}); err != nil { t.Fatalf("write a byte < 1<<2: %v", err) } @@ -148,7 +148,7 @@ func BenchmarkEncoder(b *testing.B) { b.Run(fmt.Sprint("1e", e), func(b *testing.B) { b.SetBytes(int64(n)) for i := 0; i < b.N; i++ { - w := NewWriter(ioutil.Discard, LSB, 8) + w := NewWriter(io.Discard, LSB, 8) w.Write(buf1) w.Close() } diff --git a/src/compress/zlib/writer_test.go b/src/compress/zlib/writer_test.go index d501974078..c518729146 100644 --- a/src/compress/zlib/writer_test.go +++ b/src/compress/zlib/writer_test.go @@ -34,7 +34,7 @@ func testFileLevelDict(t *testing.T, fn string, level int, d string) { return } defer golden.Close() - b0, err0 := ioutil.ReadAll(golden) + b0, err0 := io.ReadAll(golden) if err0 != nil { t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err0) return @@ -74,7 +74,7 @@ func testLevelDict(t *testing.T, fn string, b0 []byte, level int, d string) { defer zlibr.Close() // Compare the decompressed data. - b1, err1 := ioutil.ReadAll(zlibr) + b1, err1 := io.ReadAll(zlibr) if err1 != nil { t.Errorf("%s (level=%d, dict=%q): %v", fn, level, d, err1) return diff --git a/src/crypto/tls/handshake_test.go b/src/crypto/tls/handshake_test.go index f55cd16ca8..224edcd5c7 100644 --- a/src/crypto/tls/handshake_test.go +++ b/src/crypto/tls/handshake_test.go @@ -403,7 +403,7 @@ func testHandshake(t *testing.T, clientConfig, serverConfig *Config) (serverStat } defer cli.Close() clientState = cli.ConnectionState() - buf, err := ioutil.ReadAll(cli) + buf, err := io.ReadAll(cli) if err != nil { t.Errorf("failed to call cli.Read: %v", err) } diff --git a/src/crypto/tls/tls_test.go b/src/crypto/tls/tls_test.go index 4ab8a430ba..9995538871 100644 --- a/src/crypto/tls/tls_test.go +++ b/src/crypto/tls/tls_test.go @@ -14,7 +14,6 @@ import ( "fmt" "internal/testenv" "io" - "io/ioutil" "math" "net" "os" @@ -594,7 +593,7 @@ func TestConnCloseWrite(t *testing.T) { } defer srv.Close() - data, err := ioutil.ReadAll(srv) + data, err := io.ReadAll(srv) if err != nil { return err } @@ -635,7 +634,7 @@ func TestConnCloseWrite(t *testing.T) { return fmt.Errorf("CloseWrite error = %v; want errShutdown", err) } - data, err := ioutil.ReadAll(conn) + data, err := io.ReadAll(conn) if err != nil { return err } @@ -698,7 +697,7 @@ func TestWarningAlertFlood(t *testing.T) { } defer srv.Close() - _, err = ioutil.ReadAll(srv) + _, err = io.ReadAll(srv) if err == nil { return errors.New("unexpected lack of error from server") } diff --git a/src/crypto/x509/root_ios_gen.go b/src/crypto/x509/root_ios_gen.go index 34dd5d5b22..0641c073ea 100644 --- a/src/crypto/x509/root_ios_gen.go +++ b/src/crypto/x509/root_ios_gen.go @@ -81,7 +81,7 @@ func main() { continue } - der, err := ioutil.ReadAll(tr) + der, err := io.ReadAll(tr) if err != nil { log.Fatal(err) } diff --git a/src/debug/gosym/pclntab_test.go b/src/debug/gosym/pclntab_test.go index 33772c7813..f93a5bf5e5 100644 --- a/src/debug/gosym/pclntab_test.go +++ b/src/debug/gosym/pclntab_test.go @@ -9,6 +9,7 @@ import ( "compress/gzip" "debug/elf" "internal/testenv" + "io" "io/ioutil" "os" "os/exec" @@ -287,7 +288,7 @@ func Test115PclnParsing(t *testing.T) { t.Fatal(err) } var dat []byte - dat, err = ioutil.ReadAll(gzReader) + dat, err = io.ReadAll(gzReader) if err != nil { t.Fatal(err) } diff --git a/src/encoding/ascii85/ascii85_test.go b/src/encoding/ascii85/ascii85_test.go index 1a3a87a596..c637103942 100644 --- a/src/encoding/ascii85/ascii85_test.go +++ b/src/encoding/ascii85/ascii85_test.go @@ -7,7 +7,6 @@ package ascii85 import ( "bytes" "io" - "io/ioutil" "strings" "testing" ) @@ -118,7 +117,7 @@ func TestDecode(t *testing.T) { func TestDecoder(t *testing.T) { for _, p := range pairs { decoder := NewDecoder(strings.NewReader(p.encoded)) - dbuf, err := ioutil.ReadAll(decoder) + dbuf, err := io.ReadAll(decoder) if err != nil { t.Fatal("Read failed", err) } @@ -187,7 +186,7 @@ func TestBig(t *testing.T) { if err != nil { t.Fatalf("Encoder.Close() = %v want nil", err) } - decoded, err := ioutil.ReadAll(NewDecoder(encoded)) + decoded, err := io.ReadAll(NewDecoder(encoded)) if err != nil { t.Fatalf("io.ReadAll(NewDecoder(...)): %v", err) } @@ -205,7 +204,7 @@ func TestBig(t *testing.T) { func TestDecoderInternalWhitespace(t *testing.T) { s := strings.Repeat(" ", 2048) + "z" - decoded, err := ioutil.ReadAll(NewDecoder(strings.NewReader(s))) + decoded, err := io.ReadAll(NewDecoder(strings.NewReader(s))) if err != nil { t.Errorf("Decode gave error %v", err) } diff --git a/src/encoding/base32/base32_test.go b/src/encoding/base32/base32_test.go index 0b611db0b2..8fb22b9078 100644 --- a/src/encoding/base32/base32_test.go +++ b/src/encoding/base32/base32_test.go @@ -8,7 +8,6 @@ import ( "bytes" "errors" "io" - "io/ioutil" "strings" "testing" ) @@ -361,9 +360,9 @@ func TestBig(t *testing.T) { if err != nil { t.Fatalf("Encoder.Close() = %v want nil", err) } - decoded, err := ioutil.ReadAll(NewDecoder(StdEncoding, encoded)) + decoded, err := io.ReadAll(NewDecoder(StdEncoding, encoded)) if err != nil { - t.Fatalf("ioutil.ReadAll(NewDecoder(...)): %v", err) + t.Fatalf("io.ReadAll(NewDecoder(...)): %v", err) } if !bytes.Equal(raw, decoded) { @@ -428,14 +427,14 @@ LNEBUWIIDFON2CA3DBMJXXE5LNFY== encodedShort := strings.ReplaceAll(encoded, "\n", "") dec := NewDecoder(StdEncoding, strings.NewReader(encoded)) - res1, err := ioutil.ReadAll(dec) + res1, err := io.ReadAll(dec) if err != nil { t.Errorf("ReadAll failed: %v", err) } dec = NewDecoder(StdEncoding, strings.NewReader(encodedShort)) var res2 []byte - res2, err = ioutil.ReadAll(dec) + res2, err = io.ReadAll(dec) if err != nil { t.Errorf("ReadAll failed: %v", err) } @@ -619,7 +618,7 @@ func TestBufferedDecodingSameError(t *testing.T) { }() decoder := NewDecoder(StdEncoding, pr) - _, err := ioutil.ReadAll(decoder) + _, err := io.ReadAll(decoder) if err != testcase.expected { t.Errorf("Expected %v, got %v; case %s %+v", testcase.expected, err, testcase.prefix, chunks) @@ -718,7 +717,7 @@ func TestDecodeReadAll(t *testing.T) { encoded = strings.ReplaceAll(encoded, "=", "") } - decReader, err := ioutil.ReadAll(NewDecoder(encoding, strings.NewReader(encoded))) + decReader, err := io.ReadAll(NewDecoder(encoding, strings.NewReader(encoded))) if err != nil { t.Errorf("NewDecoder error: %v", err) } diff --git a/src/encoding/base64/base64_test.go b/src/encoding/base64/base64_test.go index c2c9478a43..51047402bd 100644 --- a/src/encoding/base64/base64_test.go +++ b/src/encoding/base64/base64_test.go @@ -9,7 +9,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "reflect" "runtime/debug" "strings" @@ -324,9 +323,9 @@ func TestBig(t *testing.T) { if err != nil { t.Fatalf("Encoder.Close() = %v want nil", err) } - decoded, err := ioutil.ReadAll(NewDecoder(StdEncoding, encoded)) + decoded, err := io.ReadAll(NewDecoder(StdEncoding, encoded)) if err != nil { - t.Fatalf("ioutil.ReadAll(NewDecoder(...)): %v", err) + t.Fatalf("io.ReadAll(NewDecoder(...)): %v", err) } if !bytes.Equal(raw, decoded) { @@ -403,7 +402,7 @@ func TestDecoderIssue3577(t *testing.T) { }) errc := make(chan error, 1) go func() { - _, err := ioutil.ReadAll(d) + _, err := io.ReadAll(d) errc <- err }() select { @@ -436,14 +435,14 @@ bqbPb06551Y4 encodedShort := strings.ReplaceAll(encoded, "\n", "") dec := NewDecoder(StdEncoding, strings.NewReader(encoded)) - res1, err := ioutil.ReadAll(dec) + res1, err := io.ReadAll(dec) if err != nil { t.Errorf("ReadAll failed: %v", err) } dec = NewDecoder(StdEncoding, strings.NewReader(encodedShort)) var res2 []byte - res2, err = ioutil.ReadAll(dec) + res2, err = io.ReadAll(dec) if err != nil { t.Errorf("ReadAll failed: %v", err) } @@ -517,14 +516,14 @@ func TestDecoderRaw(t *testing.T) { // Through reader. Used to fail. r := NewDecoder(RawURLEncoding, bytes.NewReader([]byte(source))) - dec2, err := ioutil.ReadAll(io.LimitReader(r, 100)) + dec2, err := io.ReadAll(io.LimitReader(r, 100)) if err != nil || !bytes.Equal(dec2, want) { t.Errorf("reading NewDecoder(RawURLEncoding, %q) = %x, %v, want %x, nil", source, dec2, err, want) } // Should work with padding. r = NewDecoder(URLEncoding, bytes.NewReader([]byte(source+"=="))) - dec3, err := ioutil.ReadAll(r) + dec3, err := io.ReadAll(r) if err != nil || !bytes.Equal(dec3, want) { t.Errorf("reading NewDecoder(URLEncoding, %q) = %x, %v, want %x, nil", source+"==", dec3, err, want) } diff --git a/src/encoding/binary/binary_test.go b/src/encoding/binary/binary_test.go index 5971e0966a..83af89e8a7 100644 --- a/src/encoding/binary/binary_test.go +++ b/src/encoding/binary/binary_test.go @@ -8,7 +8,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "math" "reflect" "strings" @@ -524,7 +523,7 @@ func BenchmarkWriteStruct(b *testing.B) { b.SetBytes(int64(Size(&s))) b.ResetTimer() for i := 0; i < b.N; i++ { - Write(ioutil.Discard, BigEndian, &s) + Write(io.Discard, BigEndian, &s) } } diff --git a/src/encoding/gob/encoder_test.go b/src/encoding/gob/encoder_test.go index 825f0d6f03..fe2774948a 100644 --- a/src/encoding/gob/encoder_test.go +++ b/src/encoding/gob/encoder_test.go @@ -8,7 +8,7 @@ import ( "bytes" "encoding/hex" "fmt" - "io/ioutil" + "io" "reflect" "strings" "testing" @@ -938,7 +938,7 @@ func encodeAndRecover(value interface{}) (encodeErr, panicErr error) { } }() - encodeErr = NewEncoder(ioutil.Discard).Encode(value) + encodeErr = NewEncoder(io.Discard).Encode(value) return } diff --git a/src/encoding/hex/hex_test.go b/src/encoding/hex/hex_test.go index 31e3f68936..7593e20db5 100644 --- a/src/encoding/hex/hex_test.go +++ b/src/encoding/hex/hex_test.go @@ -8,7 +8,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "strings" "testing" ) @@ -150,7 +149,7 @@ func TestEncoderDecoder(t *testing.T) { func TestDecoderErr(t *testing.T) { for _, tt := range errTests { dec := NewDecoder(strings.NewReader(tt.in)) - out, err := ioutil.ReadAll(dec) + out, err := io.ReadAll(dec) wantErr := tt.err // Decoder is reading from stream, so it reports io.ErrUnexpectedEOF instead of ErrLength. if wantErr == ErrLength { diff --git a/src/encoding/json/bench_test.go b/src/encoding/json/bench_test.go index 4a5fe7ec84..73c7b09fb6 100644 --- a/src/encoding/json/bench_test.go +++ b/src/encoding/json/bench_test.go @@ -15,7 +15,7 @@ import ( "compress/gzip" "fmt" "internal/testenv" - "io/ioutil" + "io" "os" "reflect" "runtime" @@ -52,7 +52,7 @@ func codeInit() { if err != nil { panic(err) } - data, err := ioutil.ReadAll(gz) + data, err := io.ReadAll(gz) if err != nil { panic(err) } @@ -89,7 +89,7 @@ func BenchmarkCodeEncoder(b *testing.B) { b.StartTimer() } b.RunParallel(func(pb *testing.PB) { - enc := NewEncoder(ioutil.Discard) + enc := NewEncoder(io.Discard) for pb.Next() { if err := enc.Encode(&codeStruct); err != nil { b.Fatal("Encode:", err) @@ -399,7 +399,7 @@ func BenchmarkEncodeMarshaler(b *testing.B) { }{} b.RunParallel(func(pb *testing.PB) { - enc := NewEncoder(ioutil.Discard) + enc := NewEncoder(io.Discard) for pb.Next() { if err := enc.Encode(&m); err != nil { diff --git a/src/encoding/json/stream_test.go b/src/encoding/json/stream_test.go index c9e5334337..c284f2d965 100644 --- a/src/encoding/json/stream_test.go +++ b/src/encoding/json/stream_test.go @@ -7,7 +7,6 @@ package json import ( "bytes" "io" - "io/ioutil" "log" "net" "net/http" @@ -215,7 +214,7 @@ func TestDecoderBuffered(t *testing.T) { if m.Name != "Gopher" { t.Errorf("Name = %q; want Gopher", m.Name) } - rest, err := ioutil.ReadAll(d.Buffered()) + rest, err := io.ReadAll(d.Buffered()) if err != nil { t.Fatal(err) } @@ -318,7 +317,7 @@ func BenchmarkEncoderEncode(b *testing.B) { v := &T{"foo", "bar"} b.RunParallel(func(pb *testing.PB) { for pb.Next() { - if err := NewEncoder(ioutil.Discard).Encode(v); err != nil { + if err := NewEncoder(io.Discard).Encode(v); err != nil { b.Fatal(err) } } diff --git a/src/encoding/pem/pem_test.go b/src/encoding/pem/pem_test.go index 8515b46498..b2b6b15e73 100644 --- a/src/encoding/pem/pem_test.go +++ b/src/encoding/pem/pem_test.go @@ -6,7 +6,7 @@ package pem import ( "bytes" - "io/ioutil" + "io" "reflect" "strings" "testing" @@ -271,7 +271,7 @@ func BenchmarkEncode(b *testing.B) { data := &Block{Bytes: make([]byte, 65536)} b.SetBytes(int64(len(data.Bytes))) for i := 0; i < b.N; i++ { - Encode(ioutil.Discard, data) + Encode(io.Discard, data) } } diff --git a/src/flag/flag_test.go b/src/flag/flag_test.go index 2793064511..06cab79405 100644 --- a/src/flag/flag_test.go +++ b/src/flag/flag_test.go @@ -10,7 +10,6 @@ import ( "fmt" "internal/testenv" "io" - "io/ioutil" "os" "os/exec" "runtime" @@ -545,7 +544,7 @@ func TestGetters(t *testing.T) { func TestParseError(t *testing.T) { for _, typ := range []string{"bool", "int", "int64", "uint", "uint64", "float64", "duration"} { fs := NewFlagSet("parse error test", ContinueOnError) - fs.SetOutput(ioutil.Discard) + fs.SetOutput(io.Discard) _ = fs.Bool("bool", false, "") _ = fs.Int("int", 0, "") _ = fs.Int64("int64", 0, "") @@ -576,7 +575,7 @@ func TestRangeError(t *testing.T) { } for _, arg := range bad { fs := NewFlagSet("parse error test", ContinueOnError) - fs.SetOutput(ioutil.Discard) + fs.SetOutput(io.Discard) _ = fs.Int("int", 0, "") _ = fs.Int64("int64", 0, "") _ = fs.Uint("uint", 0, "") diff --git a/src/go/internal/gccgoimporter/importer.go b/src/go/internal/gccgoimporter/importer.go index 2494fd7b2a..94f2defd8d 100644 --- a/src/go/internal/gccgoimporter/importer.go +++ b/src/go/internal/gccgoimporter/importer.go @@ -221,7 +221,7 @@ func GetImporter(searchpaths []string, initmap map[*types.Package]InitData) Impo // Excluded for now: Standard gccgo doesn't support this import format currently. // case goimporterMagic: // var data []byte - // data, err = ioutil.ReadAll(reader) + // data, err = io.ReadAll(reader) // if err != nil { // return // } diff --git a/src/go/internal/gcimporter/gcimporter.go b/src/go/internal/gcimporter/gcimporter.go index fda15eaaae..b74daca246 100644 --- a/src/go/internal/gcimporter/gcimporter.go +++ b/src/go/internal/gcimporter/gcimporter.go @@ -12,7 +12,6 @@ import ( "go/token" "go/types" "io" - "io/ioutil" "os" "path/filepath" "strings" @@ -147,7 +146,7 @@ func Import(fset *token.FileSet, packages map[string]*types.Package, path, srcDi case "$$B\n": var data []byte - data, err = ioutil.ReadAll(buf) + data, err = io.ReadAll(buf) if err != nil { break } diff --git a/src/go/parser/interface.go b/src/go/parser/interface.go index b2d834fdec..cc7e455c4d 100644 --- a/src/go/parser/interface.go +++ b/src/go/parser/interface.go @@ -35,7 +35,7 @@ func readSource(filename string, src interface{}) ([]byte, error) { return s.Bytes(), nil } case io.Reader: - return ioutil.ReadAll(s) + return io.ReadAll(s) } return nil, errors.New("invalid source") } diff --git a/src/go/printer/performance_test.go b/src/go/printer/performance_test.go index 2e67154e6b..e23de3fbae 100644 --- a/src/go/printer/performance_test.go +++ b/src/go/printer/performance_test.go @@ -53,6 +53,6 @@ func BenchmarkPrint(b *testing.B) { initialize() } for i := 0; i < b.N; i++ { - testprint(ioutil.Discard, testfile) + testprint(io.Discard, testfile) } } diff --git a/src/go/types/gotype.go b/src/go/types/gotype.go index eacf68f52f..52709df17b 100644 --- a/src/go/types/gotype.go +++ b/src/go/types/gotype.go @@ -88,7 +88,7 @@ import ( "go/scanner" "go/token" "go/types" - "io/ioutil" + "io" "os" "path/filepath" "sync" @@ -191,7 +191,7 @@ func parse(filename string, src interface{}) (*ast.File, error) { } func parseStdin() (*ast.File, error) { - src, err := ioutil.ReadAll(os.Stdin) + src, err := io.ReadAll(os.Stdin) if err != nil { return nil, err } diff --git a/src/html/template/clone_test.go b/src/html/template/clone_test.go index c9c619f0d4..7cb1b9ca06 100644 --- a/src/html/template/clone_test.go +++ b/src/html/template/clone_test.go @@ -8,7 +8,7 @@ import ( "bytes" "errors" "fmt" - "io/ioutil" + "io" "strings" "sync" "testing" @@ -171,7 +171,7 @@ func TestCloneThenParse(t *testing.T) { t.Error("adding a template to a clone added it to the original") } // double check that the embedded template isn't available in the original - err := t0.ExecuteTemplate(ioutil.Discard, "a", nil) + err := t0.ExecuteTemplate(io.Discard, "a", nil) if err == nil { t.Error("expected 'no such template' error") } @@ -185,13 +185,13 @@ func TestFuncMapWorksAfterClone(t *testing.T) { // get the expected error output (no clone) uncloned := Must(New("").Funcs(funcs).Parse("{{customFunc}}")) - wantErr := uncloned.Execute(ioutil.Discard, nil) + wantErr := uncloned.Execute(io.Discard, nil) // toClone must be the same as uncloned. It has to be recreated from scratch, // since cloning cannot occur after execution. toClone := Must(New("").Funcs(funcs).Parse("{{customFunc}}")) cloned := Must(toClone.Clone()) - gotErr := cloned.Execute(ioutil.Discard, nil) + gotErr := cloned.Execute(io.Discard, nil) if wantErr.Error() != gotErr.Error() { t.Errorf("clone error message mismatch want %q got %q", wantErr, gotErr) @@ -213,7 +213,7 @@ func TestTemplateCloneExecuteRace(t *testing.T) { go func() { defer wg.Done() for i := 0; i < 100; i++ { - if err := tmpl.Execute(ioutil.Discard, "data"); err != nil { + if err := tmpl.Execute(io.Discard, "data"); err != nil { panic(err) } } @@ -237,7 +237,7 @@ func TestCloneGrowth(t *testing.T) { tmpl = Must(tmpl.Clone()) Must(tmpl.Parse(`{{define "B"}}Text{{end}}`)) for i := 0; i < 10; i++ { - tmpl.Execute(ioutil.Discard, nil) + tmpl.Execute(io.Discard, nil) } if len(tmpl.DefinedTemplates()) > 200 { t.Fatalf("too many templates: %v", len(tmpl.DefinedTemplates())) @@ -257,7 +257,7 @@ func TestCloneRedefinedName(t *testing.T) { for i := 0; i < 2; i++ { t2 := Must(t1.Clone()) t2 = Must(t2.New(fmt.Sprintf("%d", i)).Parse(page)) - err := t2.Execute(ioutil.Discard, nil) + err := t2.Execute(io.Discard, nil) if err != nil { t.Fatal(err) } diff --git a/src/html/template/exec_test.go b/src/html/template/exec_test.go index fc76ee40e5..232945a0bb 100644 --- a/src/html/template/exec_test.go +++ b/src/html/template/exec_test.go @@ -11,7 +11,7 @@ import ( "errors" "flag" "fmt" - "io/ioutil" + "io" "reflect" "strings" "testing" @@ -1335,7 +1335,7 @@ func TestExecuteGivesExecError(t *testing.T) { if err != nil { t.Fatal(err) } - err = tmpl.Execute(ioutil.Discard, 0) + err = tmpl.Execute(io.Discard, 0) if err == nil { t.Fatal("expected error; got none") } @@ -1481,7 +1481,7 @@ func TestEvalFieldErrors(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { tmpl := Must(New("tmpl").Parse(tc.src)) - err := tmpl.Execute(ioutil.Discard, tc.value) + err := tmpl.Execute(io.Discard, tc.value) got := "" if err != nil { got = err.Error() @@ -1498,7 +1498,7 @@ func TestMaxExecDepth(t *testing.T) { t.Skip("skipping in -short mode") } tmpl := Must(New("tmpl").Parse(`{{template "tmpl" .}}`)) - err := tmpl.Execute(ioutil.Discard, nil) + err := tmpl.Execute(io.Discard, nil) got := "" if err != nil { got = err.Error() diff --git a/src/image/gif/writer_test.go b/src/image/gif/writer_test.go index 1e622b3674..af0105c6be 100644 --- a/src/image/gif/writer_test.go +++ b/src/image/gif/writer_test.go @@ -11,7 +11,7 @@ import ( "image/color/palette" "image/draw" _ "image/png" - "io/ioutil" + "io" "math/rand" "os" "reflect" @@ -285,7 +285,7 @@ func TestEncodeMismatchDelay(t *testing.T) { Image: images, Delay: make([]int, 1), } - if err := EncodeAll(ioutil.Discard, g0); err == nil { + if err := EncodeAll(io.Discard, g0); err == nil { t.Error("expected error from mismatched delay and image slice lengths") } @@ -297,13 +297,13 @@ func TestEncodeMismatchDelay(t *testing.T) { for i := range g1.Disposal { g1.Disposal[i] = DisposalNone } - if err := EncodeAll(ioutil.Discard, g1); err == nil { + if err := EncodeAll(io.Discard, g1); err == nil { t.Error("expected error from mismatched disposal and image slice lengths") } } func TestEncodeZeroGIF(t *testing.T) { - if err := EncodeAll(ioutil.Discard, &GIF{}); err == nil { + if err := EncodeAll(io.Discard, &GIF{}); err == nil { t.Error("expected error from providing empty gif") } } @@ -324,7 +324,7 @@ func TestEncodeAllFramesOutOfBounds(t *testing.T) { Height: upperBound, }, } - err := EncodeAll(ioutil.Discard, g) + err := EncodeAll(io.Discard, g) if upperBound >= 8 { if err != nil { t.Errorf("upperBound=%d: %v", upperBound, err) @@ -430,7 +430,7 @@ func TestEncodeImplicitConfigSize(t *testing.T) { Image: images, Delay: make([]int, len(images)), } - err := EncodeAll(ioutil.Discard, g) + err := EncodeAll(io.Discard, g) if lowerBound >= 0 { if err != nil { t.Errorf("lowerBound=%d: %v", lowerBound, err) @@ -509,7 +509,7 @@ func TestEncodeBadPalettes(t *testing.T) { } } - err := EncodeAll(ioutil.Discard, &GIF{ + err := EncodeAll(io.Discard, &GIF{ Image: []*image.Paletted{ image.NewPaletted(image.Rect(0, 0, w, h), pal), }, @@ -668,7 +668,7 @@ func BenchmarkEncodeRandomPaletted(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - Encode(ioutil.Discard, paletted, nil) + Encode(io.Discard, paletted, nil) } } @@ -691,7 +691,7 @@ func BenchmarkEncodeRandomRGBA(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - Encode(ioutil.Discard, rgba, nil) + Encode(io.Discard, rgba, nil) } } @@ -708,7 +708,7 @@ func BenchmarkEncodeRealisticPaletted(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - Encode(ioutil.Discard, paletted, nil) + Encode(io.Discard, paletted, nil) } } @@ -729,6 +729,6 @@ func BenchmarkEncodeRealisticRGBA(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - Encode(ioutil.Discard, rgba, nil) + Encode(io.Discard, rgba, nil) } } diff --git a/src/image/jpeg/writer_test.go b/src/image/jpeg/writer_test.go index 3aff742632..abd5e32333 100644 --- a/src/image/jpeg/writer_test.go +++ b/src/image/jpeg/writer_test.go @@ -10,7 +10,7 @@ import ( "image" "image/color" "image/png" - "io/ioutil" + "io" "math/rand" "os" "testing" @@ -261,7 +261,7 @@ func BenchmarkEncodeRGBA(b *testing.B) { b.ResetTimer() options := &Options{Quality: 90} for i := 0; i < b.N; i++ { - Encode(ioutil.Discard, img, options) + Encode(io.Discard, img, options) } } @@ -283,6 +283,6 @@ func BenchmarkEncodeYCbCr(b *testing.B) { b.ResetTimer() options := &Options{Quality: 90} for i := 0; i < b.N; i++ { - Encode(ioutil.Discard, img, options) + Encode(io.Discard, img, options) } } diff --git a/src/image/png/writer_test.go b/src/image/png/writer_test.go index 5d131ff823..47aa861339 100644 --- a/src/image/png/writer_test.go +++ b/src/image/png/writer_test.go @@ -12,7 +12,6 @@ import ( "image" "image/color" "io" - "io/ioutil" "testing" ) @@ -169,7 +168,7 @@ func TestWriterPaletted(t *testing.T) { t.Error(err) return } - n, err := io.Copy(ioutil.Discard, r) + n, err := io.Copy(io.Discard, r) if err != nil { t.Errorf("got error while reading image data: %v", err) } @@ -234,7 +233,7 @@ func BenchmarkEncodeGray(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - Encode(ioutil.Discard, img) + Encode(io.Discard, img) } } @@ -259,7 +258,7 @@ func BenchmarkEncodeGrayWithBufferPool(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - e.Encode(ioutil.Discard, img) + e.Encode(io.Discard, img) } } @@ -279,7 +278,7 @@ func BenchmarkEncodeNRGBOpaque(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - Encode(ioutil.Discard, img) + Encode(io.Discard, img) } } @@ -292,7 +291,7 @@ func BenchmarkEncodeNRGBA(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - Encode(ioutil.Discard, img) + Encode(io.Discard, img) } } @@ -305,7 +304,7 @@ func BenchmarkEncodePaletted(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - Encode(ioutil.Discard, img) + Encode(io.Discard, img) } } @@ -325,7 +324,7 @@ func BenchmarkEncodeRGBOpaque(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - Encode(ioutil.Discard, img) + Encode(io.Discard, img) } } @@ -338,6 +337,6 @@ func BenchmarkEncodeRGBA(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - Encode(ioutil.Discard, img) + Encode(io.Discard, img) } } diff --git a/src/internal/obscuretestdata/obscuretestdata.go b/src/internal/obscuretestdata/obscuretestdata.go index 512f3759b4..06cd1df22c 100644 --- a/src/internal/obscuretestdata/obscuretestdata.go +++ b/src/internal/obscuretestdata/obscuretestdata.go @@ -47,5 +47,5 @@ func ReadFile(name string) ([]byte, error) { return nil, err } defer f.Close() - return ioutil.ReadAll(base64.NewDecoder(base64.StdEncoding, f)) + return io.ReadAll(base64.NewDecoder(base64.StdEncoding, f)) } diff --git a/src/internal/profile/profile.go b/src/internal/profile/profile.go index a6275bc6de..29568aa4b5 100644 --- a/src/internal/profile/profile.go +++ b/src/internal/profile/profile.go @@ -12,7 +12,6 @@ import ( "compress/gzip" "fmt" "io" - "io/ioutil" "regexp" "strings" "time" @@ -125,7 +124,7 @@ type Function struct { // may be a gzip-compressed encoded protobuf or one of many legacy // profile formats which may be unsupported in the future. func Parse(r io.Reader) (*Profile, error) { - orig, err := ioutil.ReadAll(r) + orig, err := io.ReadAll(r) if err != nil { return nil, err } @@ -136,7 +135,7 @@ func Parse(r io.Reader) (*Profile, error) { if err != nil { return nil, fmt.Errorf("decompressing profile: %v", err) } - data, err := ioutil.ReadAll(gz) + data, err := io.ReadAll(gz) if err != nil { return nil, fmt.Errorf("decompressing profile: %v", err) } diff --git a/src/io/example_test.go b/src/io/example_test.go index 4706032429..6d338acd14 100644 --- a/src/io/example_test.go +++ b/src/io/example_test.go @@ -8,7 +8,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "log" "os" "strings" @@ -141,7 +140,7 @@ func ExampleTeeReader() { r = io.TeeReader(r, os.Stdout) // Everything read from r will be copied to stdout. - ioutil.ReadAll(r) + io.ReadAll(r) // Output: // some io.Reader stream to be read @@ -245,7 +244,7 @@ func ExamplePipe() { func ExampleReadAll() { r := strings.NewReader("Go is a general-purpose language designed with systems programming in mind.") - b, err := ioutil.ReadAll(r) + b, err := io.ReadAll(r) if err != nil { log.Fatal(err) } 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) { diff --git a/src/io/multi_test.go b/src/io/multi_test.go index f05d5f74ef..909b6d8be2 100644 --- a/src/io/multi_test.go +++ b/src/io/multi_test.go @@ -10,7 +10,6 @@ import ( "errors" "fmt" . "io" - "io/ioutil" "runtime" "strings" "testing" @@ -142,7 +141,7 @@ func testMultiWriter(t *testing.T, sink interface { } } -// writerFunc is an io.Writer implemented by the underlying func. +// writerFunc is an Writer implemented by the underlying func. type writerFunc func(p []byte) (int, error) func (f writerFunc) Write(p []byte) (int, error) { @@ -196,7 +195,7 @@ func TestMultiReaderCopy(t *testing.T) { slice := []Reader{strings.NewReader("hello world")} r := MultiReader(slice...) slice[0] = nil - data, err := ioutil.ReadAll(r) + data, err := ReadAll(r) if err != nil || string(data) != "hello world" { t.Errorf("ReadAll() = %q, %v, want %q, nil", data, err, "hello world") } @@ -217,7 +216,7 @@ func TestMultiWriterCopy(t *testing.T) { } } -// readerFunc is an io.Reader implemented by the underlying func. +// readerFunc is an Reader implemented by the underlying func. type readerFunc func(p []byte) (int, error) func (f readerFunc) Read(p []byte) (int, error) { @@ -261,7 +260,7 @@ func TestMultiReaderFlatten(t *testing.T) { } // byteAndEOFReader is a Reader which reads one byte (the underlying -// byte) and io.EOF at once in its Read call. +// byte) and EOF at once in its Read call. type byteAndEOFReader byte func (b byteAndEOFReader) Read(p []byte) (n int, err error) { @@ -276,7 +275,7 @@ func (b byteAndEOFReader) Read(p []byte) (n int, err error) { // This used to yield bytes forever; issue 16795. func TestMultiReaderSingleByteWithEOF(t *testing.T) { - got, err := ioutil.ReadAll(LimitReader(MultiReader(byteAndEOFReader('a'), byteAndEOFReader('b')), 10)) + got, err := ReadAll(LimitReader(MultiReader(byteAndEOFReader('a'), byteAndEOFReader('b')), 10)) if err != nil { t.Fatal(err) } diff --git a/src/mime/encodedword_test.go b/src/mime/encodedword_test.go index 6c54e502ad..2a98794380 100644 --- a/src/mime/encodedword_test.go +++ b/src/mime/encodedword_test.go @@ -7,7 +7,6 @@ package mime import ( "errors" "io" - "io/ioutil" "strings" "testing" ) @@ -182,7 +181,7 @@ func TestCharsetDecoder(t *testing.T) { if charset != test.charsets[i] { t.Errorf("DecodeHeader(%q), got charset %q, want %q", test.src, charset, test.charsets[i]) } - content, err := ioutil.ReadAll(input) + content, err := io.ReadAll(input) if err != nil { t.Errorf("DecodeHeader(%q), error in reader: %v", test.src, err) } diff --git a/src/mime/example_test.go b/src/mime/example_test.go index 85795976f0..8a96873e5d 100644 --- a/src/mime/example_test.go +++ b/src/mime/example_test.go @@ -8,7 +8,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "mime" ) @@ -38,7 +37,7 @@ func ExampleWordDecoder_Decode() { // Fake character set for example. // Real use would integrate with packages such // as code.google.com/p/go-charset - content, err := ioutil.ReadAll(input) + content, err := io.ReadAll(input) if err != nil { return nil, err } @@ -77,7 +76,7 @@ func ExampleWordDecoder_DecodeHeader() { // Fake character set for example. // Real use would integrate with packages such // as code.google.com/p/go-charset - content, err := ioutil.ReadAll(input) + content, err := io.ReadAll(input) if err != nil { return nil, err } diff --git a/src/mime/multipart/example_test.go b/src/mime/multipart/example_test.go index 6d6ba81d5e..fe154ac4f6 100644 --- a/src/mime/multipart/example_test.go +++ b/src/mime/multipart/example_test.go @@ -7,7 +7,6 @@ package multipart_test import ( "fmt" "io" - "io/ioutil" "log" "mime" "mime/multipart" @@ -39,7 +38,7 @@ func ExampleNewReader() { if err != nil { log.Fatal(err) } - slurp, err := ioutil.ReadAll(p) + slurp, err := io.ReadAll(p) if err != nil { log.Fatal(err) } diff --git a/src/mime/multipart/multipart.go b/src/mime/multipart/multipart.go index 1750300fb5..cb8bf39338 100644 --- a/src/mime/multipart/multipart.go +++ b/src/mime/multipart/multipart.go @@ -17,7 +17,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "mime" "mime/quotedprintable" "net/textproto" @@ -278,7 +277,7 @@ func matchAfterPrefix(buf, prefix []byte, readErr error) int { } func (p *Part) Close() error { - io.Copy(ioutil.Discard, p) + io.Copy(io.Discard, p) return nil } diff --git a/src/mime/multipart/multipart_test.go b/src/mime/multipart/multipart_test.go index b60c54a204..741d2304ed 100644 --- a/src/mime/multipart/multipart_test.go +++ b/src/mime/multipart/multipart_test.go @@ -9,7 +9,6 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "net/textproto" "os" "reflect" @@ -307,7 +306,7 @@ Oh no, premature EOF! if err != nil { t.Fatalf("didn't get a part") } - _, err = io.Copy(ioutil.Discard, part) + _, err = io.Copy(io.Discard, part) if err != io.ErrUnexpectedEOF { t.Fatalf("expected error io.ErrUnexpectedEOF; got %v", err) } @@ -372,7 +371,7 @@ Body 2 if !reflect.DeepEqual(part.Header, hdr) { t.Errorf("Part %d: part.Header = %v, want %v", i, part.Header, hdr) } - data, err := ioutil.ReadAll(part) + data, err := io.ReadAll(part) expectEq(t, body, string(data), fmt.Sprintf("Part %d body", i)) if err != nil { t.Fatalf("Part %d: ReadAll failed: %v", i, err) @@ -530,14 +529,14 @@ func TestNested(t *testing.T) { if err != nil { t.Fatalf("reading text/plain part: %v", err) } - if b, err := ioutil.ReadAll(p); string(b) != "*body*\r\n" || err != nil { + if b, err := io.ReadAll(p); string(b) != "*body*\r\n" || err != nil { t.Fatalf("reading text/plain part: got %q, %v", b, err) } p, err = mr2.NextPart() if err != nil { t.Fatalf("reading text/html part: %v", err) } - if b, err := ioutil.ReadAll(p); string(b) != "body\r\n" || err != nil { + if b, err := io.ReadAll(p); string(b) != "body\r\n" || err != nil { t.Fatalf("reading text/html part: got %q, %v", b, err) } @@ -850,7 +849,7 @@ Cases: t.Errorf("in test %q, NextPart: %v", tt.name, err) continue Cases } - pbody, err := ioutil.ReadAll(p) + pbody, err := io.ReadAll(p) if err != nil { t.Errorf("in test %q, error reading part: %v", tt.name, err) continue Cases @@ -882,7 +881,7 @@ func partsFromReader(r *Reader) ([]headerBody, error) { if err != nil { return nil, fmt.Errorf("NextPart: %v", err) } - pbody, err := ioutil.ReadAll(p) + pbody, err := io.ReadAll(p) if err != nil { return nil, fmt.Errorf("error reading part: %v", err) } diff --git a/src/mime/multipart/writer_test.go b/src/mime/multipart/writer_test.go index b89b093fff..cfc0f09f37 100644 --- a/src/mime/multipart/writer_test.go +++ b/src/mime/multipart/writer_test.go @@ -6,7 +6,7 @@ package multipart import ( "bytes" - "io/ioutil" + "io" "mime" "net/textproto" "strings" @@ -51,7 +51,7 @@ func TestWriter(t *testing.T) { if g, e := part.FormName(), "myfile"; g != e { t.Errorf("part 1: want form name %q, got %q", e, g) } - slurp, err := ioutil.ReadAll(part) + slurp, err := io.ReadAll(part) if err != nil { t.Fatalf("part 1: ReadAll: %v", err) } @@ -66,7 +66,7 @@ func TestWriter(t *testing.T) { if g, e := part.FormName(), "key"; g != e { t.Errorf("part 2: want form name %q, got %q", e, g) } - slurp, err = ioutil.ReadAll(part) + slurp, err = io.ReadAll(part) if err != nil { t.Fatalf("part 2: ReadAll: %v", err) } @@ -134,7 +134,7 @@ func TestWriterBoundaryGoroutines(t *testing.T) { // different goroutines. This was previously broken by // https://codereview.appspot.com/95760043/ and reverted in // https://codereview.appspot.com/117600043/ - w := NewWriter(ioutil.Discard) + w := NewWriter(io.Discard) done := make(chan int) go func() { w.CreateFormField("foo") diff --git a/src/mime/quotedprintable/example_test.go b/src/mime/quotedprintable/example_test.go index 5a9ab450a3..e5a479a3a7 100644 --- a/src/mime/quotedprintable/example_test.go +++ b/src/mime/quotedprintable/example_test.go @@ -6,7 +6,7 @@ package quotedprintable_test import ( "fmt" - "io/ioutil" + "io" "mime/quotedprintable" "os" "strings" @@ -18,7 +18,7 @@ func ExampleNewReader() { `invalid escape: hello`, "Hello, Gophers! This symbol will be unescaped: =3D and this will be written in =\r\none line.", } { - b, err := ioutil.ReadAll(quotedprintable.NewReader(strings.NewReader(s))) + b, err := io.ReadAll(quotedprintable.NewReader(strings.NewReader(s))) fmt.Printf("%s %v\n", b, err) } // Output: diff --git a/src/mime/quotedprintable/writer_test.go b/src/mime/quotedprintable/writer_test.go index d494c1e3dc..42de0f3d6e 100644 --- a/src/mime/quotedprintable/writer_test.go +++ b/src/mime/quotedprintable/writer_test.go @@ -6,7 +6,7 @@ package quotedprintable import ( "bytes" - "io/ioutil" + "io" "strings" "testing" ) @@ -128,7 +128,7 @@ func TestRoundTrip(t *testing.T) { } r := NewReader(buf) - gotBytes, err := ioutil.ReadAll(r) + gotBytes, err := io.ReadAll(r) if err != nil { t.Fatalf("Error while reading from Reader: %v", err) } @@ -151,7 +151,7 @@ var testMsg = []byte("Quoted-Printable (QP) est un format d'encodage de données func BenchmarkWriter(b *testing.B) { for i := 0; i < b.N; i++ { - w := NewWriter(ioutil.Discard) + w := NewWriter(io.Discard) w.Write(testMsg) w.Close() } diff --git a/src/net/http/alpn_test.go b/src/net/http/alpn_test.go index 618bdbe54a..a51038c355 100644 --- a/src/net/http/alpn_test.go +++ b/src/net/http/alpn_test.go @@ -11,7 +11,6 @@ import ( "crypto/x509" "fmt" "io" - "io/ioutil" . "net/http" "net/http/httptest" "strings" @@ -49,7 +48,7 @@ func TestNextProtoUpgrade(t *testing.T) { if err != nil { t.Fatal(err) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { t.Fatal(err) } @@ -93,7 +92,7 @@ func TestNextProtoUpgrade(t *testing.T) { t.Fatal(err) } conn.Write([]byte("GET /foo\n")) - body, err := ioutil.ReadAll(conn) + body, err := io.ReadAll(conn) if err != nil { t.Fatal(err) } diff --git a/src/net/http/cgi/child.go b/src/net/http/cgi/child.go index 690986335c..0114da377b 100644 --- a/src/net/http/cgi/child.go +++ b/src/net/http/cgi/child.go @@ -13,7 +13,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "net" "net/http" "net/url" @@ -32,7 +31,7 @@ func Request() (*http.Request, error) { return nil, err } if r.ContentLength > 0 { - r.Body = ioutil.NopCloser(io.LimitReader(os.Stdin, r.ContentLength)) + r.Body = io.NopCloser(io.LimitReader(os.Stdin, r.ContentLength)) } return r, nil } diff --git a/src/net/http/client.go b/src/net/http/client.go index 6ca0d2e6cf..88e2028bc3 100644 --- a/src/net/http/client.go +++ b/src/net/http/client.go @@ -16,7 +16,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "log" "net/url" "reflect" @@ -282,7 +281,7 @@ func send(ireq *Request, rt RoundTripper, deadline time.Time) (resp *Response, d if resp.ContentLength > 0 && req.Method != "HEAD" { return nil, didTimeout, fmt.Errorf("http: RoundTripper implementation (%T) returned a *Response with content length %d but a nil Body", rt, resp.ContentLength) } - resp.Body = ioutil.NopCloser(strings.NewReader("")) + resp.Body = io.NopCloser(strings.NewReader("")) } if !deadline.IsZero() { resp.Body = &cancelTimerBody{ @@ -697,7 +696,7 @@ func (c *Client) do(req *Request) (retres *Response, reterr error) { // fails, the Transport won't reuse it anyway. const maxBodySlurpSize = 2 << 10 if resp.ContentLength == -1 || resp.ContentLength <= maxBodySlurpSize { - io.CopyN(ioutil.Discard, resp.Body, maxBodySlurpSize) + io.CopyN(io.Discard, resp.Body, maxBodySlurpSize) } resp.Body.Close() diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go index 4bd62735e8..d90b4841c6 100644 --- a/src/net/http/client_test.go +++ b/src/net/http/client_test.go @@ -14,7 +14,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "log" "net" . "net/http" @@ -35,7 +34,7 @@ var robotsTxtHandler = HandlerFunc(func(w ResponseWriter, r *Request) { fmt.Fprintf(w, "User-agent: go\nDisallow: /something/") }) -// pedanticReadAll works like ioutil.ReadAll but additionally +// pedanticReadAll works like io.ReadAll but additionally // verifies that r obeys the documented io.Reader contract. func pedanticReadAll(r io.Reader) (b []byte, err error) { var bufa [64]byte @@ -190,7 +189,7 @@ func TestPostFormRequestFormat(t *testing.T) { if g, e := tr.req.ContentLength, int64(len(expectedBody)); g != e { t.Errorf("got ContentLength %d, want %d", g, e) } - bodyb, err := ioutil.ReadAll(tr.req.Body) + bodyb, err := io.ReadAll(tr.req.Body) if err != nil { t.Fatalf("ReadAll on req.Body: %v", err) } @@ -421,7 +420,7 @@ func testRedirectsByMethod(t *testing.T, method string, table []redirectTest, wa var ts *httptest.Server ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { log.Lock() - slurp, _ := ioutil.ReadAll(r.Body) + slurp, _ := io.ReadAll(r.Body) fmt.Fprintf(&log.Buffer, "%s %s %q", r.Method, r.RequestURI, slurp) if cl := r.Header.Get("Content-Length"); r.Method == "GET" && len(slurp) == 0 && (r.ContentLength != 0 || cl != "") { fmt.Fprintf(&log.Buffer, " (but with body=%T, content-length = %v, %q)", r.Body, r.ContentLength, cl) @@ -452,7 +451,7 @@ func testRedirectsByMethod(t *testing.T, method string, table []redirectTest, wa for _, tt := range table { content := tt.redirectBody req, _ := NewRequest(method, ts.URL+tt.suffix, strings.NewReader(content)) - req.GetBody = func() (io.ReadCloser, error) { return ioutil.NopCloser(strings.NewReader(content)), nil } + req.GetBody = func() (io.ReadCloser, error) { return io.NopCloser(strings.NewReader(content)), nil } res, err := c.Do(req) if err != nil { @@ -522,7 +521,7 @@ func TestClientRedirectUseResponse(t *testing.T) { t.Errorf("status = %d; want %d", res.StatusCode, StatusFound) } defer res.Body.Close() - slurp, err := ioutil.ReadAll(res.Body) + slurp, err := io.ReadAll(res.Body) if err != nil { t.Fatal(err) } @@ -1042,7 +1041,7 @@ func testClientHeadContentLength(t *testing.T, h2 bool) { if res.ContentLength != tt.want { t.Errorf("Content-Length = %d; want %d", res.ContentLength, tt.want) } - bs, err := ioutil.ReadAll(res.Body) + bs, err := io.ReadAll(res.Body) if err != nil { t.Fatal(err) } @@ -1257,7 +1256,7 @@ func testClientTimeout(t *testing.T, h2 bool) { errc := make(chan error, 1) go func() { - _, err := ioutil.ReadAll(res.Body) + _, err := io.ReadAll(res.Body) errc <- err res.Body.Close() }() @@ -1348,7 +1347,7 @@ func TestClientTimeoutCancel(t *testing.T) { t.Fatal(err) } cancel() - _, err = io.Copy(ioutil.Discard, res.Body) + _, err = io.Copy(io.Discard, res.Body) if err != ExportErrRequestCanceled { t.Fatalf("error = %v; want errRequestCanceled", err) } @@ -1372,7 +1371,7 @@ func testClientRedirectEatsBody(t *testing.T, h2 bool) { if err != nil { t.Fatal(err) } - _, err = ioutil.ReadAll(res.Body) + _, err = io.ReadAll(res.Body) res.Body.Close() if err != nil { t.Fatal(err) @@ -1450,7 +1449,7 @@ func (issue15577Tripper) RoundTrip(*Request) (*Response, error) { resp := &Response{ StatusCode: 303, Header: map[string][]string{"Location": {"http://www.example.com/"}}, - Body: ioutil.NopCloser(strings.NewReader("")), + Body: io.NopCloser(strings.NewReader("")), } return resp, nil } @@ -1591,7 +1590,7 @@ func TestClientCopyHostOnRedirect(t *testing.T) { if resp.StatusCode != 200 { t.Fatal(resp.Status) } - if got, err := ioutil.ReadAll(resp.Body); err != nil || string(got) != wantBody { + if got, err := io.ReadAll(resp.Body); err != nil || string(got) != wantBody { t.Errorf("body = %q; want %q", got, wantBody) } } @@ -2020,7 +2019,7 @@ func TestClientPopulatesNilResponseBody(t *testing.T) { } }() - if b, err := ioutil.ReadAll(resp.Body); err != nil { + if b, err := io.ReadAll(resp.Body); err != nil { t.Errorf("read error from substitute Response.Body: %v", err) } else if len(b) != 0 { t.Errorf("substitute Response.Body was unexpectedly non-empty: %q", b) diff --git a/src/net/http/clientserver_test.go b/src/net/http/clientserver_test.go index 439818bb2f..5e227181ac 100644 --- a/src/net/http/clientserver_test.go +++ b/src/net/http/clientserver_test.go @@ -15,7 +15,6 @@ import ( "fmt" "hash" "io" - "io/ioutil" "log" "net" . "net/http" @@ -53,7 +52,7 @@ func (t *clientServerTest) getURL(u string) string { t.t.Fatal(err) } defer res.Body.Close() - slurp, err := ioutil.ReadAll(res.Body) + slurp, err := io.ReadAll(res.Body) if err != nil { t.t.Fatal(err) } @@ -152,7 +151,7 @@ func TestChunkedResponseHeaders_h2(t *testing.T) { testChunkedResponseHeaders(t, func testChunkedResponseHeaders(t *testing.T, h2 bool) { defer afterTest(t) - log.SetOutput(ioutil.Discard) // is noisy otherwise + log.SetOutput(io.Discard) // is noisy otherwise defer log.SetOutput(os.Stderr) cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { w.Header().Set("Content-Length", "intentional gibberish") // we check that this is deleted @@ -266,11 +265,11 @@ func (tt h12Compare) normalizeRes(t *testing.T, res *Response, wantProto string) } else { t.Errorf("got %q response; want %q", res.Proto, wantProto) } - slurp, err := ioutil.ReadAll(res.Body) + slurp, err := io.ReadAll(res.Body) res.Body.Close() res.Body = slurpResult{ - ReadCloser: ioutil.NopCloser(bytes.NewReader(slurp)), + ReadCloser: io.NopCloser(bytes.NewReader(slurp)), body: slurp, err: err, } @@ -477,7 +476,7 @@ func test304Responses(t *testing.T, h2 bool) { if len(res.TransferEncoding) > 0 { t.Errorf("expected no TransferEncoding; got %v", res.TransferEncoding) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { t.Error(err) } @@ -564,7 +563,7 @@ func testCancelRequestMidBody(t *testing.T, h2 bool) { close(cancel) - rest, err := ioutil.ReadAll(res.Body) + rest, err := io.ReadAll(res.Body) all := string(firstRead) + string(rest) if all != "Hello" { t.Errorf("Read %q (%q + %q); want Hello", all, firstRead, rest) @@ -587,7 +586,7 @@ func testTrailersClientToServer(t *testing.T, h2 bool) { } sort.Strings(decl) - slurp, err := ioutil.ReadAll(r.Body) + slurp, err := io.ReadAll(r.Body) if err != nil { t.Errorf("Server reading request body: %v", err) } @@ -721,7 +720,7 @@ func testResponseBodyReadAfterClose(t *testing.T, h2 bool) { t.Fatal(err) } res.Body.Close() - data, err := ioutil.ReadAll(res.Body) + data, err := io.ReadAll(res.Body) if len(data) != 0 || err == nil { t.Fatalf("ReadAll returned %q, %v; want error", data, err) } @@ -740,7 +739,7 @@ func testConcurrentReadWriteReqBody(t *testing.T, h2 bool) { // Read in one goroutine. go func() { defer wg.Done() - data, err := ioutil.ReadAll(r.Body) + data, err := io.ReadAll(r.Body) if string(data) != reqBody { t.Errorf("Handler read %q; want %q", data, reqBody) } @@ -770,7 +769,7 @@ func testConcurrentReadWriteReqBody(t *testing.T, h2 bool) { if err != nil { t.Fatal(err) } - data, err := ioutil.ReadAll(res.Body) + data, err := io.ReadAll(res.Body) defer res.Body.Close() if err != nil { t.Fatal(err) @@ -887,7 +886,7 @@ func testTransportUserAgent(t *testing.T, h2 bool) { t.Errorf("%d. RoundTrip = %v", i, err) continue } - slurp, err := ioutil.ReadAll(res.Body) + slurp, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { t.Errorf("%d. read body = %v", i, err) @@ -1019,7 +1018,7 @@ func TestTransportDiscardsUnneededConns(t *testing.T) { } } defer resp.Body.Close() - slurp, err := ioutil.ReadAll(resp.Body) + slurp, err := io.ReadAll(resp.Body) if err != nil { t.Error(err) } @@ -1064,7 +1063,7 @@ func testTransportGCRequest(t *testing.T, h2, body bool) { setParallel(t) defer afterTest(t) cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { - ioutil.ReadAll(r.Body) + io.ReadAll(r.Body) if body { io.WriteString(w, "Hello.") } @@ -1080,7 +1079,7 @@ func testTransportGCRequest(t *testing.T, h2, body bool) { if err != nil { t.Fatal(err) } - if _, err := ioutil.ReadAll(res.Body); err != nil { + if _, err := io.ReadAll(res.Body); err != nil { t.Fatal(err) } if err := res.Body.Close(); err != nil { @@ -1141,7 +1140,7 @@ func testTransportRejectsInvalidHeaders(t *testing.T, h2 bool) { res, err := cst.c.Do(req) var body []byte if err == nil { - body, _ = ioutil.ReadAll(res.Body) + body, _ = io.ReadAll(res.Body) res.Body.Close() } var dialed bool @@ -1198,7 +1197,7 @@ func testInterruptWithPanic(t *testing.T, h2 bool, panicValue interface{}) { } gotHeaders <- true defer res.Body.Close() - slurp, err := ioutil.ReadAll(res.Body) + slurp, err := io.ReadAll(res.Body) if string(slurp) != msg { t.Errorf("client read %q; want %q", slurp, msg) } @@ -1363,7 +1362,7 @@ func testServerUndeclaredTrailers(t *testing.T, h2 bool) { if err != nil { t.Fatal(err) } - if _, err := io.Copy(ioutil.Discard, res.Body); err != nil { + if _, err := io.Copy(io.Discard, res.Body); err != nil { t.Fatal(err) } res.Body.Close() @@ -1381,7 +1380,7 @@ func testServerUndeclaredTrailers(t *testing.T, h2 bool) { func TestBadResponseAfterReadingBody(t *testing.T) { defer afterTest(t) cst := newClientServerTest(t, false, HandlerFunc(func(w ResponseWriter, r *Request) { - _, err := io.Copy(ioutil.Discard, r.Body) + _, err := io.Copy(io.Discard, r.Body) if err != nil { t.Fatal(err) } @@ -1474,7 +1473,7 @@ func testWriteHeaderAfterWrite(t *testing.T, h2, hijack bool) { t.Fatal(err) } defer res.Body.Close() - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { t.Fatal(err) } diff --git a/src/net/http/doc.go b/src/net/http/doc.go index 7855feaaa9..ae9b708c69 100644 --- a/src/net/http/doc.go +++ b/src/net/http/doc.go @@ -21,7 +21,7 @@ The client must close the response body when finished with it: // handle error } defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) // ... For control over HTTP client headers, redirect policy, and other diff --git a/src/net/http/example_test.go b/src/net/http/example_test.go index a783b46618..c677d52238 100644 --- a/src/net/http/example_test.go +++ b/src/net/http/example_test.go @@ -8,7 +8,6 @@ import ( "context" "fmt" "io" - "io/ioutil" "log" "net/http" "os" @@ -46,7 +45,7 @@ func ExampleGet() { if err != nil { log.Fatal(err) } - robots, err := ioutil.ReadAll(res.Body) + robots, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { log.Fatal(err) diff --git a/src/net/http/fcgi/child.go b/src/net/http/fcgi/child.go index 34761f32ee..e97b8440e1 100644 --- a/src/net/http/fcgi/child.go +++ b/src/net/http/fcgi/child.go @@ -11,7 +11,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "net" "net/http" "net/http/cgi" @@ -186,7 +185,7 @@ func (c *child) serve() { var errCloseConn = errors.New("fcgi: connection should be closed") -var emptyBody = ioutil.NopCloser(strings.NewReader("")) +var emptyBody = io.NopCloser(strings.NewReader("")) // ErrRequestAborted is returned by Read when a handler attempts to read the // body of a request that has been aborted by the web server. @@ -325,7 +324,7 @@ func (c *child) serveRequest(req *request, body io.ReadCloser) { // some sort of abort request to the host, so the host // can properly cut off the client sending all the data. // For now just bound it a little and - io.CopyN(ioutil.Discard, body, 100<<20) + io.CopyN(io.Discard, body, 100<<20) body.Close() if !req.keepConn { diff --git a/src/net/http/fcgi/fcgi_test.go b/src/net/http/fcgi/fcgi_test.go index 4a27a12c35..d3b704f821 100644 --- a/src/net/http/fcgi/fcgi_test.go +++ b/src/net/http/fcgi/fcgi_test.go @@ -8,7 +8,6 @@ import ( "bytes" "errors" "io" - "io/ioutil" "net/http" "strings" "testing" @@ -243,7 +242,7 @@ func TestChildServeCleansUp(t *testing.T) { r *http.Request, ) { // block on reading body of request - _, err := io.Copy(ioutil.Discard, r.Body) + _, err := io.Copy(io.Discard, r.Body) if err != tt.err { t.Errorf("Expected %#v, got %#v", tt.err, err) } @@ -275,7 +274,7 @@ func TestMalformedParams(t *testing.T) { // end of params 1, 4, 0, 1, 0, 0, 0, 0, } - rw := rwNopCloser{bytes.NewReader(input), ioutil.Discard} + rw := rwNopCloser{bytes.NewReader(input), io.Discard} c := newChild(rw, http.DefaultServeMux) c.serve() } diff --git a/src/net/http/filetransport_test.go b/src/net/http/filetransport_test.go index 2a2f32c769..fdfd44d967 100644 --- a/src/net/http/filetransport_test.go +++ b/src/net/http/filetransport_test.go @@ -5,6 +5,7 @@ package http import ( + "io" "io/ioutil" "os" "path/filepath" @@ -48,7 +49,7 @@ func TestFileTransport(t *testing.T) { if res.Body == nil { t.Fatalf("for %s, nil Body", urlstr) } - slurp, err := ioutil.ReadAll(res.Body) + slurp, err := io.ReadAll(res.Body) res.Body.Close() check("ReadAll "+urlstr, err) if string(slurp) != "Bar" { diff --git a/src/net/http/fs_test.go b/src/net/http/fs_test.go index c9f324cff6..2e4751114d 100644 --- a/src/net/http/fs_test.go +++ b/src/net/http/fs_test.go @@ -160,7 +160,7 @@ Cases: if g, w := part.Header.Get("Content-Range"), wantContentRange; g != w { t.Errorf("range=%q: part Content-Range = %q; want %q", rt.r, g, w) } - body, err := ioutil.ReadAll(part) + body, err := io.ReadAll(part) if err != nil { t.Errorf("range=%q, reading part index %d body: %v", rt.r, ri, err) continue Cases @@ -312,7 +312,7 @@ func TestFileServerEscapesNames(t *testing.T) { if err != nil { t.Fatalf("test %q: Get: %v", test.name, err) } - b, err := ioutil.ReadAll(res.Body) + b, err := io.ReadAll(res.Body) if err != nil { t.Fatalf("test %q: read Body: %v", test.name, err) } @@ -360,7 +360,7 @@ func TestFileServerSortsNames(t *testing.T) { } defer res.Body.Close() - b, err := ioutil.ReadAll(res.Body) + b, err := io.ReadAll(res.Body) if err != nil { t.Fatalf("read Body: %v", err) } @@ -394,7 +394,7 @@ func TestFileServerImplicitLeadingSlash(t *testing.T) { if err != nil { t.Fatalf("Get %s: %v", suffix, err) } - b, err := ioutil.ReadAll(res.Body) + b, err := io.ReadAll(res.Body) if err != nil { t.Fatalf("ReadAll %s: %v", suffix, err) } @@ -617,7 +617,7 @@ func TestServeIndexHtmlFS(t *testing.T) { if err != nil { t.Fatal(err) } - b, err := ioutil.ReadAll(res.Body) + b, err := io.ReadAll(res.Body) if err != nil { t.Fatal("reading Body:", err) } @@ -745,7 +745,7 @@ func TestDirectoryIfNotModified(t *testing.T) { if err != nil { t.Fatal(err) } - b, err := ioutil.ReadAll(res.Body) + b, err := io.ReadAll(res.Body) if err != nil { t.Fatal(err) } @@ -1082,7 +1082,7 @@ func TestServeContent(t *testing.T) { if err != nil { t.Fatal(err) } - io.Copy(ioutil.Discard, res.Body) + io.Copy(io.Discard, res.Body) res.Body.Close() if res.StatusCode != tt.wantStatus { t.Errorf("test %q using %q: got status = %d; want %d", testName, method, res.StatusCode, tt.wantStatus) @@ -1196,7 +1196,7 @@ func TestLinuxSendfile(t *testing.T) { if err != nil { t.Fatalf("http client error: %v", err) } - _, err = io.Copy(ioutil.Discard, res.Body) + _, err = io.Copy(io.Discard, res.Body) if err != nil { t.Fatalf("client body read error: %v", err) } @@ -1218,7 +1218,7 @@ func getBody(t *testing.T, testName string, req Request, client *Client) (*Respo if err != nil { t.Fatalf("%s: for URL %q, send error: %v", testName, req.URL.String(), err) } - b, err := ioutil.ReadAll(r.Body) + b, err := io.ReadAll(r.Body) if err != nil { t.Fatalf("%s: for URL %q, reading body: %v", testName, req.URL.String(), err) } @@ -1401,7 +1401,7 @@ func testServeFileRejectsInvalidSuffixLengths(t *testing.T, h2 bool) { if g, w := res.StatusCode, tt.wantCode; g != w { t.Errorf("StatusCode mismatch: got %d want %d", g, w) } - slurp, err := ioutil.ReadAll(res.Body) + slurp, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { t.Fatal(err) diff --git a/src/net/http/httptest/example_test.go b/src/net/http/httptest/example_test.go index 54e77dbb84..a6738432eb 100644 --- a/src/net/http/httptest/example_test.go +++ b/src/net/http/httptest/example_test.go @@ -7,7 +7,6 @@ package httptest_test import ( "fmt" "io" - "io/ioutil" "log" "net/http" "net/http/httptest" @@ -23,7 +22,7 @@ func ExampleResponseRecorder() { handler(w, req) resp := w.Result() - body, _ := ioutil.ReadAll(resp.Body) + body, _ := io.ReadAll(resp.Body) fmt.Println(resp.StatusCode) fmt.Println(resp.Header.Get("Content-Type")) @@ -45,7 +44,7 @@ func ExampleServer() { if err != nil { log.Fatal(err) } - greeting, err := ioutil.ReadAll(res.Body) + greeting, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { log.Fatal(err) @@ -67,7 +66,7 @@ func ExampleServer_hTTP2() { if err != nil { log.Fatal(err) } - greeting, err := ioutil.ReadAll(res.Body) + greeting, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { log.Fatal(err) @@ -89,7 +88,7 @@ func ExampleNewTLSServer() { log.Fatal(err) } - greeting, err := ioutil.ReadAll(res.Body) + greeting, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { log.Fatal(err) diff --git a/src/net/http/httptest/httptest.go b/src/net/http/httptest/httptest.go index f7202da92f..9bedefd2bc 100644 --- a/src/net/http/httptest/httptest.go +++ b/src/net/http/httptest/httptest.go @@ -10,7 +10,6 @@ import ( "bytes" "crypto/tls" "io" - "io/ioutil" "net/http" "strings" ) @@ -66,7 +65,7 @@ func NewRequest(method, target string, body io.Reader) *http.Request { if rc, ok := body.(io.ReadCloser); ok { req.Body = rc } else { - req.Body = ioutil.NopCloser(body) + req.Body = io.NopCloser(body) } } diff --git a/src/net/http/httptest/httptest_test.go b/src/net/http/httptest/httptest_test.go index ef7d943837..071add67ea 100644 --- a/src/net/http/httptest/httptest_test.go +++ b/src/net/http/httptest/httptest_test.go @@ -7,7 +7,6 @@ package httptest import ( "crypto/tls" "io" - "io/ioutil" "net/http" "net/url" "reflect" @@ -155,7 +154,7 @@ func TestNewRequest(t *testing.T) { } { t.Run(tt.name, func(t *testing.T) { got := NewRequest(tt.method, tt.uri, tt.body) - slurp, err := ioutil.ReadAll(got.Body) + slurp, err := io.ReadAll(got.Body) if err != nil { t.Errorf("ReadAll: %v", err) } diff --git a/src/net/http/httptest/recorder.go b/src/net/http/httptest/recorder.go index 66e67e78b3..2428482612 100644 --- a/src/net/http/httptest/recorder.go +++ b/src/net/http/httptest/recorder.go @@ -7,7 +7,7 @@ package httptest import ( "bytes" "fmt" - "io/ioutil" + "io" "net/http" "net/textproto" "strconv" @@ -179,7 +179,7 @@ func (rw *ResponseRecorder) Result() *http.Response { } res.Status = fmt.Sprintf("%03d %s", res.StatusCode, http.StatusText(res.StatusCode)) if rw.Body != nil { - res.Body = ioutil.NopCloser(bytes.NewReader(rw.Body.Bytes())) + res.Body = io.NopCloser(bytes.NewReader(rw.Body.Bytes())) } else { res.Body = http.NoBody } diff --git a/src/net/http/httptest/recorder_test.go b/src/net/http/httptest/recorder_test.go index e9534894b6..a865e878b9 100644 --- a/src/net/http/httptest/recorder_test.go +++ b/src/net/http/httptest/recorder_test.go @@ -7,7 +7,6 @@ package httptest import ( "fmt" "io" - "io/ioutil" "net/http" "testing" ) @@ -42,7 +41,7 @@ func TestRecorder(t *testing.T) { } hasResultContents := func(want string) checkFunc { return func(rec *ResponseRecorder) error { - contentBytes, err := ioutil.ReadAll(rec.Result().Body) + contentBytes, err := io.ReadAll(rec.Result().Body) if err != nil { return err } diff --git a/src/net/http/httptest/server_test.go b/src/net/http/httptest/server_test.go index 0aad15c5ed..39568b358c 100644 --- a/src/net/http/httptest/server_test.go +++ b/src/net/http/httptest/server_test.go @@ -6,7 +6,7 @@ package httptest import ( "bufio" - "io/ioutil" + "io" "net" "net/http" "testing" @@ -61,7 +61,7 @@ func testServer(t *testing.T, newServer newServerFunc) { if err != nil { t.Fatal(err) } - got, err := ioutil.ReadAll(res.Body) + got, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { t.Fatal(err) @@ -81,7 +81,7 @@ func testGetAfterClose(t *testing.T, newServer newServerFunc) { if err != nil { t.Fatal(err) } - got, err := ioutil.ReadAll(res.Body) + got, err := io.ReadAll(res.Body) if err != nil { t.Fatal(err) } @@ -93,7 +93,7 @@ func testGetAfterClose(t *testing.T, newServer newServerFunc) { res, err = http.Get(ts.URL) if err == nil { - body, _ := ioutil.ReadAll(res.Body) + body, _ := io.ReadAll(res.Body) t.Fatalf("Unexpected response after close: %v, %v, %s", res.Status, res.Header, body) } } @@ -152,7 +152,7 @@ func testServerClient(t *testing.T, newTLSServer newServerFunc) { if err != nil { t.Fatal(err) } - got, err := ioutil.ReadAll(res.Body) + got, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { t.Fatal(err) diff --git a/src/net/http/httputil/dump.go b/src/net/http/httputil/dump.go index c97be066d7..4c9d28bed8 100644 --- a/src/net/http/httputil/dump.go +++ b/src/net/http/httputil/dump.go @@ -10,7 +10,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "net" "net/http" "net/url" @@ -35,7 +34,7 @@ func drainBody(b io.ReadCloser) (r1, r2 io.ReadCloser, err error) { if err = b.Close(); err != nil { return nil, b, err } - return ioutil.NopCloser(&buf), ioutil.NopCloser(bytes.NewReader(buf.Bytes())), nil + return io.NopCloser(&buf), io.NopCloser(bytes.NewReader(buf.Bytes())), nil } // dumpConn is a net.Conn which writes to Writer and reads from Reader @@ -81,7 +80,7 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) { if !body { contentLength := outgoingLength(req) if contentLength != 0 { - req.Body = ioutil.NopCloser(io.LimitReader(neverEnding('x'), contentLength)) + req.Body = io.NopCloser(io.LimitReader(neverEnding('x'), contentLength)) dummyBody = true } } else { @@ -133,7 +132,7 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) { if err == nil { // Ensure all the body is read; otherwise // we'll get a partial dump. - io.Copy(ioutil.Discard, req.Body) + io.Copy(io.Discard, req.Body) req.Body.Close() } select { @@ -296,7 +295,7 @@ func (failureToReadBody) Read([]byte) (int, error) { return 0, errNoBody } func (failureToReadBody) Close() error { return nil } // emptyBody is an instance of empty reader. -var emptyBody = ioutil.NopCloser(strings.NewReader("")) +var emptyBody = io.NopCloser(strings.NewReader("")) // DumpResponse is like DumpRequest but dumps a response. func DumpResponse(resp *http.Response, body bool) ([]byte, error) { diff --git a/src/net/http/httputil/dump_test.go b/src/net/http/httputil/dump_test.go index ead56bc172..7571eb0820 100644 --- a/src/net/http/httputil/dump_test.go +++ b/src/net/http/httputil/dump_test.go @@ -9,7 +9,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "net/http" "net/url" "runtime" @@ -268,7 +267,7 @@ func TestDumpRequest(t *testing.T) { } switch b := ti.Body.(type) { case []byte: - req.Body = ioutil.NopCloser(bytes.NewReader(b)) + req.Body = io.NopCloser(bytes.NewReader(b)) case func() io.ReadCloser: req.Body = b() default: @@ -363,7 +362,7 @@ var dumpResTests = []struct { Header: http.Header{ "Foo": []string{"Bar"}, }, - Body: ioutil.NopCloser(strings.NewReader("foo")), // shouldn't be used + Body: io.NopCloser(strings.NewReader("foo")), // shouldn't be used }, body: false, // to verify we see 50, not empty or 3. want: `HTTP/1.1 200 OK @@ -379,7 +378,7 @@ Foo: Bar`, ProtoMajor: 1, ProtoMinor: 1, ContentLength: 3, - Body: ioutil.NopCloser(strings.NewReader("foo")), + Body: io.NopCloser(strings.NewReader("foo")), }, body: true, want: `HTTP/1.1 200 OK @@ -396,7 +395,7 @@ foo`, ProtoMajor: 1, ProtoMinor: 1, ContentLength: -1, - Body: ioutil.NopCloser(strings.NewReader("foo")), + Body: io.NopCloser(strings.NewReader("foo")), TransferEncoding: []string{"chunked"}, }, body: true, diff --git a/src/net/http/httputil/example_test.go b/src/net/http/httputil/example_test.go index 6191603674..b77a243ca3 100644 --- a/src/net/http/httputil/example_test.go +++ b/src/net/http/httputil/example_test.go @@ -6,7 +6,7 @@ package httputil_test import ( "fmt" - "io/ioutil" + "io" "log" "net/http" "net/http/httptest" @@ -39,7 +39,7 @@ func ExampleDumpRequest() { } defer resp.Body.Close() - b, err := ioutil.ReadAll(resp.Body) + b, err := io.ReadAll(resp.Body) if err != nil { log.Fatal(err) } @@ -111,7 +111,7 @@ func ExampleReverseProxy() { log.Fatal(err) } - b, err := ioutil.ReadAll(resp.Body) + b, err := io.ReadAll(resp.Body) if err != nil { log.Fatal(err) } diff --git a/src/net/http/httputil/reverseproxy_test.go b/src/net/http/httputil/reverseproxy_test.go index cc05d55d87..3acbd940e4 100644 --- a/src/net/http/httputil/reverseproxy_test.go +++ b/src/net/http/httputil/reverseproxy_test.go @@ -13,7 +13,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "log" "net/http" "net/http/httptest" @@ -84,7 +83,7 @@ func TestReverseProxy(t *testing.T) { t.Fatal(err) } proxyHandler := NewSingleHostReverseProxy(backendURL) - proxyHandler.ErrorLog = log.New(ioutil.Discard, "", 0) // quiet for tests + proxyHandler.ErrorLog = log.New(io.Discard, "", 0) // quiet for tests frontend := httptest.NewServer(proxyHandler) defer frontend.Close() frontendClient := frontend.Client() @@ -124,7 +123,7 @@ func TestReverseProxy(t *testing.T) { if cookie := res.Cookies()[0]; cookie.Name != "flavor" { t.Errorf("unexpected cookie %q", cookie.Name) } - bodyBytes, _ := ioutil.ReadAll(res.Body) + bodyBytes, _ := io.ReadAll(res.Body) if g, e := string(bodyBytes), backendResponse; g != e { t.Errorf("got body %q; expected %q", g, e) } @@ -218,7 +217,7 @@ func TestReverseProxyStripHeadersPresentInConnection(t *testing.T) { t.Fatalf("Get: %v", err) } defer res.Body.Close() - bodyBytes, err := ioutil.ReadAll(res.Body) + bodyBytes, err := io.ReadAll(res.Body) if err != nil { t.Fatalf("reading body: %v", err) } @@ -271,7 +270,7 @@ func TestXForwardedFor(t *testing.T) { if g, e := res.StatusCode, backendStatus; g != e { t.Errorf("got res.StatusCode %d; expected %d", g, e) } - bodyBytes, _ := ioutil.ReadAll(res.Body) + bodyBytes, _ := io.ReadAll(res.Body) if g, e := string(bodyBytes), backendResponse; g != e { t.Errorf("got body %q; expected %q", g, e) } @@ -373,7 +372,7 @@ func TestReverseProxyFlushInterval(t *testing.T) { t.Fatalf("Get: %v", err) } defer res.Body.Close() - if bodyBytes, _ := ioutil.ReadAll(res.Body); string(bodyBytes) != expected { + if bodyBytes, _ := io.ReadAll(res.Body); string(bodyBytes) != expected { t.Errorf("got body %q; expected %q", bodyBytes, expected) } } @@ -441,7 +440,7 @@ func TestReverseProxyCancellation(t *testing.T) { defer backend.Close() - backend.Config.ErrorLog = log.New(ioutil.Discard, "", 0) + backend.Config.ErrorLog = log.New(io.Discard, "", 0) backendURL, err := url.Parse(backend.URL) if err != nil { @@ -452,7 +451,7 @@ func TestReverseProxyCancellation(t *testing.T) { // Discards errors of the form: // http: proxy error: read tcp 127.0.0.1:44643: use of closed network connection - proxyHandler.ErrorLog = log.New(ioutil.Discard, "", 0) + proxyHandler.ErrorLog = log.New(io.Discard, "", 0) frontend := httptest.NewServer(proxyHandler) defer frontend.Close() @@ -504,7 +503,7 @@ func TestNilBody(t *testing.T) { t.Fatal(err) } defer res.Body.Close() - slurp, err := ioutil.ReadAll(res.Body) + slurp, err := io.ReadAll(res.Body) if err != nil { t.Fatal(err) } @@ -533,7 +532,7 @@ func TestUserAgentHeader(t *testing.T) { t.Fatal(err) } proxyHandler := NewSingleHostReverseProxy(backendURL) - proxyHandler.ErrorLog = log.New(ioutil.Discard, "", 0) // quiet for tests + proxyHandler.ErrorLog = log.New(io.Discard, "", 0) // quiet for tests frontend := httptest.NewServer(proxyHandler) defer frontend.Close() frontendClient := frontend.Client() @@ -606,7 +605,7 @@ func TestReverseProxyGetPutBuffer(t *testing.T) { if err != nil { t.Fatalf("Get: %v", err) } - slurp, err := ioutil.ReadAll(res.Body) + slurp, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { t.Fatalf("reading body: %v", err) @@ -627,7 +626,7 @@ func TestReverseProxy_Post(t *testing.T) { const backendStatus = 200 var requestBody = bytes.Repeat([]byte("a"), 1<<20) backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - slurp, err := ioutil.ReadAll(r.Body) + slurp, err := io.ReadAll(r.Body) if err != nil { t.Errorf("Backend body read = %v", err) } @@ -656,7 +655,7 @@ func TestReverseProxy_Post(t *testing.T) { if g, e := res.StatusCode, backendStatus; g != e { t.Errorf("got res.StatusCode %d; expected %d", g, e) } - bodyBytes, _ := ioutil.ReadAll(res.Body) + bodyBytes, _ := io.ReadAll(res.Body) if g, e := string(bodyBytes), backendResponse; g != e { t.Errorf("got body %q; expected %q", g, e) } @@ -672,7 +671,7 @@ func (fn RoundTripperFunc) RoundTrip(req *http.Request) (*http.Response, error) func TestReverseProxy_NilBody(t *testing.T) { backendURL, _ := url.Parse("http://fake.tld/") proxyHandler := NewSingleHostReverseProxy(backendURL) - proxyHandler.ErrorLog = log.New(ioutil.Discard, "", 0) // quiet for tests + proxyHandler.ErrorLog = log.New(io.Discard, "", 0) // quiet for tests proxyHandler.Transport = RoundTripperFunc(func(req *http.Request) (*http.Response, error) { if req.Body != nil { t.Error("Body != nil; want a nil Body") @@ -695,8 +694,8 @@ func TestReverseProxy_NilBody(t *testing.T) { // Issue 33142: always allocate the request headers func TestReverseProxy_AllocatedHeader(t *testing.T) { proxyHandler := new(ReverseProxy) - proxyHandler.ErrorLog = log.New(ioutil.Discard, "", 0) // quiet for tests - proxyHandler.Director = func(*http.Request) {} // noop + proxyHandler.ErrorLog = log.New(io.Discard, "", 0) // quiet for tests + proxyHandler.Director = func(*http.Request) {} // noop proxyHandler.Transport = RoundTripperFunc(func(req *http.Request) (*http.Response, error) { if req.Header == nil { t.Error("Header == nil; want a non-nil Header") @@ -722,7 +721,7 @@ func TestReverseProxyModifyResponse(t *testing.T) { rpURL, _ := url.Parse(backendServer.URL) rproxy := NewSingleHostReverseProxy(rpURL) - rproxy.ErrorLog = log.New(ioutil.Discard, "", 0) // quiet for tests + rproxy.ErrorLog = log.New(io.Discard, "", 0) // quiet for tests rproxy.ModifyResponse = func(resp *http.Response) error { if resp.Header.Get("X-Hit-Mod") != "true" { return fmt.Errorf("tried to by-pass proxy") @@ -821,7 +820,7 @@ func TestReverseProxyErrorHandler(t *testing.T) { if rproxy.Transport == nil { rproxy.Transport = failingRoundTripper{} } - rproxy.ErrorLog = log.New(ioutil.Discard, "", 0) // quiet for tests + rproxy.ErrorLog = log.New(io.Discard, "", 0) // quiet for tests if tt.errorHandler != nil { rproxy.ErrorHandler = tt.errorHandler } @@ -896,7 +895,7 @@ func (t *staticTransport) RoundTrip(r *http.Request) (*http.Response, error) { func BenchmarkServeHTTP(b *testing.B) { res := &http.Response{ StatusCode: 200, - Body: ioutil.NopCloser(strings.NewReader("")), + Body: io.NopCloser(strings.NewReader("")), } proxy := &ReverseProxy{ Director: func(*http.Request) {}, @@ -953,7 +952,7 @@ func TestServeHTTPDeepCopy(t *testing.T) { // Issue 18327: verify we always do a deep copy of the Request.Header map // before any mutations. func TestClonesRequestHeaders(t *testing.T) { - log.SetOutput(ioutil.Discard) + log.SetOutput(io.Discard) defer log.SetOutput(os.Stderr) req, _ := http.NewRequest("GET", "http://foo.tld/", nil) req.RemoteAddr = "1.2.3.4:56789" @@ -1031,7 +1030,7 @@ func (cc *checkCloser) Read(b []byte) (int, error) { // Issue 23643: panic on body copy error func TestReverseProxy_PanicBodyError(t *testing.T) { - log.SetOutput(ioutil.Discard) + log.SetOutput(io.Discard) defer log.SetOutput(os.Stderr) backendServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { out := "this call was relayed by the reverse proxy" @@ -1148,7 +1147,7 @@ func TestReverseProxyWebSocket(t *testing.T) { backURL, _ := url.Parse(backendServer.URL) rproxy := NewSingleHostReverseProxy(backURL) - rproxy.ErrorLog = log.New(ioutil.Discard, "", 0) // quiet for tests + rproxy.ErrorLog = log.New(io.Discard, "", 0) // quiet for tests rproxy.ModifyResponse = func(res *http.Response) error { res.Header.Add("X-Modified", "true") return nil @@ -1265,7 +1264,7 @@ func TestReverseProxyWebSocketCancelation(t *testing.T) { backendURL, _ := url.Parse(cst.URL) rproxy := NewSingleHostReverseProxy(backendURL) - rproxy.ErrorLog = log.New(ioutil.Discard, "", 0) // quiet for tests + rproxy.ErrorLog = log.New(io.Discard, "", 0) // quiet for tests rproxy.ModifyResponse = func(res *http.Response) error { res.Header.Add("X-Modified", "true") return nil @@ -1352,7 +1351,7 @@ func TestUnannouncedTrailer(t *testing.T) { t.Fatal(err) } proxyHandler := NewSingleHostReverseProxy(backendURL) - proxyHandler.ErrorLog = log.New(ioutil.Discard, "", 0) // quiet for tests + proxyHandler.ErrorLog = log.New(io.Discard, "", 0) // quiet for tests frontend := httptest.NewServer(proxyHandler) defer frontend.Close() frontendClient := frontend.Client() @@ -1362,7 +1361,7 @@ func TestUnannouncedTrailer(t *testing.T) { t.Fatalf("Get: %v", err) } - ioutil.ReadAll(res.Body) + io.ReadAll(res.Body) if g, w := res.Trailer.Get("X-Unannounced-Trailer"), "unannounced_trailer_value"; g != w { t.Errorf("Trailer(X-Unannounced-Trailer) = %q; want %q", g, w) diff --git a/src/net/http/internal/chunked_test.go b/src/net/http/internal/chunked_test.go index d06716591a..08152ed1e2 100644 --- a/src/net/http/internal/chunked_test.go +++ b/src/net/http/internal/chunked_test.go @@ -9,7 +9,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "strings" "testing" ) @@ -29,7 +28,7 @@ func TestChunk(t *testing.T) { } r := NewChunkedReader(&b) - data, err := ioutil.ReadAll(r) + data, err := io.ReadAll(r) if err != nil { t.Logf(`data: "%s"`, data) t.Fatalf("ReadAll from reader: %v", err) @@ -177,7 +176,7 @@ func TestChunkReadingIgnoresExtensions(t *testing.T) { "17;someext\r\n" + // token without value "world! 0123456789abcdef\r\n" + "0;someextension=sometoken\r\n" // token=token - data, err := ioutil.ReadAll(NewChunkedReader(strings.NewReader(in))) + data, err := io.ReadAll(NewChunkedReader(strings.NewReader(in))) if err != nil { t.Fatalf("ReadAll = %q, %v", data, err) } diff --git a/src/net/http/main_test.go b/src/net/http/main_test.go index 35cc80977c..6564627998 100644 --- a/src/net/http/main_test.go +++ b/src/net/http/main_test.go @@ -6,7 +6,7 @@ package http_test import ( "fmt" - "io/ioutil" + "io" "log" "net/http" "os" @@ -17,7 +17,7 @@ import ( "time" ) -var quietLog = log.New(ioutil.Discard, "", 0) +var quietLog = log.New(io.Discard, "", 0) func TestMain(m *testing.M) { v := m.Run() diff --git a/src/net/http/pprof/pprof_test.go b/src/net/http/pprof/pprof_test.go index f6f9ef5b04..84757e401a 100644 --- a/src/net/http/pprof/pprof_test.go +++ b/src/net/http/pprof/pprof_test.go @@ -8,7 +8,7 @@ import ( "bytes" "fmt" "internal/profile" - "io/ioutil" + "io" "net/http" "net/http/httptest" "runtime" @@ -63,7 +63,7 @@ func TestHandlers(t *testing.T) { t.Errorf("status code: got %d; want %d", got, want) } - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { t.Errorf("when reading response body, expected non-nil err; got %v", err) } @@ -227,7 +227,7 @@ func query(endpoint string) (*profile.Profile, error) { return nil, fmt.Errorf("failed to fetch %q: %v", url, r.Status) } - b, err := ioutil.ReadAll(r.Body) + b, err := io.ReadAll(r.Body) r.Body.Close() if err != nil { return nil, fmt.Errorf("failed to read and parse the result from %q: %v", url, err) diff --git a/src/net/http/readrequest_test.go b/src/net/http/readrequest_test.go index b227bb6d38..1950f4907a 100644 --- a/src/net/http/readrequest_test.go +++ b/src/net/http/readrequest_test.go @@ -9,7 +9,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "net/url" "reflect" "strings" @@ -468,7 +467,7 @@ func TestReadRequest_Bad(t *testing.T) { for _, tt := range badRequestTests { got, err := ReadRequest(bufio.NewReader(bytes.NewReader(tt.req))) if err == nil { - all, err := ioutil.ReadAll(got.Body) + all, err := io.ReadAll(got.Body) t.Errorf("%s: got unexpected request = %#v\n Body = %q, %v", tt.name, got, all, err) } } diff --git a/src/net/http/request.go b/src/net/http/request.go index df73d5f62d..adba5406e9 100644 --- a/src/net/http/request.go +++ b/src/net/http/request.go @@ -15,7 +15,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "mime" "mime/multipart" "net" @@ -870,7 +869,7 @@ func NewRequestWithContext(ctx context.Context, method, url string, body io.Read } rc, ok := body.(io.ReadCloser) if !ok && body != nil { - rc = ioutil.NopCloser(body) + rc = io.NopCloser(body) } // The host's colon:port should be normalized. See Issue 14836. u.Host = removeEmptyPort(u.Host) @@ -892,21 +891,21 @@ func NewRequestWithContext(ctx context.Context, method, url string, body io.Read buf := v.Bytes() req.GetBody = func() (io.ReadCloser, error) { r := bytes.NewReader(buf) - return ioutil.NopCloser(r), nil + return io.NopCloser(r), nil } case *bytes.Reader: req.ContentLength = int64(v.Len()) snapshot := *v req.GetBody = func() (io.ReadCloser, error) { r := snapshot - return ioutil.NopCloser(&r), nil + return io.NopCloser(&r), nil } case *strings.Reader: req.ContentLength = int64(v.Len()) snapshot := *v req.GetBody = func() (io.ReadCloser, error) { r := snapshot - return ioutil.NopCloser(&r), nil + return io.NopCloser(&r), nil } default: // This is where we'd set it to -1 (at least @@ -1205,7 +1204,7 @@ func parsePostForm(r *Request) (vs url.Values, err error) { maxFormSize = int64(10 << 20) // 10 MB is a lot of text. reader = io.LimitReader(r.Body, maxFormSize+1) } - b, e := ioutil.ReadAll(reader) + b, e := io.ReadAll(reader) if e != nil { if err == nil { err = e diff --git a/src/net/http/request_test.go b/src/net/http/request_test.go index 461d66e05d..b4ef472e71 100644 --- a/src/net/http/request_test.go +++ b/src/net/http/request_test.go @@ -103,7 +103,7 @@ func TestParseFormUnknownContentType(t *testing.T) { req := &Request{ Method: "POST", Header: test.contentType, - Body: ioutil.NopCloser(strings.NewReader("body")), + Body: io.NopCloser(strings.NewReader("body")), } err := req.ParseForm() switch { @@ -150,7 +150,7 @@ func TestMultipartReader(t *testing.T) { req := &Request{ Method: "POST", Header: Header{"Content-Type": {test.contentType}}, - Body: ioutil.NopCloser(new(bytes.Buffer)), + Body: io.NopCloser(new(bytes.Buffer)), } multipart, err := req.MultipartReader() if test.shouldError { @@ -187,7 +187,7 @@ binary data req := &Request{ Method: "POST", Header: Header{"Content-Type": {`multipart/form-data; boundary=xxx`}}, - Body: ioutil.NopCloser(strings.NewReader(postData)), + Body: io.NopCloser(strings.NewReader(postData)), } initialFormItems := map[string]string{ @@ -231,7 +231,7 @@ func TestParseMultipartForm(t *testing.T) { req := &Request{ Method: "POST", Header: Header{"Content-Type": {`multipart/form-data; boundary="foo123"`}}, - Body: ioutil.NopCloser(new(bytes.Buffer)), + Body: io.NopCloser(new(bytes.Buffer)), } err := req.ParseMultipartForm(25) if err == nil { @@ -756,10 +756,10 @@ func (dr delayedEOFReader) Read(p []byte) (n int, err error) { } func TestIssue10884_MaxBytesEOF(t *testing.T) { - dst := ioutil.Discard + dst := io.Discard _, err := io.Copy(dst, MaxBytesReader( responseWriterJustWriter{dst}, - ioutil.NopCloser(delayedEOFReader{strings.NewReader("12345")}), + io.NopCloser(delayedEOFReader{strings.NewReader("12345")}), 5)) if err != nil { t.Fatal(err) @@ -799,7 +799,7 @@ func TestMaxBytesReaderStickyError(t *testing.T) { 2: {101, 100}, } for i, tt := range tests { - rc := MaxBytesReader(nil, ioutil.NopCloser(bytes.NewReader(make([]byte, tt.readable))), tt.limit) + rc := MaxBytesReader(nil, io.NopCloser(bytes.NewReader(make([]byte, tt.readable))), tt.limit) if err := isSticky(rc); err != nil { t.Errorf("%d. error: %v", i, err) } @@ -900,7 +900,7 @@ func TestNewRequestGetBody(t *testing.T) { t.Errorf("test[%d]: GetBody = nil", i) continue } - slurp1, err := ioutil.ReadAll(req.Body) + slurp1, err := io.ReadAll(req.Body) if err != nil { t.Errorf("test[%d]: ReadAll(Body) = %v", i, err) } @@ -908,7 +908,7 @@ func TestNewRequestGetBody(t *testing.T) { if err != nil { t.Errorf("test[%d]: GetBody = %v", i, err) } - slurp2, err := ioutil.ReadAll(newBody) + slurp2, err := io.ReadAll(newBody) if err != nil { t.Errorf("test[%d]: ReadAll(GetBody()) = %v", i, err) } @@ -1145,7 +1145,7 @@ func benchmarkFileAndServer(b *testing.B, n int64) { func runFileAndServerBenchmarks(b *testing.B, tlsOption bool, f *os.File, n int64) { handler := HandlerFunc(func(rw ResponseWriter, req *Request) { defer req.Body.Close() - nc, err := io.Copy(ioutil.Discard, req.Body) + nc, err := io.Copy(io.Discard, req.Body) if err != nil { panic(err) } @@ -1172,7 +1172,7 @@ func runFileAndServerBenchmarks(b *testing.B, tlsOption bool, f *os.File, n int6 } b.StartTimer() - req, err := NewRequest("PUT", cst.URL, ioutil.NopCloser(f)) + req, err := NewRequest("PUT", cst.URL, io.NopCloser(f)) if err != nil { b.Fatal(err) } diff --git a/src/net/http/requestwrite_test.go b/src/net/http/requestwrite_test.go index 9ac6701cfd..1157bdfff9 100644 --- a/src/net/http/requestwrite_test.go +++ b/src/net/http/requestwrite_test.go @@ -10,7 +10,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "net" "net/url" "strings" @@ -229,7 +228,7 @@ var reqWriteTests = []reqWriteTest{ ContentLength: 0, // as if unset by user }, - Body: func() io.ReadCloser { return ioutil.NopCloser(io.LimitReader(strings.NewReader("xx"), 0)) }, + Body: func() io.ReadCloser { return io.NopCloser(io.LimitReader(strings.NewReader("xx"), 0)) }, WantWrite: "POST / HTTP/1.1\r\n" + "Host: example.com\r\n" + @@ -281,7 +280,7 @@ var reqWriteTests = []reqWriteTest{ ContentLength: 0, // as if unset by user }, - Body: func() io.ReadCloser { return ioutil.NopCloser(io.LimitReader(strings.NewReader("xx"), 1)) }, + Body: func() io.ReadCloser { return io.NopCloser(io.LimitReader(strings.NewReader("xx"), 1)) }, WantWrite: "POST / HTTP/1.1\r\n" + "Host: example.com\r\n" + @@ -351,7 +350,7 @@ var reqWriteTests = []reqWriteTest{ Body: func() io.ReadCloser { err := errors.New("Custom reader error") errReader := iotest.ErrReader(err) - return ioutil.NopCloser(io.MultiReader(strings.NewReader("x"), errReader)) + return io.NopCloser(io.MultiReader(strings.NewReader("x"), errReader)) }, WantError: errors.New("Custom reader error"), @@ -371,7 +370,7 @@ var reqWriteTests = []reqWriteTest{ Body: func() io.ReadCloser { err := errors.New("Custom reader error") errReader := iotest.ErrReader(err) - return ioutil.NopCloser(errReader) + return io.NopCloser(errReader) }, WantError: errors.New("Custom reader error"), @@ -620,7 +619,7 @@ func TestRequestWrite(t *testing.T) { } switch b := tt.Body.(type) { case []byte: - tt.Req.Body = ioutil.NopCloser(bytes.NewReader(b)) + tt.Req.Body = io.NopCloser(bytes.NewReader(b)) case func() io.ReadCloser: tt.Req.Body = b() } @@ -716,20 +715,20 @@ func TestRequestWriteTransport(t *testing.T) { }, { method: "GET", - body: ioutil.NopCloser(strings.NewReader("")), + body: io.NopCloser(strings.NewReader("")), want: noContentLengthOrTransferEncoding, }, { method: "GET", clen: -1, - body: ioutil.NopCloser(strings.NewReader("")), + body: io.NopCloser(strings.NewReader("")), want: noContentLengthOrTransferEncoding, }, // A GET with a body, with explicit content length: { method: "GET", clen: 7, - body: ioutil.NopCloser(strings.NewReader("foobody")), + body: io.NopCloser(strings.NewReader("foobody")), want: all(matchSubstr("Content-Length: 7"), matchSubstr("foobody")), }, @@ -737,7 +736,7 @@ func TestRequestWriteTransport(t *testing.T) { { method: "GET", clen: -1, - body: ioutil.NopCloser(strings.NewReader("foobody")), + body: io.NopCloser(strings.NewReader("foobody")), want: all(matchSubstr("Transfer-Encoding: chunked"), matchSubstr("\r\n1\r\nf\r\n"), matchSubstr("oobody")), @@ -747,14 +746,14 @@ func TestRequestWriteTransport(t *testing.T) { { method: "POST", clen: -1, - body: ioutil.NopCloser(strings.NewReader("foobody")), + body: io.NopCloser(strings.NewReader("foobody")), want: all(matchSubstr("Transfer-Encoding: chunked"), matchSubstr("foobody")), }, { method: "POST", clen: -1, - body: ioutil.NopCloser(strings.NewReader("")), + body: io.NopCloser(strings.NewReader("")), want: all(matchSubstr("Transfer-Encoding: chunked")), }, // Verify that a blocking Request.Body doesn't block forever. @@ -766,7 +765,7 @@ func TestRequestWriteTransport(t *testing.T) { tt.afterReqRead = func() { pw.Close() } - tt.body = ioutil.NopCloser(pr) + tt.body = io.NopCloser(pr) }, want: matchSubstr("Transfer-Encoding: chunked"), }, @@ -937,7 +936,7 @@ func dumpRequestOut(req *Request, onReadHeaders func()) ([]byte, error) { } // Ensure all the body is read; otherwise // we'll get a partial dump. - io.Copy(ioutil.Discard, req.Body) + io.Copy(io.Discard, req.Body) req.Body.Close() } dr.c <- strings.NewReader("HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n") diff --git a/src/net/http/response_test.go b/src/net/http/response_test.go index ce872606b1..8eef65474e 100644 --- a/src/net/http/response_test.go +++ b/src/net/http/response_test.go @@ -12,7 +12,6 @@ import ( "fmt" "go/token" "io" - "io/ioutil" "net/http/internal" "net/url" "reflect" @@ -620,7 +619,7 @@ func TestWriteResponse(t *testing.T) { t.Errorf("#%d: %v", i, err) continue } - err = resp.Write(ioutil.Discard) + err = resp.Write(io.Discard) if err != nil { t.Errorf("#%d: %v", i, err) continue @@ -722,7 +721,7 @@ func TestReadResponseCloseInMiddle(t *testing.T) { } resp.Body.Close() - rest, err := ioutil.ReadAll(bufr) + rest, err := io.ReadAll(bufr) checkErr(err, "ReadAll on remainder") if e, g := "Next Request Here", string(rest); e != g { g = regexp.MustCompile(`(xx+)`).ReplaceAllStringFunc(g, func(match string) string { diff --git a/src/net/http/responsewrite_test.go b/src/net/http/responsewrite_test.go index d41d89896e..1cc87b942e 100644 --- a/src/net/http/responsewrite_test.go +++ b/src/net/http/responsewrite_test.go @@ -6,7 +6,7 @@ package http import ( "bytes" - "io/ioutil" + "io" "strings" "testing" ) @@ -26,7 +26,7 @@ func TestResponseWrite(t *testing.T) { ProtoMinor: 0, Request: dummyReq("GET"), Header: Header{}, - Body: ioutil.NopCloser(strings.NewReader("abcdef")), + Body: io.NopCloser(strings.NewReader("abcdef")), ContentLength: 6, }, @@ -42,7 +42,7 @@ func TestResponseWrite(t *testing.T) { ProtoMinor: 0, Request: dummyReq("GET"), Header: Header{}, - Body: ioutil.NopCloser(strings.NewReader("abcdef")), + Body: io.NopCloser(strings.NewReader("abcdef")), ContentLength: -1, }, "HTTP/1.0 200 OK\r\n" + @@ -57,7 +57,7 @@ func TestResponseWrite(t *testing.T) { ProtoMinor: 1, Request: dummyReq("GET"), Header: Header{}, - Body: ioutil.NopCloser(strings.NewReader("abcdef")), + Body: io.NopCloser(strings.NewReader("abcdef")), ContentLength: -1, Close: true, }, @@ -74,7 +74,7 @@ func TestResponseWrite(t *testing.T) { ProtoMinor: 1, Request: dummyReq11("GET"), Header: Header{}, - Body: ioutil.NopCloser(strings.NewReader("abcdef")), + Body: io.NopCloser(strings.NewReader("abcdef")), ContentLength: -1, Close: false, }, @@ -92,7 +92,7 @@ func TestResponseWrite(t *testing.T) { ProtoMinor: 1, Request: dummyReq11("GET"), Header: Header{}, - Body: ioutil.NopCloser(strings.NewReader("abcdef")), + Body: io.NopCloser(strings.NewReader("abcdef")), ContentLength: -1, TransferEncoding: []string{"chunked"}, Close: false, @@ -125,7 +125,7 @@ func TestResponseWrite(t *testing.T) { ProtoMinor: 1, Request: dummyReq11("GET"), Header: Header{}, - Body: ioutil.NopCloser(strings.NewReader("")), + Body: io.NopCloser(strings.NewReader("")), ContentLength: 0, Close: false, }, @@ -141,7 +141,7 @@ func TestResponseWrite(t *testing.T) { ProtoMinor: 1, Request: dummyReq11("GET"), Header: Header{}, - Body: ioutil.NopCloser(strings.NewReader("foo")), + Body: io.NopCloser(strings.NewReader("foo")), ContentLength: 0, Close: false, }, @@ -157,7 +157,7 @@ func TestResponseWrite(t *testing.T) { ProtoMinor: 1, Request: dummyReq("GET"), Header: Header{}, - Body: ioutil.NopCloser(strings.NewReader("abcdef")), + Body: io.NopCloser(strings.NewReader("abcdef")), ContentLength: 6, TransferEncoding: []string{"chunked"}, Close: true, @@ -218,7 +218,7 @@ func TestResponseWrite(t *testing.T) { Request: &Request{Method: "POST"}, Header: Header{}, ContentLength: -1, - Body: ioutil.NopCloser(strings.NewReader("abcdef")), + Body: io.NopCloser(strings.NewReader("abcdef")), }, "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\nabcdef", }, diff --git a/src/net/http/roundtrip_js.go b/src/net/http/roundtrip_js.go index b09923c386..c6a221ac62 100644 --- a/src/net/http/roundtrip_js.go +++ b/src/net/http/roundtrip_js.go @@ -10,7 +10,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "strconv" "syscall/js" ) @@ -92,7 +91,7 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) { // See https://github.com/web-platform-tests/wpt/issues/7693 for WHATWG tests issue. // See https://developer.mozilla.org/en-US/docs/Web/API/Streams_API for more details on the Streams API // and browser support. - body, err := ioutil.ReadAll(req.Body) + body, err := io.ReadAll(req.Body) if err != nil { req.Body.Close() // RoundTrip must always close the body, including on errors. return nil, err diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go index d84804c2e9..ba54b31a29 100644 --- a/src/net/http/serve_test.go +++ b/src/net/http/serve_test.go @@ -18,7 +18,6 @@ import ( "fmt" "internal/testenv" "io" - "io/ioutil" "log" "math/rand" "net" @@ -529,7 +528,7 @@ func TestServeWithSlashRedirectKeepsQueryString(t *testing.T) { if err != nil { continue } - slurp, _ := ioutil.ReadAll(res.Body) + slurp, _ := io.ReadAll(res.Body) res.Body.Close() if !tt.statusOk { if got, want := res.StatusCode, 404; got != want { @@ -689,7 +688,7 @@ func testServerTimeouts(timeout time.Duration) error { if err != nil { return fmt.Errorf("http Get #1: %v", err) } - got, err := ioutil.ReadAll(r.Body) + got, err := io.ReadAll(r.Body) expected := "req=1" if string(got) != expected || err != nil { return fmt.Errorf("Unexpected response for request #1; got %q ,%v; expected %q, nil", @@ -721,7 +720,7 @@ func testServerTimeouts(timeout time.Duration) error { if err != nil { return fmt.Errorf("http Get #2: %v", err) } - got, err = ioutil.ReadAll(r.Body) + got, err = io.ReadAll(r.Body) r.Body.Close() expected = "req=2" if string(got) != expected || err != nil { @@ -734,7 +733,7 @@ func testServerTimeouts(timeout time.Duration) error { return fmt.Errorf("long Dial: %v", err) } defer conn.Close() - go io.Copy(ioutil.Discard, conn) + go io.Copy(io.Discard, conn) for i := 0; i < 5; i++ { _, err := conn.Write([]byte("GET / HTTP/1.1\r\nHost: foo\r\n\r\n")) if err != nil { @@ -954,7 +953,7 @@ func TestOnlyWriteTimeout(t *testing.T) { errc <- err return } - _, err = io.Copy(ioutil.Discard, res.Body) + _, err = io.Copy(io.Discard, res.Body) res.Body.Close() errc <- err }() @@ -1058,7 +1057,7 @@ func TestIdentityResponse(t *testing.T) { } // The ReadAll will hang for a failing test. - got, _ := ioutil.ReadAll(conn) + got, _ := io.ReadAll(conn) expectedSuffix := "\r\n\r\ntoo short" if !strings.HasSuffix(string(got), expectedSuffix) { t.Errorf("Expected output to end with %q; got response body %q", @@ -1099,7 +1098,7 @@ func testTCPConnectionCloses(t *testing.T, req string, h Handler) { } }() - _, err = ioutil.ReadAll(r) + _, err = io.ReadAll(r) if err != nil { t.Fatal("read error:", err) } @@ -1129,7 +1128,7 @@ func testTCPConnectionStaysOpen(t *testing.T, req string, handler Handler) { if err != nil { t.Fatalf("res %d: %v", i+1, err) } - if _, err := io.Copy(ioutil.Discard, res.Body); err != nil { + if _, err := io.Copy(io.Discard, res.Body); err != nil { t.Fatalf("res %d body copy: %v", i+1, err) } res.Body.Close() @@ -1235,7 +1234,7 @@ func testSetsRemoteAddr(t *testing.T, h2 bool) { if err != nil { t.Fatalf("Get error: %v", err) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { t.Fatalf("ReadAll error: %v", err) } @@ -1299,7 +1298,7 @@ func TestServerAllowsBlockingRemoteAddr(t *testing.T) { return } defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { t.Errorf("Request %d: %v", num, err) response <- "" @@ -1381,7 +1380,7 @@ func testHeadResponses(t *testing.T, h2 bool) { if v := res.ContentLength; v != 10 { t.Errorf("Content-Length: %d; want 10", v) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { t.Error(err) } @@ -1432,7 +1431,7 @@ func TestTLSServer(t *testing.T) { } } })) - ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0) + ts.Config.ErrorLog = log.New(io.Discard, "", 0) defer ts.Close() // Connect an idle TCP connection to this server before we run @@ -1540,7 +1539,7 @@ func TestTLSServerRejectHTTPRequests(t *testing.T) { } defer conn.Close() io.WriteString(conn, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n") - slurp, err := ioutil.ReadAll(conn) + slurp, err := io.ReadAll(conn) if err != nil { t.Fatal(err) } @@ -1734,7 +1733,7 @@ func TestServerExpect(t *testing.T) { // requests that would read from r.Body, which we only // conditionally want to do. if strings.Contains(r.URL.RawQuery, "readbody=true") { - ioutil.ReadAll(r.Body) + io.ReadAll(r.Body) w.Write([]byte("Hi")) } else { w.WriteHeader(StatusUnauthorized) @@ -1773,7 +1772,7 @@ func TestServerExpect(t *testing.T) { io.Closer }{ conn, - ioutil.NopCloser(nil), + io.NopCloser(nil), } if test.chunked { targ = httputil.NewChunkedWriter(conn) @@ -2072,7 +2071,7 @@ type testHandlerBodyConsumer struct { var testHandlerBodyConsumers = []testHandlerBodyConsumer{ {"nil", func(io.ReadCloser) {}}, {"close", func(r io.ReadCloser) { r.Close() }}, - {"discard", func(r io.ReadCloser) { io.Copy(ioutil.Discard, r) }}, + {"discard", func(r io.ReadCloser) { io.Copy(io.Discard, r) }}, } func TestRequestBodyReadErrorClosesConnection(t *testing.T) { @@ -2298,7 +2297,7 @@ func testTimeoutHandler(t *testing.T, h2 bool) { if g, e := res.StatusCode, StatusOK; g != e { t.Errorf("got res.StatusCode %d; expected %d", g, e) } - body, _ := ioutil.ReadAll(res.Body) + body, _ := io.ReadAll(res.Body) if g, e := string(body), "hi"; g != e { t.Errorf("got body %q; expected %q", g, e) } @@ -2315,7 +2314,7 @@ func testTimeoutHandler(t *testing.T, h2 bool) { if g, e := res.StatusCode, StatusServiceUnavailable; g != e { t.Errorf("got res.StatusCode %d; expected %d", g, e) } - body, _ = ioutil.ReadAll(res.Body) + body, _ = io.ReadAll(res.Body) if !strings.Contains(string(body), "Timeout") { t.Errorf("expected timeout body; got %q", string(body)) } @@ -2367,7 +2366,7 @@ func TestTimeoutHandlerRace(t *testing.T) { defer func() { <-gate }() res, err := c.Get(fmt.Sprintf("%s/%d", ts.URL, rand.Intn(50))) if err == nil { - io.Copy(ioutil.Discard, res.Body) + io.Copy(io.Discard, res.Body) res.Body.Close() } }() @@ -2410,7 +2409,7 @@ func TestTimeoutHandlerRaceHeader(t *testing.T) { return } defer res.Body.Close() - io.Copy(ioutil.Discard, res.Body) + io.Copy(io.Discard, res.Body) }() } wg.Wait() @@ -2441,7 +2440,7 @@ func TestTimeoutHandlerRaceHeaderTimeout(t *testing.T) { if g, e := res.StatusCode, StatusOK; g != e { t.Errorf("got res.StatusCode %d; expected %d", g, e) } - body, _ := ioutil.ReadAll(res.Body) + body, _ := io.ReadAll(res.Body) if g, e := string(body), "hi"; g != e { t.Errorf("got body %q; expected %q", g, e) } @@ -2458,7 +2457,7 @@ func TestTimeoutHandlerRaceHeaderTimeout(t *testing.T) { if g, e := res.StatusCode, StatusServiceUnavailable; g != e { t.Errorf("got res.StatusCode %d; expected %d", g, e) } - body, _ = ioutil.ReadAll(res.Body) + body, _ = io.ReadAll(res.Body) if !strings.Contains(string(body), "Timeout") { t.Errorf("expected timeout body; got %q", string(body)) } @@ -2630,7 +2629,7 @@ func TestRedirectContentTypeAndBody(t *testing.T) { t.Errorf("Redirect(%q, %#v) generated Content-Type header %q; want %q", tt.method, tt.ct, got, want) } resp := rec.Result() - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { t.Fatal(err) } @@ -2657,7 +2656,7 @@ func testZeroLengthPostAndResponse(t *testing.T, h2 bool) { setParallel(t) defer afterTest(t) cst := newClientServerTest(t, h2, HandlerFunc(func(rw ResponseWriter, r *Request) { - all, err := ioutil.ReadAll(r.Body) + all, err := io.ReadAll(r.Body) if err != nil { t.Fatalf("handler ReadAll: %v", err) } @@ -2683,7 +2682,7 @@ func testZeroLengthPostAndResponse(t *testing.T, h2 bool) { } for i := range resp { - all, err := ioutil.ReadAll(resp[i].Body) + all, err := io.ReadAll(resp[i].Body) if err != nil { t.Fatalf("req #%d: client ReadAll: %v", i, err) } @@ -2710,7 +2709,7 @@ func TestHandlerPanicWithHijack(t *testing.T) { func testHandlerPanic(t *testing.T, withHijack, h2 bool, wrapper func(Handler) Handler, panicValue interface{}) { defer afterTest(t) - // Unlike the other tests that set the log output to ioutil.Discard + // Unlike the other tests that set the log output to io.Discard // to quiet the output, this test uses a pipe. The pipe serves three // purposes: // @@ -2970,7 +2969,7 @@ func testRequestBodyLimit(t *testing.T, h2 bool) { const limit = 1 << 20 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { r.Body = MaxBytesReader(w, r.Body, limit) - n, err := io.Copy(ioutil.Discard, r.Body) + n, err := io.Copy(io.Discard, r.Body) if err == nil { t.Errorf("expected error from io.Copy") } @@ -3020,7 +3019,7 @@ func TestClientWriteShutdown(t *testing.T) { donec := make(chan bool) go func() { defer close(donec) - bs, err := ioutil.ReadAll(conn) + bs, err := io.ReadAll(conn) if err != nil { t.Errorf("ReadAll: %v", err) } @@ -3341,7 +3340,7 @@ func TestHijackBeforeRequestBodyRead(t *testing.T) { r.Body = nil // to test that server.go doesn't use this value. gone := w.(CloseNotifier).CloseNotify() - slurp, err := ioutil.ReadAll(reqBody) + slurp, err := io.ReadAll(reqBody) if err != nil { t.Errorf("Body read: %v", err) return @@ -3643,7 +3642,7 @@ func TestAcceptMaxFds(t *testing.T) { }}} server := &Server{ Handler: HandlerFunc(HandlerFunc(func(ResponseWriter, *Request) {})), - ErrorLog: log.New(ioutil.Discard, "", 0), // noisy otherwise + ErrorLog: log.New(io.Discard, "", 0), // noisy otherwise } err := server.Serve(ln) if err != io.EOF { @@ -3782,7 +3781,7 @@ func testServerReaderFromOrder(t *testing.T, h2 bool) { close(done) }() time.Sleep(25 * time.Millisecond) // give Copy a chance to break things - n, err := io.Copy(ioutil.Discard, req.Body) + n, err := io.Copy(io.Discard, req.Body) if err != nil { t.Errorf("handler Copy: %v", err) return @@ -3804,7 +3803,7 @@ func testServerReaderFromOrder(t *testing.T, h2 bool) { if err != nil { t.Fatal(err) } - all, err := ioutil.ReadAll(res.Body) + all, err := io.ReadAll(res.Body) if err != nil { t.Fatal(err) } @@ -3929,7 +3928,7 @@ func testTransportAndServerSharedBodyRace(t *testing.T, h2 bool) { errorf("Proxy outbound request: %v", err) return } - _, err = io.CopyN(ioutil.Discard, bresp.Body, bodySize/2) + _, err = io.CopyN(io.Discard, bresp.Body, bodySize/2) if err != nil { errorf("Proxy copy error: %v", err) return @@ -4136,7 +4135,7 @@ func TestServerConnState(t *testing.T) { ts.Close() }() - ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0) + ts.Config.ErrorLog = log.New(io.Discard, "", 0) ts.Config.ConnState = func(c net.Conn, state ConnState) { if c == nil { t.Errorf("nil conn seen in state %s", state) @@ -4176,7 +4175,7 @@ func TestServerConnState(t *testing.T) { t.Errorf("Error fetching %s: %v", url, err) return } - _, err = ioutil.ReadAll(res.Body) + _, err = io.ReadAll(res.Body) defer res.Body.Close() if err != nil { t.Errorf("Error reading %s: %v", url, err) @@ -4233,7 +4232,7 @@ func TestServerConnState(t *testing.T) { if err != nil { t.Fatal(err) } - if _, err := io.Copy(ioutil.Discard, res.Body); err != nil { + if _, err := io.Copy(io.Discard, res.Body); err != nil { t.Fatal(err) } c.Close() @@ -4285,7 +4284,7 @@ func testServerEmptyBodyRace(t *testing.T, h2 bool) { } } defer res.Body.Close() - _, err = io.Copy(ioutil.Discard, res.Body) + _, err = io.Copy(io.Discard, res.Body) if err != nil { t.Error(err) return @@ -4311,7 +4310,7 @@ func TestServerConnStateNew(t *testing.T) { srv.Serve(&oneConnListener{ conn: &rwTestConn{ Reader: strings.NewReader("GET / HTTP/1.1\r\nHost: foo\r\n\r\n"), - Writer: ioutil.Discard, + Writer: io.Discard, }, }) if !sawNew { // testing that this read isn't racy @@ -4367,7 +4366,7 @@ func TestServerFlushAndHijack(t *testing.T) { t.Fatal(err) } defer res.Body.Close() - all, err := ioutil.ReadAll(res.Body) + all, err := io.ReadAll(res.Body) if err != nil { t.Fatal(err) } @@ -4555,7 +4554,7 @@ Host: foo go Serve(ln, HandlerFunc(func(w ResponseWriter, r *Request) { numReq++ if r.URL.Path == "/readbody" { - ioutil.ReadAll(r.Body) + io.ReadAll(r.Body) } io.WriteString(w, "Hello world!") })) @@ -4608,7 +4607,7 @@ func testHandlerSetsBodyNil(t *testing.T, h2 bool) { t.Fatal(err) } defer res.Body.Close() - slurp, err := ioutil.ReadAll(res.Body) + slurp, err := io.ReadAll(res.Body) if err != nil { t.Fatal(err) } @@ -4724,7 +4723,7 @@ func TestServerHandlersCanHandleH2PRI(t *testing.T) { } defer c.Close() io.WriteString(c, "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n") - slurp, err := ioutil.ReadAll(c) + slurp, err := io.ReadAll(c) if err != nil { t.Fatal(err) } @@ -4958,7 +4957,7 @@ func BenchmarkClientServer(b *testing.B) { if err != nil { b.Fatal("Get:", err) } - all, err := ioutil.ReadAll(res.Body) + all, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { b.Fatal("ReadAll:", err) @@ -5009,7 +5008,7 @@ func benchmarkClientServerParallel(b *testing.B, parallelism int, useTLS bool) { b.Logf("Get: %v", err) continue } - all, err := ioutil.ReadAll(res.Body) + all, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { b.Logf("ReadAll: %v", err) @@ -5044,7 +5043,7 @@ func BenchmarkServer(b *testing.B) { if err != nil { log.Panicf("Get: %v", err) } - all, err := ioutil.ReadAll(res.Body) + all, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { log.Panicf("ReadAll: %v", err) @@ -5167,7 +5166,7 @@ func BenchmarkClient(b *testing.B) { if err != nil { b.Fatalf("Get: %v", err) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { b.Fatalf("ReadAll: %v", err) @@ -5257,7 +5256,7 @@ Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3 conn := &rwTestConn{ Reader: &repeatReader{content: req, count: b.N}, - Writer: ioutil.Discard, + Writer: io.Discard, closec: make(chan bool, 1), } handled := 0 @@ -5286,7 +5285,7 @@ Host: golang.org conn := &rwTestConn{ Reader: &repeatReader{content: req, count: b.N}, - Writer: ioutil.Discard, + Writer: io.Discard, closec: make(chan bool, 1), } handled := 0 @@ -5346,7 +5345,7 @@ Host: golang.org `) conn := &rwTestConn{ Reader: &repeatReader{content: req, count: b.N}, - Writer: ioutil.Discard, + Writer: io.Discard, closec: make(chan bool, 1), } handled := 0 @@ -5375,7 +5374,7 @@ Host: golang.org conn.Close() }) conn := &rwTestConn{ - Writer: ioutil.Discard, + Writer: io.Discard, closec: make(chan bool, 1), } ln := &oneConnListener{conn: conn} @@ -5438,7 +5437,7 @@ func TestServerIdleTimeout(t *testing.T) { setParallel(t) defer afterTest(t) ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) { - io.Copy(ioutil.Discard, r.Body) + io.Copy(io.Discard, r.Body) io.WriteString(w, r.RemoteAddr) })) ts.Config.ReadHeaderTimeout = 1 * time.Second @@ -5453,7 +5452,7 @@ func TestServerIdleTimeout(t *testing.T) { t.Fatal(err) } defer res.Body.Close() - slurp, err := ioutil.ReadAll(res.Body) + slurp, err := io.ReadAll(res.Body) if err != nil { t.Fatal(err) } @@ -5478,7 +5477,7 @@ func TestServerIdleTimeout(t *testing.T) { defer conn.Close() conn.Write([]byte("GET / HTTP/1.1\r\nHost: foo.com\r\n")) time.Sleep(2 * time.Second) - if _, err := io.CopyN(ioutil.Discard, conn, 1); err == nil { + if _, err := io.CopyN(io.Discard, conn, 1); err == nil { t.Fatal("copy byte succeeded; want err") } } @@ -5489,7 +5488,7 @@ func get(t *testing.T, c *Client, url string) string { t.Fatal(err) } defer res.Body.Close() - slurp, err := ioutil.ReadAll(res.Body) + slurp, err := io.ReadAll(res.Body) if err != nil { t.Fatal(err) } @@ -5739,7 +5738,7 @@ func TestServerCancelsReadTimeoutWhenIdle(t *testing.T) { if err != nil { return fmt.Errorf("Get: %v", err) } - slurp, err := ioutil.ReadAll(res.Body) + slurp, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { return fmt.Errorf("Body ReadAll: %v", err) @@ -5802,7 +5801,7 @@ func TestServerDuplicateBackgroundRead(t *testing.T) { wg.Add(1) go func() { defer wg.Done() - io.Copy(ioutil.Discard, cn) + io.Copy(io.Discard, cn) }() for j := 0; j < requests; j++ { @@ -5902,7 +5901,7 @@ func TestServerHijackGetsBackgroundByte_big(t *testing.T) { return } defer conn.Close() - slurp, err := ioutil.ReadAll(buf.Reader) + slurp, err := io.ReadAll(buf.Reader) if err != nil { t.Errorf("Copy: %v", err) } @@ -6436,13 +6435,13 @@ func fetchWireResponse(host string, http1ReqBody []byte) ([]byte, error) { if _, err := conn.Write(http1ReqBody); err != nil { return nil, err } - return ioutil.ReadAll(conn) + return io.ReadAll(conn) } func BenchmarkResponseStatusLine(b *testing.B) { b.ReportAllocs() b.RunParallel(func(pb *testing.PB) { - bw := bufio.NewWriter(ioutil.Discard) + bw := bufio.NewWriter(io.Discard) var buf3 [3]byte for pb.Next() { Export_writeStatusLine(bw, true, 200, buf3[:]) diff --git a/src/net/http/server.go b/src/net/http/server.go index fab229c92a..ba473d14f5 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -14,7 +14,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "log" "net" "net/textproto" @@ -1368,7 +1367,7 @@ func (cw *chunkWriter) writeHeader(p []byte) { } if discard { - _, err := io.CopyN(ioutil.Discard, w.reqBody, maxPostHandlerReadBytes+1) + _, err := io.CopyN(io.Discard, w.reqBody, maxPostHandlerReadBytes+1) switch err { case nil: // There must be even more data left over. @@ -3407,7 +3406,7 @@ func (globalOptionsHandler) ServeHTTP(w ResponseWriter, r *Request) { // (or an attack) and we abort and close the connection, // courtesy of MaxBytesReader's EOF behavior. mb := MaxBytesReader(w, r.Body, 4<<10) - io.Copy(ioutil.Discard, mb) + io.Copy(io.Discard, mb) } } diff --git a/src/net/http/sniff_test.go b/src/net/http/sniff_test.go index a1157a0823..8d5350374d 100644 --- a/src/net/http/sniff_test.go +++ b/src/net/http/sniff_test.go @@ -8,7 +8,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "log" . "net/http" "reflect" @@ -123,7 +122,7 @@ func testServerContentType(t *testing.T, h2 bool) { if ct := resp.Header.Get("Content-Type"); ct != wantContentType { t.Errorf("%v: Content-Type = %q, want %q", tt.desc, ct, wantContentType) } - data, err := ioutil.ReadAll(resp.Body) + data, err := io.ReadAll(resp.Body) if err != nil { t.Errorf("%v: reading body: %v", tt.desc, err) } else if !bytes.Equal(data, tt.data) { @@ -185,7 +184,7 @@ func testContentTypeWithCopy(t *testing.T, h2 bool) { if ct := resp.Header.Get("Content-Type"); ct != expected { t.Errorf("Content-Type = %q, want %q", ct, expected) } - data, err := ioutil.ReadAll(resp.Body) + data, err := io.ReadAll(resp.Body) if err != nil { t.Errorf("reading body: %v", err) } else if !bytes.Equal(data, []byte(input)) { @@ -216,7 +215,7 @@ func testSniffWriteSize(t *testing.T, h2 bool) { if err != nil { t.Fatalf("size %d: %v", size, err) } - if _, err := io.Copy(ioutil.Discard, res.Body); err != nil { + if _, err := io.Copy(io.Discard, res.Body); err != nil { t.Fatalf("size %d: io.Copy of body = %v", size, err) } if err := res.Body.Close(); err != nil { diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go index c3234f30cc..fbb0c39829 100644 --- a/src/net/http/transfer.go +++ b/src/net/http/transfer.go @@ -10,7 +10,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "net/http/httptrace" "net/http/internal" "net/textproto" @@ -156,7 +155,7 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) { // servers. See Issue 18257, as one example. // // The only reason we'd send such a request is if the user set the Body to a -// non-nil value (say, ioutil.NopCloser(bytes.NewReader(nil))) and didn't +// non-nil value (say, io.NopCloser(bytes.NewReader(nil))) and didn't // set ContentLength, or NewRequest set it to -1 (unknown), so then we assume // there's bytes to send. // @@ -370,7 +369,7 @@ func (t *transferWriter) writeBody(w io.Writer) (err error) { return err } var nextra int64 - nextra, err = t.doBodyCopy(ioutil.Discard, body) + nextra, err = t.doBodyCopy(io.Discard, body) ncopy += nextra } if err != nil { @@ -992,7 +991,7 @@ func (b *body) Close() error { var n int64 // Consume the body, or, which will also lead to us reading // the trailer headers after the body, if present. - n, err = io.CopyN(ioutil.Discard, bodyLocked{b}, maxPostHandlerReadBytes) + n, err = io.CopyN(io.Discard, bodyLocked{b}, maxPostHandlerReadBytes) if err == io.EOF { err = nil } @@ -1003,7 +1002,7 @@ func (b *body) Close() error { default: // Fully consume the body, which will also lead to us reading // the trailer headers after the body, if present. - _, err = io.Copy(ioutil.Discard, bodyLocked{b}) + _, err = io.Copy(io.Discard, bodyLocked{b}) } b.closed = true return err @@ -1075,7 +1074,7 @@ func (fr finishAsyncByteRead) Read(p []byte) (n int, err error) { return } -var nopCloserType = reflect.TypeOf(ioutil.NopCloser(nil)) +var nopCloserType = reflect.TypeOf(io.NopCloser(nil)) // isKnownInMemoryReader reports whether r is a type known to not // block on Read. Its caller uses this as an optional optimization to diff --git a/src/net/http/transfer_test.go b/src/net/http/transfer_test.go index 185225fa93..1f3d32526d 100644 --- a/src/net/http/transfer_test.go +++ b/src/net/http/transfer_test.go @@ -81,11 +81,11 @@ func TestDetectInMemoryReaders(t *testing.T) { {bytes.NewBuffer(nil), true}, {strings.NewReader(""), true}, - {ioutil.NopCloser(pr), false}, + {io.NopCloser(pr), false}, - {ioutil.NopCloser(bytes.NewReader(nil)), true}, - {ioutil.NopCloser(bytes.NewBuffer(nil)), true}, - {ioutil.NopCloser(strings.NewReader("")), true}, + {io.NopCloser(bytes.NewReader(nil)), true}, + {io.NopCloser(bytes.NewBuffer(nil)), true}, + {io.NopCloser(strings.NewReader("")), true}, } for i, tt := range tests { got := isKnownInMemoryReader(tt.r) @@ -104,12 +104,12 @@ var _ io.ReaderFrom = (*mockTransferWriter)(nil) func (w *mockTransferWriter) ReadFrom(r io.Reader) (int64, error) { w.CalledReader = r - return io.Copy(ioutil.Discard, r) + return io.Copy(io.Discard, r) } func (w *mockTransferWriter) Write(p []byte) (int, error) { w.WriteCalled = true - return ioutil.Discard.Write(p) + return io.Discard.Write(p) } func TestTransferWriterWriteBodyReaderTypes(t *testing.T) { @@ -166,7 +166,7 @@ func TestTransferWriterWriteBodyReaderTypes(t *testing.T) { method: "PUT", bodyFunc: func() (io.Reader, func(), error) { r, cleanup, err := newFileFunc() - return ioutil.NopCloser(r), cleanup, err + return io.NopCloser(r), cleanup, err }, contentLength: nBytes, limitedReader: true, @@ -206,7 +206,7 @@ func TestTransferWriterWriteBodyReaderTypes(t *testing.T) { method: "PUT", bodyFunc: func() (io.Reader, func(), error) { r, cleanup, err := newBufferFunc() - return ioutil.NopCloser(r), cleanup, err + return io.NopCloser(r), cleanup, err }, contentLength: nBytes, limitedReader: true, diff --git a/src/net/http/transport_internal_test.go b/src/net/http/transport_internal_test.go index 92729e65b2..1097ffd173 100644 --- a/src/net/http/transport_internal_test.go +++ b/src/net/http/transport_internal_test.go @@ -11,7 +11,6 @@ import ( "crypto/tls" "errors" "io" - "io/ioutil" "net" "net/http/internal" "strings" @@ -226,7 +225,7 @@ func TestTransportBodyAltRewind(t *testing.T) { TLSNextProto: map[string]func(string, *tls.Conn) RoundTripper{ "foo": func(authority string, c *tls.Conn) RoundTripper { return roundTripFunc(func(r *Request) (*Response, error) { - n, _ := io.Copy(ioutil.Discard, r.Body) + n, _ := io.Copy(io.Discard, r.Body) if n == 0 { t.Error("body length is zero") } diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go index b152007282..58f0d9db98 100644 --- a/src/net/http/transport_test.go +++ b/src/net/http/transport_test.go @@ -173,7 +173,7 @@ func TestTransportKeepAlives(t *testing.T) { if err != nil { t.Fatalf("error in disableKeepAlive=%v, req #%d, GET: %v", disableKeepAlive, n, err) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { t.Fatalf("error in disableKeepAlive=%v, req #%d, ReadAll: %v", disableKeepAlive, n, err) } @@ -220,7 +220,7 @@ func TestTransportConnectionCloseOnResponse(t *testing.T) { t.Fatalf("error in connectionClose=%v, req #%d, Do: %v", connectionClose, n, err) } defer res.Body.Close() - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { t.Fatalf("error in connectionClose=%v, req #%d, ReadAll: %v", connectionClose, n, err) } @@ -273,7 +273,7 @@ func TestTransportConnectionCloseOnRequest(t *testing.T) { t.Errorf("For connectionClose = %v; handler's X-Saw-Close was %v; want %v", connectionClose, got, !connectionClose) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { t.Fatalf("error in connectionClose=%v, req #%d, ReadAll: %v", connectionClose, n, err) } @@ -382,7 +382,7 @@ func TestTransportIdleCacheKeys(t *testing.T) { if err != nil { t.Error(err) } - ioutil.ReadAll(resp.Body) + io.ReadAll(resp.Body) keys := tr.IdleConnKeysForTesting() if e, g := 1, len(keys); e != g { @@ -495,7 +495,7 @@ func TestTransportMaxPerHostIdleConns(t *testing.T) { t.Error(err) return } - if _, err := ioutil.ReadAll(resp.Body); err != nil { + if _, err := io.ReadAll(resp.Body); err != nil { t.Errorf("ReadAll: %v", err) return } @@ -575,7 +575,7 @@ func TestTransportMaxConnsPerHostIncludeDialInProgress(t *testing.T) { if err != nil { t.Errorf("unexpected error for request %s: %v", reqId, err) } - _, err = ioutil.ReadAll(resp.Body) + _, err = io.ReadAll(resp.Body) if err != nil { t.Errorf("unexpected error for request %s: %v", reqId, err) } @@ -655,7 +655,7 @@ func TestTransportMaxConnsPerHost(t *testing.T) { t.Fatalf("request failed: %v", err) } defer resp.Body.Close() - _, err = ioutil.ReadAll(resp.Body) + _, err = io.ReadAll(resp.Body) if err != nil { t.Fatalf("read body failed: %v", err) } @@ -733,7 +733,7 @@ func TestTransportRemovesDeadIdleConnections(t *testing.T) { t.Fatalf("%s: %v", name, res.Status) } defer res.Body.Close() - slurp, err := ioutil.ReadAll(res.Body) + slurp, err := io.ReadAll(res.Body) if err != nil { t.Fatalf("%s: %v", name, err) } @@ -783,7 +783,7 @@ func TestTransportServerClosingUnexpectedly(t *testing.T) { condFatalf("error in req #%d, GET: %v", n, err) continue } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { condFatalf("error in req #%d, ReadAll: %v", n, err) continue @@ -903,7 +903,7 @@ func TestTransportHeadResponses(t *testing.T) { if e, g := int64(123), res.ContentLength; e != g { t.Errorf("loop %d: expected res.ContentLength of %v, got %v", i, e, g) } - if all, err := ioutil.ReadAll(res.Body); err != nil { + if all, err := io.ReadAll(res.Body); err != nil { t.Errorf("loop %d: Body ReadAll: %v", i, err) } else if len(all) != 0 { t.Errorf("Bogus body %q", all) @@ -1006,10 +1006,10 @@ func TestRoundTripGzip(t *testing.T) { t.Errorf("%d. gzip NewReader: %v", i, err) continue } - body, err = ioutil.ReadAll(r) + body, err = io.ReadAll(r) res.Body.Close() } else { - body, err = ioutil.ReadAll(res.Body) + body, err = io.ReadAll(res.Body) } if err != nil { t.Errorf("%d. Error: %q", i, err) @@ -1090,7 +1090,7 @@ func TestTransportGzip(t *testing.T) { if err != nil { t.Fatal(err) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { t.Fatal(err) } @@ -1133,7 +1133,7 @@ func TestTransportExpect100Continue(t *testing.T) { switch req.URL.Path { case "/100": // This endpoint implicitly responds 100 Continue and reads body. - if _, err := io.Copy(ioutil.Discard, req.Body); err != nil { + if _, err := io.Copy(io.Discard, req.Body); err != nil { t.Error("Failed to read Body", err) } rw.WriteHeader(StatusOK) @@ -1159,7 +1159,7 @@ func TestTransportExpect100Continue(t *testing.T) { if err != nil { log.Fatal(err) } - if _, err := io.CopyN(ioutil.Discard, bufrw, req.ContentLength); err != nil { + if _, err := io.CopyN(io.Discard, bufrw, req.ContentLength); err != nil { t.Error("Failed to read Body", err) } bufrw.WriteString("HTTP/1.1 200 OK\r\n\r\n") @@ -1625,7 +1625,7 @@ func TestTransportGzipRecursive(t *testing.T) { if err != nil { t.Fatal(err) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) if err != nil { t.Fatal(err) } @@ -1654,7 +1654,7 @@ func TestTransportGzipShort(t *testing.T) { t.Fatal(err) } defer res.Body.Close() - _, err = ioutil.ReadAll(res.Body) + _, err = io.ReadAll(res.Body) if err == nil { t.Fatal("Expect an error from reading a body.") } @@ -1999,7 +1999,7 @@ func TestIssue3644(t *testing.T) { t.Fatal(err) } defer res.Body.Close() - bs, err := ioutil.ReadAll(res.Body) + bs, err := io.ReadAll(res.Body) if err != nil { t.Fatal(err) } @@ -2024,7 +2024,7 @@ func TestIssue3595(t *testing.T) { t.Errorf("Post: %v", err) return } - got, err := ioutil.ReadAll(res.Body) + got, err := io.ReadAll(res.Body) if err != nil { t.Fatalf("Body ReadAll: %v", err) } @@ -2096,7 +2096,7 @@ func TestTransportConcurrency(t *testing.T) { wg.Done() continue } - all, err := ioutil.ReadAll(res.Body) + all, err := io.ReadAll(res.Body) if err != nil { t.Errorf("read error on req %s: %v", req, err) wg.Done() @@ -2163,7 +2163,7 @@ func TestIssue4191_InfiniteGetTimeout(t *testing.T) { t.Errorf("Error issuing GET: %v", err) break } - _, err = io.Copy(ioutil.Discard, sres.Body) + _, err = io.Copy(io.Discard, sres.Body) if err == nil { t.Errorf("Unexpected successful copy") break @@ -2184,7 +2184,7 @@ func TestIssue4191_InfiniteGetToPutTimeout(t *testing.T) { }) mux.HandleFunc("/put", func(w ResponseWriter, r *Request) { defer r.Body.Close() - io.Copy(ioutil.Discard, r.Body) + io.Copy(io.Discard, r.Body) }) ts := httptest.NewServer(mux) timeout := 100 * time.Millisecond @@ -2338,7 +2338,7 @@ func TestTransportCancelRequest(t *testing.T) { tr.CancelRequest(req) }() t0 := time.Now() - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) d := time.Since(t0) if err != ExportErrRequestCanceled { @@ -2497,7 +2497,7 @@ func TestCancelRequestWithChannel(t *testing.T) { close(ch) }() t0 := time.Now() - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) d := time.Since(t0) if err != ExportErrRequestCanceled { @@ -2678,7 +2678,7 @@ func (fooProto) RoundTrip(req *Request) (*Response, error) { Status: "200 OK", StatusCode: 200, Header: make(Header), - Body: ioutil.NopCloser(strings.NewReader("You wanted " + req.URL.String())), + Body: io.NopCloser(strings.NewReader("You wanted " + req.URL.String())), } return res, nil } @@ -2692,7 +2692,7 @@ func TestTransportAltProto(t *testing.T) { if err != nil { t.Fatal(err) } - bodyb, err := ioutil.ReadAll(res.Body) + bodyb, err := io.ReadAll(res.Body) if err != nil { t.Fatal(err) } @@ -2769,7 +2769,7 @@ func TestTransportSocketLateBinding(t *testing.T) { // let the foo response finish so we can use its // connection for /bar fooGate <- true - io.Copy(ioutil.Discard, fooRes.Body) + io.Copy(io.Discard, fooRes.Body) fooRes.Body.Close() }) @@ -2808,7 +2808,7 @@ func TestTransportReading100Continue(t *testing.T) { t.Error(err) return } - slurp, err := ioutil.ReadAll(req.Body) + slurp, err := io.ReadAll(req.Body) if err != nil { t.Errorf("Server request body slurp: %v", err) return @@ -2872,7 +2872,7 @@ Content-Length: %d if id, idBack := req.Header.Get("Request-Id"), res.Header.Get("Echo-Request-Id"); id != "" && id != idBack { t.Errorf("%s: response id %q != request id %q", name, idBack, id) } - _, err = ioutil.ReadAll(res.Body) + _, err = io.ReadAll(res.Body) if err != nil { t.Fatalf("%s: Slurp error: %v", name, err) } @@ -3151,7 +3151,7 @@ func TestIdleConnChannelLeak(t *testing.T) { func TestTransportClosesRequestBody(t *testing.T) { defer afterTest(t) ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { - io.Copy(ioutil.Discard, r.Body) + io.Copy(io.Discard, r.Body) })) defer ts.Close() @@ -3258,7 +3258,7 @@ func TestTLSServerClosesConnection(t *testing.T) { t.Fatal(err) } <-closedc - slurp, err := ioutil.ReadAll(res.Body) + slurp, err := io.ReadAll(res.Body) if err != nil { t.Fatal(err) } @@ -3273,7 +3273,7 @@ func TestTLSServerClosesConnection(t *testing.T) { errs = append(errs, err) continue } - slurp, err = ioutil.ReadAll(res.Body) + slurp, err = io.ReadAll(res.Body) if err != nil { errs = append(errs, err) continue @@ -3344,7 +3344,7 @@ func TestTransportNoReuseAfterEarlyResponse(t *testing.T) { sconn.c = conn sconn.Unlock() conn.Write([]byte("HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo")) // keep-alive - go io.Copy(ioutil.Discard, conn) + go io.Copy(io.Discard, conn) })) defer ts.Close() c := ts.Client() @@ -3593,7 +3593,7 @@ func TestTransportClosesBodyOnError(t *testing.T) { defer afterTest(t) readBody := make(chan error, 1) ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { - _, err := ioutil.ReadAll(r.Body) + _, err := io.ReadAll(r.Body) readBody <- err })) defer ts.Close() @@ -3941,7 +3941,7 @@ func TestTransportResponseCancelRace(t *testing.T) { // If we do an early close, Transport just throws the connection away and // doesn't reuse it. In order to trigger the bug, it has to reuse the connection // so read the body - if _, err := io.Copy(ioutil.Discard, res.Body); err != nil { + if _, err := io.Copy(io.Discard, res.Body); err != nil { t.Fatal(err) } @@ -3978,7 +3978,7 @@ func TestTransportContentEncodingCaseInsensitive(t *testing.T) { t.Fatal(err) } - body, err := ioutil.ReadAll(res.Body) + body, err := io.ReadAll(res.Body) res.Body.Close() if err != nil { t.Fatal(err) @@ -4085,7 +4085,7 @@ func TestTransportFlushesBodyChunks(t *testing.T) { if err != nil { t.Fatal(err) } - io.Copy(ioutil.Discard, req.Body) + io.Copy(io.Discard, req.Body) // Unblock the transport's roundTrip goroutine. resBody <- strings.NewReader("HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n") @@ -4466,7 +4466,7 @@ func testTransportEventTrace(t *testing.T, h2 bool, noHooks bool) { // Do nothing for the second request. return } - if _, err := ioutil.ReadAll(r.Body); err != nil { + if _, err := io.ReadAll(r.Body); err != nil { t.Error(err) } if !noHooks { @@ -4554,7 +4554,7 @@ func testTransportEventTrace(t *testing.T, h2 bool, noHooks bool) { t.Fatal(err) } logf("got roundtrip.response") - slurp, err := ioutil.ReadAll(res.Body) + slurp, err := io.ReadAll(res.Body) if err != nil { t.Fatal(err) } @@ -5236,7 +5236,7 @@ func wantBody(res *Response, err error, want string) error { if err != nil { return err } - slurp, err := ioutil.ReadAll(res.Body) + slurp, err := io.ReadAll(res.Body) if err != nil { return fmt.Errorf("error reading body: %v", err) } @@ -5335,7 +5335,7 @@ func TestMissingStatusNoPanic(t *testing.T) { conn, _ := ln.Accept() if conn != nil { io.WriteString(conn, raw) - ioutil.ReadAll(conn) + io.ReadAll(conn) conn.Close() } }() @@ -5353,7 +5353,7 @@ func TestMissingStatusNoPanic(t *testing.T) { t.Error("panicked, expecting an error") } if res != nil && res.Body != nil { - io.Copy(ioutil.Discard, res.Body) + io.Copy(io.Discard, res.Body) res.Body.Close() } @@ -5539,7 +5539,7 @@ func TestClientTimeoutKillsConn_AfterHeaders(t *testing.T) { } close(cancel) - got, err := ioutil.ReadAll(res.Body) + got, err := io.ReadAll(res.Body) if err == nil { t.Fatalf("unexpected success; read %q, nil", got) } @@ -5678,7 +5678,7 @@ func TestTransportCONNECTBidi(t *testing.T) { } func TestTransportRequestReplayable(t *testing.T) { - someBody := ioutil.NopCloser(strings.NewReader("")) + someBody := io.NopCloser(strings.NewReader("")) tests := []struct { name string req *Request @@ -5839,7 +5839,7 @@ func TestTransportRequestWriteRoundTrip(t *testing.T) { t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) { - io.Copy(ioutil.Discard, r.Body) + io.Copy(io.Discard, r.Body) r.Body.Close() w.WriteHeader(200) }), @@ -5975,7 +5975,7 @@ func TestTransportIgnores408(t *testing.T) { if err != nil { t.Fatal(err) } - slurp, err := ioutil.ReadAll(res.Body) + slurp, err := io.ReadAll(res.Body) if err != nil { t.Fatal(err) } @@ -6237,7 +6237,7 @@ func TestTransportDecrementConnWhenIdleConnRemoved(t *testing.T) { return } defer resp.Body.Close() - _, err = ioutil.ReadAll(resp.Body) + _, err = io.ReadAll(resp.Body) if err != nil { errCh <- fmt.Errorf("read body failed: %v", err) } @@ -6299,7 +6299,7 @@ func (f roundTripFunc) RoundTrip(r *Request) (*Response, error) { return f(r) } func TestIssue32441(t *testing.T) { defer afterTest(t) ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { - if n, _ := io.Copy(ioutil.Discard, r.Body); n == 0 { + if n, _ := io.Copy(io.Discard, r.Body); n == 0 { t.Error("body length is zero") } })) @@ -6307,7 +6307,7 @@ func TestIssue32441(t *testing.T) { c := ts.Client() c.Transport.(*Transport).RegisterProtocol("http", roundTripFunc(func(r *Request) (*Response, error) { // Draining body to trigger failure condition on actual request to server. - if n, _ := io.Copy(ioutil.Discard, r.Body); n == 0 { + if n, _ := io.Copy(io.Discard, r.Body); n == 0 { t.Error("body length is zero during round trip") } return nil, ErrSkipAltProtocol @@ -6389,7 +6389,7 @@ func testTransportRace(req *Request) { if err == nil { // Ensure all the body is read; otherwise // we'll get a partial dump. - io.Copy(ioutil.Discard, req.Body) + io.Copy(io.Discard, req.Body) req.Body.Close() } select { diff --git a/src/net/mail/example_test.go b/src/net/mail/example_test.go index c3365642aa..d325dc791f 100644 --- a/src/net/mail/example_test.go +++ b/src/net/mail/example_test.go @@ -6,7 +6,7 @@ package mail_test import ( "fmt" - "io/ioutil" + "io" "log" "net/mail" "strings" @@ -62,7 +62,7 @@ Message body fmt.Println("To:", header.Get("To")) fmt.Println("Subject:", header.Get("Subject")) - body, err := ioutil.ReadAll(m.Body) + body, err := io.ReadAll(m.Body) if err != nil { log.Fatal(err) } diff --git a/src/net/mail/message_test.go b/src/net/mail/message_test.go index 67e3643aeb..188d0bf766 100644 --- a/src/net/mail/message_test.go +++ b/src/net/mail/message_test.go @@ -7,7 +7,6 @@ package mail import ( "bytes" "io" - "io/ioutil" "mime" "reflect" "strings" @@ -53,7 +52,7 @@ func TestParsing(t *testing.T) { t.Errorf("test #%d: Incorrectly parsed message header.\nGot:\n%+v\nWant:\n%+v", i, msg.Header, test.header) } - body, err := ioutil.ReadAll(msg.Body) + body, err := io.ReadAll(msg.Body) if err != nil { t.Errorf("test #%d: Failed reading body: %v", i, err) continue @@ -842,7 +841,7 @@ func TestAddressParser(t *testing.T) { ap := AddressParser{WordDecoder: &mime.WordDecoder{ CharsetReader: func(charset string, input io.Reader) (io.Reader, error) { - in, err := ioutil.ReadAll(input) + in, err := io.ReadAll(input) if err != nil { return nil, err } diff --git a/src/net/rpc/jsonrpc/all_test.go b/src/net/rpc/jsonrpc/all_test.go index 4e73edc70b..667f839f58 100644 --- a/src/net/rpc/jsonrpc/all_test.go +++ b/src/net/rpc/jsonrpc/all_test.go @@ -10,7 +10,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "net" "net/rpc" "reflect" @@ -249,7 +248,7 @@ func TestMalformedInput(t *testing.T) { func TestMalformedOutput(t *testing.T) { cli, srv := net.Pipe() go srv.Write([]byte(`{"id":0,"result":null,"error":null}`)) - go ioutil.ReadAll(srv) + go io.ReadAll(srv) client := NewClient(cli) defer client.Close() @@ -271,7 +270,7 @@ func TestServerErrorHasNullResult(t *testing.T) { }{ Reader: strings.NewReader(`{"method": "Arith.Add", "id": "123", "params": []}`), Writer: &out, - Closer: ioutil.NopCloser(nil), + Closer: io.NopCloser(nil), }) r := new(rpc.Request) if err := sc.ReadRequestHeader(r); err != nil { diff --git a/src/net/sendfile_test.go b/src/net/sendfile_test.go index 13842a1261..657a36599f 100644 --- a/src/net/sendfile_test.go +++ b/src/net/sendfile_test.go @@ -12,7 +12,6 @@ import ( "encoding/hex" "fmt" "io" - "io/ioutil" "os" "runtime" "sync" @@ -282,7 +281,7 @@ func TestSendfilePipe(t *testing.T) { return } defer conn.Close() - io.Copy(ioutil.Discard, conn) + io.Copy(io.Discard, conn) }() // Wait for the byte to be copied, meaning that sendfile has diff --git a/src/net/splice_test.go b/src/net/splice_test.go index 0ba2f164c2..8a0cda6564 100644 --- a/src/net/splice_test.go +++ b/src/net/splice_test.go @@ -8,7 +8,6 @@ package net import ( "io" - "io/ioutil" "log" "os" "os/exec" @@ -202,7 +201,7 @@ func testSpliceIssue25985(t *testing.T, upNet, downNet string) { } defer fromProxy.Close() - _, err = ioutil.ReadAll(fromProxy) + _, err = io.ReadAll(fromProxy) if err != nil { t.Fatal(err) } diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go index a00fd2395f..5c3084f8a7 100644 --- a/src/net/textproto/reader.go +++ b/src/net/textproto/reader.go @@ -9,7 +9,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "strconv" "strings" "sync" @@ -426,7 +425,7 @@ func (r *Reader) closeDot() { // // See the documentation for the DotReader method for details about dot-encoding. func (r *Reader) ReadDotBytes() ([]byte, error) { - return ioutil.ReadAll(r.DotReader()) + return io.ReadAll(r.DotReader()) } // ReadDotLines reads a dot-encoding and returns a slice diff --git a/src/net/timeout_test.go b/src/net/timeout_test.go index ad14cd79ac..205aaa430b 100644 --- a/src/net/timeout_test.go +++ b/src/net/timeout_test.go @@ -11,7 +11,6 @@ import ( "fmt" "internal/testenv" "io" - "io/ioutil" "net/internal/socktest" "os" "runtime" @@ -874,7 +873,7 @@ func testVariousDeadlines(t *testing.T) { if err := c.SetDeadline(t0.Add(timeout)); err != nil { t.Error(err) } - n, err := io.Copy(ioutil.Discard, c) + n, err := io.Copy(io.Discard, c) dt := time.Since(t0) c.Close() ch <- result{n, err, dt} diff --git a/src/net/writev_test.go b/src/net/writev_test.go index a6b3285e57..d603b7f70a 100644 --- a/src/net/writev_test.go +++ b/src/net/writev_test.go @@ -11,7 +11,6 @@ import ( "fmt" "internal/poll" "io" - "io/ioutil" "reflect" "runtime" "sync" @@ -28,7 +27,7 @@ func TestBuffers_read(t *testing.T) { []byte("in "), []byte("Gopherland ... "), } - got, err := ioutil.ReadAll(&buffers) + got, err := io.ReadAll(&buffers) if err != nil { t.Fatal(err) } @@ -141,7 +140,7 @@ func testBuffer_writeTo(t *testing.T, chunks int, useCopy bool) { } return nil }, func(c *TCPConn) error { - all, err := ioutil.ReadAll(c) + all, err := io.ReadAll(c) if !bytes.Equal(all, want.Bytes()) || err != nil { return fmt.Errorf("client read %q, %v; want %q, nil", all, err, want.Bytes()) } diff --git a/src/os/exec/example_test.go b/src/os/exec/example_test.go index 62866fa710..a66890be69 100644 --- a/src/os/exec/example_test.go +++ b/src/os/exec/example_test.go @@ -10,7 +10,6 @@ import ( "encoding/json" "fmt" "io" - "io/ioutil" "log" "os" "os/exec" @@ -128,7 +127,7 @@ func ExampleCmd_StderrPipe() { log.Fatal(err) } - slurp, _ := ioutil.ReadAll(stderr) + slurp, _ := io.ReadAll(stderr) fmt.Printf("%s\n", slurp) if err := cmd.Wait(); err != nil { diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go index 9746722980..cd3d759ebc 100644 --- a/src/os/exec/exec_test.go +++ b/src/os/exec/exec_test.go @@ -637,7 +637,7 @@ func TestExtraFiles(t *testing.T) { // cgo), to make sure none of that potential C code leaks fds. ts := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})) // quiet expected TLS handshake error "remote error: bad certificate" - ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0) + ts.Config.ErrorLog = log.New(io.Discard, "", 0) ts.StartTLS() defer ts.Close() _, err = http.Get(ts.URL) @@ -830,7 +830,7 @@ func TestHelperProcess(*testing.T) { } } case "stdinClose": - b, err := ioutil.ReadAll(os.Stdin) + b, err := io.ReadAll(os.Stdin) if err != nil { fmt.Fprintf(os.Stderr, "Error: %v\n", err) os.Exit(1) diff --git a/src/os/exec/read3.go b/src/os/exec/read3.go index 25d732a991..8852023e77 100644 --- a/src/os/exec/read3.go +++ b/src/os/exec/read3.go @@ -15,7 +15,7 @@ package main import ( "fmt" "internal/poll" - "io/ioutil" + "io" "os" "os/exec" "runtime" @@ -24,7 +24,7 @@ import ( func main() { fd3 := os.NewFile(3, "fd3") - bs, err := ioutil.ReadAll(fd3) + bs, err := io.ReadAll(fd3) if err != nil { fmt.Printf("ReadAll from fd 3: %v\n", err) os.Exit(1) diff --git a/src/os/timeout_test.go b/src/os/timeout_test.go index 99b94c2e4c..d848e41642 100644 --- a/src/os/timeout_test.go +++ b/src/os/timeout_test.go @@ -429,7 +429,7 @@ func testVariousDeadlines(t *testing.T) { if err := r.SetDeadline(t0.Add(timeout)); err != nil { t.Error(err) } - n, err := io.Copy(ioutil.Discard, r) + n, err := io.Copy(io.Discard, r) dt := time.Since(t0) r.Close() actvch <- result{n, err, dt} @@ -565,7 +565,7 @@ func TestRacyWrite(t *testing.T) { var wg sync.WaitGroup defer wg.Wait() - go io.Copy(ioutil.Discard, r) + go io.Copy(io.Discard, r) w.SetWriteDeadline(time.Now().Add(time.Millisecond)) for i := 0; i < 10; i++ { diff --git a/src/runtime/crash_unix_test.go b/src/runtime/crash_unix_test.go index 8ef52aba48..fc87f37408 100644 --- a/src/runtime/crash_unix_test.go +++ b/src/runtime/crash_unix_test.go @@ -241,7 +241,7 @@ func TestPanicSystemstack(t *testing.T) { } // Get traceback. - tb, err := ioutil.ReadAll(pr) + tb, err := io.ReadAll(pr) if err != nil { t.Fatal("reading traceback from pipe: ", err) } diff --git a/src/runtime/testdata/testprogcgo/eintr.go b/src/runtime/testdata/testprogcgo/eintr.go index 791ff1bedc..1722a75eb9 100644 --- a/src/runtime/testdata/testprogcgo/eintr.go +++ b/src/runtime/testdata/testprogcgo/eintr.go @@ -32,7 +32,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "log" "net" "os" @@ -242,5 +241,5 @@ func testExec(wg *sync.WaitGroup) { // Block blocks until stdin is closed. func Block() { - io.Copy(ioutil.Discard, os.Stdin) + io.Copy(io.Discard, os.Stdin) } diff --git a/src/strings/reader_test.go b/src/strings/reader_test.go index a4c211d699..5adea6f7ab 100644 --- a/src/strings/reader_test.go +++ b/src/strings/reader_test.go @@ -8,7 +8,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "strings" "sync" "testing" @@ -162,7 +161,7 @@ func TestWriteTo(t *testing.T) { // tests that Len is affected by reads, but Size is not. func TestReaderLenSize(t *testing.T) { r := strings.NewReader("abc") - io.CopyN(ioutil.Discard, r, 1) + io.CopyN(io.Discard, r, 1) if r.Len() != 2 { t.Errorf("Len = %d; want 2", r.Len()) } @@ -182,7 +181,7 @@ func TestReaderReset(t *testing.T) { if err := r.UnreadRune(); err == nil { t.Errorf("UnreadRune: expected error, got nil") } - buf, err := ioutil.ReadAll(r) + buf, err := io.ReadAll(r) if err != nil { t.Errorf("ReadAll: unexpected error: %v", err) } @@ -228,7 +227,7 @@ func TestReaderZero(t *testing.T) { t.Errorf("UnreadRune: got nil, want error") } - if n, err := (&strings.Reader{}).WriteTo(ioutil.Discard); n != 0 || err != nil { + if n, err := (&strings.Reader{}).WriteTo(io.Discard); n != 0 || err != nil { t.Errorf("WriteTo: got %d, %v; want 0, nil", n, err) } } diff --git a/src/syscall/mkpost.go b/src/syscall/mkpost.go index d5f5c8d6d6..ef89128310 100644 --- a/src/syscall/mkpost.go +++ b/src/syscall/mkpost.go @@ -14,7 +14,7 @@ package main import ( "fmt" "go/format" - "io/ioutil" + "io" "log" "os" "regexp" @@ -22,7 +22,7 @@ import ( ) func main() { - b, err := ioutil.ReadAll(os.Stdin) + b, err := io.ReadAll(os.Stdin) if err != nil { log.Fatal(err) } diff --git a/src/syscall/syscall_unix_test.go b/src/syscall/syscall_unix_test.go index d754c075f1..1c34ed2c27 100644 --- a/src/syscall/syscall_unix_test.go +++ b/src/syscall/syscall_unix_test.go @@ -225,7 +225,7 @@ func TestPassFD(t *testing.T) { f := os.NewFile(uintptr(gotFds[0]), "fd-from-child") defer f.Close() - got, err := ioutil.ReadAll(f) + got, err := io.ReadAll(f) want := "Hello from child process!\n" if string(got) != want { t.Errorf("child process ReadAll: %q, %v; want %q", got, err, want) diff --git a/src/testing/iotest/reader.go b/src/testing/iotest/reader.go index 33b782dcb6..770d87f26b 100644 --- a/src/testing/iotest/reader.go +++ b/src/testing/iotest/reader.go @@ -10,7 +10,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" ) // OneByteReader returns a Reader that implements @@ -142,7 +141,7 @@ func TestReader(r io.Reader, content []byte) error { } } - data, err := ioutil.ReadAll(&smallByteReader{r: r}) + data, err := io.ReadAll(&smallByteReader{r: r}) if err != nil { return err } @@ -181,7 +180,7 @@ func TestReader(r io.Reader, content []byte) error { } // Reading forward should return the last part of the file. - data, err := ioutil.ReadAll(&smallByteReader{r: r}) + data, err := io.ReadAll(&smallByteReader{r: r}) if err != nil { return fmt.Errorf("ReadAll from offset %d: %v", middle, err) } @@ -198,7 +197,7 @@ func TestReader(r io.Reader, content []byte) error { } // Reading forward should return the last part of the file (again). - data, err = ioutil.ReadAll(&smallByteReader{r: r}) + data, err = io.ReadAll(&smallByteReader{r: r}) if err != nil { return fmt.Errorf("ReadAll from offset %d: %v", middle, err) } @@ -210,7 +209,7 @@ func TestReader(r io.Reader, content []byte) error { if off, err := r.Seek(int64(middle/2), 0); off != int64(middle/2) || err != nil { return fmt.Errorf("Seek(%d, 0) from EOF = %d, %v, want %d, nil", middle/2, off, err, middle/2) } - data, err = ioutil.ReadAll(r) + data, err = io.ReadAll(r) if err != nil { return fmt.Errorf("ReadAll from offset %d: %v", middle/2, err) } diff --git a/src/text/tabwriter/tabwriter_test.go b/src/text/tabwriter/tabwriter_test.go index 6a97d4c427..a51358dbed 100644 --- a/src/text/tabwriter/tabwriter_test.go +++ b/src/text/tabwriter/tabwriter_test.go @@ -8,7 +8,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "testing" . "text/tabwriter" ) @@ -664,7 +663,7 @@ func BenchmarkTable(b *testing.B) { b.Run("new", func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - w := NewWriter(ioutil.Discard, 4, 4, 1, ' ', 0) // no particular reason for these settings + w := NewWriter(io.Discard, 4, 4, 1, ' ', 0) // no particular reason for these settings // Write the line h times. for j := 0; j < h; j++ { w.Write(line) @@ -675,7 +674,7 @@ func BenchmarkTable(b *testing.B) { b.Run("reuse", func(b *testing.B) { b.ReportAllocs() - w := NewWriter(ioutil.Discard, 4, 4, 1, ' ', 0) // no particular reason for these settings + w := NewWriter(io.Discard, 4, 4, 1, ' ', 0) // no particular reason for these settings for i := 0; i < b.N; i++ { // Write the line h times. for j := 0; j < h; j++ { @@ -696,7 +695,7 @@ func BenchmarkPyramid(b *testing.B) { b.Run(fmt.Sprintf("%d", x), func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - w := NewWriter(ioutil.Discard, 4, 4, 1, ' ', 0) // no particular reason for these settings + w := NewWriter(io.Discard, 4, 4, 1, ' ', 0) // no particular reason for these settings // Write increasing prefixes of that line. for j := 0; j < x; j++ { w.Write(line[:j*2]) @@ -718,7 +717,7 @@ func BenchmarkRagged(b *testing.B) { b.Run(fmt.Sprintf("%d", h), func(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - w := NewWriter(ioutil.Discard, 4, 4, 1, ' ', 0) // no particular reason for these settings + w := NewWriter(io.Discard, 4, 4, 1, ' ', 0) // no particular reason for these settings // Write the lines in turn h times. for j := 0; j < h; j++ { w.Write(lines[j%len(lines)]) @@ -746,7 +745,7 @@ lines func BenchmarkCode(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { - w := NewWriter(ioutil.Discard, 4, 4, 1, ' ', 0) // no particular reason for these settings + w := NewWriter(io.Discard, 4, 4, 1, ' ', 0) // no particular reason for these settings // The code is small, so it's reasonable for the tabwriter user // to write it all at once, or buffer the writes. w.Write([]byte(codeSnippet)) diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go index 3309b33e3e..1611ee054f 100644 --- a/src/text/template/exec_test.go +++ b/src/text/template/exec_test.go @@ -9,7 +9,7 @@ import ( "errors" "flag" "fmt" - "io/ioutil" + "io" "reflect" "strings" "testing" @@ -1328,7 +1328,7 @@ func TestExecuteGivesExecError(t *testing.T) { if err != nil { t.Fatal(err) } - err = tmpl.Execute(ioutil.Discard, 0) + err = tmpl.Execute(io.Discard, 0) if err == nil { t.Fatal("expected error; got none") } @@ -1474,7 +1474,7 @@ func TestEvalFieldErrors(t *testing.T) { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { tmpl := Must(New("tmpl").Parse(tc.src)) - err := tmpl.Execute(ioutil.Discard, tc.value) + err := tmpl.Execute(io.Discard, tc.value) got := "" if err != nil { got = err.Error() @@ -1491,7 +1491,7 @@ func TestMaxExecDepth(t *testing.T) { t.Skip("skipping in -short mode") } tmpl := Must(New("tmpl").Parse(`{{template "tmpl" .}}`)) - err := tmpl.Execute(ioutil.Discard, nil) + err := tmpl.Execute(io.Discard, nil) got := "" if err != nil { got = err.Error() diff --git a/src/time/genzabbrs.go b/src/time/genzabbrs.go index 38397f91b7..1d59ba73ce 100644 --- a/src/time/genzabbrs.go +++ b/src/time/genzabbrs.go @@ -17,6 +17,7 @@ import ( "encoding/xml" "flag" "go/format" + "io" "io/ioutil" "log" "net/http" @@ -71,7 +72,7 @@ func readWindowsZones() ([]*zone, error) { } defer r.Body.Close() - data, err := ioutil.ReadAll(r.Body) + data, err := io.ReadAll(r.Body) if err != nil { return nil, err } -- cgit v1.3 From b5ddc42b465dd5b9532ee336d98343d81a6d35b2 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 22 Oct 2020 12:11:29 -0400 Subject: io/fs, path, path/filepath, testing/fstest: validate patterns in Match, Glob According to #28614, proposal review agreed in December 2018 that Match should return an error for failed matches where the unmatched part of the pattern has a syntax error. (The failed match has to date caused the scan of the pattern to stop early.) This change implements that behavior: the match loop continues scanning to the end of the pattern, even after a confirmed mismatch, to check whether the pattern is even well-formed. The change applies to both path.Match and filepath.Match. Then filepath.Glob and fs.Glob make a single validity-checking call to Match before beginning their usual processing. Also update fstest.TestFS to check for correct validation in custom Glob implementations. Fixes #28614. Change-Id: Ic1d35a4bb9c3565184ae83dbefc425c5c96318e7 Reviewed-on: https://go-review.googlesource.com/c/go/+/264397 Trust: Russ Cox Reviewed-by: Rob Pike --- src/io/fs/glob.go | 4 +++ src/io/fs/glob_test.go | 10 +++++-- src/path/filepath/match.go | 61 +++++++++++++++++++++++++---------------- src/path/filepath/match_test.go | 12 +++++--- src/path/match.go | 60 +++++++++++++++++++++++++++------------- src/path/match_test.go | 4 ++- src/testing/fstest/testfs.go | 6 ++++ 7 files changed, 106 insertions(+), 51 deletions(-) (limited to 'src/io') diff --git a/src/io/fs/glob.go b/src/io/fs/glob.go index 77f6ebbaaf..cde6c49f3d 100644 --- a/src/io/fs/glob.go +++ b/src/io/fs/glob.go @@ -36,6 +36,10 @@ func Glob(fsys FS, pattern string) (matches []string, err error) { return fsys.Glob(pattern) } + // Check pattern is well-formed. + if _, err := path.Match(pattern, ""); err != nil { + return nil, err + } if !hasMeta(pattern) { if _, err = Stat(fsys, pattern); err != nil { return nil, nil diff --git a/src/io/fs/glob_test.go b/src/io/fs/glob_test.go index 0183a49b6c..5c8ac3fbf3 100644 --- a/src/io/fs/glob_test.go +++ b/src/io/fs/glob_test.go @@ -7,6 +7,7 @@ package fs_test import ( . "io/fs" "os" + "path" "testing" ) @@ -44,9 +45,12 @@ func TestGlob(t *testing.T) { } func TestGlobError(t *testing.T) { - _, err := Glob(os.DirFS("."), "[]") - if err == nil { - t.Error("expected error for bad pattern; got none") + bad := []string{`[]`, `nonexist/[]`} + for _, pattern := range bad { + _, err := Glob(os.DirFS("."), pattern) + if err != path.ErrBadPattern { + t.Errorf("Glob(fs, %#q) returned err=%v, want path.ErrBadPattern", pattern, err) + } } } diff --git a/src/path/filepath/match.go b/src/path/filepath/match.go index 20a334805b..c77a26952a 100644 --- a/src/path/filepath/match.go +++ b/src/path/filepath/match.go @@ -122,25 +122,28 @@ Scan: // If so, it returns the remainder of s (after the match). // Chunk is all single-character operators: literals, char classes, and ?. func matchChunk(chunk, s string) (rest string, ok bool, err error) { + // failed records whether the match has failed. + // After the match fails, the loop continues on processing chunk, + // checking that the pattern is well-formed but no longer reading s. + failed := false for len(chunk) > 0 { - if len(s) == 0 { - return + if !failed && len(s) == 0 { + failed = true } switch chunk[0] { case '[': // character class - r, n := utf8.DecodeRuneInString(s) - s = s[n:] - chunk = chunk[1:] - // We can't end right after '[', we're expecting at least - // a closing bracket and possibly a caret. - if len(chunk) == 0 { - err = ErrBadPattern - return + var r rune + if !failed { + var n int + r, n = utf8.DecodeRuneInString(s) + s = s[n:] } + chunk = chunk[1:] // possibly negated - negated := chunk[0] == '^' - if negated { + negated := false + if len(chunk) > 0 && chunk[0] == '^' { + negated = true chunk = chunk[1:] } // parse all ranges @@ -153,12 +156,12 @@ func matchChunk(chunk, s string) (rest string, ok bool, err error) { } var lo, hi rune if lo, chunk, err = getEsc(chunk); err != nil { - return + return "", false, err } hi = lo if chunk[0] == '-' { if hi, chunk, err = getEsc(chunk[1:]); err != nil { - return + return "", false, err } } if lo <= r && r <= hi { @@ -167,35 +170,41 @@ func matchChunk(chunk, s string) (rest string, ok bool, err error) { nrange++ } if match == negated { - return + failed = true } case '?': - if s[0] == Separator { - return + if !failed { + if s[0] == Separator { + failed = true + } + _, n := utf8.DecodeRuneInString(s) + s = s[n:] } - _, n := utf8.DecodeRuneInString(s) - s = s[n:] chunk = chunk[1:] case '\\': if runtime.GOOS != "windows" { chunk = chunk[1:] if len(chunk) == 0 { - err = ErrBadPattern - return + return "", false, ErrBadPattern } } fallthrough default: - if chunk[0] != s[0] { - return + if !failed { + if chunk[0] != s[0] { + failed = true + } + s = s[1:] } - s = s[1:] chunk = chunk[1:] } } + if failed { + return "", false, nil + } return s, true, nil } @@ -232,6 +241,10 @@ func getEsc(chunk string) (r rune, nchunk string, err error) { // The only possible returned error is ErrBadPattern, when pattern // is malformed. func Glob(pattern string) (matches []string, err error) { + // Check pattern is well-formed. + if _, err := Match(pattern, ""); err != nil { + return nil, err + } if !hasMeta(pattern) { if _, err = os.Lstat(pattern); err != nil { return nil, nil diff --git a/src/path/filepath/match_test.go b/src/path/filepath/match_test.go index b8657626bc..1c3b567fa3 100644 --- a/src/path/filepath/match_test.go +++ b/src/path/filepath/match_test.go @@ -75,8 +75,10 @@ var matchTests = []MatchTest{ {"[", "a", false, ErrBadPattern}, {"[^", "a", false, ErrBadPattern}, {"[^bc", "a", false, ErrBadPattern}, - {"a[", "a", false, nil}, + {"a[", "a", false, ErrBadPattern}, {"a[", "ab", false, ErrBadPattern}, + {"a[", "x", false, ErrBadPattern}, + {"a/b[", "x", false, ErrBadPattern}, {"*x", "xxx", true, nil}, } @@ -155,9 +157,11 @@ func TestGlob(t *testing.T) { } func TestGlobError(t *testing.T) { - _, err := Glob("[]") - if err == nil { - t.Error("expected error for bad pattern; got none") + bad := []string{`[]`, `nonexist/[]`} + for _, pattern := range bad { + if _, err := Glob(pattern); err != ErrBadPattern { + t.Errorf("Glob(%#q) returned err=%v, want ErrBadPattern", pattern, err) + } } } diff --git a/src/path/match.go b/src/path/match.go index 837eb8bb8b..918624c60e 100644 --- a/src/path/match.go +++ b/src/path/match.go @@ -75,6 +75,14 @@ Pattern: } } } + // Before returning false with no error, + // check that the remainder of the pattern is syntactically valid. + for len(pattern) > 0 { + _, chunk, pattern = scanChunk(pattern) + if _, _, err := matchChunk(chunk, ""); err != nil { + return false, err + } + } return false, nil } return len(name) == 0, nil @@ -114,20 +122,28 @@ Scan: // If so, it returns the remainder of s (after the match). // Chunk is all single-character operators: literals, char classes, and ?. func matchChunk(chunk, s string) (rest string, ok bool, err error) { + // failed records whether the match has failed. + // After the match fails, the loop continues on processing chunk, + // checking that the pattern is well-formed but no longer reading s. + failed := false for len(chunk) > 0 { - if len(s) == 0 { - return + if !failed && len(s) == 0 { + failed = true } switch chunk[0] { case '[': // character class - r, n := utf8.DecodeRuneInString(s) - s = s[n:] + var r rune + if !failed { + var n int + r, n = utf8.DecodeRuneInString(s) + s = s[n:] + } chunk = chunk[1:] // possibly negated - notNegated := true + negated := false if len(chunk) > 0 && chunk[0] == '^' { - notNegated = false + negated = true chunk = chunk[1:] } // parse all ranges @@ -140,12 +156,12 @@ func matchChunk(chunk, s string) (rest string, ok bool, err error) { } var lo, hi rune if lo, chunk, err = getEsc(chunk); err != nil { - return + return "", false, err } hi = lo if chunk[0] == '-' { if hi, chunk, err = getEsc(chunk[1:]); err != nil { - return + return "", false, err } } if lo <= r && r <= hi { @@ -153,34 +169,40 @@ func matchChunk(chunk, s string) (rest string, ok bool, err error) { } nrange++ } - if match != notNegated { - return + if match == negated { + failed = true } case '?': - if s[0] == '/' { - return + if !failed { + if s[0] == '/' { + failed = true + } + _, n := utf8.DecodeRuneInString(s) + s = s[n:] } - _, n := utf8.DecodeRuneInString(s) - s = s[n:] chunk = chunk[1:] case '\\': chunk = chunk[1:] if len(chunk) == 0 { - err = ErrBadPattern - return + return "", false, ErrBadPattern } fallthrough default: - if chunk[0] != s[0] { - return + if !failed { + if chunk[0] != s[0] { + failed = true + } + s = s[1:] } - s = s[1:] chunk = chunk[1:] } } + if failed { + return "", false, nil + } return s, true, nil } diff --git a/src/path/match_test.go b/src/path/match_test.go index 3e027e1f68..996bd691eb 100644 --- a/src/path/match_test.go +++ b/src/path/match_test.go @@ -67,8 +67,10 @@ var matchTests = []MatchTest{ {"[", "a", false, ErrBadPattern}, {"[^", "a", false, ErrBadPattern}, {"[^bc", "a", false, ErrBadPattern}, - {"a[", "a", false, nil}, + {"a[", "a", false, ErrBadPattern}, {"a[", "ab", false, ErrBadPattern}, + {"a[", "x", false, ErrBadPattern}, + {"a/b[", "x", false, ErrBadPattern}, {"*x", "xxx", true, nil}, } diff --git a/src/testing/fstest/testfs.go b/src/testing/fstest/testfs.go index 21cd00e5b6..4912a271b2 100644 --- a/src/testing/fstest/testfs.go +++ b/src/testing/fstest/testfs.go @@ -282,6 +282,12 @@ func (t *fsTester) checkGlob(dir string, list []fs.DirEntry) { glob = strings.Join(elem, "/") + "/" } + // Test that malformed patterns are detected. + // The error is likely path.ErrBadPattern but need not be. + if _, err := t.fsys.(fs.GlobFS).Glob(glob + "nonexist/[]"); err == nil { + t.errorf("%s: Glob(%#q): bad pattern not detected", dir, glob+"nonexist/[]") + } + // Try to find a letter that appears in only some of the final names. c := rune('a') for ; c <= 'z'; c++ { -- cgit v1.3 From 362d25f2c82980860cb4eb5bfd0648116504788d Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sun, 19 Jul 2020 01:31:05 -0400 Subject: io/fs: add WalkDir This commit is a copy of filepath.WalkDir adapted to use fs.FS instead of the native OS file system. It is the last implementation piece of the io/fs proposal. The original io/fs proposal was to adopt filepath.Walk, but we have since introduced the more efficient filepath.WalkDir (#42027), so this CL adopts that more efficient option instead. (The changes in path/filepath bring the two copies more in line with each other. The main change is unembedding the field in statDirEntry, so that the fs.DirEntry passed to the WalkDirFunc for the root of the tree does not have any extra methods.) For #41190. Change-Id: I9359dfcc110338c0ec64535f22cafb38d0b613a6 Reviewed-on: https://go-review.googlesource.com/c/go/+/243916 Trust: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Go Bot Reviewed-by: Rob Pike --- src/io/fs/walk.go | 132 +++++++++++++++++++++++++++++++++ src/io/fs/walk_test.go | 155 +++++++++++++++++++++++++++++++++++++++ src/path/filepath/export_test.go | 2 - src/path/filepath/path.go | 77 +++---------------- src/path/filepath/path_test.go | 15 +++- 5 files changed, 310 insertions(+), 71 deletions(-) create mode 100644 src/io/fs/walk.go create mode 100644 src/io/fs/walk_test.go (limited to 'src/io') diff --git a/src/io/fs/walk.go b/src/io/fs/walk.go new file mode 100644 index 0000000000..e50c1bb15c --- /dev/null +++ b/src/io/fs/walk.go @@ -0,0 +1,132 @@ +// Copyright 2020 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 fs + +import ( + "errors" + "path" +) + +// SkipDir is used as a return value from WalkFuncs to indicate that +// the directory named in the call is to be skipped. It is not returned +// as an error by any function. +var SkipDir = errors.New("skip this directory") + +// WalkDirFunc is the type of the function called by WalkDir to visit +// each each file or directory. +// +// The path argument contains the argument to Walk as a prefix. +// That is, if Walk is called with root argument "dir" and finds a file +// named "a" in that directory, the walk function will be called with +// argument "dir/a". +// +// The directory and file are joined with Join, which may clean the +// directory name: if Walk is called with the root argument "x/../dir" +// and finds a file named "a" in that directory, the walk function will +// be called with argument "dir/a", not "x/../dir/a". +// +// The d argument is the fs.DirEntry for the named path. +// +// The error result returned by the function controls how WalkDir +// continues. If the function returns the special value SkipDir, WalkDir +// skips the current directory (path if d.IsDir() is true, otherwise +// path's parent directory). Otherwise, if the function returns a non-nil +// error, WalkDir stops entirely and returns that error. +// +// The err argument reports an error related to path, signaling that +// WalkDir will not walk into that directory. The function can decide how +// to handle that error; as described earlier, returning the error will +// cause WalkDir to stop walking the entire tree. +// +// WalkDir calls the function with a non-nil err argument in two cases. +// +// First, if the initial os.Lstat on the root directory fails, WalkDir +// calls the function with path set to root, d set to nil, and err set to +// the error from os.Lstat. +// +// Second, if a directory's ReadDir method fails, WalkDir calls the +// function with path set to the directory's path, d set to an +// fs.DirEntry describing the directory, and err set to the error from +// ReadDir. In this second case, the function is called twice with the +// path of the directory: the first call is before the directory read is +// attempted and has err set to nil, giving the function a chance to +// return SkipDir and avoid the ReadDir entirely. The second call is +// after a failed ReadDir and reports the error from ReadDir. +// (If ReadDir succeeds, there is no second call.) +// +// The differences between WalkDirFunc compared to WalkFunc are: +// +// - The second argument has type fs.DirEntry instead of fs.FileInfo. +// - The function is called before reading a directory, to allow SkipDir +// to bypass the directory read entirely. +// - If a directory read fails, the function is called a second time +// for that directory to report the error. +// +type WalkDirFunc func(path string, entry DirEntry, err error) error + +// walkDir recursively descends path, calling walkDirFn. +func walkDir(fsys FS, name string, d DirEntry, walkDirFn WalkDirFunc) error { + if err := walkDirFn(name, d, nil); err != nil || !d.IsDir() { + if err == SkipDir && d.IsDir() { + // Successfully skipped directory. + err = nil + } + return err + } + + dirs, err := ReadDir(fsys, name) + if err != nil { + // Second call, to report ReadDir error. + err = walkDirFn(name, d, err) + if err != nil { + return err + } + } + + for _, d1 := range dirs { + name1 := path.Join(name, d1.Name()) + if err := walkDir(fsys, name1, d1, walkDirFn); err != nil { + if err == SkipDir { + break + } + return err + } + } + return nil +} + +// WalkDir walks the file tree rooted at root, calling fn for each file or +// directory in the tree, including root. +// +// All errors that arise visiting files and directories are filtered by fn: +// see the fs.WalkDirFunc documentation for details. +// +// The files are walked in lexical order, which makes the output deterministic +// but requires WalkDir to read an entire directory into memory before proceeding +// to walk that directory. +// +// WalkDir does not follow symbolic links found in directories, +// but if root itself is a symbolic link, its target will be walked. +func WalkDir(fsys FS, root string, fn WalkDirFunc) error { + info, err := Stat(fsys, root) + if err != nil { + err = fn(root, nil, err) + } else { + err = walkDir(fsys, root, &statDirEntry{info}, fn) + } + if err == SkipDir { + return nil + } + return err +} + +type statDirEntry struct { + info FileInfo +} + +func (d *statDirEntry) Name() string { return d.info.Name() } +func (d *statDirEntry) IsDir() bool { return d.info.IsDir() } +func (d *statDirEntry) Type() FileMode { return d.info.Mode().Type() } +func (d *statDirEntry) Info() (FileInfo, error) { return d.info, nil } diff --git a/src/io/fs/walk_test.go b/src/io/fs/walk_test.go new file mode 100644 index 0000000000..395471e2e8 --- /dev/null +++ b/src/io/fs/walk_test.go @@ -0,0 +1,155 @@ +// Copyright 2020 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 fs_test + +import ( + . "io/fs" + "io/ioutil" + "os" + pathpkg "path" + "runtime" + "testing" + "testing/fstest" +) + +type Node struct { + name string + entries []*Node // nil if the entry is a file + mark int +} + +var tree = &Node{ + "testdata", + []*Node{ + {"a", nil, 0}, + {"b", []*Node{}, 0}, + {"c", nil, 0}, + { + "d", + []*Node{ + {"x", nil, 0}, + {"y", []*Node{}, 0}, + { + "z", + []*Node{ + {"u", nil, 0}, + {"v", nil, 0}, + }, + 0, + }, + }, + 0, + }, + }, + 0, +} + +func walkTree(n *Node, path string, f func(path string, n *Node)) { + f(path, n) + for _, e := range n.entries { + walkTree(e, pathpkg.Join(path, e.name), f) + } +} + +func makeTree(t *testing.T) FS { + fsys := fstest.MapFS{} + walkTree(tree, tree.name, func(path string, n *Node) { + if n.entries == nil { + fsys[path] = &fstest.MapFile{} + } else { + fsys[path] = &fstest.MapFile{Mode: ModeDir} + } + }) + return fsys +} + +func markTree(n *Node) { walkTree(n, "", func(path string, n *Node) { n.mark++ }) } + +func checkMarks(t *testing.T, report bool) { + walkTree(tree, tree.name, func(path string, n *Node) { + if n.mark != 1 && report { + t.Errorf("node %s mark = %d; expected 1", path, n.mark) + } + n.mark = 0 + }) +} + +// Assumes that each node name is unique. Good enough for a test. +// If clear is true, any incoming error is cleared before return. The errors +// are always accumulated, though. +func mark(entry DirEntry, err error, errors *[]error, clear bool) error { + name := entry.Name() + walkTree(tree, tree.name, func(path string, n *Node) { + if n.name == name { + n.mark++ + } + }) + if err != nil { + *errors = append(*errors, err) + if clear { + return nil + } + return err + } + return nil +} + +func chtmpdir(t *testing.T) (restore func()) { + oldwd, err := os.Getwd() + if err != nil { + t.Fatalf("chtmpdir: %v", err) + } + d, err := ioutil.TempDir("", "test") + if err != nil { + t.Fatalf("chtmpdir: %v", err) + } + if err := os.Chdir(d); err != nil { + t.Fatalf("chtmpdir: %v", err) + } + return func() { + if err := os.Chdir(oldwd); err != nil { + t.Fatalf("chtmpdir: %v", err) + } + os.RemoveAll(d) + } +} + +func TestWalkDir(t *testing.T) { + if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" { + restore := chtmpdir(t) + defer restore() + } + + tmpDir, err := ioutil.TempDir("", "TestWalk") + if err != nil { + t.Fatal("creating temp dir:", err) + } + defer os.RemoveAll(tmpDir) + + origDir, err := os.Getwd() + if err != nil { + t.Fatal("finding working dir:", err) + } + if err = os.Chdir(tmpDir); err != nil { + t.Fatal("entering temp dir:", err) + } + defer os.Chdir(origDir) + + fsys := makeTree(t) + errors := make([]error, 0, 10) + clear := true + markFn := func(path string, entry DirEntry, err error) error { + return mark(entry, err, &errors, clear) + } + // Expect no errors. + err = WalkDir(fsys, ".", markFn) + if err != nil { + t.Fatalf("no error expected, found: %s", err) + } + if len(errors) != 0 { + t.Fatalf("unexpected errors: %s", errors) + } + checkMarks(t, true) +} diff --git a/src/path/filepath/export_test.go b/src/path/filepath/export_test.go index e7ad7dd01a..0cf9e3bca1 100644 --- a/src/path/filepath/export_test.go +++ b/src/path/filepath/export_test.go @@ -5,5 +5,3 @@ package filepath var LstatP = &lstat - -type DirEntryFromInfo = dirEntryFromInfo diff --git a/src/path/filepath/path.go b/src/path/filepath/path.go index 3f7e5c713d..2e7b439355 100644 --- a/src/path/filepath/path.go +++ b/src/path/filepath/path.go @@ -334,59 +334,7 @@ func Rel(basepath, targpath string) (string, error) { // SkipDir is used as a return value from WalkFuncs to indicate that // the directory named in the call is to be skipped. It is not returned // as an error by any function. -var SkipDir = errors.New("skip this directory") - -// WalkDirFunc is the type of the function called by WalkDir to visit -// each each file or directory. -// -// The path argument contains the argument to Walk as a prefix. -// That is, if Walk is called with root argument "dir" and finds a file -// named "a" in that directory, the walk function will be called with -// argument "dir/a". -// -// The directory and file are joined with Join, which may clean the -// directory name: if Walk is called with the root argument "x/../dir" -// and finds a file named "a" in that directory, the walk function will -// be called with argument "dir/a", not "x/../dir/a". -// -// The d argument is the fs.DirEntry for the named path. -// -// The error result returned by the function controls how WalkDir -// continues. If the function returns the special value SkipDir, WalkDir -// skips the current directory (path if d.IsDir() is true, otherwise -// path's parent directory). Otherwise, if the function returns a non-nil -// error, WalkDir stops entirely and returns that error. -// -// The err argument reports an error related to path, signaling that -// WalkDir will not walk into that directory. The function can decide how -// to handle that error; as described earlier, returning the error will -// cause WalkDir to stop walking the entire tree. -// -// WalkDir calls the function with a non-nil err argument in two cases. -// -// First, if the initial os.Lstat on the root directory fails, WalkDir -// calls the function with path set to root, d set to nil, and err set to -// the error from os.Lstat. -// -// Second, if a directory's ReadDir method fails, WalkDir calls the -// function with path set to the directory's path, d set to an -// fs.DirEntry describing the directory, and err set to the error from -// ReadDir. In this second case, the function is called twice with the -// path of the directory: the first call is before the directory read is -// attempted and has err set to nil, giving the function a chance to -// return SkipDir and avoid the ReadDir entirely. The second call is -// after a failed ReadDir and reports the error from ReadDir. -// (If ReadDir succeeds, there is no second call.) -// -// The differences between WalkDirFunc compared to WalkFunc are: -// -// - The second argument has type fs.DirEntry instead of fs.FileInfo. -// - The function is called before reading a directory, to allow SkipDir -// to bypass the directory read entirely. -// - If a directory read fails, the function is called a second time -// for that directory to report the error. -// -type WalkDirFunc func(path string, d fs.DirEntry, err error) error +var SkipDir error = fs.SkipDir // WalkFunc is the type of the function called by Walk to visit each each // file or directory. @@ -430,7 +378,7 @@ type WalkFunc func(path string, info fs.FileInfo, err error) error var lstat = os.Lstat // for testing // walkDir recursively descends path, calling walkDirFn. -func walkDir(path string, d fs.DirEntry, walkDirFn WalkDirFunc) error { +func walkDir(path string, d fs.DirEntry, walkDirFn fs.WalkDirFunc) error { if err := walkDirFn(path, d, nil); err != nil || !d.IsDir() { if err == SkipDir && d.IsDir() { // Successfully skipped directory. @@ -502,19 +450,19 @@ func walk(path string, info fs.FileInfo, walkFn WalkFunc) error { // directory in the tree, including root. // // All errors that arise visiting files and directories are filtered by fn: -// see the WalkDirFunc documentation for details. +// see the fs.WalkDirFunc documentation for details. // // The files are walked in lexical order, which makes the output deterministic // but requires WalkDir to read an entire directory into memory before proceeding // to walk that directory. // // WalkDir does not follow symbolic links. -func WalkDir(root string, fn WalkDirFunc) error { +func WalkDir(root string, fn fs.WalkDirFunc) error { info, err := os.Lstat(root) if err != nil { err = fn(root, nil, err) } else { - err = walkDir(root, &dirEntryFromInfo{info}, fn) + err = walkDir(root, &statDirEntry{info}, fn) } if err == SkipDir { return nil @@ -522,17 +470,14 @@ func WalkDir(root string, fn WalkDirFunc) error { return err } -type dirEntryFromInfo struct { - fs.FileInfo +type statDirEntry struct { + info fs.FileInfo } -func (e *dirEntryFromInfo) Type() fs.FileMode { - return e.Mode().Type() -} - -func (e *dirEntryFromInfo) Info() (fs.FileInfo, error) { - return e.FileInfo, nil -} +func (d *statDirEntry) Name() string { return d.info.Name() } +func (d *statDirEntry) IsDir() bool { return d.info.IsDir() } +func (d *statDirEntry) Type() fs.FileMode { return d.info.Mode().Type() } +func (d *statDirEntry) Info() (fs.FileInfo, error) { return d.info, nil } // Walk walks the file tree rooted at root, calling fn for each file or // directory in the tree, including root. diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go index ec6f8f2de9..d760530e26 100644 --- a/src/path/filepath/path_test.go +++ b/src/path/filepath/path_test.go @@ -432,19 +432,28 @@ func chtmpdir(t *testing.T) (restore func()) { } func TestWalk(t *testing.T) { - walk := func(root string, fn filepath.WalkDirFunc) error { + walk := func(root string, fn fs.WalkDirFunc) error { return filepath.Walk(root, func(path string, info fs.FileInfo, err error) error { - return fn(path, &filepath.DirEntryFromInfo{info}, err) + return fn(path, &statDirEntry{info}, err) }) } testWalk(t, walk, 1) } +type statDirEntry struct { + info fs.FileInfo +} + +func (d *statDirEntry) Name() string { return d.info.Name() } +func (d *statDirEntry) IsDir() bool { return d.info.IsDir() } +func (d *statDirEntry) Type() fs.FileMode { return d.info.Mode().Type() } +func (d *statDirEntry) Info() (fs.FileInfo, error) { return d.info, nil } + func TestWalkDir(t *testing.T) { testWalk(t, filepath.WalkDir, 2) } -func testWalk(t *testing.T, walk func(string, filepath.WalkDirFunc) error, errVisit int) { +func testWalk(t *testing.T, walk func(string, fs.WalkDirFunc) error, errVisit int) { if runtime.GOOS == "ios" { restore := chtmpdir(t) defer restore() -- cgit v1.3 From c906608406f22087e9bc3ee7616c3f1fbba2503b Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 9 Nov 2020 09:25:05 -0500 Subject: io/fs: fix reference to WalkFunc The comment explains differences between WalkDirFunc and WalkFunc, but when this code moved out of path/filepath, we forgot to change the reference to be filepath.WalkFunc. Fix that. (The text should not be deleted, because path/filepath does not contain this type - WalkDirFunc - nor this text anymore.) Pointed out by Carl Johnson on CL 243916 post-submit. For #41190. Change-Id: I44c64d0b7e60cd6d3694cfd6d0b95468ec4612fe Reviewed-on: https://go-review.googlesource.com/c/go/+/268417 Trust: Russ Cox Reviewed-by: Dmitri Shuralyov --- src/io/fs/walk.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/io') diff --git a/src/io/fs/walk.go b/src/io/fs/walk.go index e50c1bb15c..dfc73767bc 100644 --- a/src/io/fs/walk.go +++ b/src/io/fs/walk.go @@ -9,7 +9,7 @@ import ( "path" ) -// SkipDir is used as a return value from WalkFuncs to indicate that +// SkipDir is used as a return value from WalkDirFuncs to indicate that // the directory named in the call is to be skipped. It is not returned // as an error by any function. var SkipDir = errors.New("skip this directory") @@ -56,7 +56,7 @@ var SkipDir = errors.New("skip this directory") // after a failed ReadDir and reports the error from ReadDir. // (If ReadDir succeeds, there is no second call.) // -// The differences between WalkDirFunc compared to WalkFunc are: +// The differences between WalkDirFunc compared to filepath.WalkFunc are: // // - The second argument has type fs.DirEntry instead of fs.FileInfo. // - The function is called before reading a directory, to allow SkipDir -- cgit v1.3 From f3ce010b331513b4dca26a12dc0fd12dc4385d9c Mon Sep 17 00:00:00 2001 From: fzipp Date: Sun, 8 Nov 2020 13:50:30 +0000 Subject: io/fs: make WalkDirFunc parameter name consistent with doc comment The the DirEntry parameter of WalkDirFunc is referred to as `d` in the doc comment. Change-Id: Ibfcf7908eaa0ef1309898150e8fd71101e7de09b GitHub-Last-Rev: e858c52d81b93d293621d7e744bdcb7d6cbd412c GitHub-Pull-Request: golang/go#42447 Reviewed-on: https://go-review.googlesource.com/c/go/+/268277 Trust: Emmanuel Odeke Reviewed-by: Russ Cox --- src/io/fs/walk.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/io') diff --git a/src/io/fs/walk.go b/src/io/fs/walk.go index dfc73767bc..06d0b1769c 100644 --- a/src/io/fs/walk.go +++ b/src/io/fs/walk.go @@ -64,7 +64,7 @@ var SkipDir = errors.New("skip this directory") // - If a directory read fails, the function is called a second time // for that directory to report the error. // -type WalkDirFunc func(path string, entry DirEntry, err error) error +type WalkDirFunc func(path string, d DirEntry, err error) error // walkDir recursively descends path, calling walkDirFn. func walkDir(fsys FS, name string, d DirEntry, walkDirFn WalkDirFunc) error { -- cgit v1.3 From 3d913a926675d8d6fcdc3cfaefd3136dfeba06e1 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Thu, 29 Oct 2020 13:51:20 -0400 Subject: os: add ReadFile, WriteFile, CreateTemp (was TempFile), MkdirTemp (was TempDir) from io/ioutil io/ioutil was a poorly defined collection of helpers. Proposal #40025 moved out the generic I/O helpers to io. This CL for proposal #42026 moves the OS-specific helpers to os, making the entire io/ioutil package deprecated. For #42026. Change-Id: I018bcb2115ef2ff1bc7ca36a9247eda429af21ad Reviewed-on: https://go-review.googlesource.com/c/go/+/266364 Trust: Russ Cox Trust: Emmanuel Odeke Run-TryBot: Russ Cox TryBot-Result: Go Bot Reviewed-by: Emmanuel Odeke --- src/io/ioutil/ioutil.go | 70 +++++------------ src/os/dir.go | 22 +++++- src/os/example_test.go | 96 +++++++++++++++++++++++ src/os/export_test.go | 1 + src/os/file.go | 60 +++++++++++++++ src/os/os_test.go | 26 ++++++- src/os/read_test.go | 127 +++++++++++++++++++++++++++++++ src/os/removeall_test.go | 7 +- src/os/tempfile.go | 118 +++++++++++++++++++++++++++++ src/os/tempfile_test.go | 193 +++++++++++++++++++++++++++++++++++++++++++++++ src/os/testdata/hello | 1 + src/runtime/stubs.go | 3 + 12 files changed, 666 insertions(+), 58 deletions(-) create mode 100644 src/os/read_test.go create mode 100644 src/os/tempfile.go create mode 100644 src/os/tempfile_test.go create mode 100644 src/os/testdata/hello (limited to 'src/io') diff --git a/src/io/ioutil/ioutil.go b/src/io/ioutil/ioutil.go index a001c86b2f..45682b89c9 100644 --- a/src/io/ioutil/ioutil.go +++ b/src/io/ioutil/ioutil.go @@ -3,6 +3,11 @@ // license that can be found in the LICENSE file. // Package ioutil implements some I/O utility functions. +// +// As of Go 1.16, the same functionality is now provided +// by package io or package os, and those implementations +// should be preferred in new code. +// See the specific function documentation for details. package ioutil import ( @@ -26,67 +31,30 @@ func ReadAll(r io.Reader) ([]byte, error) { // A successful call returns err == nil, not err == EOF. Because ReadFile // reads the whole file, it does not treat an EOF from Read as an error // to be reported. +// +// As of Go 1.16, this function simply calls os.ReadFile. func ReadFile(filename string) ([]byte, error) { - f, err := os.Open(filename) - if err != nil { - return nil, err - } - defer f.Close() - // It's a good but not certain bet that FileInfo will tell us exactly how much to - // read, so let's try it but be prepared for the answer to be wrong. - const minRead = 512 - var n int64 = minRead - - if fi, err := f.Stat(); err == nil { - // As initial capacity for readAll, use Size + a little extra in case Size - // is zero, and to avoid another allocation after Read has filled the - // buffer. The readAll call will read into its allocated internal buffer - // cheaply. If the size was wrong, we'll either waste some space off the end - // or reallocate as needed, but in the overwhelmingly common case we'll get - // it just right. - if size := fi.Size() + minRead; size > n { - n = size - } - } - - if int64(int(n)) != n { - n = minRead - } - - b := make([]byte, 0, n) - for { - if len(b) == cap(b) { - // Add more capacity (let append pick how much). - b = append(b, 0)[:len(b)] - } - n, err := f.Read(b[len(b):cap(b)]) - b = b[:len(b)+n] - if err != nil { - if err == io.EOF { - err = nil - } - return b, err - } - } + return os.ReadFile(filename) } // WriteFile writes data to a file named by filename. // If the file does not exist, WriteFile creates it with permissions perm // (before umask); otherwise WriteFile truncates it before writing, without changing permissions. +// +// As of Go 1.16, this function simply calls os.WriteFile. func WriteFile(filename string, data []byte, perm fs.FileMode) error { - f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm) - if err != nil { - return err - } - _, err = f.Write(data) - if err1 := f.Close(); err == nil { - err = err1 - } - return err + return os.WriteFile(filename, data, perm) } // ReadDir reads the directory named by dirname and returns -// a list of directory entries sorted by filename. +// a list of fs.FileInfo for the directory's contents, +// sorted by filename. If an error occurs reading the directory, +// ReadDir returns no directory entries along with the error. +// +// As of Go 1.16, os.ReadDir is a more efficient and correct choice: +// it returns a list of fs.DirEntry instead of fs.FileInfo, +// and it returns partial results in the case of an error +// midway through reading a directory. func ReadDir(dirname string) ([]fs.FileInfo, error) { f, err := os.Open(dirname) if err != nil { diff --git a/src/os/dir.go b/src/os/dir.go index 1d90b970e7..5306bcb3ba 100644 --- a/src/os/dir.go +++ b/src/os/dir.go @@ -4,7 +4,10 @@ package os -import "io/fs" +import ( + "io/fs" + "sort" +) type readdirMode int @@ -103,3 +106,20 @@ func (f *File) ReadDir(n int) ([]DirEntry, error) { // testingForceReadDirLstat forces ReadDir to call Lstat, for testing that code path. // This can be difficult to provoke on some Unix systems otherwise. var testingForceReadDirLstat bool + +// ReadDir reads the named directory, +// returning all its directory entries sorted by filename. +// If an error occurs reading the directory, +// ReadDir returns the entries it was able to read before the error, +// along with the error. +func ReadDir(name string) ([]DirEntry, error) { + f, err := Open(name) + if err != nil { + return nil, err + } + defer f.Close() + + dirs, err := f.ReadDir(-1) + sort.Slice(dirs, func(i, j int) bool { return dirs[i].Name() < dirs[j].Name() }) + return dirs, err +} diff --git a/src/os/example_test.go b/src/os/example_test.go index fbb277b6f1..3adce51784 100644 --- a/src/os/example_test.go +++ b/src/os/example_test.go @@ -9,6 +9,7 @@ import ( "io/fs" "log" "os" + "path/filepath" "time" ) @@ -144,3 +145,98 @@ func ExampleUnsetenv() { os.Setenv("TMPDIR", "/my/tmp") defer os.Unsetenv("TMPDIR") } + +func ExampleReadDir() { + files, err := os.ReadDir(".") + if err != nil { + log.Fatal(err) + } + + for _, file := range files { + fmt.Println(file.Name()) + } +} + +func ExampleMkdirTemp() { + dir, err := os.MkdirTemp("", "example") + if err != nil { + log.Fatal(err) + } + defer os.RemoveAll(dir) // clean up + + file := filepath.Join(dir, "tmpfile") + if err := os.WriteFile(file, []byte("content"), 0666); err != nil { + log.Fatal(err) + } +} + +func ExampleMkdirTemp_suffix() { + logsDir, err := os.MkdirTemp("", "*-logs") + if err != nil { + log.Fatal(err) + } + defer os.RemoveAll(logsDir) // clean up + + // Logs can be cleaned out earlier if needed by searching + // for all directories whose suffix ends in *-logs. + globPattern := filepath.Join(os.TempDir(), "*-logs") + matches, err := filepath.Glob(globPattern) + if err != nil { + log.Fatalf("Failed to match %q: %v", globPattern, err) + } + + for _, match := range matches { + if err := os.RemoveAll(match); err != nil { + log.Printf("Failed to remove %q: %v", match, err) + } + } +} + +func ExampleCreateTemp() { + f, err := os.CreateTemp("", "example") + if err != nil { + log.Fatal(err) + } + defer os.Remove(f.Name()) // clean up + + if _, err := f.Write([]byte("content")); err != nil { + log.Fatal(err) + } + if err := f.Close(); err != nil { + log.Fatal(err) + } +} + +func ExampleCreateTemp_suffix() { + f, err := os.CreateTemp("", "example.*.txt") + if err != nil { + log.Fatal(err) + } + defer os.Remove(f.Name()) // clean up + + if _, err := f.Write([]byte("content")); err != nil { + f.Close() + log.Fatal(err) + } + if err := f.Close(); err != nil { + log.Fatal(err) + } +} + +func ExampleReadFile() { + data, err := os.ReadFile("testdata/hello") + if err != nil { + log.Fatal(err) + } + os.Stdout.Write(data) + + // Output: + // Hello, Gophers! +} + +func ExampleWriteFile() { + err := os.WriteFile("testdata/hello", []byte("Hello, Gophers!"), 0666) + if err != nil { + log.Fatal(err) + } +} diff --git a/src/os/export_test.go b/src/os/export_test.go index d66264a68f..f3cb1a2bef 100644 --- a/src/os/export_test.go +++ b/src/os/export_test.go @@ -10,3 +10,4 @@ var Atime = atime var LstatP = &lstat var ErrWriteAtInAppendMode = errWriteAtInAppendMode var TestingForceReadDirLstat = &testingForceReadDirLstat +var ErrPatternHasSeparator = errPatternHasSeparator diff --git a/src/os/file.go b/src/os/file.go index 420e62ef2c..304b055dbe 100644 --- a/src/os/file.go +++ b/src/os/file.go @@ -625,3 +625,63 @@ func (dir dirFS) Open(name string) (fs.File, error) { } return f, nil } + +// ReadFile reads the named file and returns the contents. +// A successful call returns err == nil, not err == EOF. +// Because ReadFile reads the whole file, it does not treat an EOF from Read +// as an error to be reported. +func ReadFile(name string) ([]byte, error) { + f, err := Open(name) + if err != nil { + return nil, err + } + defer f.Close() + + var size int + if info, err := f.Stat(); err == nil { + size64 := info.Size() + if int64(int(size64)) == size64 { + size = int(size64) + } + } + size++ // one byte for final read at EOF + + // If a file claims a small size, read at least 512 bytes. + // In particular, files in Linux's /proc claim size 0 but + // then do not work right if read in small pieces, + // so an initial read of 1 byte would not work correctly. + if size < 512 { + size = 512 + } + + data := make([]byte, 0, size) + for { + if len(data) >= cap(data) { + d := append(data[:cap(data)], 0) + data = d[:len(data)] + } + n, err := f.Read(data[len(data):cap(data)]) + data = data[:len(data)+n] + if err != nil { + if err == io.EOF { + err = nil + } + return data, err + } + } +} + +// WriteFile writes data to the named file, creating it if necessary. +// If the file does not exist, WriteFile creates it with permissions perm (before umask); +// otherwise WriteFile truncates it before writing, without changing permissions. +func WriteFile(name string, data []byte, perm FileMode) error { + f, err := OpenFile(name, O_WRONLY|O_CREATE|O_TRUNC, perm) + if err != nil { + return err + } + _, err = f.Write(data) + if err1 := f.Close(); err1 != nil && err == nil { + err = err1 + } + return err +} diff --git a/src/os/os_test.go b/src/os/os_test.go index a1c0578887..c5e5cbbb1b 100644 --- a/src/os/os_test.go +++ b/src/os/os_test.go @@ -419,19 +419,19 @@ func testReadDir(dir string, contents []string, t *testing.T) { } } -func TestReaddirnames(t *testing.T) { +func TestFileReaddirnames(t *testing.T) { testReaddirnames(".", dot, t) testReaddirnames(sysdir.name, sysdir.files, t) testReaddirnames(t.TempDir(), nil, t) } -func TestReaddir(t *testing.T) { +func TestFileReaddir(t *testing.T) { testReaddir(".", dot, t) testReaddir(sysdir.name, sysdir.files, t) testReaddir(t.TempDir(), nil, t) } -func TestReadDir(t *testing.T) { +func TestFileReadDir(t *testing.T) { testReadDir(".", dot, t) testReadDir(sysdir.name, sysdir.files, t) testReadDir(t.TempDir(), nil, t) @@ -1235,6 +1235,7 @@ func TestChmod(t *testing.T) { } func checkSize(t *testing.T, f *File, size int64) { + t.Helper() dir, err := f.Stat() if err != nil { t.Fatalf("Stat %q (looking for size %d): %s", f.Name(), size, err) @@ -2690,3 +2691,22 @@ func TestDirFS(t *testing.T) { t.Fatal(err) } } + +func TestReadFileProc(t *testing.T) { + // Linux files in /proc report 0 size, + // but then if ReadFile reads just a single byte at offset 0, + // the read at offset 1 returns EOF instead of more data. + // ReadFile has a minimum read size of 512 to work around this, + // but test explicitly that it's working. + name := "/proc/sys/fs/pipe-max-size" + if _, err := Stat(name); err != nil { + t.Skip(err) + } + data, err := ReadFile(name) + if err != nil { + t.Fatal(err) + } + if len(data) == 0 || data[len(data)-1] != '\n' { + t.Fatalf("read %s: not newline-terminated: %q", name, data) + } +} diff --git a/src/os/read_test.go b/src/os/read_test.go new file mode 100644 index 0000000000..5c58d7d7df --- /dev/null +++ b/src/os/read_test.go @@ -0,0 +1,127 @@ +// Copyright 2009 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 os_test + +import ( + "bytes" + . "os" + "path/filepath" + "testing" +) + +func checkNamedSize(t *testing.T, path string, size int64) { + dir, err := Stat(path) + if err != nil { + t.Fatalf("Stat %q (looking for size %d): %s", path, size, err) + } + if dir.Size() != size { + t.Errorf("Stat %q: size %d want %d", path, dir.Size(), size) + } +} + +func TestReadFile(t *testing.T) { + filename := "rumpelstilzchen" + contents, err := ReadFile(filename) + if err == nil { + t.Fatalf("ReadFile %s: error expected, none found", filename) + } + + filename = "read_test.go" + contents, err = ReadFile(filename) + if err != nil { + t.Fatalf("ReadFile %s: %v", filename, err) + } + + checkNamedSize(t, filename, int64(len(contents))) +} + +func TestWriteFile(t *testing.T) { + f, err := CreateTemp("", "ioutil-test") + if err != nil { + t.Fatal(err) + } + defer f.Close() + defer Remove(f.Name()) + + msg := "Programming today is a race between software engineers striving to " + + "build bigger and better idiot-proof programs, and the Universe trying " + + "to produce bigger and better idiots. So far, the Universe is winning." + + if err := WriteFile(f.Name(), []byte(msg), 0644); err != nil { + t.Fatalf("WriteFile %s: %v", f.Name(), err) + } + + data, err := ReadFile(f.Name()) + if err != nil { + t.Fatalf("ReadFile %s: %v", f.Name(), err) + } + + if string(data) != msg { + t.Fatalf("ReadFile: wrong data:\nhave %q\nwant %q", string(data), msg) + } +} + +func TestReadOnlyWriteFile(t *testing.T) { + if Getuid() == 0 { + t.Skipf("Root can write to read-only files anyway, so skip the read-only test.") + } + + // We don't want to use CreateTemp directly, since that opens a file for us as 0600. + tempDir, err := MkdirTemp("", t.Name()) + if err != nil { + t.Fatal(err) + } + defer RemoveAll(tempDir) + filename := filepath.Join(tempDir, "blurp.txt") + + shmorp := []byte("shmorp") + florp := []byte("florp") + err = WriteFile(filename, shmorp, 0444) + if err != nil { + t.Fatalf("WriteFile %s: %v", filename, err) + } + err = WriteFile(filename, florp, 0444) + if err == nil { + t.Fatalf("Expected an error when writing to read-only file %s", filename) + } + got, err := ReadFile(filename) + if err != nil { + t.Fatalf("ReadFile %s: %v", filename, err) + } + if !bytes.Equal(got, shmorp) { + t.Fatalf("want %s, got %s", shmorp, got) + } +} + +func TestReadDir(t *testing.T) { + dirname := "rumpelstilzchen" + _, err := ReadDir(dirname) + if err == nil { + t.Fatalf("ReadDir %s: error expected, none found", dirname) + } + + dirname = "." + list, err := ReadDir(dirname) + if err != nil { + t.Fatalf("ReadDir %s: %v", dirname, err) + } + + foundFile := false + foundSubDir := false + for _, dir := range list { + switch { + case !dir.IsDir() && dir.Name() == "read_test.go": + foundFile = true + case dir.IsDir() && dir.Name() == "exec": + foundSubDir = true + } + } + if !foundFile { + t.Fatalf("ReadDir %s: read_test.go file not found", dirname) + } + if !foundSubDir { + t.Fatalf("ReadDir %s: exec directory not found", dirname) + } +} diff --git a/src/os/removeall_test.go b/src/os/removeall_test.go index bc9c468ce3..90efa313ea 100644 --- a/src/os/removeall_test.go +++ b/src/os/removeall_test.go @@ -355,11 +355,12 @@ func TestRemoveAllButReadOnlyAndPathError(t *testing.T) { // 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) + want := filepath.Join(tempDir, "b", "y") + if pathErr.Path != want { + t.Errorf("RemoveAll(%q): err.Path=%q, want %q", tempDir, pathErr.Path, want) } } else { - t.Errorf("got %T, expected *fs.PathError", err) + t.Errorf("RemoveAll(%q): error has type %T, want *fs.PathError", tempDir, err) } for _, dir := range dirs { diff --git a/src/os/tempfile.go b/src/os/tempfile.go new file mode 100644 index 0000000000..2728485c32 --- /dev/null +++ b/src/os/tempfile.go @@ -0,0 +1,118 @@ +// Copyright 2010 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 os + +import ( + "errors" + "strings" +) + +// fastrand provided by runtime. +// We generate random temporary file names so that there's a good +// chance the file doesn't exist yet - keeps the number of tries in +// TempFile to a minimum. +func fastrand() uint32 + +func nextRandom() string { + return uitoa(uint(fastrand())) +} + +// CreateTemp creates a new temporary file in the directory dir, +// opens the file for reading and writing, and returns the resulting file. +// The filename is generated by taking pattern and adding a random string to the end. +// If pattern includes a "*", the random string replaces the last "*". +// If dir is the empty string, TempFile uses the default directory for temporary files, as returned by TempDir. +// Multiple programs or goroutines calling CreateTemp simultaneously will not choose the same file. +// The caller can use the file's Name method to find the pathname of the file. +// It is the caller's responsibility to remove the file when it is no longer needed. +func CreateTemp(dir, pattern string) (*File, error) { + if dir == "" { + dir = TempDir() + } + + prefix, suffix, err := prefixAndSuffix(pattern) + if err != nil { + return nil, &PathError{Op: "createtemp", Path: pattern, Err: err} + } + prefix = joinPath(dir, prefix) + + try := 0 + for { + name := prefix + nextRandom() + suffix + f, err := OpenFile(name, O_RDWR|O_CREATE|O_EXCL, 0600) + if IsExist(err) { + if try++; try < 10000 { + continue + } + return nil, &PathError{Op: "createtemp", Path: dir + string(PathSeparator) + prefix + "*" + suffix, Err: ErrExist} + } + return f, err + } +} + +var errPatternHasSeparator = errors.New("pattern contains path separator") + +// prefixAndSuffix splits pattern by the last wildcard "*", if applicable, +// returning prefix as the part before "*" and suffix as the part after "*". +func prefixAndSuffix(pattern string) (prefix, suffix string, err error) { + for i := 0; i < len(pattern); i++ { + if IsPathSeparator(pattern[i]) { + return "", "", errPatternHasSeparator + } + } + if pos := strings.LastIndex(pattern, "*"); pos != -1 { + prefix, suffix = pattern[:pos], pattern[pos+1:] + } else { + prefix = pattern + } + return prefix, suffix, nil +} + +// MkdirTemp creates a new temporary directory in the directory dir +// and returns the pathname of the new directory. +// The new directory's name is generated by adding a random string to the end of pattern. +// If pattern includes a "*", the random string replaces the last "*" instead. +// If dir is the empty string, TempFile uses the default directory for temporary files, as returned by TempDir. +// Multiple programs or goroutines calling MkdirTemp simultaneously will not choose the same directory. +// It is the caller's responsibility to remove the directory when it is no longer needed. +func MkdirTemp(dir, pattern string) (string, error) { + if dir == "" { + dir = TempDir() + } + + prefix, suffix, err := prefixAndSuffix(pattern) + if err != nil { + return "", &PathError{Op: "mkdirtemp", Path: pattern, Err: err} + } + prefix = joinPath(dir, prefix) + + try := 0 + for { + name := prefix + nextRandom() + suffix + err := Mkdir(name, 0700) + if err == nil { + return name, nil + } + if IsExist(err) { + if try++; try < 10000 { + continue + } + return "", &PathError{Op: "mkdirtemp", Path: dir + string(PathSeparator) + prefix + "*" + suffix, Err: ErrExist} + } + if IsNotExist(err) { + if _, err := Stat(dir); IsNotExist(err) { + return "", err + } + } + return "", err + } +} + +func joinPath(dir, name string) string { + if len(dir) > 0 && IsPathSeparator(dir[len(dir)-1]) { + return dir + name + } + return dir + string(PathSeparator) + name +} diff --git a/src/os/tempfile_test.go b/src/os/tempfile_test.go new file mode 100644 index 0000000000..e71a2444c9 --- /dev/null +++ b/src/os/tempfile_test.go @@ -0,0 +1,193 @@ +// Copyright 2010 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 os_test + +import ( + "errors" + "io/fs" + . "os" + "path/filepath" + "regexp" + "strings" + "testing" +) + +func TestCreateTemp(t *testing.T) { + dir, err := MkdirTemp("", "TestCreateTempBadDir") + if err != nil { + t.Fatal(err) + } + defer RemoveAll(dir) + + nonexistentDir := filepath.Join(dir, "_not_exists_") + f, err := CreateTemp(nonexistentDir, "foo") + if f != nil || err == nil { + t.Errorf("CreateTemp(%q, `foo`) = %v, %v", nonexistentDir, f, err) + } +} + +func TestCreateTempPattern(t *testing.T) { + tests := []struct{ pattern, prefix, suffix string }{ + {"tempfile_test", "tempfile_test", ""}, + {"tempfile_test*", "tempfile_test", ""}, + {"tempfile_test*xyz", "tempfile_test", "xyz"}, + } + for _, test := range tests { + f, err := CreateTemp("", test.pattern) + if err != nil { + t.Errorf("CreateTemp(..., %q) error: %v", test.pattern, err) + continue + } + defer Remove(f.Name()) + base := filepath.Base(f.Name()) + f.Close() + if !(strings.HasPrefix(base, test.prefix) && strings.HasSuffix(base, test.suffix)) { + t.Errorf("CreateTemp pattern %q created bad name %q; want prefix %q & suffix %q", + test.pattern, base, test.prefix, test.suffix) + } + } +} + +func TestCreateTempBadPattern(t *testing.T) { + tmpDir, err := MkdirTemp("", t.Name()) + if err != nil { + t.Fatal(err) + } + defer RemoveAll(tmpDir) + + const sep = string(PathSeparator) + tests := []struct { + pattern string + wantErr bool + }{ + {"ioutil*test", false}, + {"tempfile_test*foo", false}, + {"tempfile_test" + sep + "foo", true}, + {"tempfile_test*" + sep + "foo", true}, + {"tempfile_test" + sep + "*foo", true}, + {sep + "tempfile_test" + sep + "*foo", true}, + {"tempfile_test*foo" + sep, true}, + } + for _, tt := range tests { + t.Run(tt.pattern, func(t *testing.T) { + tmpfile, err := CreateTemp(tmpDir, tt.pattern) + if tmpfile != nil { + defer tmpfile.Close() + } + if tt.wantErr { + if err == nil { + t.Errorf("CreateTemp(..., %#q) succeeded, expected error", tt.pattern) + } + if !errors.Is(err, ErrPatternHasSeparator) { + t.Errorf("CreateTemp(..., %#q): %v, expected ErrPatternHasSeparator", tt.pattern, err) + } + } else if err != nil { + t.Errorf("CreateTemp(..., %#q): %v", tt.pattern, err) + } + }) + } +} + +func TestMkdirTemp(t *testing.T) { + name, err := MkdirTemp("/_not_exists_", "foo") + if name != "" || err == nil { + t.Errorf("MkdirTemp(`/_not_exists_`, `foo`) = %v, %v", name, err) + } + + tests := []struct { + pattern string + wantPrefix, wantSuffix string + }{ + {"tempfile_test", "tempfile_test", ""}, + {"tempfile_test*", "tempfile_test", ""}, + {"tempfile_test*xyz", "tempfile_test", "xyz"}, + } + + dir := filepath.Clean(TempDir()) + + runTestMkdirTemp := func(t *testing.T, pattern, wantRePat string) { + name, err := MkdirTemp(dir, pattern) + if name == "" || err != nil { + t.Fatalf("MkdirTemp(dir, `tempfile_test`) = %v, %v", name, err) + } + defer Remove(name) + + re := regexp.MustCompile(wantRePat) + if !re.MatchString(name) { + t.Errorf("MkdirTemp(%q, %q) created bad name\n\t%q\ndid not match pattern\n\t%q", dir, pattern, name, wantRePat) + } + } + + for _, tt := range tests { + t.Run(tt.pattern, func(t *testing.T) { + wantRePat := "^" + regexp.QuoteMeta(filepath.Join(dir, tt.wantPrefix)) + "[0-9]+" + regexp.QuoteMeta(tt.wantSuffix) + "$" + runTestMkdirTemp(t, tt.pattern, wantRePat) + }) + } + + // Separately testing "*xyz" (which has no prefix). That is when constructing the + // pattern to assert on, as in the previous loop, using filepath.Join for an empty + // prefix filepath.Join(dir, ""), produces the pattern: + // ^[0-9]+xyz$ + // yet we just want to match + // "^/[0-9]+xyz" + t.Run("*xyz", func(t *testing.T) { + wantRePat := "^" + regexp.QuoteMeta(filepath.Join(dir)) + regexp.QuoteMeta(string(filepath.Separator)) + "[0-9]+xyz$" + runTestMkdirTemp(t, "*xyz", wantRePat) + }) +} + +// test that we return a nice error message if the dir argument to TempDir doesn't +// exist (or that it's empty and TempDir doesn't exist) +func TestMkdirTempBadDir(t *testing.T) { + dir, err := MkdirTemp("", "MkdirTempBadDir") + if err != nil { + t.Fatal(err) + } + defer RemoveAll(dir) + + badDir := filepath.Join(dir, "not-exist") + _, err = MkdirTemp(badDir, "foo") + if pe, ok := err.(*fs.PathError); !ok || !IsNotExist(err) || pe.Path != badDir { + t.Errorf("TempDir error = %#v; want PathError for path %q satisifying IsNotExist", err, badDir) + } +} + +func TestMkdirTempBadPattern(t *testing.T) { + tmpDir, err := MkdirTemp("", t.Name()) + if err != nil { + t.Fatal(err) + } + defer RemoveAll(tmpDir) + + const sep = string(PathSeparator) + tests := []struct { + pattern string + wantErr bool + }{ + {"ioutil*test", false}, + {"tempfile_test*foo", false}, + {"tempfile_test" + sep + "foo", true}, + {"tempfile_test*" + sep + "foo", true}, + {"tempfile_test" + sep + "*foo", true}, + {sep + "tempfile_test" + sep + "*foo", true}, + {"tempfile_test*foo" + sep, true}, + } + for _, tt := range tests { + t.Run(tt.pattern, func(t *testing.T) { + _, err := MkdirTemp(tmpDir, tt.pattern) + if tt.wantErr { + if err == nil { + t.Errorf("MkdirTemp(..., %#q) succeeded, expected error", tt.pattern) + } + if !errors.Is(err, ErrPatternHasSeparator) { + t.Errorf("MkdirTemp(..., %#q): %v, expected ErrPatternHasSeparator", tt.pattern, err) + } + } else if err != nil { + t.Errorf("MkdirTemp(..., %#q): %v", tt.pattern, err) + } + }) + } +} diff --git a/src/os/testdata/hello b/src/os/testdata/hello new file mode 100644 index 0000000000..e47c092a51 --- /dev/null +++ b/src/os/testdata/hello @@ -0,0 +1 @@ +Hello, Gophers! diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go index d77cb4d460..b55c3c0590 100644 --- a/src/runtime/stubs.go +++ b/src/runtime/stubs.go @@ -133,6 +133,9 @@ func sync_fastrand() uint32 { return fastrand() } //go:linkname net_fastrand net.fastrand func net_fastrand() uint32 { return fastrand() } +//go:linkname os_fastrand os.fastrand +func os_fastrand() uint32 { return fastrand() } + // in internal/bytealg/equal_*.s //go:noescape func memequal(a, b unsafe.Pointer, size uintptr) bool -- cgit v1.3 From 478bde3a4388997924a02ee9296864866d8ba3ba Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Wed, 2 Dec 2020 12:49:20 -0500 Subject: io/fs: add Sub Sub provides a convenient way to refer to a subdirectory automatically in future operations, like Unix's chdir(2). The CL also includes updates to fstest to check Sub implementations. As part of updating fstest, I changed the meaning of TestFS's expected list to introduce a special case: if you list no expected files, that means the FS must be empty. In general it's OK not to list all the expected files, but if you list none, that's almost certainly a mistake - if your FS were broken and empty, you wouldn't find out. Making no expected files mean "must be empty" makes the mistake less likely - if your file system ever worked, then your test will keep it working. That change found a testing bug: embedtest was making exactly that mistake. Fixes #42322. Change-Id: I63fd4aa866b30061a0e51ca9a1927e576d6ec41e Reviewed-on: https://go-review.googlesource.com/c/go/+/274856 Trust: Russ Cox Run-TryBot: Russ Cox TryBot-Result: Go Bot Reviewed-by: Ian Lance Taylor --- doc/go1.16.html | 2 +- src/embed/internal/embedtest/embed_test.go | 2 +- src/io/fs/readdir_test.go | 12 ++- src/io/fs/readfile_test.go | 16 ++++ src/io/fs/sub.go | 127 +++++++++++++++++++++++++++++ src/io/fs/sub_test.go | 57 +++++++++++++ src/os/file.go | 7 ++ src/testing/fstest/mapfs.go | 10 +++ src/testing/fstest/testfs.go | 42 ++++++++++ 9 files changed, 271 insertions(+), 4 deletions(-) create mode 100644 src/io/fs/sub.go create mode 100644 src/io/fs/sub_test.go (limited to 'src/io') diff --git a/doc/go1.16.html b/doc/go1.16.html index 4d4b459009..62d9b97db8 100644 --- a/doc/go1.16.html +++ b/doc/go1.16.html @@ -384,7 +384,7 @@ Do not send CLs removing the interior tags from such phrases. the new embed.FS type implements fs.FS, as does zip.Reader. - The new os.Dir function + The new os.DirFS function provides an implementation of fs.FS backed by a tree of operating system files.

diff --git a/src/embed/internal/embedtest/embed_test.go b/src/embed/internal/embedtest/embed_test.go index b1707a4c04..c6a7bea7a3 100644 --- a/src/embed/internal/embedtest/embed_test.go +++ b/src/embed/internal/embedtest/embed_test.go @@ -65,7 +65,7 @@ func TestGlobal(t *testing.T) { testFiles(t, global, "testdata/hello.txt", "hello, world\n") testFiles(t, global, "testdata/glass.txt", "I can eat glass and it doesn't hurt me.\n") - if err := fstest.TestFS(global); err != nil { + if err := fstest.TestFS(global, "concurrency.txt", "testdata/hello.txt"); err != nil { t.Fatal(err) } diff --git a/src/io/fs/readdir_test.go b/src/io/fs/readdir_test.go index 46a4bc2788..405bfa67ca 100644 --- a/src/io/fs/readdir_test.go +++ b/src/io/fs/readdir_test.go @@ -16,12 +16,12 @@ func (readDirOnly) Open(name string) (File, error) { return nil, ErrNotExist } func TestReadDir(t *testing.T) { check := func(desc string, dirs []DirEntry, err error) { t.Helper() - if err != nil || len(dirs) != 1 || dirs[0].Name() != "hello.txt" { + if err != nil || len(dirs) != 2 || dirs[0].Name() != "hello.txt" || dirs[1].Name() != "sub" { var names []string for _, d := range dirs { names = append(names, d.Name()) } - t.Errorf("ReadDir(%s) = %v, %v, want %v, nil", desc, names, err, []string{"hello.txt"}) + t.Errorf("ReadDir(%s) = %v, %v, want %v, nil", desc, names, err, []string{"hello.txt", "sub"}) } } @@ -32,4 +32,12 @@ func TestReadDir(t *testing.T) { // Test that ReadDir uses Open when the method is not present. dirs, err = ReadDir(openOnly{testFsys}, ".") check("openOnly", dirs, err) + + // Test that ReadDir on Sub of . works (sub_test checks non-trivial subs). + sub, err := Sub(testFsys, ".") + if err != nil { + t.Fatal(err) + } + dirs, err = ReadDir(sub, ".") + check("sub(.)", dirs, err) } diff --git a/src/io/fs/readfile_test.go b/src/io/fs/readfile_test.go index 0afa334ace..07219c1445 100644 --- a/src/io/fs/readfile_test.go +++ b/src/io/fs/readfile_test.go @@ -18,6 +18,12 @@ var testFsys = fstest.MapFS{ ModTime: time.Now(), Sys: &sysValue, }, + "sub/goodbye.txt": { + Data: []byte("goodbye, world"), + Mode: 0456, + ModTime: time.Now(), + Sys: &sysValue, + }, } var sysValue int @@ -40,4 +46,14 @@ func TestReadFile(t *testing.T) { if string(data) != "hello, world" || err != nil { t.Fatalf(`ReadFile(openOnly, "hello.txt") = %q, %v, want %q, nil`, data, err, "hello, world") } + + // Test that ReadFile on Sub of . works (sub_test checks non-trivial subs). + sub, err := Sub(testFsys, ".") + if err != nil { + t.Fatal(err) + } + data, err = ReadFile(sub, "hello.txt") + if string(data) != "hello, world" || err != nil { + t.Fatalf(`ReadFile(sub(.), "hello.txt") = %q, %v, want %q, nil`, data, err, "hello, world") + } } diff --git a/src/io/fs/sub.go b/src/io/fs/sub.go new file mode 100644 index 0000000000..381f409504 --- /dev/null +++ b/src/io/fs/sub.go @@ -0,0 +1,127 @@ +// Copyright 2020 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 fs + +import ( + "errors" + "path" +) + +// A SubFS is a file system with a Sub method. +type SubFS interface { + FS + + // Sub returns an FS corresponding to the subtree rooted at dir. + Sub(dir string) (FS, error) +} + +// Sub returns an FS corresponding to the subtree rooted at fsys's dir. +// +// If fs implements SubFS, Sub calls returns fsys.Sub(dir). +// Otherwise, if dir is ".", Sub returns fsys unchanged. +// Otherwise, Sub returns a new FS implementation sub that, +// in effect, implements sub.Open(dir) as fsys.Open(path.Join(dir, name)). +// The implementation also translates calls to ReadDir, ReadFile, and Glob appropriately. +// +// Note that Sub(os.DirFS("/"), "prefix") is equivalent to os.DirFS("/prefix") +// and that neither of them guarantees to avoid operating system +// accesses outside "/prefix", because the implementation of os.DirFS +// does not check for symbolic links inside "/prefix" that point to +// other directories. That is, os.DirFS is not a general substitute for a +// chroot-style security mechanism, and Sub does not change that fact. +func Sub(fsys FS, dir string) (FS, error) { + if !ValidPath(dir) { + return nil, &PathError{Op: "sub", Path: dir, Err: errors.New("invalid name")} + } + if dir == "." { + return fsys, nil + } + if fsys, ok := fsys.(SubFS); ok { + return fsys.Sub(dir) + } + return &subFS{fsys, dir}, nil +} + +type subFS struct { + fsys FS + dir string +} + +// fullName maps name to the fully-qualified name dir/name. +func (f *subFS) fullName(op string, name string) (string, error) { + if !ValidPath(name) { + return "", &PathError{Op: op, Path: name, Err: errors.New("invalid name")} + } + return path.Join(f.dir, name), nil +} + +// shorten maps name, which should start with f.dir, back to the suffix after f.dir. +func (f *subFS) shorten(name string) (rel string, ok bool) { + if name == f.dir { + return ".", true + } + if len(name) >= len(f.dir)+2 && name[len(f.dir)] == '/' && name[:len(f.dir)] == f.dir { + return name[len(f.dir)+1:], true + } + return "", false +} + +// fixErr shortens any reported names in PathErrors by stripping dir. +func (f *subFS) fixErr(err error) error { + if e, ok := err.(*PathError); ok { + if short, ok := f.shorten(e.Path); ok { + e.Path = short + } + } + return err +} + +func (f *subFS) Open(name string) (File, error) { + full, err := f.fullName("open", name) + if err != nil { + return nil, err + } + file, err := f.fsys.Open(full) + return file, f.fixErr(err) +} + +func (f *subFS) ReadDir(name string) ([]DirEntry, error) { + full, err := f.fullName("open", name) + if err != nil { + return nil, err + } + dir, err := ReadDir(f.fsys, full) + return dir, f.fixErr(err) +} + +func (f *subFS) ReadFile(name string) ([]byte, error) { + full, err := f.fullName("open", name) + if err != nil { + return nil, err + } + data, err := ReadFile(f.fsys, full) + return data, f.fixErr(err) +} + +func (f *subFS) Glob(pattern string) ([]string, error) { + // Check pattern is well-formed. + if _, err := path.Match(pattern, ""); err != nil { + return nil, err + } + if pattern == "." { + return []string{"."}, nil + } + + full := f.dir + "/" + pattern + list, err := Glob(f.fsys, full) + for i, name := range list { + name, ok := f.shorten(name) + if !ok { + return nil, errors.New("invalid result from inner fsys Glob: " + name + " not in " + f.dir) // can't use fmt in this package + } + list[i] = name + } + return list, f.fixErr(err) +} diff --git a/src/io/fs/sub_test.go b/src/io/fs/sub_test.go new file mode 100644 index 0000000000..451b0efb02 --- /dev/null +++ b/src/io/fs/sub_test.go @@ -0,0 +1,57 @@ +// Copyright 2020 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 fs_test + +import ( + . "io/fs" + "testing" +) + +type subOnly struct{ SubFS } + +func (subOnly) Open(name string) (File, error) { return nil, ErrNotExist } + +func TestSub(t *testing.T) { + check := func(desc string, sub FS, err error) { + t.Helper() + if err != nil { + t.Errorf("Sub(sub): %v", err) + return + } + data, err := ReadFile(sub, "goodbye.txt") + if string(data) != "goodbye, world" || err != nil { + t.Errorf(`ReadFile(%s, "goodbye.txt" = %q, %v, want %q, nil`, desc, string(data), err, "goodbye, world") + } + + dirs, err := ReadDir(sub, ".") + if err != nil || len(dirs) != 1 || dirs[0].Name() != "goodbye.txt" { + var names []string + for _, d := range dirs { + names = append(names, d.Name()) + } + t.Errorf(`ReadDir(%s, ".") = %v, %v, want %v, nil`, desc, names, err, []string{"goodbye.txt"}) + } + } + + // Test that Sub uses the method when present. + sub, err := Sub(subOnly{testFsys}, "sub") + check("subOnly", sub, err) + + // Test that Sub uses Open when the method is not present. + sub, err = Sub(openOnly{testFsys}, "sub") + check("openOnly", sub, err) + + _, err = sub.Open("nonexist") + if err == nil { + t.Fatal("Open(nonexist): succeeded") + } + pe, ok := err.(*PathError) + if !ok { + t.Fatalf("Open(nonexist): error is %T, want *PathError", err) + } + if pe.Path != "nonexist" { + t.Fatalf("Open(nonexist): err.Path = %q, want %q", pe.Path, "nonexist") + } +} diff --git a/src/os/file.go b/src/os/file.go index 304b055dbe..416bc0efa6 100644 --- a/src/os/file.go +++ b/src/os/file.go @@ -609,6 +609,13 @@ func isWindowsNulName(name string) bool { } // DirFS returns a file system (an fs.FS) for the tree of files rooted at the directory dir. +// +// Note that DirFS("/prefix") only guarantees that the Open calls it makes to the +// operating system will begin with "/prefix": DirFS("/prefix").Open("file") is the +// same as os.Open("/prefix/file"). So if /prefix/file is a symbolic link pointing outside +// the /prefix tree, then using DirFS does not stop the access any more than using +// os.Open does. DirFS is therefore not a general substitute for a chroot-style security +// mechanism when the directory tree contains arbitrary content. func DirFS(dir string) fs.FS { return dirFS(dir) } diff --git a/src/testing/fstest/mapfs.go b/src/testing/fstest/mapfs.go index 10e56f5b3c..a5d4a23fac 100644 --- a/src/testing/fstest/mapfs.go +++ b/src/testing/fstest/mapfs.go @@ -132,6 +132,16 @@ func (fsys MapFS) Glob(pattern string) ([]string, error) { return fs.Glob(fsOnly{fsys}, pattern) } +type noSub struct { + MapFS +} + +func (noSub) Sub() {} // not the fs.SubFS signature + +func (fsys MapFS) Sub(dir string) (fs.FS, error) { + return fs.Sub(noSub{fsys}, dir) +} + // A mapFileInfo implements fs.FileInfo and fs.DirEntry for a given map file. type mapFileInfo struct { name string diff --git a/src/testing/fstest/testfs.go b/src/testing/fstest/testfs.go index 4912a271b2..2602bdf0cc 100644 --- a/src/testing/fstest/testfs.go +++ b/src/testing/fstest/testfs.go @@ -22,6 +22,8 @@ import ( // It walks the entire tree of files in fsys, // opening and checking that each file behaves correctly. // It also checks that the file system contains at least the expected files. +// As a special case, if no expected files are listed, fsys must be empty. +// Otherwise, fsys must only contain at least the listed files: it can also contain others. // // If TestFS finds any misbehaviors, it returns an error reporting all of them. // The error text spans multiple lines, one per detected misbehavior. @@ -33,6 +35,32 @@ import ( // } // func TestFS(fsys fs.FS, expected ...string) error { + if err := testFS(fsys, expected...); err != nil { + return err + } + for _, name := range expected { + if i := strings.Index(name, "/"); i >= 0 { + dir, dirSlash := name[:i], name[:i+1] + var subExpected []string + for _, name := range expected { + if strings.HasPrefix(name, dirSlash) { + subExpected = append(subExpected, name[len(dirSlash):]) + } + } + sub, err := fs.Sub(fsys, dir) + if err != nil { + return err + } + if err := testFS(sub, subExpected...); err != nil { + return fmt.Errorf("testing fs.Sub(fsys, %s): %v", dir, err) + } + break // one sub-test is enough + } + } + return nil +} + +func testFS(fsys fs.FS, expected ...string) error { t := fsTester{fsys: fsys} t.checkDir(".") t.checkOpen(".") @@ -43,6 +71,20 @@ func TestFS(fsys fs.FS, expected ...string) error { for _, file := range t.files { found[file] = true } + delete(found, ".") + if len(expected) == 0 && len(found) > 0 { + var list []string + for k := range found { + if k != "." { + list = append(list, k) + } + } + sort.Strings(list) + if len(list) > 15 { + list = append(list[:10], "...") + } + t.errorf("expected empty file system but found files:\n%s", strings.Join(list, "\n")) + } for _, name := range expected { if !found[name] { t.errorf("expected but not found: %s", name) -- cgit v1.3 From 7ad6596c4711c48ef95334c9c6516a0c30979bd9 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Mon, 7 Dec 2020 15:20:37 -0500 Subject: io/fs: fix Sub method error text Noticed in (and alternative to) CL 275520. Change-Id: If6c107ee9928dd1910facd4dc66da7234cb91c39 Reviewed-on: https://go-review.googlesource.com/c/go/+/275879 Trust: Russ Cox Trust: Robert Griesemer Run-TryBot: Russ Cox Reviewed-by: Robert Griesemer TryBot-Result: Go Bot --- src/io/fs/sub.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/io') diff --git a/src/io/fs/sub.go b/src/io/fs/sub.go index 381f409504..64cdffe6de 100644 --- a/src/io/fs/sub.go +++ b/src/io/fs/sub.go @@ -88,7 +88,7 @@ func (f *subFS) Open(name string) (File, error) { } func (f *subFS) ReadDir(name string) ([]DirEntry, error) { - full, err := f.fullName("open", name) + full, err := f.fullName("read", name) if err != nil { return nil, err } @@ -97,7 +97,7 @@ func (f *subFS) ReadDir(name string) ([]DirEntry, error) { } func (f *subFS) ReadFile(name string) ([]byte, error) { - full, err := f.fullName("open", name) + full, err := f.fullName("read", name) if err != nil { return nil, err } -- cgit v1.3