]> Cypherpunks repositories - gostls13.git/commitdiff
os: fix race in ReadAt/WriteAt on Windows
authorAlex Brainman <alex.brainman@gmail.com>
Tue, 26 Apr 2011 08:09:46 +0000 (18:09 +1000)
committerAlex Brainman <alex.brainman@gmail.com>
Tue, 26 Apr 2011 08:09:46 +0000 (18:09 +1000)
R=bradfitzgo, rsc, peterGo
CC=golang-dev
https://golang.org/cl/4441051

src/pkg/os/file.go
src/pkg/os/file_plan9.go
src/pkg/os/file_unix.go
src/pkg/os/file_windows.go
src/pkg/syscall/syscall_windows.go

index 643b225ce7f608e225e213fbfe6a03502be0ea40..dff8fa862cee8de54f93de8553513ada7ec6a16b 100644 (file)
@@ -8,6 +8,7 @@ package os
 
 import (
        "runtime"
+       "sync"
        "syscall"
 )
 
@@ -15,8 +16,9 @@ import (
 type File struct {
        fd      int
        name    string
-       dirinfo *dirInfo // nil unless directory being read
-       nepipe  int      // number of consecutive EPIPE in Write
+       dirinfo *dirInfo   // nil unless directory being read
+       nepipe  int        // number of consecutive EPIPE in Write
+       l       sync.Mutex // used to implement windows pread/pwrite
 }
 
 // Fd returns the integer Unix file descriptor referencing the open file.
@@ -30,7 +32,7 @@ func NewFile(fd int, name string) *File {
        if fd < 0 {
                return nil
        }
-       f := &File{fd, name, nil, 0}
+       f := &File{fd: fd, name: name}
        runtime.SetFinalizer(f, (*File).Close)
        return f
 }
@@ -85,7 +87,7 @@ func (file *File) Read(b []byte) (n int, err Error) {
        if file == nil {
                return 0, EINVAL
        }
-       n, e := syscall.Read(file.fd, b)
+       n, e := file.read(b)
        if n < 0 {
                n = 0
        }
@@ -107,7 +109,7 @@ func (file *File) ReadAt(b []byte, off int64) (n int, err Error) {
                return 0, EINVAL
        }
        for len(b) > 0 {
-               m, e := syscall.Pread(file.fd, b, off)
+               m, e := file.pread(b, off)
                if m == 0 && !iserror(e) {
                        return n, EOF
                }
@@ -129,7 +131,7 @@ func (file *File) Write(b []byte) (n int, err Error) {
        if file == nil {
                return 0, EINVAL
        }
-       n, e := syscall.Write(file.fd, b)
+       n, e := file.write(b)
        if n < 0 {
                n = 0
        }
@@ -150,7 +152,7 @@ func (file *File) WriteAt(b []byte, off int64) (n int, err Error) {
                return 0, EINVAL
        }
        for len(b) > 0 {
-               m, e := syscall.Pwrite(file.fd, b, off)
+               m, e := file.pwrite(b, off)
                if iserror(e) {
                        err = &PathError{"write", file.name, Errno(e)}
                        break
@@ -167,7 +169,7 @@ func (file *File) WriteAt(b []byte, off int64) (n int, err Error) {
 // relative to the current offset, and 2 means relative to the end.
 // It returns the new offset and an Error, if any.
 func (file *File) Seek(offset int64, whence int) (ret int64, err Error) {
-       r, e := syscall.Seek(file.fd, offset, whence)
+       r, e := file.seek(offset, whence)
        if !iserror(e) && file.dirinfo != nil && r != 0 {
                e = syscall.EISDIR
        }
index c8d0efba40532e63147b0415e8fe7b4c5078b872..7b473f802216f791f67374c556ef9f59b33e27df 100644 (file)
@@ -117,6 +117,39 @@ func (f *File) Sync() (err Error) {
        return nil
 }
 
+// read reads up to len(b) bytes from the File.
+// It returns the number of bytes read and an error, if any.
+func (f *File) read(b []byte) (n int, err syscall.Error) {
+       return syscall.Read(f.fd, b)
+}
+
+// pread reads len(b) bytes from the File starting at byte offset off.
+// It returns the number of bytes read and the error, if any.
+// EOF is signaled by a zero count with err set to nil.
+func (f *File) pread(b []byte, off int64) (n int, err syscall.Error) {
+       return syscall.Pread(f.fd, b, off)
+}
+
+// write writes len(b) bytes to the File.
+// It returns the number of bytes written and an error, if any.
+func (f *File) write(b []byte) (n int, err syscall.Error) {
+       return syscall.Write(f.fd, b)
+}
+
+// pwrite writes len(b) bytes to the File starting at byte offset off.
+// It returns the number of bytes written and an error, if any.
+func (f *File) pwrite(b []byte, off int64) (n int, err syscall.Error) {
+       return syscall.Pwrite(f.fd, b, off)
+}
+
+// seek sets the offset for the next Read or Write on file to offset, interpreted
+// according to whence: 0 means relative to the origin of the file, 1 means
+// relative to the current offset, and 2 means relative to the end.
+// It returns the new offset and an error, if any.
+func (f *File) seek(offset int64, whence int) (ret int64, err syscall.Error) {
+       return syscall.Seek(f.fd, offset, whence)
+}
+
 // Truncate changes the size of the named file.
 // If the file is a symbolic link, it changes the size of the link's target.
 func Truncate(name string, size int64) Error {
index f2b94f4c2dbb82bcffa475a673eddf555ffb3113..2fb28df6556c82da03483366b5a8da5909511a5e 100644 (file)
@@ -96,6 +96,39 @@ func (file *File) Readdir(count int) (fi []FileInfo, err Error) {
        return
 }
 
+// read reads up to len(b) bytes from the File.
+// It returns the number of bytes read and an error, if any.
+func (f *File) read(b []byte) (n int, err int) {
+       return syscall.Read(f.fd, b)
+}
+
+// pread reads len(b) bytes from the File starting at byte offset off.
+// It returns the number of bytes read and the error, if any.
+// EOF is signaled by a zero count with err set to 0.
+func (f *File) pread(b []byte, off int64) (n int, err int) {
+       return syscall.Pread(f.fd, b, off)
+}
+
+// write writes len(b) bytes to the File.
+// It returns the number of bytes written and an error, if any.
+func (f *File) write(b []byte) (n int, err int) {
+       return syscall.Write(f.fd, b)
+}
+
+// pwrite writes len(b) bytes to the File starting at byte offset off.
+// It returns the number of bytes written and an error, if any.
+func (f *File) pwrite(b []byte, off int64) (n int, err int) {
+       return syscall.Pwrite(f.fd, b, off)
+}
+
+// seek sets the offset for the next Read or Write on file to offset, interpreted
+// according to whence: 0 means relative to the origin of the file, 1 means
+// relative to the current offset, and 2 means relative to the end.
+// It returns the new offset and an error, if any.
+func (f *File) seek(offset int64, whence int) (ret int64, err int) {
+       return syscall.Seek(f.fd, offset, whence)
+}
+
 // Truncate changes the size of the named file.
 // If the file is a symbolic link, it changes the size of the link's target.
 func Truncate(name string, size int64) Error {
index 862baf6b913f301f79a3f8b9426bc5e038b5bb28..95f60b73519f478fbaa528d1bf09118111accbbb 100644 (file)
@@ -165,6 +165,77 @@ func (file *File) Readdir(count int) (fi []FileInfo, err Error) {
        return fi, nil
 }
 
+// read reads up to len(b) bytes from the File.
+// It returns the number of bytes read and an error, if any.
+func (f *File) read(b []byte) (n int, err int) {
+       f.l.Lock()
+       defer f.l.Unlock()
+       return syscall.Read(f.fd, b)
+}
+
+// pread reads len(b) bytes from the File starting at byte offset off.
+// It returns the number of bytes read and the error, if any.
+// EOF is signaled by a zero count with err set to 0.
+func (f *File) pread(b []byte, off int64) (n int, err int) {
+       f.l.Lock()
+       defer f.l.Unlock()
+       curoffset, e := syscall.Seek(f.fd, 0, 1)
+       if e != 0 {
+               return 0, e
+       }
+       defer syscall.Seek(f.fd, curoffset, 0)
+       o := syscall.Overlapped{
+               OffsetHigh: uint32(off >> 32),
+               Offset:     uint32(off),
+       }
+       var done uint32
+       e = syscall.ReadFile(int32(f.fd), b, &done, &o)
+       if e != 0 {
+               return 0, e
+       }
+       return int(done), 0
+}
+
+// write writes len(b) bytes to the File.
+// It returns the number of bytes written and an error, if any.
+func (f *File) write(b []byte) (n int, err int) {
+       f.l.Lock()
+       defer f.l.Unlock()
+       return syscall.Write(f.fd, b)
+}
+
+// pwrite writes len(b) bytes to the File starting at byte offset off.
+// It returns the number of bytes written and an error, if any.
+func (f *File) pwrite(b []byte, off int64) (n int, err int) {
+       f.l.Lock()
+       defer f.l.Unlock()
+       curoffset, e := syscall.Seek(f.fd, 0, 1)
+       if e != 0 {
+               return 0, e
+       }
+       defer syscall.Seek(f.fd, curoffset, 0)
+       o := syscall.Overlapped{
+               OffsetHigh: uint32(off >> 32),
+               Offset:     uint32(off),
+       }
+       var done uint32
+       e = syscall.WriteFile(int32(f.fd), b, &done, &o)
+       if e != 0 {
+               return 0, e
+       }
+       return int(done), 0
+}
+
+// seek sets the offset for the next Read or Write on file to offset, interpreted
+// according to whence: 0 means relative to the origin of the file, 1 means
+// relative to the current offset, and 2 means relative to the end.
+// It returns the new offset and an error, if any.
+func (f *File) seek(offset int64, whence int) (ret int64, err int) {
+       f.l.Lock()
+       defer f.l.Unlock()
+       return syscall.Seek(f.fd, offset, whence)
+}
+
 // Truncate changes the size of the named file.
 // If the file is a symbolic link, it changes the size of the link's target.
 func Truncate(name string, size int64) Error {
index e01310deff03c8a297f05f461d5a488f431c7fef..1fbb3ccbf4acef6bb7bfac18500de9e65f91692e 100644 (file)
@@ -250,27 +250,6 @@ func Read(fd int, p []byte) (n int, errno int) {
        return int(done), 0
 }
 
-// TODO(brainman): ReadFile/WriteFile change file offset, therefore
-// i use Seek here to preserve semantics of unix pread/pwrite,
-// not sure if I should do that
-
-func Pread(fd int, p []byte, offset int64) (n int, errno int) {
-       curoffset, e := Seek(fd, 0, 1)
-       if e != 0 {
-               return 0, e
-       }
-       defer Seek(fd, curoffset, 0)
-       var o Overlapped
-       o.OffsetHigh = uint32(offset >> 32)
-       o.Offset = uint32(offset)
-       var done uint32
-       e = ReadFile(int32(fd), p, &done, &o)
-       if e != 0 {
-               return 0, e
-       }
-       return int(done), 0
-}
-
 func Write(fd int, p []byte) (n int, errno int) {
        var done uint32
        e := WriteFile(int32(fd), p, &done, nil)
@@ -280,23 +259,6 @@ func Write(fd int, p []byte) (n int, errno int) {
        return int(done), 0
 }
 
-func Pwrite(fd int, p []byte, offset int64) (n int, errno int) {
-       curoffset, e := Seek(fd, 0, 1)
-       if e != 0 {
-               return 0, e
-       }
-       defer Seek(fd, curoffset, 0)
-       var o Overlapped
-       o.OffsetHigh = uint32(offset >> 32)
-       o.Offset = uint32(offset)
-       var done uint32
-       e = WriteFile(int32(fd), p, &done, &o)
-       if e != 0 {
-               return 0, e
-       }
-       return int(done), 0
-}
-
 func Seek(fd int, offset int64, whence int) (newoffset int64, errno int) {
        var w uint32
        switch whence {