Skip to content

Commit

Permalink
os: delete os.EINVAL and so on
Browse files Browse the repository at this point in the history
The set of errors forwarded by the os package varied with system and
was therefore non-portable.
Three helpers added for portable error checking: IsExist, IsNotExist, and IsPermission.
One or two more may need to come, but let's keep the set very small to discourage
thinking about errors that way.

R=mikioh.mikioh, gustavo, r, rsc
CC=golang-dev
https://golang.org/cl/5672047
  • Loading branch information
robpike committed Feb 16, 2012
1 parent c560a07 commit 56069f0
Show file tree
Hide file tree
Showing 42 changed files with 278 additions and 218 deletions.
21 changes: 20 additions & 1 deletion doc/go1.html
Original file line number Diff line number Diff line change
Expand Up @@ -1494,12 +1494,31 @@ <h4 id="os_fileinfo">The os.FileInfo type</h4>
The vast majority of uses of <code>FileInfo</code> need only the methods
of the standard interface.
</p>


<p>
The <code>os</code> package no longer contains wrappers for the POSIX errors
such as <code>ENOENT</code>.
For the few programs that need to verify particular error conditions, there are
now the boolean functions
<a href="/pkg/os/#IsExist"><code>IsExist</code></a>,
<a href="/pkg/os/#IsNotExist"><code>IsNotExist</code></a>
and
<a href="/pkg/os/#IsPermission"><code>IsPermission</code></a>.
</p>

<pre><!--{{code "progs/go1.go" `/os\.Open/` `/}/`}}
--> f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
if os.IsExist(err) {
log.Printf(&#34;%s already exists&#34;, name)
}</pre>

<p>
<em>Updating</em>:
Running <code>go fix</code> will update code that uses the old equivalent of the current <code>os.FileInfo</code>
and <code>os.FileMode</code> API.
Code that needs system-specific file details will need to be updated by hand.
Code that uses the old POSIX error values from the <code>os</code> package
will fail to compile and will also need to be updated by hand.
</p>

<h3 id="path_filepath">The path/filepath package</h3>
Expand Down
17 changes: 16 additions & 1 deletion doc/go1.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -1397,12 +1397,27 @@ the i-number expression could be contracted to
The vast majority of uses of <code>FileInfo</code> need only the methods
of the standard interface.
</p>


<p>
The <code>os</code> package no longer contains wrappers for the POSIX errors
such as <code>ENOENT</code>.
For the few programs that need to verify particular error conditions, there are
now the boolean functions
<a href="/pkg/os/#IsExist"><code>IsExist</code></a>,
<a href="/pkg/os/#IsNotExist"><code>IsNotExist</code></a>
and
<a href="/pkg/os/#IsPermission"><code>IsPermission</code></a>.
</p>

{{code "progs/go1.go" `/os\.Open/` `/}/`}}

<p>
<em>Updating</em>:
Running <code>go fix</code> will update code that uses the old equivalent of the current <code>os.FileInfo</code>
and <code>os.FileMode</code> API.
Code that needs system-specific file details will need to be updated by hand.
Code that uses the old POSIX error values from the <code>os</code> package
will fail to compile and will also need to be updated by hand.
</p>

<h3 id="path_filepath">The path/filepath package</h3>
Expand Down
8 changes: 4 additions & 4 deletions doc/go_tutorial.html
Original file line number Diff line number Diff line change
Expand Up @@ -623,7 +623,7 @@ <h2>An I/O Package</h2>
<pre><!--{{code "progs/file.go" `/Close/` "$"}}
-->func (file *File) Close() error {
if file == nil {
return os.EINVAL
return os.ErrInvalid
}
err := syscall.Close(file.fd)
file.fd = -1 // so it can&#39;t be closed again
Expand All @@ -632,15 +632,15 @@ <h2>An I/O Package</h2>

func (file *File) Read(b []byte) (ret int, err error) {
if file == nil {
return -1, os.EINVAL
return -1, os.ErrInvalid
}
r, err := syscall.Read(file.fd, b)
return int(r), err
}

func (file *File) Write(b []byte) (ret int, err error) {
if file == nil {
return -1, os.EINVAL
return -1, os.ErrInvalid
}
r, err := syscall.Write(file.fd, b)
return int(r), err
Expand All @@ -659,7 +659,7 @@ <h2>An I/O Package</h2>
The <code>String</code> method is so called because of a printing convention we'll
describe later.
<p>
The methods use the public variable <code>os.EINVAL</code> to return the (<code>error</code>
The methods use the public variable <code>os.ErrInvalid</code> to return the (<code>error</code>
version of the) Unix error code <code>EINVAL</code>. The <code>os</code> library defines a standard
set of such error values.
<p>
Expand Down
2 changes: 1 addition & 1 deletion doc/go_tutorial.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ array, not just for <code>structs</code>. We'll see an example with arrays lat
The <code>String</code> method is so called because of a printing convention we'll
describe later.
<p>
The methods use the public variable <code>os.EINVAL</code> to return the (<code>error</code>
The methods use the public variable <code>os.ErrInvalid</code> to return the (<code>error</code>
version of the) Unix error code <code>EINVAL</code>. The <code>os</code> library defines a standard
set of such error values.
<p>
Expand Down
6 changes: 3 additions & 3 deletions doc/progs/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func Create(name string) (file *File, err error) {

func (file *File) Close() error {
if file == nil {
return os.EINVAL
return os.ErrInvalid
}
err := syscall.Close(file.fd)
file.fd = -1 // so it can't be closed again
Expand All @@ -58,15 +58,15 @@ func (file *File) Close() error {

func (file *File) Read(b []byte) (ret int, err error) {
if file == nil {
return -1, os.EINVAL
return -1, os.ErrInvalid
}
r, err := syscall.Read(file.fd, b)
return int(r), err
}

func (file *File) Write(b []byte) (ret int, err error) {
if file == nil {
return -1, os.EINVAL
return -1, os.ErrInvalid
}
r, err := syscall.Write(file.fd, b)
return int(r), err
Expand Down
6 changes: 3 additions & 3 deletions doc/progs/file_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func Create(name string) (file *File, err error) {

func (file *File) Close() error {
if file == nil {
return os.EINVAL
return os.ErrInvalid
}
err := syscall.Close(file.fd)
file.fd = syscall.InvalidHandle // so it can't be closed again
Expand All @@ -58,15 +58,15 @@ func (file *File) Close() error {

func (file *File) Read(b []byte) (ret int, err error) {
if file == nil {
return -1, os.EINVAL
return -1, os.ErrInvalid
}
r, err := syscall.Read(file.fd, b)
return int(r), err
}

func (file *File) Write(b []byte) (ret int, err error) {
if file == nil {
return -1, os.EINVAL
return -1, os.ErrInvalid
}
r, err := syscall.Write(file.fd, b)
return int(r), err
Expand Down
11 changes: 11 additions & 0 deletions doc/progs/go1.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"flag"
"fmt"
"log"
"os"
"testing"
"time"
"unicode"
Expand All @@ -27,6 +28,7 @@ func main() {
runeType()
errorExample()
timePackage()
osIsExist()
}

var timeout = flag.Duration("timeout", 30*time.Second, "how long to wait for completion")
Expand Down Expand Up @@ -206,3 +208,12 @@ func BenchmarkSprintf(b *testing.B) {
fmt.Sprintf("%x", 23)
}
}

func osIsExist() {
name := "go1.go"
f, err := os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
if os.IsExist(err) {
log.Printf("%s already exists", name)
}
_ = f
}
4 changes: 2 additions & 2 deletions src/pkg/io/ioutil/tempfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func TempFile(dir, prefix string) (f *os.File, err error) {
for i := 0; i < 10000; i++ {
name := filepath.Join(dir, prefix+nextSuffix())
f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
if pe, ok := err.(*os.PathError); ok && pe.Err == os.EEXIST {
if os.IsExist(err) {
if nconflict++; nconflict > 10 {
rand = reseed()
}
Expand All @@ -76,7 +76,7 @@ func TempDir(dir, prefix string) (name string, err error) {
for i := 0; i < 10000; i++ {
try := filepath.Join(dir, prefix+nextSuffix())
err = os.Mkdir(try, 0700)
if pe, ok := err.(*os.PathError); ok && pe.Err == os.EEXIST {
if os.IsExist(err) {
if nconflict++; nconflict > 10 {
rand = reseed()
}
Expand Down
2 changes: 1 addition & 1 deletion src/pkg/net/fd.go
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ func (fd *netFD) Write(p []byte) (int, error) {
}
defer fd.decref()
if fd.sysfile == nil {
return 0, os.EINVAL
return 0, syscall.EINVAL
}

var err error
Expand Down
20 changes: 11 additions & 9 deletions src/pkg/net/fd_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ func (fd *netFD) Close() error {

func (fd *netFD) shutdown(how int) error {
if fd == nil || fd.sysfd == syscall.InvalidHandle {
return os.EINVAL
return syscall.EINVAL
}
err := syscall.Shutdown(fd.sysfd, how)
if err != nil {
Expand Down Expand Up @@ -369,7 +369,7 @@ func (o *readOp) Name() string {

func (fd *netFD) Read(buf []byte) (int, error) {
if fd == nil {
return 0, os.EINVAL
return 0, syscall.EINVAL
}
fd.rio.Lock()
defer fd.rio.Unlock()
Expand All @@ -378,7 +378,7 @@ func (fd *netFD) Read(buf []byte) (int, error) {
}
defer fd.decref()
if fd.sysfd == syscall.InvalidHandle {
return 0, os.EINVAL
return 0, syscall.EINVAL
}
var o readOp
o.Init(fd, buf, 'r')
Expand Down Expand Up @@ -408,7 +408,7 @@ func (o *readFromOp) Name() string {

func (fd *netFD) ReadFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) {
if fd == nil {
return 0, nil, os.EINVAL
return 0, nil, syscall.EINVAL
}
if len(buf) == 0 {
return 0, nil, nil
Expand Down Expand Up @@ -447,7 +447,7 @@ func (o *writeOp) Name() string {

func (fd *netFD) Write(buf []byte) (int, error) {
if fd == nil {
return 0, os.EINVAL
return 0, syscall.EINVAL
}
fd.wio.Lock()
defer fd.wio.Unlock()
Expand Down Expand Up @@ -478,7 +478,7 @@ func (o *writeToOp) Name() string {

func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
if fd == nil {
return 0, os.EINVAL
return 0, syscall.EINVAL
}
if len(buf) == 0 {
return 0, nil
Expand All @@ -490,7 +490,7 @@ func (fd *netFD) WriteTo(buf []byte, sa syscall.Sockaddr) (int, error) {
}
defer fd.decref()
if fd.sysfd == syscall.InvalidHandle {
return 0, os.EINVAL
return 0, syscall.EINVAL
}
var o writeToOp
o.Init(fd, buf, 'w')
Expand Down Expand Up @@ -578,10 +578,12 @@ func (fd *netFD) dup() (*os.File, error) {
return nil, os.NewSyscallError("dup", syscall.EWINDOWS)
}

var errNoSupport = errors.New("address family not supported")

func (fd *netFD) ReadMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
return 0, 0, 0, nil, os.EAFNOSUPPORT
return 0, 0, 0, nil, errNoSupport
}

func (fd *netFD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
return 0, 0, os.EAFNOSUPPORT
return 0, 0, errNoSupport
}
8 changes: 4 additions & 4 deletions src/pkg/net/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func newFileFD(f *os.File) (*netFD, error) {
switch sa.(type) {
default:
closesocket(fd)
return nil, os.EINVAL
return nil, syscall.EINVAL
case *syscall.SockaddrInet4:
family = syscall.AF_INET
if proto == syscall.SOCK_DGRAM {
Expand Down Expand Up @@ -84,7 +84,7 @@ func FileConn(f *os.File) (c Conn, err error) {
return newIPConn(fd), nil
}
fd.Close()
return nil, os.EINVAL
return nil, syscall.EINVAL
}

// FileListener returns a copy of the network listener corresponding
Expand All @@ -103,7 +103,7 @@ func FileListener(f *os.File) (l Listener, err error) {
return &UnixListener{fd, laddr.Name}, nil
}
fd.Close()
return nil, os.EINVAL
return nil, syscall.EINVAL
}

// FilePacketConn returns a copy of the packet network connection
Expand All @@ -122,5 +122,5 @@ func FilePacketConn(f *os.File) (c PacketConn, err error) {
return newUnixConn(fd), nil
}
fd.Close()
return nil, os.EINVAL
return nil, syscall.EINVAL
}
3 changes: 2 additions & 1 deletion src/pkg/net/http/fs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package http_test

import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
Expand Down Expand Up @@ -131,7 +132,7 @@ func TestFileServerCleans(t *testing.T) {
ch := make(chan string, 1)
fs := FileServer(&testFileSystem{func(name string) (File, error) {
ch <- name
return nil, os.ENOENT
return nil, errors.New("file does not exist")
}})
tests := []struct {
reqPath, openArg string
Expand Down
4 changes: 2 additions & 2 deletions src/pkg/net/http/httputil/persist.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ import (
"net"
"net/http"
"net/textproto"
"os"
"sync"
)

var (
ErrPersistEOF = &http.ProtocolError{ErrorString: "persistent connection closed"}
ErrClosed = &http.ProtocolError{ErrorString: "connection closed by user"}
ErrPipeline = &http.ProtocolError{ErrorString: "pipeline error"}
)

Expand Down Expand Up @@ -191,7 +191,7 @@ func (sc *ServerConn) Write(req *http.Request, resp *http.Response) error {
}
if sc.c == nil { // connection closed by user in the meantime
defer sc.lk.Unlock()
return os.EBADF
return ErrClosed
}
c := sc.c
if sc.nread <= sc.nwritten {
Expand Down
Loading

0 comments on commit 56069f0

Please sign in to comment.