Update Red Hat Copyright Notices
[nbdkit.git] / plugins / golang / src / libguestfs.org / nbdkit / nbdkit.go
bloba047c1937e95516ac163756a57504cca172b919a
1 /* Go helper functions.
2 * Copyright Red Hat
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * * Neither the name of Red Hat nor the names of its contributors may be
16 * used to endorse or promote products derived from this software without
17 * specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY RED HAT AND CONTRIBUTORS ''AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
22 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL RED HAT OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
29 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
33 package nbdkit
36 #cgo pkg-config: nbdkit
37 #cgo LDFLAGS: -Wl,--unresolved-symbols=ignore-in-object-files
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <errno.h>
43 #define NBDKIT_API_VERSION 2
44 #include <nbdkit-plugin.h>
45 #include "wrappers.h"
47 import "C"
49 import (
50 "fmt"
51 "reflect"
52 "syscall"
53 "unsafe"
56 // The plugin may raise errors by returning this struct (instead of nil).
57 type PluginError struct {
58 Errmsg string // string (passed to nbdkit_error)
59 Errno syscall.Errno // errno (optional, use 0 if not available)
62 func (e PluginError) String() string {
63 if e.Errno != 0 {
64 return e.Errmsg
65 } else {
66 return fmt.Sprintf("%s (errno %d)", e.Errmsg, e.Errno)
70 func (e PluginError) Error() string {
71 return e.String()
74 // Flags and other constants.
75 const (
76 ThreadModelSerializeConnections = uint32(C.NBDKIT_THREAD_MODEL_SERIALIZE_CONNECTIONS)
77 ThreadModelSerializeAllRequests = uint32(C.NBDKIT_THREAD_MODEL_SERIALIZE_ALL_REQUESTS)
78 ThreadModelSerializeRequests = uint32(C.NBDKIT_THREAD_MODEL_SERIALIZE_REQUESTS)
79 ThreadModelParallel = uint32(C.NBDKIT_THREAD_MODEL_PARALLEL)
81 FlagMayTrim = uint32(C.NBDKIT_FLAG_MAY_TRIM)
82 FlagFUA = uint32(C.NBDKIT_FLAG_FUA)
83 FlagReqOne = uint32(C.NBDKIT_FLAG_REQ_ONE)
84 FlagFastZero = uint32(C.NBDKIT_FLAG_FAST_ZERO)
86 FUANone = uint32(C.NBDKIT_FUA_NONE)
87 FUAEmulate = uint32(C.NBDKIT_FUA_EMULATE)
88 FUANative = uint32(C.NBDKIT_FUA_NATIVE)
90 CacheNone = uint32(C.NBDKIT_CACHE_NONE)
91 CacheEmulate = uint32(C.NBDKIT_CACHE_EMULATE)
92 CacheNative = uint32(C.NBDKIT_CACHE_NATIVE)
94 ExtentHole = uint32(C.NBDKIT_EXTENT_HOLE)
95 ExtentZero = uint32(C.NBDKIT_EXTENT_ZERO)
97 // This is not defined by the header, but by this file. It
98 // might be useful for plugins to know this (even though they
99 // probably wouldn't be source-compatible with other API
100 // versions) so we expose it to golang code.
101 APIVersion = uint32(C.NBDKIT_API_VERSION)
104 // The plugin interface.
105 type PluginInterface interface {
106 Load()
107 Unload()
109 DumpPlugin()
111 Config(key string, value string) error
112 ConfigComplete() error
113 GetReady() error
115 PreConnect(readonly bool) error
116 Open(readonly bool) (ConnectionInterface, error) // required
119 // The client connection interface.
120 type ConnectionInterface interface {
121 GetSize() (uint64, error) // required
122 IsRotational() (bool, error)
123 CanMultiConn() (bool, error)
125 PRead(buf []byte, offset uint64, flags uint32) error // required
127 // NB: PWrite will NOT be called unless CanWrite returns true.
128 CanWrite() (bool, error)
129 PWrite(buf []byte, offset uint64, flags uint32) error
131 // NB: Flush will NOT be called unless CanFlush returns true.
132 CanFlush() (bool, error)
133 Flush(flags uint32) error
135 // NB: Trim will NOT be called unless CanTrim returns true.
136 CanTrim() (bool, error)
137 Trim(count uint32, offset uint64, flags uint32) error
139 // NB: Zero will NOT be called unless CanZero returns true.
140 CanZero() (bool, error)
141 Zero(count uint32, offset uint64, flags uint32) error
143 Close()
146 // Default implementations for plugin interface methods.
147 type Plugin struct{}
148 type Connection struct{}
150 func (p *Plugin) Load() {
153 func (p *Plugin) Unload() {
156 func (p *Plugin) DumpPlugin() {
159 func (p *Plugin) Config(key string, value string) error {
160 return nil
163 func (p *Plugin) ConfigComplete() error {
164 return nil
167 func (p *Plugin) GetReady() error {
168 return nil
171 func (p *Plugin) PreConnect(readonly bool) error {
172 return nil
175 func (p *Plugin) Open(readonly bool) (ConnectionInterface, error) {
176 panic("plugin must implement Open()")
179 func (c *Connection) Close() {
182 func (c *Connection) GetSize() (uint64, error) {
183 panic("plugin must implement GetSize()")
186 func (c *Connection) CanWrite() (bool, error) {
187 return false, nil
190 func (c *Connection) CanFlush() (bool, error) {
191 return false, nil
194 func (c *Connection) IsRotational() (bool, error) {
195 return false, nil
198 func (c *Connection) CanTrim() (bool, error) {
199 return false, nil
202 func (c *Connection) CanZero() (bool, error) {
203 return false, nil
206 func (c *Connection) CanMultiConn() (bool, error) {
207 return false, nil
210 func (c *Connection) PRead(buf []byte, offset uint64, flags uint32) error {
211 panic("plugin must implement PRead()")
214 func (c *Connection) PWrite(buf []byte, offset uint64, flags uint32) error {
215 panic("plugin CanWrite returns true, but no PWrite() function")
218 func (c *Connection) Flush(flags uint32) error {
219 panic("plugin CanFlush returns true, but no Flush() function")
222 func (c *Connection) Trim(count uint32, offset uint64, flags uint32) error {
223 panic("plugin CanTrim returns true, but no Trim() function")
226 func (c *Connection) Zero(count uint32, offset uint64, flags uint32) error {
227 panic("plugin CanZero returns true, but no Zero() function")
230 // The implementation of the user plugin.
231 var pluginImpl PluginInterface
232 var nextConnectionId uintptr
233 var connectionMap map[uintptr]ConnectionInterface
235 // Callbacks from the server. These translate C to Go and back.
237 func set_error(err error) {
238 perr, ok := err.(PluginError)
239 if ok {
240 if perr.Errno != 0 {
241 SetError(perr.Errno)
243 Error(perr.Errmsg)
244 } else {
245 Error(err.Error())
249 //export implLoad
250 func implLoad() {
251 pluginImpl.Load()
254 //export implUnload
255 func implUnload() {
256 pluginImpl.Unload()
259 //export implDumpPlugin
260 func implDumpPlugin() {
261 pluginImpl.DumpPlugin()
264 //export implConfig
265 func implConfig(key *C.char, value *C.char) C.int {
266 err := pluginImpl.Config(C.GoString(key), C.GoString(value))
267 if err != nil {
268 set_error(err)
269 return -1
271 return 0
274 //export implConfigComplete
275 func implConfigComplete() C.int {
276 err := pluginImpl.ConfigComplete()
277 if err != nil {
278 set_error(err)
279 return -1
281 return 0
284 //export implGetReady
285 func implGetReady() C.int {
286 err := pluginImpl.GetReady()
287 if err != nil {
288 set_error(err)
289 return -1
291 return 0
294 //export implPreConnect
295 func implPreConnect(c_readonly C.int) C.int {
296 readonly := false
297 if c_readonly != 0 {
298 readonly = true
300 err := pluginImpl.PreConnect(readonly)
301 if err != nil {
302 set_error(err)
303 return -1
305 return 0
308 //export implOpen
309 func implOpen(c_readonly C.int) unsafe.Pointer {
310 readonly := false
311 if c_readonly != 0 {
312 readonly = true
314 h, err := pluginImpl.Open(readonly)
315 if err != nil {
316 set_error(err)
317 return nil
319 id := nextConnectionId
320 nextConnectionId++
321 connectionMap[id] = h
322 return unsafe.Pointer(id)
325 func getConn(handle unsafe.Pointer) ConnectionInterface {
326 id := uintptr(handle)
327 h, ok := connectionMap[id]
328 if !ok {
329 panic(fmt.Sprintf("connection %d was not open", id))
331 return h
334 //export implClose
335 func implClose(handle unsafe.Pointer) {
336 h := getConn(handle)
337 h.Close()
338 id := uintptr(handle)
339 delete(connectionMap, id)
342 //export implGetSize
343 func implGetSize(handle unsafe.Pointer) C.int64_t {
344 h := getConn(handle)
345 size, err := h.GetSize()
346 if err != nil {
347 set_error(err)
348 return -1
350 return C.int64_t(size)
353 //export implCanWrite
354 func implCanWrite(handle unsafe.Pointer) C.int {
355 h := getConn(handle)
356 b, err := h.CanWrite()
357 if err != nil {
358 set_error(err)
359 return -1
361 if b {
362 return 1
363 } else {
364 return 0
368 //export implCanFlush
369 func implCanFlush(handle unsafe.Pointer) C.int {
370 h := getConn(handle)
371 b, err := h.CanFlush()
372 if err != nil {
373 set_error(err)
374 return -1
376 if b {
377 return 1
378 } else {
379 return 0
383 //export implIsRotational
384 func implIsRotational(handle unsafe.Pointer) C.int {
385 h := getConn(handle)
386 b, err := h.IsRotational()
387 if err != nil {
388 set_error(err)
389 return -1
391 if b {
392 return 1
393 } else {
394 return 0
398 //export implCanTrim
399 func implCanTrim(handle unsafe.Pointer) C.int {
400 h := getConn(handle)
401 b, err := h.CanTrim()
402 if err != nil {
403 set_error(err)
404 return -1
406 if b {
407 return 1
408 } else {
409 return 0
413 //export implCanZero
414 func implCanZero(handle unsafe.Pointer) C.int {
415 h := getConn(handle)
416 b, err := h.CanZero()
417 if err != nil {
418 set_error(err)
419 return -1
421 if b {
422 return 1
423 } else {
424 return 0
428 //export implCanMultiConn
429 func implCanMultiConn(handle unsafe.Pointer) C.int {
430 h := getConn(handle)
431 b, err := h.CanMultiConn()
432 if err != nil {
433 set_error(err)
434 return -1
436 if b {
437 return 1
438 } else {
439 return 0
443 //export implPRead
444 func implPRead(handle unsafe.Pointer, c_buf unsafe.Pointer,
445 count C.uint32_t, offset C.uint64_t, flags C.uint32_t) C.int {
446 h := getConn(handle)
447 // https://github.com/golang/go/issues/13656
448 // https://stackoverflow.com/a/25776046
449 hdr := reflect.SliceHeader{
450 Data: uintptr(c_buf),
451 Len: int(count),
452 Cap: int(count),
454 buf := *(*[]byte)(unsafe.Pointer(&hdr))
455 err := h.PRead(buf, uint64(offset), uint32(flags))
456 if err != nil {
457 set_error(err)
458 return -1
460 return 0
463 //export implPWrite
464 func implPWrite(handle unsafe.Pointer, c_buf unsafe.Pointer,
465 count C.uint32_t, offset C.uint64_t, flags C.uint32_t) C.int {
466 h := getConn(handle)
467 // https://github.com/golang/go/issues/13656
468 // https://stackoverflow.com/a/25776046
469 hdr := reflect.SliceHeader{
470 Data: uintptr(c_buf),
471 Len: int(count),
472 Cap: int(count),
474 buf := *(*[]byte)(unsafe.Pointer(&hdr))
475 err := h.PWrite(buf, uint64(offset), uint32(flags))
476 if err != nil {
477 set_error(err)
478 return -1
480 return 0
483 //export implFlush
484 func implFlush(handle unsafe.Pointer, flags C.uint32_t) C.int {
485 h := getConn(handle)
486 err := h.Flush(uint32(flags))
487 if err != nil {
488 set_error(err)
489 return -1
491 return 0
494 //export implTrim
495 func implTrim(handle unsafe.Pointer,
496 count C.uint32_t, offset C.uint64_t, flags C.uint32_t) C.int {
497 h := getConn(handle)
498 err := h.Trim(uint32(count), uint64(offset), uint32(flags))
499 if err != nil {
500 set_error(err)
501 return -1
503 return 0
506 //export implZero
507 func implZero(handle unsafe.Pointer,
508 count C.uint32_t, offset C.uint64_t, flags C.uint32_t) C.int {
509 h := getConn(handle)
510 err := h.Zero(uint32(count), uint64(offset), uint32(flags))
511 if err != nil {
512 set_error(err)
513 return -1
515 return 0
518 // Called from C plugin_init function.
519 func PluginInitialize(name string, impl PluginInterface) unsafe.Pointer {
520 // Initialize the connection map. Note that connection IDs
521 // must start counting from 1 since we must never return what
522 // looks like a NULL pointer to the C code.
523 connectionMap = make(map[uintptr]ConnectionInterface)
524 nextConnectionId = 1
526 pluginImpl = impl
528 plugin := C.struct_nbdkit_plugin{}
530 // Set up the hidden plugin fields as for C.
531 struct_size := C.ulong(unsafe.Sizeof(plugin))
532 plugin._struct_size = C.uint64_t(struct_size)
533 plugin._api_version = C.NBDKIT_API_VERSION
534 plugin._thread_model = C.NBDKIT_THREAD_MODEL_PARALLEL
536 // Set up the other fields.
537 plugin.name = C.CString(name)
538 plugin.load = (*[0]byte)(C.wrapper_load)
539 plugin.unload = (*[0]byte)(C.wrapper_unload)
540 plugin.dump_plugin = (*[0]byte)(C.wrapper_dump_plugin)
541 plugin.config = (*[0]byte)(C.wrapper_config)
542 plugin.config_complete = (*[0]byte)(C.wrapper_config_complete)
543 plugin.get_ready = (*[0]byte)(C.wrapper_get_ready)
544 plugin.preconnect = (*[0]byte)(C.wrapper_preconnect)
545 plugin.open = (*[0]byte)(C.wrapper_open)
546 plugin.close = (*[0]byte)(C.wrapper_close)
547 plugin.get_size = (*[0]byte)(C.wrapper_get_size)
548 plugin.can_write = (*[0]byte)(C.wrapper_can_write)
549 plugin.can_flush = (*[0]byte)(C.wrapper_can_flush)
550 plugin.is_rotational = (*[0]byte)(C.wrapper_is_rotational)
551 plugin.can_trim = (*[0]byte)(C.wrapper_can_trim)
552 plugin.can_zero = (*[0]byte)(C.wrapper_can_zero)
553 plugin.can_multi_conn = (*[0]byte)(C.wrapper_can_multi_conn)
554 plugin.pread = (*[0]byte)(C.wrapper_pread)
555 plugin.pwrite = (*[0]byte)(C.wrapper_pwrite)
556 plugin.flush = (*[0]byte)(C.wrapper_flush)
557 plugin.trim = (*[0]byte)(C.wrapper_trim)
558 plugin.zero = (*[0]byte)(C.wrapper_zero)
560 // Golang plugins don't preserve errno correctly.
561 plugin.errno_is_preserved = 0
563 // Return a newly malloced copy of the struct. This must be
564 // globally available to the C code in the server, so it is
565 // never freed.
566 p := (*C.struct_nbdkit_plugin)(C.malloc(C.size_t(struct_size)))
567 *p = plugin
568 return unsafe.Pointer(p)