overlapped

package module
v1.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 9, 2022 License: MIT Imports: 7 Imported by: 3

README

overlapped

Go Reference gopherbadger-tag-do-not-edit

Provides easy asynchronous (and synchronous) I/O to any windows.Handle by abstracting away the need to manage OVERLAPPED struct and event handles.

Initial code was based on the MIT licensed overlappedFile struct implementation by @jstarks, more information on the ORIGINAL file.

Usage

func ReadAndWrite(path []uint16) {
	handle, _ := windows.CreateFile(
		&path[0],
		windows.GENERIC_READ | windows.GENERIC_WRITE,
		windows.FILE_SHARE_READ | windows.FILE_SHARE_WRITE,
		nil,
		windows.OPEN_EXISTING,
		windows.FILE_FLAG_OVERLAPPED,
		0)
	h := overlapped.New(handle)
	defer h.Close()
	go func() {
		b := make([]byte, 10)
		n, _ := h.Read(b)
		fmt.Println(string(b[:n])) // Foobar
	}()
	fmt.Fprint(h, "Foobar")
}

By default calls are blocking. This can be controlled by setting Handle.DefaultTimeout on per-handle basis.

  • -1: blocking
  • 0: non-blocking
  • >0: with timeout

Custom I/O

Handle.Custom() allows using the underlying functionality to call any function that shares signature with windows.ReadFile and windows.WriteFile. This allows for example wrapping other syscalls that expect use of OVERLAPPED.

Usage
func AlwaysReadFoobar(handle windows.Handle) (b []byte, err error) {
	h := overlapped.New(handle)
	fn := func(h windows.Handle, b []byte, n *uint32, o *windows.Overlapped) error {
		*n = uint32(copy(b, []byte("Foobar")))
		return nil
	}
	_, err = h.Custom(fn, b, -1)
	return
}

Warning

overlapped.Handle does not retain position between reads and writes. This can cause issues when doing things like ioutil.ReadAll that expect to receive io.EOF after they read the last bit of data.

While the main case of this library is not for large static files there are couple ways past this issue if needed:

  • First option is to use Handle.ReadAt() and keep track of position based on how many bytes have been read.
  • Second option is to use the provided PositionHandle struct to wrap the overlapped.Handle and use that.
PositionHandle

overlapped.PositionHandle wraps overlapped.Handle while keeping track of the read/write position between calls.

The position is shared between read and write calls, so a single PositionHandle should only be used for single use and additional ones should be created for other clients. This allows PositionHandle to be used for reading content that doesn't fit the size of a single buffer, or using functions like ioutil.ReadAll that require io.EOF to be passed after all data has been read.

Usage
func ReadHandle(handle windows.Handle) (b []byte, err error) {
	h := overlapped.New(handle)
	ph := &PositionHandle{Handle: h}
	b, err = ioutil.ReadAll(ph)
}

Issues & Contributing

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Handle

type Handle struct {

	// DefaultTimeout allows changing the default timeout used for Write() and Read() functions. Defaults to -1 (blocking)
	DefaultTimeout int
	// contains filtered or unexported fields
}

func New

func New(h windows.Handle) *Handle

New returns a new overlapped.Handle that wraps the original handle, allowing both asynchronous and synchronous I/O.

func (*Handle) Close

func (f *Handle) Close() error

Close cancels all currently waiting reads/writes, closes the wrapped handle, as well as all event handles created for overlapped I/O.

func (*Handle) Custom added in v1.0.3

func (f *Handle) Custom(fn func(windows.Handle, []byte, *uint32, *windows.Overlapped) error, b []byte, milliseconds int) (int, error)

Custom allows I/O using function that has the same signature as windows.ReadFile/windows.WriteFile

Example
f, h, err := newFile()
if err != nil {
	return
}
defer os.Remove(f.Name())
defer windows.CloseHandle(h)

oh := New(h)
defer oh.Close()

go func() {
	fmt.Fprint(oh, "Bacon")
}()

time.Sleep(time.Millisecond * 10)
b := make([]byte, 10)
fn := func(h windows.Handle, b []byte, n *uint32, o *windows.Overlapped) error {
	*n = uint32(copy(b, []byte("Foobar")))
	return nil
}
n, _ := oh.Custom(fn, b, -1)
fmt.Print(string(b[:n]))
Output:

Foobar

func (*Handle) Read

func (f *Handle) Read(b []byte) (int, error)

Read reads from the wrapped handle, using the timeout set in Handle.DefaultTimeout (default: -1)

Example
f, h, err := newFile()
if err != nil {
	return
}
defer os.Remove(f.Name())
defer windows.CloseHandle(h)

oh := New(h)
defer oh.Close()

go func() {
	fmt.Fprint(oh, "Foobar")
}()

time.Sleep(time.Millisecond * 10)
b := make([]byte, 10)
n, _ := oh.Read(b)
fmt.Print(string(b[:n]))
Output:

Foobar

func (*Handle) ReadAt

func (f *Handle) ReadAt(b []byte, off int64) (int, error)

ReadAt reads from specific offset, using the timeout set in Handle.DefaultTimeout (default: -1)

Example
f, h, _ := newFile()
defer os.Remove(f.Name())

oh := New(h)
defer oh.Close()

fmt.Fprint(oh, "Bacon")

b := make([]byte, 3)
var pos int64 = 0
for i := 0; i < 3; i++ {
	n, err := oh.ReadAt(b, pos)
	pos += int64(n)
	fmt.Println(string(b[:n]), err)
	
Output:

Bac <nil>
on EOF
 EOF

func (*Handle) ReadTimeout

func (f *Handle) ReadTimeout(b []byte, milliseconds int) (int, error)

ReadTimeout reads from the wrapped handle, allowing custom timeout to be set

-1: blocking
 0: non-blocking
>0: with timeout

func (*Handle) Write

func (f *Handle) Write(b []byte) (int, error)

Read writes to the wrapped handle, using the timeout set in Handle.DefaultTimeout (default: -1)

func (*Handle) WriteAt

func (f *Handle) WriteAt(b []byte, off int64) (int, error)

Read writes from specific offset, using the timeout set in Handle.DefaultTimeout (default: -1)

func (*Handle) WriteTimeout

func (f *Handle) WriteTimeout(b []byte, milliseconds int) (int, error)

WriteTimeout writes into the wrapped handle, allowing custom timeout to be set

-1: blocking
 0: non-blocking
>0: with timeout

type PositionHandle

type PositionHandle struct {
	*Handle
	// contains filtered or unexported fields
}

Positionhandle wraps overlapped.Handle, keeping a pointer at the location where last read/write ended. The position is shared between writes and reads, so a PositionHandle should not be shared between different uses, instead a new PositionHandle can be created for each client if needed.

func (*PositionHandle) Read

func (f *PositionHandle) Read(b []byte) (int, error)

Read reads forward from the current position and moves the position forward the amount read

Example
f, h, _ := newFile()
defer os.Remove(f.Name())

oh := New(h)
defer oh.Close()

fmt.Fprint(oh, "Bacon")

oh2 := &PositionHandle{Handle: New(h)}
b := make([]byte, 3)
for i := 0; i < 3; i++ {
	n, err := oh2.Read(b)
	fmt.Println(string(b[:n]), err)
	
Output:

Bac <nil>
on <nil>
 EOF

func (*PositionHandle) Write

func (f *PositionHandle) Write(b []byte) (int, error)

Write writes to the current position and moves the position forward the amount written

Example
f, h, err := newFile()
if err != nil {
	return
}
defer os.Remove(f.Name())
defer windows.CloseHandle(h)

oh := New(h)
ph := &PositionHandle{Handle: oh}
defer oh.Close()

ph.Write([]byte("Ba"))
ph.Write([]byte("con"))

rh := &PositionHandle{Handle: oh}
b, _ := ioutil.ReadAll(rh)
fmt.Print(string(b))
Output:

Bacon

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL