Skip to content

Commit

Permalink
Flip Handle from syscall to windows, and everything changes
Browse files Browse the repository at this point in the history
syscall.Handle is core to a _lot_ of structures and APIs, so this
great-big commit contains the entire rest of the conversion from syscall
to x/sys/windows.

I also eliminated a bunch of generated syscall wrappers which had
_direct_ equivalents in x/sys/windows. There's still a bunch which exist
in x/sys/windows and either have worse implementations, e.g.
windows.CreateFile, or somehow expose different APIs, e.g. the calls
used by privileges.go

Signed-off-by: Paul "TBBle" Hampson <[email protected]>
  • Loading branch information
TBBle committed Apr 21, 2021
1 parent dd8acb7 commit 0ba5488
Show file tree
Hide file tree
Showing 17 changed files with 135 additions and 238 deletions.
19 changes: 9 additions & 10 deletions backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,13 @@ import (
"io/ioutil"
"os"
"runtime"
"syscall"
"unicode/utf16"

"golang.org/x/sys/windows"
)

//sys backupRead(h syscall.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead
//sys backupWrite(h syscall.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupWrite
//sys backupRead(h windows.Handle, b []byte, bytesRead *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupRead
//sys backupWrite(h windows.Handle, b []byte, bytesWritten *uint32, abort bool, processSecurity bool, context *uintptr) (err error) = BackupWrite

const (
BackupData = uint32(iota + 1)
Expand Down Expand Up @@ -102,7 +101,7 @@ func (r *BackupStreamReader) Next() (*BackupHeader, error) {
if err := binary.Read(r.r, binary.LittleEndian, name); err != nil {
return nil, err
}
hdr.Name = syscall.UTF16ToString(name)
hdr.Name = windows.UTF16ToString(name)
}
if wsi.StreamId == BackupSparseBlock {
if err := binary.Read(r.r, binary.LittleEndian, &hdr.Offset); err != nil {
Expand Down Expand Up @@ -203,7 +202,7 @@ func NewBackupFileReader(f *os.File, includeSecurity bool) *BackupFileReader {
// Read reads a backup stream from the file by calling the Win32 API BackupRead().
func (r *BackupFileReader) Read(b []byte) (int, error) {
var bytesRead uint32
err := backupRead(syscall.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx)
err := backupRead(windows.Handle(r.f.Fd()), b, &bytesRead, false, r.includeSecurity, &r.ctx)
if err != nil {
return 0, &os.PathError{"BackupRead", r.f.Name(), err}
}
Expand All @@ -218,7 +217,7 @@ func (r *BackupFileReader) Read(b []byte) (int, error) {
// the underlying file.
func (r *BackupFileReader) Close() error {
if r.ctx != 0 {
backupRead(syscall.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx)
backupRead(windows.Handle(r.f.Fd()), nil, nil, true, false, &r.ctx)
runtime.KeepAlive(r.f)
r.ctx = 0
}
Expand All @@ -242,7 +241,7 @@ func NewBackupFileWriter(f *os.File, includeSecurity bool) *BackupFileWriter {
// Write restores a portion of the file using the provided backup stream.
func (w *BackupFileWriter) Write(b []byte) (int, error) {
var bytesWritten uint32
err := backupWrite(syscall.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx)
err := backupWrite(windows.Handle(w.f.Fd()), b, &bytesWritten, false, w.includeSecurity, &w.ctx)
if err != nil {
return 0, &os.PathError{"BackupWrite", w.f.Name(), err}
}
Expand All @@ -257,7 +256,7 @@ func (w *BackupFileWriter) Write(b []byte) (int, error) {
// close the underlying file.
func (w *BackupFileWriter) Close() error {
if w.ctx != 0 {
backupWrite(syscall.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx)
backupWrite(windows.Handle(w.f.Fd()), nil, nil, true, false, &w.ctx)
runtime.KeepAlive(w.f)
w.ctx = 0
}
Expand All @@ -269,11 +268,11 @@ func (w *BackupFileWriter) Close() error {
//
// If the file opened was a directory, it cannot be used with Readdir().
func OpenForBackup(path string, access uint32, share uint32, createmode uint32) (*os.File, error) {
winPath, err := syscall.UTF16FromString(path)
winPath, err := windows.UTF16FromString(path)
if err != nil {
return nil, err
}
h, err := syscall.CreateFile(&winPath[0], access, share, nil, createmode, windows.FILE_FLAG_BACKUP_SEMANTICS|windows.FILE_FLAG_OPEN_REPARSE_POINT, 0)
h, err := windows.CreateFile(&winPath[0], access, share, nil, createmode, windows.FILE_FLAG_BACKUP_SEMANTICS|windows.FILE_FLAG_OPEN_REPARSE_POINT, 0)
if err != nil {
err = &os.PathError{Op: "open", Path: path, Err: err}
return nil, err
Expand Down
5 changes: 3 additions & 2 deletions backup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import (
"io"
"io/ioutil"
"os"
"syscall"
"testing"

"golang.org/x/sys/windows"
)

var testFileName string
Expand Down Expand Up @@ -205,7 +206,7 @@ func makeSparseFile() error {
FSCTL_SET_ZERO_DATA = 0x000980c8
)

err = syscall.DeviceIoControl(syscall.Handle(f.Fd()), FSCTL_SET_SPARSE, nil, 0, nil, 0, nil, nil)
err = windows.DeviceIoControl(windows.Handle(f.Fd()), FSCTL_SET_SPARSE, nil, 0, nil, 0, nil, nil)
if err != nil {
return err
}
Expand Down
5 changes: 3 additions & 2 deletions ea_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import (
"io/ioutil"
"os"
"reflect"
"syscall"
"testing"
"unsafe"

"golang.org/x/sys/windows"
)

var (
Expand Down Expand Up @@ -81,7 +82,7 @@ func Test_SetFileEa(t *testing.T) {
}
defer os.Remove(f.Name())
defer f.Close()
ntdll := syscall.MustLoadDLL("ntdll.dll")
ntdll := windows.MustLoadDLL("ntdll.dll")
ntSetEaFile := ntdll.MustFindProc("NtSetEaFile")
var iosb [2]uintptr
r, _, _ := ntSetEaFile.Call(f.Fd(), uintptr(unsafe.Pointer(&iosb[0])), uintptr(unsafe.Pointer(&testEasEncoded[0])), uintptr(len(testEasEncoded)))
Expand Down
46 changes: 22 additions & 24 deletions file.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,13 @@ import (
"runtime"
"sync"
"sync/atomic"
"syscall"
"time"
"unsafe"

"golang.org/x/sys/windows"
)

//sys cancelIoEx(file syscall.Handle, o *syscall.Overlapped) (err error) = CancelIoEx
//sys createIoCompletionPort(file syscall.Handle, port syscall.Handle, key uintptr, threadCount uint32) (newport syscall.Handle, err error) = CreateIoCompletionPort
//sys getQueuedCompletionStatus(port syscall.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus
//sys setFileCompletionNotificationModes(h syscall.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes
//sys wsaGetOverlappedResult(h syscall.Handle, o *syscall.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult
//sys wsaGetOverlappedResult(h windows.Handle, o *windows.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult

type atomicBool int32

Expand Down Expand Up @@ -52,7 +48,7 @@ func (e *timeoutError) Temporary() bool { return true }
type timeoutChan chan struct{}

var ioInitOnce sync.Once
var ioCompletionPort syscall.Handle
var ioCompletionPort windows.Handle

// ioResult contains the result of an asynchronous IO operation
type ioResult struct {
Expand All @@ -62,12 +58,12 @@ type ioResult struct {

// ioOperation represents an outstanding asynchronous Win32 IO
type ioOperation struct {
o syscall.Overlapped
o windows.Overlapped
ch chan ioResult
}

func initIo() {
h, err := createIoCompletionPort(syscall.InvalidHandle, 0, 0, 0xffffffff)
h, err := windows.CreateIoCompletionPort(windows.InvalidHandle, 0, 0, 0xffffffff)
if err != nil {
panic(err)
}
Expand All @@ -78,7 +74,7 @@ func initIo() {
// win32File implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall.
// It takes ownership of this handle and will close it if it is garbage collected.
type win32File struct {
handle syscall.Handle
handle windows.Handle
wg sync.WaitGroup
wgLock sync.RWMutex
closing atomicBool
Expand All @@ -96,14 +92,14 @@ type deadlineHandler struct {
}

// makeWin32File makes a new win32File from an existing file handle
func makeWin32File(h syscall.Handle) (*win32File, error) {
func makeWin32File(h windows.Handle) (*win32File, error) {
f := &win32File{handle: h}
ioInitOnce.Do(initIo)
_, err := createIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff)
_, err := windows.CreateIoCompletionPort(h, ioCompletionPort, 0, 0xffffffff)
if err != nil {
return nil, err
}
err = setFileCompletionNotificationModes(h, cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS|cFILE_SKIP_SET_EVENT_ON_HANDLE)
err = windows.SetFileCompletionNotificationModes(h, cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS|cFILE_SKIP_SET_EVENT_ON_HANDLE)
if err != nil {
return nil, err
}
Expand All @@ -112,7 +108,7 @@ func makeWin32File(h syscall.Handle) (*win32File, error) {
return f, nil
}

func MakeOpenFile(h syscall.Handle) (io.ReadWriteCloser, error) {
func MakeOpenFile(h windows.Handle) (io.ReadWriteCloser, error) {
// If we return the result of makeWin32File directly, it can result in an
// interface-wrapped nil, rather than a nil interface value.
f, err := makeWin32File(h)
Expand All @@ -129,10 +125,10 @@ func (f *win32File) closeHandle() {
if !f.closing.swap(true) {
f.wgLock.Unlock()
// cancel all IO and wait for it to complete
cancelIoEx(f.handle, nil)
windows.CancelIoEx(f.handle, nil)
f.wg.Wait()
// at this point, no new IO can start
syscall.Close(f.handle)
windows.Close(f.handle)
f.handle = 0
} else {
f.wgLock.Unlock()
Expand Down Expand Up @@ -161,12 +157,14 @@ func (f *win32File) prepareIo() (*ioOperation, error) {
}

// ioCompletionProcessor processes completed async IOs forever
func ioCompletionProcessor(h syscall.Handle) {
func ioCompletionProcessor(h windows.Handle) {
for {
var bytes uint32
var key uintptr
var key uint32
var op *ioOperation
err := getQueuedCompletionStatus(h, &bytes, &key, &op, windows.INFINITE)
// Safe: windows.Overlapped is the leading member of ioOperation
opPtr := (**windows.Overlapped)(unsafe.Pointer(&op))
err := windows.GetQueuedCompletionStatus(h, &bytes, &key, opPtr, windows.INFINITE)
if op == nil {
panic(err)
}
Expand All @@ -182,7 +180,7 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er
}

if f.closing.isSet() {
cancelIoEx(f.handle, &c.o)
windows.CancelIoEx(f.handle, &c.o)
}

var timeout timeoutChan
Expand All @@ -206,7 +204,7 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er
err = wsaGetOverlappedResult(f.handle, &c.o, &bytes, false, &flags)
}
case <-timeout:
cancelIoEx(f.handle, &c.o)
windows.CancelIoEx(f.handle, &c.o)
r = <-c.ch
err = r.err
if err == windows.ERROR_OPERATION_ABORTED {
Expand Down Expand Up @@ -234,7 +232,7 @@ func (f *win32File) Read(b []byte) (int, error) {
}

var bytes uint32
err = syscall.ReadFile(f.handle, b, &bytes, &c.o)
err = windows.ReadFile(f.handle, b, &bytes, &c.o)
n, err := f.asyncIo(c, &f.readDeadline, bytes, err)
runtime.KeepAlive(b)

Expand All @@ -261,7 +259,7 @@ func (f *win32File) Write(b []byte) (int, error) {
}

var bytes uint32
err = syscall.WriteFile(f.handle, b, &bytes, &c.o)
err = windows.WriteFile(f.handle, b, &bytes, &c.o)
n, err := f.asyncIo(c, &f.writeDeadline, bytes, err)
runtime.KeepAlive(b)
return n, err
Expand All @@ -276,7 +274,7 @@ func (f *win32File) SetWriteDeadline(deadline time.Time) error {
}

func (f *win32File) Flush() error {
return syscall.FlushFileBuffers(f.handle)
return windows.FlushFileBuffers(f.handle)
}

func (f *win32File) Fd() uintptr {
Expand Down
25 changes: 12 additions & 13 deletions hvsock.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,14 @@ import (
"io"
"net"
"os"
"syscall"
"time"
"unsafe"

"github.com/Microsoft/go-winio/pkg/guid"
"golang.org/x/sys/windows"
)

//sys bind(s syscall.Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socketError] = ws2_32.bind
//sys bind(s windows.Handle, name unsafe.Pointer, namelen int32) (err error) [failretval==socketError] = ws2_32.bind

const (
afHvSock = 34 // AF_HYPERV
Expand Down Expand Up @@ -78,13 +77,13 @@ type HvsockConn struct {
}

func newHvSocket() (*win32File, error) {
fd, err := syscall.Socket(afHvSock, windows.SOCK_STREAM, 1)
fd, err := windows.Socket(afHvSock, windows.SOCK_STREAM, 1)
if err != nil {
return nil, os.NewSyscallError("socket", err)
}
f, err := makeWin32File(fd)
if err != nil {
syscall.Close(fd)
windows.Close(fd)
return nil, err
}
f.socket = true
Expand All @@ -103,7 +102,7 @@ func ListenHvsock(addr *HvsockAddr) (_ *HvsockListener, err error) {
if err != nil {
return nil, l.opErr("listen", os.NewSyscallError("socket", err))
}
err = syscall.Listen(sock.handle, 16)
err = windows.Listen(sock.handle, 16)
if err != nil {
return nil, l.opErr("listen", os.NewSyscallError("listen", err))
}
Expand Down Expand Up @@ -141,7 +140,7 @@ func (l *HvsockListener) Accept() (_ net.Conn, err error) {
var addrbuf [addrlen * 2]byte

var bytes uint32
err = syscall.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0, addrlen, addrlen, &bytes, &c.o)
err = windows.AcceptEx(l.sock.handle, sock.handle, &addrbuf[0], 0, addrlen, addrlen, &bytes, &c.o)
_, err = l.sock.asyncIo(c, nil, bytes, err)
if err != nil {
return nil, l.opErr("accept", os.NewSyscallError("acceptex", err))
Expand Down Expand Up @@ -201,12 +200,12 @@ func (conn *HvsockConn) Read(b []byte) (int, error) {
return 0, conn.opErr("read", err)
}
defer conn.sock.wg.Done()
buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
buf := windows.WSABuf{Buf: &b[0], Len: uint32(len(b))}
var flags, bytes uint32
err = syscall.WSARecv(conn.sock.handle, &buf, 1, &bytes, &flags, &c.o, nil)
err = windows.WSARecv(conn.sock.handle, &buf, 1, &bytes, &flags, &c.o, nil)
n, err := conn.sock.asyncIo(c, &conn.sock.readDeadline, bytes, err)
if err != nil {
if _, ok := err.(syscall.Errno); ok {
if _, ok := err.(windows.Errno); ok {
err = os.NewSyscallError("wsarecv", err)
}
return 0, conn.opErr("read", err)
Expand Down Expand Up @@ -235,12 +234,12 @@ func (conn *HvsockConn) write(b []byte) (int, error) {
return 0, conn.opErr("write", err)
}
defer conn.sock.wg.Done()
buf := syscall.WSABuf{Buf: &b[0], Len: uint32(len(b))}
buf := windows.WSABuf{Buf: &b[0], Len: uint32(len(b))}
var bytes uint32
err = syscall.WSASend(conn.sock.handle, &buf, 1, &bytes, 0, &c.o, nil)
err = windows.WSASend(conn.sock.handle, &buf, 1, &bytes, 0, &c.o, nil)
n, err := conn.sock.asyncIo(c, &conn.sock.writeDeadline, bytes, err)
if err != nil {
if _, ok := err.(syscall.Errno); ok {
if _, ok := err.(windows.Errno); ok {
err = os.NewSyscallError("wsasend", err)
}
return 0, conn.opErr("write", err)
Expand All @@ -254,7 +253,7 @@ func (conn *HvsockConn) Close() error {
}

func (conn *HvsockConn) shutdown(how int) error {
err := syscall.Shutdown(conn.sock.handle, windows.SHUT_RD)
err := windows.Shutdown(conn.sock.handle, windows.SHUT_RD)
if err != nil {
return os.NewSyscallError("shutdown", err)
}
Expand Down
Loading

0 comments on commit 0ba5488

Please sign in to comment.